github.com/pulumi/terraform@v1.4.0/pkg/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 "github.com/pulumi/terraform/pkg/configs/configschema" 9 proto "github.com/pulumi/terraform/pkg/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 }, 130 Required: true, 131 }, 132 { 133 Name: "nested_set", 134 NestedType: &proto.Schema_Object{ 135 Nesting: proto.Schema_Object_SET, 136 Attributes: []*proto.Schema_Attribute{ 137 { 138 Name: "required", 139 Type: []byte(`"string"`), 140 Computed: true, 141 }, 142 }, 143 }, 144 Required: true, 145 }, 146 { 147 Name: "nested_map", 148 NestedType: &proto.Schema_Object{ 149 Nesting: proto.Schema_Object_MAP, 150 Attributes: []*proto.Schema_Attribute{ 151 { 152 Name: "required", 153 Type: []byte(`"string"`), 154 Computed: true, 155 }, 156 }, 157 }, 158 Required: true, 159 }, 160 }, 161 }, 162 &configschema.Block{ 163 Attributes: map[string]*configschema.Attribute{ 164 "computed": { 165 Type: cty.List(cty.Bool), 166 Computed: true, 167 }, 168 "optional": { 169 Type: cty.String, 170 Optional: true, 171 }, 172 "optional_computed": { 173 Type: cty.Map(cty.Bool), 174 Optional: true, 175 Computed: true, 176 }, 177 "required": { 178 Type: cty.Number, 179 Required: true, 180 }, 181 "nested_type": { 182 NestedType: &configschema.Object{ 183 Attributes: map[string]*configschema.Attribute{ 184 "computed": { 185 Type: cty.List(cty.Bool), 186 Computed: true, 187 }, 188 "optional": { 189 Type: cty.String, 190 Optional: true, 191 }, 192 "optional_computed": { 193 Type: cty.Map(cty.Bool), 194 Optional: true, 195 Computed: true, 196 }, 197 "required": { 198 Type: cty.Number, 199 Required: true, 200 }, 201 }, 202 Nesting: configschema.NestingSingle, 203 }, 204 Required: true, 205 }, 206 "deeply_nested_type": { 207 NestedType: &configschema.Object{ 208 Attributes: map[string]*configschema.Attribute{ 209 "first_level": { 210 NestedType: &configschema.Object{ 211 Nesting: configschema.NestingSingle, 212 Attributes: map[string]*configschema.Attribute{ 213 "computed": { 214 Type: cty.List(cty.Bool), 215 Computed: true, 216 }, 217 "optional": { 218 Type: cty.String, 219 Optional: true, 220 }, 221 "optional_computed": { 222 Type: cty.Map(cty.Bool), 223 Optional: true, 224 Computed: true, 225 }, 226 "required": { 227 Type: cty.Number, 228 Required: true, 229 }, 230 }, 231 }, 232 Computed: true, 233 }, 234 }, 235 Nesting: configschema.NestingSingle, 236 }, 237 Required: true, 238 }, 239 "nested_list": { 240 NestedType: &configschema.Object{ 241 Nesting: configschema.NestingList, 242 Attributes: map[string]*configschema.Attribute{ 243 "required": { 244 Type: cty.String, 245 Computed: true, 246 }, 247 }, 248 }, 249 Required: true, 250 }, 251 "nested_map": { 252 NestedType: &configschema.Object{ 253 Nesting: configschema.NestingMap, 254 Attributes: map[string]*configschema.Attribute{ 255 "required": { 256 Type: cty.String, 257 Computed: true, 258 }, 259 }, 260 }, 261 Required: true, 262 }, 263 "nested_set": { 264 NestedType: &configschema.Object{ 265 Nesting: configschema.NestingSet, 266 Attributes: map[string]*configschema.Attribute{ 267 "required": { 268 Type: cty.String, 269 Computed: true, 270 }, 271 }, 272 }, 273 Required: true, 274 }, 275 }, 276 }, 277 }, 278 "blocks": { 279 &proto.Schema_Block{ 280 BlockTypes: []*proto.Schema_NestedBlock{ 281 { 282 TypeName: "list", 283 Nesting: proto.Schema_NestedBlock_LIST, 284 Block: &proto.Schema_Block{}, 285 }, 286 { 287 TypeName: "map", 288 Nesting: proto.Schema_NestedBlock_MAP, 289 Block: &proto.Schema_Block{}, 290 }, 291 { 292 TypeName: "set", 293 Nesting: proto.Schema_NestedBlock_SET, 294 Block: &proto.Schema_Block{}, 295 }, 296 { 297 TypeName: "single", 298 Nesting: proto.Schema_NestedBlock_SINGLE, 299 Block: &proto.Schema_Block{ 300 Attributes: []*proto.Schema_Attribute{ 301 { 302 Name: "foo", 303 Type: []byte(`"dynamic"`), 304 Required: true, 305 }, 306 }, 307 }, 308 }, 309 }, 310 }, 311 &configschema.Block{ 312 BlockTypes: map[string]*configschema.NestedBlock{ 313 "list": &configschema.NestedBlock{ 314 Nesting: configschema.NestingList, 315 }, 316 "map": &configschema.NestedBlock{ 317 Nesting: configschema.NestingMap, 318 }, 319 "set": &configschema.NestedBlock{ 320 Nesting: configschema.NestingSet, 321 }, 322 "single": &configschema.NestedBlock{ 323 Nesting: configschema.NestingSingle, 324 Block: configschema.Block{ 325 Attributes: map[string]*configschema.Attribute{ 326 "foo": { 327 Type: cty.DynamicPseudoType, 328 Required: true, 329 }, 330 }, 331 }, 332 }, 333 }, 334 }, 335 }, 336 "deep block nesting": { 337 &proto.Schema_Block{ 338 BlockTypes: []*proto.Schema_NestedBlock{ 339 { 340 TypeName: "single", 341 Nesting: proto.Schema_NestedBlock_SINGLE, 342 Block: &proto.Schema_Block{ 343 BlockTypes: []*proto.Schema_NestedBlock{ 344 { 345 TypeName: "list", 346 Nesting: proto.Schema_NestedBlock_LIST, 347 Block: &proto.Schema_Block{ 348 BlockTypes: []*proto.Schema_NestedBlock{ 349 { 350 TypeName: "set", 351 Nesting: proto.Schema_NestedBlock_SET, 352 Block: &proto.Schema_Block{}, 353 }, 354 }, 355 }, 356 }, 357 }, 358 }, 359 }, 360 }, 361 }, 362 &configschema.Block{ 363 BlockTypes: map[string]*configschema.NestedBlock{ 364 "single": &configschema.NestedBlock{ 365 Nesting: configschema.NestingSingle, 366 Block: configschema.Block{ 367 BlockTypes: map[string]*configschema.NestedBlock{ 368 "list": &configschema.NestedBlock{ 369 Nesting: configschema.NestingList, 370 Block: configschema.Block{ 371 BlockTypes: map[string]*configschema.NestedBlock{ 372 "set": &configschema.NestedBlock{ 373 Nesting: configschema.NestingSet, 374 }, 375 }, 376 }, 377 }, 378 }, 379 }, 380 }, 381 }, 382 }, 383 }, 384 } 385 386 for name, tc := range tests { 387 t.Run(name, func(t *testing.T) { 388 converted := ProtoToConfigSchema(tc.Block) 389 if !cmp.Equal(converted, tc.Want, typeComparer, valueComparer, equateEmpty) { 390 t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, valueComparer, equateEmpty)) 391 } 392 }) 393 } 394 } 395 396 // Test that we can convert configschema to protobuf types and back again. 397 func TestConvertProtoSchemaBlocks(t *testing.T) { 398 tests := map[string]struct { 399 Want *proto.Schema_Block 400 Block *configschema.Block 401 }{ 402 "attributes": { 403 &proto.Schema_Block{ 404 Attributes: []*proto.Schema_Attribute{ 405 { 406 Name: "computed", 407 Type: []byte(`["list","bool"]`), 408 Computed: true, 409 }, 410 { 411 Name: "optional", 412 Type: []byte(`"string"`), 413 Optional: true, 414 }, 415 { 416 Name: "optional_computed", 417 Type: []byte(`["map","bool"]`), 418 Optional: true, 419 Computed: true, 420 }, 421 { 422 Name: "required", 423 Type: []byte(`"number"`), 424 Required: true, 425 }, 426 }, 427 }, 428 &configschema.Block{ 429 Attributes: map[string]*configschema.Attribute{ 430 "computed": { 431 Type: cty.List(cty.Bool), 432 Computed: true, 433 }, 434 "optional": { 435 Type: cty.String, 436 Optional: true, 437 }, 438 "optional_computed": { 439 Type: cty.Map(cty.Bool), 440 Optional: true, 441 Computed: true, 442 }, 443 "required": { 444 Type: cty.Number, 445 Required: true, 446 }, 447 }, 448 }, 449 }, 450 "blocks": { 451 &proto.Schema_Block{ 452 BlockTypes: []*proto.Schema_NestedBlock{ 453 { 454 TypeName: "list", 455 Nesting: proto.Schema_NestedBlock_LIST, 456 Block: &proto.Schema_Block{}, 457 }, 458 { 459 TypeName: "map", 460 Nesting: proto.Schema_NestedBlock_MAP, 461 Block: &proto.Schema_Block{}, 462 }, 463 { 464 TypeName: "set", 465 Nesting: proto.Schema_NestedBlock_SET, 466 Block: &proto.Schema_Block{}, 467 }, 468 { 469 TypeName: "single", 470 Nesting: proto.Schema_NestedBlock_SINGLE, 471 Block: &proto.Schema_Block{ 472 Attributes: []*proto.Schema_Attribute{ 473 { 474 Name: "foo", 475 Type: []byte(`"dynamic"`), 476 Required: true, 477 }, 478 }, 479 }, 480 }, 481 }, 482 }, 483 &configschema.Block{ 484 BlockTypes: map[string]*configschema.NestedBlock{ 485 "list": &configschema.NestedBlock{ 486 Nesting: configschema.NestingList, 487 }, 488 "map": &configschema.NestedBlock{ 489 Nesting: configschema.NestingMap, 490 }, 491 "set": &configschema.NestedBlock{ 492 Nesting: configschema.NestingSet, 493 }, 494 "single": &configschema.NestedBlock{ 495 Nesting: configschema.NestingSingle, 496 Block: configschema.Block{ 497 Attributes: map[string]*configschema.Attribute{ 498 "foo": { 499 Type: cty.DynamicPseudoType, 500 Required: true, 501 }, 502 }, 503 }, 504 }, 505 }, 506 }, 507 }, 508 "deep block nesting": { 509 &proto.Schema_Block{ 510 BlockTypes: []*proto.Schema_NestedBlock{ 511 { 512 TypeName: "single", 513 Nesting: proto.Schema_NestedBlock_SINGLE, 514 Block: &proto.Schema_Block{ 515 BlockTypes: []*proto.Schema_NestedBlock{ 516 { 517 TypeName: "list", 518 Nesting: proto.Schema_NestedBlock_LIST, 519 Block: &proto.Schema_Block{ 520 BlockTypes: []*proto.Schema_NestedBlock{ 521 { 522 TypeName: "set", 523 Nesting: proto.Schema_NestedBlock_SET, 524 Block: &proto.Schema_Block{}, 525 }, 526 }, 527 }, 528 }, 529 }, 530 }, 531 }, 532 }, 533 }, 534 &configschema.Block{ 535 BlockTypes: map[string]*configschema.NestedBlock{ 536 "single": &configschema.NestedBlock{ 537 Nesting: configschema.NestingSingle, 538 Block: configschema.Block{ 539 BlockTypes: map[string]*configschema.NestedBlock{ 540 "list": &configschema.NestedBlock{ 541 Nesting: configschema.NestingList, 542 Block: configschema.Block{ 543 BlockTypes: map[string]*configschema.NestedBlock{ 544 "set": &configschema.NestedBlock{ 545 Nesting: configschema.NestingSet, 546 }, 547 }, 548 }, 549 }, 550 }, 551 }, 552 }, 553 }, 554 }, 555 }, 556 } 557 558 for name, tc := range tests { 559 t.Run(name, func(t *testing.T) { 560 converted := ConfigSchemaToProto(tc.Block) 561 if !cmp.Equal(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported) { 562 t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported)) 563 } 564 }) 565 } 566 }