github.com/oam-dev/kubevela@v1.9.11/pkg/definition/gen_sdk/gen_sdk_test.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package gen_sdk 18 19 import ( 20 "os" 21 "path/filepath" 22 23 "github.com/getkin/kin-openapi/openapi3" 24 . "github.com/onsi/ginkgo/v2" 25 . "github.com/onsi/gomega" 26 27 "github.com/oam-dev/kubevela/pkg/utils/common" 28 ) 29 30 var _outputDir string 31 32 var _ = Describe("Test Generating SDK", func() { 33 var err error 34 outputDir := filepath.Join("testdata", "output") 35 _outputDir = outputDir 36 lang := "go" 37 meta := GenMeta{ 38 Output: outputDir, 39 Lang: lang, 40 Package: "github.com/kubevela-contrib/kubevela-go-sdk", 41 APIDirectory: defaultAPIDir[lang], 42 Verbose: true, 43 } 44 var langArgs []string 45 46 BeforeEach(func() { 47 meta.InitSDK = false 48 meta.File = []string{filepath.Join("testdata", "cron-task.cue")} 49 meta.cuePaths = []string{} 50 }) 51 52 checkDirNotEmpty := func(dir string) { 53 _, err = os.Stat(dir) 54 Expect(err).Should(BeNil()) 55 } 56 genWithMeta := func() { 57 err = meta.Init(common.Args{}, langArgs) 58 Expect(err).Should(BeNil()) 59 err = meta.CreateScaffold() 60 Expect(err).Should(BeNil()) 61 err = meta.PrepareGeneratorAndTemplate() 62 Expect(err).Should(BeNil()) 63 err = meta.Run() 64 Expect(err).Should(BeNil()) 65 } 66 It("Test generating SDK and init the scaffold", func() { 67 meta.InitSDK = true 68 genWithMeta() 69 checkDirNotEmpty(filepath.Join(outputDir, "pkg", "apis")) 70 checkDirNotEmpty(filepath.Join(outputDir, "pkg", "apis", "component", "cron-task")) 71 }) 72 73 It("Test generating SDK, append apis", func() { 74 meta.File = append(meta.File, "testdata/shared-resource.cue") 75 76 genWithMeta() 77 checkDirNotEmpty(filepath.Join(outputDir, "pkg", "apis", "policy", "shared-resource")) 78 }) 79 80 It("Test free form parameter {...}", func() { 81 meta.File = []string{"testdata/json-merge-patch.cue"} 82 meta.Verbose = true 83 84 genWithMeta() 85 checkDirNotEmpty(filepath.Join(outputDir, "pkg", "apis", "trait", "json-merge-patch")) 86 }) 87 88 It("Test workflow step", func() { 89 meta.File = []string{"testdata/deploy.cue"} 90 meta.Verbose = true 91 92 genWithMeta() 93 checkDirNotEmpty(filepath.Join(outputDir, "pkg", "apis", "workflow-step", "deploy")) 94 }) 95 96 It("Test step-group", func() { 97 meta.File = []string{"testdata/step-group.cue"} 98 meta.Verbose = true 99 100 genWithMeta() 101 checkDirNotEmpty(filepath.Join(outputDir, "pkg", "apis", "workflow-step", "step-group")) 102 By("check if AddSubStep is generated") 103 content, err := os.ReadFile(filepath.Join(outputDir, "pkg", "apis", "workflow-step", "step-group", "step_group.go")) 104 Expect(err).Should(BeNil()) 105 Expect(string(content)).Should(ContainSubstring("AddSubStep")) 106 }) 107 108 It("Test oneOf", func() { 109 meta.File = []string{"testdata/one_of.cue"} 110 meta.Verbose = true 111 112 genWithMeta() 113 checkDirNotEmpty(filepath.Join(outputDir, "pkg", "apis", "workflow-step", "one_of")) 114 }) 115 116 It("Test known issue: apply-terraform-provider", func() { 117 meta.Verbose = true 118 meta.File = []string{"testdata/apply-terraform-provider.cue"} 119 genWithMeta() 120 }) 121 122 It("Test generate sub-module", func() { 123 meta.APIDirectory = "pkg/apis/addons/test_addon" 124 langArgs = []string{ 125 string(mainModuleVersionKey) + "=" + mainModuleVersion.Default, 126 } 127 meta.IsSubModule = true 128 genWithMeta() 129 checkDirNotEmpty(filepath.Join(outputDir, "pkg", "apis", "addons", "test_addon", "component", "cron-task")) 130 }) 131 132 }) 133 134 var _ = AfterSuite(func() { 135 By("Cleaning up generated files") 136 _ = os.RemoveAll(_outputDir) 137 }) 138 139 var _ = Describe("FixSchemaWithOneAnyAllOf", func() { 140 var ( 141 schema *openapi3.SchemaRef 142 ) 143 144 It("should set default value to right sub-schema", func() { 145 By(`cpu?: *1 | number | string`) 146 schema = &openapi3.SchemaRef{ 147 Ref: "", 148 Value: &openapi3.Schema{ 149 Default: 1, 150 OneOf: openapi3.SchemaRefs{ 151 { 152 Value: &openapi3.Schema{ 153 Type: "number", 154 }, 155 }, 156 { 157 Value: &openapi3.Schema{ 158 Type: "string", 159 }, 160 }, 161 }, 162 }, 163 } 164 fixSchemaWithOneOf(schema) 165 166 Expect(schema.Value.OneOf[0].Value.Default).To(Equal(1)) 167 Expect(schema.Value.OneOf[1].Value.Default).To(BeNil()) 168 Expect(schema.Value.Default).To(BeNil()) 169 }) 170 171 It("should remove duplicated type in oneOf", func() { 172 By(`language: "go" | "java" | "python" | "node" | "ruby" | string`) 173 By(`image: language | string`) 174 schema = &openapi3.SchemaRef{ 175 Value: &openapi3.Schema{ 176 Type: "string", 177 Title: "image", 178 OneOf: openapi3.SchemaRefs{ 179 { 180 Value: &openapi3.Schema{ 181 Type: "string", 182 Enum: []interface{}{"go", "java", "python", "node", "ruby"}, 183 }, 184 }, 185 { 186 Value: &openapi3.Schema{ 187 Type: "string", 188 }, 189 }, 190 }, 191 }, 192 } 193 fixSchemaWithOneOf(schema) 194 195 Expect(schema.Value.OneOf).To(HaveLen(1)) 196 Expect(schema.Value.OneOf[0].Value.Type).To(Equal("string")) 197 Expect(schema.Value.OneOf[0].Value.Enum).To(Equal([]interface{}{"go", "java", "python", "node", "ruby"})) 198 }) 199 200 It("should both move type and remove duplicated type in oneOf", func() { 201 schema = &openapi3.SchemaRef{ 202 Value: &openapi3.Schema{ 203 Type: "string", 204 Title: "image", 205 OneOf: openapi3.SchemaRefs{ 206 { 207 Value: &openapi3.Schema{ 208 Enum: []interface{}{"go", "java", "python", "node", "ruby"}, 209 }, 210 }, 211 { 212 Value: &openapi3.Schema{ 213 Type: "string", 214 }, 215 }, 216 }, 217 }, 218 } 219 220 fixSchemaWithOneOf(schema) 221 Expect(schema.Value.OneOf).To(HaveLen(1)) 222 Expect(schema.Value.OneOf[0].Value.Type).To(Equal("string")) 223 Expect(schema.Value.OneOf[0].Value.Enum).To(Equal([]interface{}{"go", "java", "python", "node", "ruby"})) 224 }) 225 }) 226 227 var _ = Describe("TestNewLanguageArgs", func() { 228 type args struct { 229 lang string 230 langArgs []string 231 } 232 tests := []struct { 233 name string 234 args args 235 want map[string]string 236 wantErr bool 237 }{ 238 { 239 name: "should create a languageArgs struct with the correct values", 240 args: args{ 241 lang: "go", 242 langArgs: []string{"flag1=value1", "flag2=value2"}, 243 }, 244 want: map[string]string{"flag1": "value1", "flag2": "value2"}, 245 wantErr: false, 246 }, 247 { 248 name: "should not set a value for an unknown flag", 249 args: args{ 250 lang: "go", 251 langArgs: []string{"unknownFlag=value"}, 252 }, 253 want: map[string]string{}, 254 wantErr: true, 255 }, 256 { 257 name: "should warn if an argument is not in the key=value format", 258 args: args{ 259 lang: "go", 260 langArgs: []string{"invalidArgument"}, 261 }, 262 want: map[string]string{}, 263 wantErr: true, 264 }, 265 } 266 for _, tt := range tests { 267 It(tt.name, func() { 268 got, err := NewLanguageArgs(tt.args.lang, tt.args.langArgs) 269 if tt.wantErr { 270 Expect(err).To(HaveOccurred()) 271 return 272 } 273 for k, v := range tt.want { 274 Expect(got.Get(langArgKey(k))).To(Equal(v)) 275 } 276 }) 277 } 278 279 }) 280 281 var _ = Describe("getValueType", func() { 282 283 type valueTypeTest struct { 284 input interface{} 285 expected CUEType 286 } 287 288 tests := []valueTypeTest{ 289 {nil, ""}, 290 {"hello", "string"}, 291 {42, "integer"}, 292 {float32(3.14), "number"}, 293 {3.14159265358979323846, "number"}, 294 {true, "boolean"}, 295 {map[string]interface{}{"key": "value"}, "object"}, 296 {[]interface{}{1, 2, 3}, "array"}, 297 } 298 299 for _, tt := range tests { 300 tt := tt // capture range variable 301 It("should return the correct CUEType for the input", func() { 302 Expect(getValueType(tt.input)).To(Equal(tt.expected)) 303 }) 304 } 305 }) 306 307 var _ = Describe("type fit", func() { 308 309 var schema *openapi3.Schema 310 311 BeforeEach(func() { 312 schema = &openapi3.Schema{Type: "string"} 313 }) 314 315 var testCases = []struct { 316 name string 317 cueType CUEType 318 expectedFit bool 319 schemaType string 320 }{ 321 {"string can be oas string", CUEType("string"), true, "string"}, 322 {"string not oas integer", CUEType("string"), false, "integer"}, 323 {"integer can be oas integer", CUEType("integer"), true, "integer"}, 324 {"integer can be oas number", CUEType("integer"), true, "number"}, 325 {"number can be oas number", CUEType("number"), true, "number"}, 326 {"number not oas integer", CUEType("number"), false, "integer"}, 327 {"boolean can be oas boolean", CUEType("boolean"), true, "boolean"}, 328 {"array can be oas array", CUEType("array"), true, "array"}, 329 {"invalid type and any schema", CUEType(""), false, "anyschema"}, 330 } 331 332 It("should return whether the CUEType fits the schema type or not", func() { 333 for _, tc := range testCases { 334 schema.Type = tc.schemaType 335 result := tc.cueType.fit(schema) 336 Expect(result).To(Equal(tc.expectedFit), tc.name) 337 } 338 }) 339 })