kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/plugin6/convert/schema_test.go (about) 1 package convert 2 3 import ( 4 "testing" 5 6 "github.com/google/go-cmp/cmp" 7 "github.com/google/go-cmp/cmp/cmpopts" 8 "kubeform.dev/terraform-backend-sdk/configs/configschema" 9 proto "kubeform.dev/terraform-backend-sdk/tfplugin6" 10 "github.com/zclconf/go-cty/cty" 11 ) 12 13 var ( 14 equateEmpty = cmpopts.EquateEmpty() 15 typeComparer = cmp.Comparer(cty.Type.Equals) 16 valueComparer = cmp.Comparer(cty.Value.RawEquals) 17 ) 18 19 // Test that we can convert configschema to protobuf types and back again. 20 func TestConvertSchemaBlocks(t *testing.T) { 21 tests := map[string]struct { 22 Block *proto.Schema_Block 23 Want *configschema.Block 24 }{ 25 "attributes": { 26 &proto.Schema_Block{ 27 Attributes: []*proto.Schema_Attribute{ 28 { 29 Name: "computed", 30 Type: []byte(`["list","bool"]`), 31 Computed: true, 32 }, 33 { 34 Name: "optional", 35 Type: []byte(`"string"`), 36 Optional: true, 37 }, 38 { 39 Name: "optional_computed", 40 Type: []byte(`["map","bool"]`), 41 Optional: true, 42 Computed: true, 43 }, 44 { 45 Name: "required", 46 Type: []byte(`"number"`), 47 Required: true, 48 }, 49 { 50 Name: "nested_type", 51 NestedType: &proto.Schema_Object{ 52 Nesting: proto.Schema_Object_SINGLE, 53 Attributes: []*proto.Schema_Attribute{ 54 { 55 Name: "computed", 56 Type: []byte(`["list","bool"]`), 57 Computed: true, 58 }, 59 { 60 Name: "optional", 61 Type: []byte(`"string"`), 62 Optional: true, 63 }, 64 { 65 Name: "optional_computed", 66 Type: []byte(`["map","bool"]`), 67 Optional: true, 68 Computed: true, 69 }, 70 { 71 Name: "required", 72 Type: []byte(`"number"`), 73 Required: true, 74 }, 75 }, 76 }, 77 Required: true, 78 }, 79 { 80 Name: "deeply_nested_type", 81 NestedType: &proto.Schema_Object{ 82 Nesting: proto.Schema_Object_SINGLE, 83 Attributes: []*proto.Schema_Attribute{ 84 { 85 Name: "first_level", 86 NestedType: &proto.Schema_Object{ 87 Nesting: proto.Schema_Object_SINGLE, 88 Attributes: []*proto.Schema_Attribute{ 89 { 90 Name: "computed", 91 Type: []byte(`["list","bool"]`), 92 Computed: true, 93 }, 94 { 95 Name: "optional", 96 Type: []byte(`"string"`), 97 Optional: true, 98 }, 99 { 100 Name: "optional_computed", 101 Type: []byte(`["map","bool"]`), 102 Optional: true, 103 Computed: true, 104 }, 105 { 106 Name: "required", 107 Type: []byte(`"number"`), 108 Required: true, 109 }, 110 }, 111 }, 112 Computed: true, 113 }, 114 }, 115 }, 116 Required: true, 117 }, 118 { 119 Name: "nested_list", 120 NestedType: &proto.Schema_Object{ 121 Nesting: proto.Schema_Object_LIST, 122 Attributes: []*proto.Schema_Attribute{ 123 { 124 Name: "required", 125 Type: []byte(`"string"`), 126 Computed: true, 127 }, 128 }, 129 MinItems: 3, 130 }, 131 Required: true, 132 }, 133 { 134 Name: "nested_set", 135 NestedType: &proto.Schema_Object{ 136 Nesting: proto.Schema_Object_SET, 137 Attributes: []*proto.Schema_Attribute{ 138 { 139 Name: "required", 140 Type: []byte(`"string"`), 141 Computed: true, 142 }, 143 }, 144 }, 145 Required: true, 146 }, 147 { 148 Name: "nested_map", 149 NestedType: &proto.Schema_Object{ 150 Nesting: proto.Schema_Object_MAP, 151 Attributes: []*proto.Schema_Attribute{ 152 { 153 Name: "required", 154 Type: []byte(`"string"`), 155 Computed: true, 156 }, 157 }, 158 }, 159 Required: true, 160 }, 161 }, 162 }, 163 &configschema.Block{ 164 Attributes: map[string]*configschema.Attribute{ 165 "computed": { 166 Type: cty.List(cty.Bool), 167 Computed: true, 168 }, 169 "optional": { 170 Type: cty.String, 171 Optional: true, 172 }, 173 "optional_computed": { 174 Type: cty.Map(cty.Bool), 175 Optional: true, 176 Computed: true, 177 }, 178 "required": { 179 Type: cty.Number, 180 Required: true, 181 }, 182 "nested_type": { 183 NestedType: &configschema.Object{ 184 Attributes: map[string]*configschema.Attribute{ 185 "computed": { 186 Type: cty.List(cty.Bool), 187 Computed: true, 188 }, 189 "optional": { 190 Type: cty.String, 191 Optional: true, 192 }, 193 "optional_computed": { 194 Type: cty.Map(cty.Bool), 195 Optional: true, 196 Computed: true, 197 }, 198 "required": { 199 Type: cty.Number, 200 Required: true, 201 }, 202 }, 203 Nesting: configschema.NestingSingle, 204 }, 205 Required: true, 206 }, 207 "deeply_nested_type": { 208 NestedType: &configschema.Object{ 209 Attributes: map[string]*configschema.Attribute{ 210 "first_level": { 211 NestedType: &configschema.Object{ 212 Nesting: configschema.NestingSingle, 213 Attributes: map[string]*configschema.Attribute{ 214 "computed": { 215 Type: cty.List(cty.Bool), 216 Computed: true, 217 }, 218 "optional": { 219 Type: cty.String, 220 Optional: true, 221 }, 222 "optional_computed": { 223 Type: cty.Map(cty.Bool), 224 Optional: true, 225 Computed: true, 226 }, 227 "required": { 228 Type: cty.Number, 229 Required: true, 230 }, 231 }, 232 }, 233 Computed: true, 234 }, 235 }, 236 Nesting: configschema.NestingSingle, 237 }, 238 Required: true, 239 }, 240 "nested_list": { 241 NestedType: &configschema.Object{ 242 Nesting: configschema.NestingList, 243 Attributes: map[string]*configschema.Attribute{ 244 "required": { 245 Type: cty.String, 246 Computed: true, 247 }, 248 }, 249 MinItems: 3, 250 }, 251 Required: true, 252 }, 253 "nested_map": { 254 NestedType: &configschema.Object{ 255 Nesting: configschema.NestingMap, 256 Attributes: map[string]*configschema.Attribute{ 257 "required": { 258 Type: cty.String, 259 Computed: true, 260 }, 261 }, 262 }, 263 Required: true, 264 }, 265 "nested_set": { 266 NestedType: &configschema.Object{ 267 Nesting: configschema.NestingSet, 268 Attributes: map[string]*configschema.Attribute{ 269 "required": { 270 Type: cty.String, 271 Computed: true, 272 }, 273 }, 274 }, 275 Required: true, 276 }, 277 }, 278 }, 279 }, 280 "blocks": { 281 &proto.Schema_Block{ 282 BlockTypes: []*proto.Schema_NestedBlock{ 283 { 284 TypeName: "list", 285 Nesting: proto.Schema_NestedBlock_LIST, 286 Block: &proto.Schema_Block{}, 287 }, 288 { 289 TypeName: "map", 290 Nesting: proto.Schema_NestedBlock_MAP, 291 Block: &proto.Schema_Block{}, 292 }, 293 { 294 TypeName: "set", 295 Nesting: proto.Schema_NestedBlock_SET, 296 Block: &proto.Schema_Block{}, 297 }, 298 { 299 TypeName: "single", 300 Nesting: proto.Schema_NestedBlock_SINGLE, 301 Block: &proto.Schema_Block{ 302 Attributes: []*proto.Schema_Attribute{ 303 { 304 Name: "foo", 305 Type: []byte(`"dynamic"`), 306 Required: true, 307 }, 308 }, 309 }, 310 }, 311 }, 312 }, 313 &configschema.Block{ 314 BlockTypes: map[string]*configschema.NestedBlock{ 315 "list": &configschema.NestedBlock{ 316 Nesting: configschema.NestingList, 317 }, 318 "map": &configschema.NestedBlock{ 319 Nesting: configschema.NestingMap, 320 }, 321 "set": &configschema.NestedBlock{ 322 Nesting: configschema.NestingSet, 323 }, 324 "single": &configschema.NestedBlock{ 325 Nesting: configschema.NestingSingle, 326 Block: configschema.Block{ 327 Attributes: map[string]*configschema.Attribute{ 328 "foo": { 329 Type: cty.DynamicPseudoType, 330 Required: true, 331 }, 332 }, 333 }, 334 }, 335 }, 336 }, 337 }, 338 "deep block nesting": { 339 &proto.Schema_Block{ 340 BlockTypes: []*proto.Schema_NestedBlock{ 341 { 342 TypeName: "single", 343 Nesting: proto.Schema_NestedBlock_SINGLE, 344 Block: &proto.Schema_Block{ 345 BlockTypes: []*proto.Schema_NestedBlock{ 346 { 347 TypeName: "list", 348 Nesting: proto.Schema_NestedBlock_LIST, 349 Block: &proto.Schema_Block{ 350 BlockTypes: []*proto.Schema_NestedBlock{ 351 { 352 TypeName: "set", 353 Nesting: proto.Schema_NestedBlock_SET, 354 Block: &proto.Schema_Block{}, 355 }, 356 }, 357 }, 358 }, 359 }, 360 }, 361 }, 362 }, 363 }, 364 &configschema.Block{ 365 BlockTypes: map[string]*configschema.NestedBlock{ 366 "single": &configschema.NestedBlock{ 367 Nesting: configschema.NestingSingle, 368 Block: configschema.Block{ 369 BlockTypes: map[string]*configschema.NestedBlock{ 370 "list": &configschema.NestedBlock{ 371 Nesting: configschema.NestingList, 372 Block: configschema.Block{ 373 BlockTypes: map[string]*configschema.NestedBlock{ 374 "set": &configschema.NestedBlock{ 375 Nesting: configschema.NestingSet, 376 }, 377 }, 378 }, 379 }, 380 }, 381 }, 382 }, 383 }, 384 }, 385 }, 386 } 387 388 for name, tc := range tests { 389 t.Run(name, func(t *testing.T) { 390 converted := ProtoToConfigSchema(tc.Block) 391 if !cmp.Equal(converted, tc.Want, typeComparer, valueComparer, equateEmpty) { 392 t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, valueComparer, equateEmpty)) 393 } 394 }) 395 } 396 } 397 398 // Test that we can convert configschema to protobuf types and back again. 399 func TestConvertProtoSchemaBlocks(t *testing.T) { 400 tests := map[string]struct { 401 Want *proto.Schema_Block 402 Block *configschema.Block 403 }{ 404 "attributes": { 405 &proto.Schema_Block{ 406 Attributes: []*proto.Schema_Attribute{ 407 { 408 Name: "computed", 409 Type: []byte(`["list","bool"]`), 410 Computed: true, 411 }, 412 { 413 Name: "optional", 414 Type: []byte(`"string"`), 415 Optional: true, 416 }, 417 { 418 Name: "optional_computed", 419 Type: []byte(`["map","bool"]`), 420 Optional: true, 421 Computed: true, 422 }, 423 { 424 Name: "required", 425 Type: []byte(`"number"`), 426 Required: true, 427 }, 428 }, 429 }, 430 &configschema.Block{ 431 Attributes: map[string]*configschema.Attribute{ 432 "computed": { 433 Type: cty.List(cty.Bool), 434 Computed: true, 435 }, 436 "optional": { 437 Type: cty.String, 438 Optional: true, 439 }, 440 "optional_computed": { 441 Type: cty.Map(cty.Bool), 442 Optional: true, 443 Computed: true, 444 }, 445 "required": { 446 Type: cty.Number, 447 Required: true, 448 }, 449 }, 450 }, 451 }, 452 "blocks": { 453 &proto.Schema_Block{ 454 BlockTypes: []*proto.Schema_NestedBlock{ 455 { 456 TypeName: "list", 457 Nesting: proto.Schema_NestedBlock_LIST, 458 Block: &proto.Schema_Block{}, 459 }, 460 { 461 TypeName: "map", 462 Nesting: proto.Schema_NestedBlock_MAP, 463 Block: &proto.Schema_Block{}, 464 }, 465 { 466 TypeName: "set", 467 Nesting: proto.Schema_NestedBlock_SET, 468 Block: &proto.Schema_Block{}, 469 }, 470 { 471 TypeName: "single", 472 Nesting: proto.Schema_NestedBlock_SINGLE, 473 Block: &proto.Schema_Block{ 474 Attributes: []*proto.Schema_Attribute{ 475 { 476 Name: "foo", 477 Type: []byte(`"dynamic"`), 478 Required: true, 479 }, 480 }, 481 }, 482 }, 483 }, 484 }, 485 &configschema.Block{ 486 BlockTypes: map[string]*configschema.NestedBlock{ 487 "list": &configschema.NestedBlock{ 488 Nesting: configschema.NestingList, 489 }, 490 "map": &configschema.NestedBlock{ 491 Nesting: configschema.NestingMap, 492 }, 493 "set": &configschema.NestedBlock{ 494 Nesting: configschema.NestingSet, 495 }, 496 "single": &configschema.NestedBlock{ 497 Nesting: configschema.NestingSingle, 498 Block: configschema.Block{ 499 Attributes: map[string]*configschema.Attribute{ 500 "foo": { 501 Type: cty.DynamicPseudoType, 502 Required: true, 503 }, 504 }, 505 }, 506 }, 507 }, 508 }, 509 }, 510 "deep block nesting": { 511 &proto.Schema_Block{ 512 BlockTypes: []*proto.Schema_NestedBlock{ 513 { 514 TypeName: "single", 515 Nesting: proto.Schema_NestedBlock_SINGLE, 516 Block: &proto.Schema_Block{ 517 BlockTypes: []*proto.Schema_NestedBlock{ 518 { 519 TypeName: "list", 520 Nesting: proto.Schema_NestedBlock_LIST, 521 Block: &proto.Schema_Block{ 522 BlockTypes: []*proto.Schema_NestedBlock{ 523 { 524 TypeName: "set", 525 Nesting: proto.Schema_NestedBlock_SET, 526 Block: &proto.Schema_Block{}, 527 }, 528 }, 529 }, 530 }, 531 }, 532 }, 533 }, 534 }, 535 }, 536 &configschema.Block{ 537 BlockTypes: map[string]*configschema.NestedBlock{ 538 "single": &configschema.NestedBlock{ 539 Nesting: configschema.NestingSingle, 540 Block: configschema.Block{ 541 BlockTypes: map[string]*configschema.NestedBlock{ 542 "list": &configschema.NestedBlock{ 543 Nesting: configschema.NestingList, 544 Block: configschema.Block{ 545 BlockTypes: map[string]*configschema.NestedBlock{ 546 "set": &configschema.NestedBlock{ 547 Nesting: configschema.NestingSet, 548 }, 549 }, 550 }, 551 }, 552 }, 553 }, 554 }, 555 }, 556 }, 557 }, 558 } 559 560 for name, tc := range tests { 561 t.Run(name, func(t *testing.T) { 562 converted := ConfigSchemaToProto(tc.Block) 563 if !cmp.Equal(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported) { 564 t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported)) 565 } 566 }) 567 } 568 }