| 
									
										
										
										
											2021-03-10 11:51:53 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  Copyright 2021 The KubeVela Authors. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  You may obtain a copy of the License at | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  limitations under the License. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | package utils | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/crossplane/crossplane-runtime/pkg/test" | 
					
						
							|  |  |  | 	"github.com/getkin/kin-openapi/openapi3" | 
					
						
							|  |  |  | 	"github.com/google/go-cmp/cmp" | 
					
						
							|  |  |  | 	"gotest.tools/assert" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-24 13:27:29 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/apis/core.oam.dev/common" | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/apis/types" | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/appfile" | 
					
						
							| 
									
										
										
										
											2021-06-02 15:37:06 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/cue" | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/utils/system" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const TestDir = "testdata/definition" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestGetOpenAPISchema(t *testing.T) { | 
					
						
							|  |  |  | 	type want struct { | 
					
						
							|  |  |  | 		data string | 
					
						
							|  |  |  | 		err  error | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cases := map[string]struct { | 
					
						
							| 
									
										
										
										
											2021-05-19 20:08:51 +08:00
										 |  |  | 		reason string | 
					
						
							|  |  |  | 		name   string | 
					
						
							|  |  |  | 		data   string | 
					
						
							|  |  |  | 		want   want | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 	}{ | 
					
						
							| 
									
										
										
										
											2021-05-19 20:08:51 +08:00
										 |  |  | 		"parameter in cue is a structure type,": { | 
					
						
							|  |  |  | 			reason: "Prepare a normal parameter cue file", | 
					
						
							|  |  |  | 			name:   "workload1", | 
					
						
							|  |  |  | 			data: ` | 
					
						
							|  |  |  | project: { | 
					
						
							|  |  |  | 	name: string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	parameter: { | 
					
						
							|  |  |  | 	min: int | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | `, | 
					
						
							|  |  |  | 			want: want{data: "{\"properties\":{\"min\":{\"title\":\"min\",\"type\":\"integer\"}},\"required\":[\"min\"],\"type\":\"object\"}", err: nil}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"parameter in cue is a dict type,": { | 
					
						
							|  |  |  | 			reason: "Prepare a normal parameter cue file", | 
					
						
							|  |  |  | 			name:   "workload2", | 
					
						
							|  |  |  | 			data: ` | 
					
						
							|  |  |  | annotations: { | 
					
						
							|  |  |  | 	for k, v in parameter { | 
					
						
							|  |  |  | 		"\(k)": v | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | parameter: [string]: string | 
					
						
							|  |  |  | `, | 
					
						
							|  |  |  | 			want: want{data: "{\"additionalProperties\":{\"type\":\"string\"},\"type\":\"object\"}", err: nil}, | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2021-05-19 20:08:51 +08:00
										 |  |  | 		"parameter in cue is a string type,": { | 
					
						
							|  |  |  | 			reason: "Prepare a normal parameter cue file", | 
					
						
							|  |  |  | 			name:   "workload3", | 
					
						
							|  |  |  | 			data: ` | 
					
						
							|  |  |  | annotations: { | 
					
						
							|  |  |  | 	"test":parameter | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    parameter:string | 
					
						
							|  |  |  | `, | 
					
						
							|  |  |  | 			want: want{data: "{\"type\":\"string\"}", err: nil}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"cue doesn't contain parameter section": { | 
					
						
							|  |  |  | 			reason: "Prepare a cue file which doesn't contain `parameter` section", | 
					
						
							|  |  |  | 			name:   "invalidWorkload", | 
					
						
							|  |  |  | 			data: ` | 
					
						
							|  |  |  | project: { | 
					
						
							|  |  |  | 	name: string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | noParameter: { | 
					
						
							|  |  |  | 	min: int | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | `, | 
					
						
							|  |  |  | 			want: want{data: "", err: fmt.Errorf("capability invalidWorkload doesn't contain section `parameter`")}, | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for name, tc := range cases { | 
					
						
							|  |  |  | 		t.Run(name, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-03-24 13:27:29 +08:00
										 |  |  | 			schematic := &common.Schematic{ | 
					
						
							|  |  |  | 				CUE: &common.CUE{ | 
					
						
							| 
									
										
										
										
											2021-05-19 20:08:51 +08:00
										 |  |  | 					Template: tc.data, | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 			capability, _ := appfile.ConvertTemplateJSON2Object(tc.name, nil, schematic) | 
					
						
							| 
									
										
										
										
											2021-04-08 20:35:21 +08:00
										 |  |  | 			schema, err := getOpenAPISchema(capability, pd) | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 			if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { | 
					
						
							|  |  |  | 				t.Errorf("\n%s\ngetOpenAPISchema(...): -want error, +got error:\n%s", tc.reason, diff) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if tc.want.err == nil { | 
					
						
							|  |  |  | 				assert.Equal(t, string(schema), tc.want.data) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestFixOpenAPISchema(t *testing.T) { | 
					
						
							|  |  |  | 	cases := map[string]struct { | 
					
						
							|  |  |  | 		inputFile string | 
					
						
							|  |  |  | 		fixedFile string | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"StandardWorkload": { | 
					
						
							|  |  |  | 			inputFile: "webservice.json", | 
					
						
							|  |  |  | 			fixedFile: "webserviceFixed.json", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"ShortTagJson": { | 
					
						
							|  |  |  | 			inputFile: "shortTagSchema.json", | 
					
						
							|  |  |  | 			fixedFile: "shortTagSchemaFixed.json", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for name, tc := range cases { | 
					
						
							|  |  |  | 		t.Run(name, func(t *testing.T) { | 
					
						
							|  |  |  | 			swagger, _ := openapi3.NewSwaggerLoader().LoadSwaggerFromFile(filepath.Join(TestDir, tc.inputFile)) | 
					
						
							| 
									
										
										
										
											2021-06-02 15:37:06 +08:00
										 |  |  | 			schema := swagger.Components.Schemas[cue.ParameterTag].Value | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 			fixOpenAPISchema("", schema) | 
					
						
							|  |  |  | 			fixedSchema, _ := schema.MarshalJSON() | 
					
						
							|  |  |  | 			expectedSchema, _ := ioutil.ReadFile(filepath.Join(TestDir, tc.fixedFile)) | 
					
						
							|  |  |  | 			assert.Equal(t, string(fixedSchema), string(expectedSchema)) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestGenerateOpenAPISchemaFromCapabilityParameter(t *testing.T) { | 
					
						
							|  |  |  | 	var invalidWorkloadName = "IAmAnInvalidWorkloadDefinition" | 
					
						
							|  |  |  | 	capabilityDir, _ := system.GetCapabilityDir() | 
					
						
							|  |  |  | 	if _, err := os.Stat(capabilityDir); err != nil && os.IsNotExist(err) { | 
					
						
							|  |  |  | 		os.MkdirAll(capabilityDir, 0755) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type want struct { | 
					
						
							|  |  |  | 		data []byte | 
					
						
							|  |  |  | 		err  error | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cases := map[string]struct { | 
					
						
							|  |  |  | 		reason     string | 
					
						
							|  |  |  | 		capability types.Capability | 
					
						
							|  |  |  | 		want       want | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"GenerateOpenAPISchemaFromInvalidCapability": { | 
					
						
							|  |  |  | 			reason:     "generate OpenAPI schema for an invalid Workload/Trait", | 
					
						
							|  |  |  | 			capability: types.Capability{Name: invalidWorkloadName}, | 
					
						
							| 
									
										
										
										
											2021-03-29 17:20:33 +08:00
										 |  |  | 			want:       want{data: nil, err: fmt.Errorf("capability IAmAnInvalidWorkloadDefinition doesn't contain section `parameter`")}, | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for name, tc := range cases { | 
					
						
							|  |  |  | 		t.Run(name, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-04-08 20:35:21 +08:00
										 |  |  | 			got, err := generateOpenAPISchemaFromCapabilityParameter(tc.capability, pd) | 
					
						
							| 
									
										
										
										
											2021-03-10 10:44:58 +08:00
										 |  |  | 			if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { | 
					
						
							|  |  |  | 				t.Errorf("\n%s\ngetDefinition(...): -want error, +got error:\n%s", tc.reason, diff) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if diff := cmp.Diff(tc.want.data, got); diff != "" { | 
					
						
							|  |  |  | 				t.Errorf("\n%s\ngetDefinition(...): -want, +got:\n%s", tc.reason, diff) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |