github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/plugin/convert/schema_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package convert 5 6 import ( 7 "testing" 8 9 "github.com/google/go-cmp/cmp" 10 "github.com/google/go-cmp/cmp/cmpopts" 11 "github.com/terramate-io/tf/configs/configschema" 12 proto "github.com/terramate-io/tf/tfplugin5" 13 "github.com/zclconf/go-cty/cty" 14 ) 15 16 var ( 17 equateEmpty = cmpopts.EquateEmpty() 18 typeComparer = cmp.Comparer(cty.Type.Equals) 19 valueComparer = cmp.Comparer(cty.Value.RawEquals) 20 ) 21 22 // Test that we can convert configschema to protobuf types and back again. 23 func TestConvertSchemaBlocks(t *testing.T) { 24 tests := map[string]struct { 25 Block *proto.Schema_Block 26 Want *configschema.Block 27 }{ 28 "attributes": { 29 &proto.Schema_Block{ 30 Attributes: []*proto.Schema_Attribute{ 31 { 32 Name: "computed", 33 Type: []byte(`["list","bool"]`), 34 Computed: true, 35 }, 36 { 37 Name: "optional", 38 Type: []byte(`"string"`), 39 Optional: true, 40 }, 41 { 42 Name: "optional_computed", 43 Type: []byte(`["map","bool"]`), 44 Optional: true, 45 Computed: true, 46 }, 47 { 48 Name: "required", 49 Type: []byte(`"number"`), 50 Required: true, 51 }, 52 }, 53 }, 54 &configschema.Block{ 55 Attributes: map[string]*configschema.Attribute{ 56 "computed": { 57 Type: cty.List(cty.Bool), 58 Computed: true, 59 }, 60 "optional": { 61 Type: cty.String, 62 Optional: true, 63 }, 64 "optional_computed": { 65 Type: cty.Map(cty.Bool), 66 Optional: true, 67 Computed: true, 68 }, 69 "required": { 70 Type: cty.Number, 71 Required: true, 72 }, 73 }, 74 }, 75 }, 76 "blocks": { 77 &proto.Schema_Block{ 78 BlockTypes: []*proto.Schema_NestedBlock{ 79 { 80 TypeName: "list", 81 Nesting: proto.Schema_NestedBlock_LIST, 82 Block: &proto.Schema_Block{}, 83 }, 84 { 85 TypeName: "map", 86 Nesting: proto.Schema_NestedBlock_MAP, 87 Block: &proto.Schema_Block{}, 88 }, 89 { 90 TypeName: "set", 91 Nesting: proto.Schema_NestedBlock_SET, 92 Block: &proto.Schema_Block{}, 93 }, 94 { 95 TypeName: "single", 96 Nesting: proto.Schema_NestedBlock_SINGLE, 97 Block: &proto.Schema_Block{ 98 Attributes: []*proto.Schema_Attribute{ 99 { 100 Name: "foo", 101 Type: []byte(`"dynamic"`), 102 Required: true, 103 }, 104 }, 105 }, 106 }, 107 }, 108 }, 109 &configschema.Block{ 110 BlockTypes: map[string]*configschema.NestedBlock{ 111 "list": &configschema.NestedBlock{ 112 Nesting: configschema.NestingList, 113 }, 114 "map": &configschema.NestedBlock{ 115 Nesting: configschema.NestingMap, 116 }, 117 "set": &configschema.NestedBlock{ 118 Nesting: configschema.NestingSet, 119 }, 120 "single": &configschema.NestedBlock{ 121 Nesting: configschema.NestingSingle, 122 Block: configschema.Block{ 123 Attributes: map[string]*configschema.Attribute{ 124 "foo": { 125 Type: cty.DynamicPseudoType, 126 Required: true, 127 }, 128 }, 129 }, 130 }, 131 }, 132 }, 133 }, 134 "deep block nesting": { 135 &proto.Schema_Block{ 136 BlockTypes: []*proto.Schema_NestedBlock{ 137 { 138 TypeName: "single", 139 Nesting: proto.Schema_NestedBlock_SINGLE, 140 Block: &proto.Schema_Block{ 141 BlockTypes: []*proto.Schema_NestedBlock{ 142 { 143 TypeName: "list", 144 Nesting: proto.Schema_NestedBlock_LIST, 145 Block: &proto.Schema_Block{ 146 BlockTypes: []*proto.Schema_NestedBlock{ 147 { 148 TypeName: "set", 149 Nesting: proto.Schema_NestedBlock_SET, 150 Block: &proto.Schema_Block{}, 151 }, 152 }, 153 }, 154 }, 155 }, 156 }, 157 }, 158 }, 159 }, 160 &configschema.Block{ 161 BlockTypes: map[string]*configschema.NestedBlock{ 162 "single": &configschema.NestedBlock{ 163 Nesting: configschema.NestingSingle, 164 Block: configschema.Block{ 165 BlockTypes: map[string]*configschema.NestedBlock{ 166 "list": &configschema.NestedBlock{ 167 Nesting: configschema.NestingList, 168 Block: configschema.Block{ 169 BlockTypes: map[string]*configschema.NestedBlock{ 170 "set": &configschema.NestedBlock{ 171 Nesting: configschema.NestingSet, 172 }, 173 }, 174 }, 175 }, 176 }, 177 }, 178 }, 179 }, 180 }, 181 }, 182 } 183 184 for name, tc := range tests { 185 t.Run(name, func(t *testing.T) { 186 converted := ProtoToConfigSchema(tc.Block) 187 if !cmp.Equal(converted, tc.Want, typeComparer, valueComparer, equateEmpty) { 188 t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, valueComparer, equateEmpty)) 189 } 190 }) 191 } 192 } 193 194 // Test that we can convert configschema to protobuf types and back again. 195 func TestConvertProtoSchemaBlocks(t *testing.T) { 196 tests := map[string]struct { 197 Want *proto.Schema_Block 198 Block *configschema.Block 199 }{ 200 "attributes": { 201 &proto.Schema_Block{ 202 Attributes: []*proto.Schema_Attribute{ 203 { 204 Name: "computed", 205 Type: []byte(`["list","bool"]`), 206 Computed: true, 207 }, 208 { 209 Name: "optional", 210 Type: []byte(`"string"`), 211 Optional: true, 212 }, 213 { 214 Name: "optional_computed", 215 Type: []byte(`["map","bool"]`), 216 Optional: true, 217 Computed: true, 218 }, 219 { 220 Name: "required", 221 Type: []byte(`"number"`), 222 Required: true, 223 }, 224 }, 225 }, 226 &configschema.Block{ 227 Attributes: map[string]*configschema.Attribute{ 228 "computed": { 229 Type: cty.List(cty.Bool), 230 Computed: true, 231 }, 232 "optional": { 233 Type: cty.String, 234 Optional: true, 235 }, 236 "optional_computed": { 237 Type: cty.Map(cty.Bool), 238 Optional: true, 239 Computed: true, 240 }, 241 "required": { 242 Type: cty.Number, 243 Required: true, 244 }, 245 }, 246 }, 247 }, 248 "blocks": { 249 &proto.Schema_Block{ 250 BlockTypes: []*proto.Schema_NestedBlock{ 251 { 252 TypeName: "list", 253 Nesting: proto.Schema_NestedBlock_LIST, 254 Block: &proto.Schema_Block{}, 255 }, 256 { 257 TypeName: "map", 258 Nesting: proto.Schema_NestedBlock_MAP, 259 Block: &proto.Schema_Block{}, 260 }, 261 { 262 TypeName: "set", 263 Nesting: proto.Schema_NestedBlock_SET, 264 Block: &proto.Schema_Block{}, 265 }, 266 { 267 TypeName: "single", 268 Nesting: proto.Schema_NestedBlock_SINGLE, 269 Block: &proto.Schema_Block{ 270 Attributes: []*proto.Schema_Attribute{ 271 { 272 Name: "foo", 273 Type: []byte(`"dynamic"`), 274 Required: true, 275 }, 276 }, 277 }, 278 }, 279 }, 280 }, 281 &configschema.Block{ 282 BlockTypes: map[string]*configschema.NestedBlock{ 283 "list": &configschema.NestedBlock{ 284 Nesting: configschema.NestingList, 285 }, 286 "map": &configschema.NestedBlock{ 287 Nesting: configschema.NestingMap, 288 }, 289 "set": &configschema.NestedBlock{ 290 Nesting: configschema.NestingSet, 291 }, 292 "single": &configschema.NestedBlock{ 293 Nesting: configschema.NestingSingle, 294 Block: configschema.Block{ 295 Attributes: map[string]*configschema.Attribute{ 296 "foo": { 297 Type: cty.DynamicPseudoType, 298 Required: true, 299 }, 300 }, 301 }, 302 }, 303 }, 304 }, 305 }, 306 "deep block nesting": { 307 &proto.Schema_Block{ 308 BlockTypes: []*proto.Schema_NestedBlock{ 309 { 310 TypeName: "single", 311 Nesting: proto.Schema_NestedBlock_SINGLE, 312 Block: &proto.Schema_Block{ 313 BlockTypes: []*proto.Schema_NestedBlock{ 314 { 315 TypeName: "list", 316 Nesting: proto.Schema_NestedBlock_LIST, 317 Block: &proto.Schema_Block{ 318 BlockTypes: []*proto.Schema_NestedBlock{ 319 { 320 TypeName: "set", 321 Nesting: proto.Schema_NestedBlock_SET, 322 Block: &proto.Schema_Block{}, 323 }, 324 }, 325 }, 326 }, 327 }, 328 }, 329 }, 330 }, 331 }, 332 &configschema.Block{ 333 BlockTypes: map[string]*configschema.NestedBlock{ 334 "single": &configschema.NestedBlock{ 335 Nesting: configschema.NestingSingle, 336 Block: configschema.Block{ 337 BlockTypes: map[string]*configschema.NestedBlock{ 338 "list": &configschema.NestedBlock{ 339 Nesting: configschema.NestingList, 340 Block: configschema.Block{ 341 BlockTypes: map[string]*configschema.NestedBlock{ 342 "set": &configschema.NestedBlock{ 343 Nesting: configschema.NestingSet, 344 }, 345 }, 346 }, 347 }, 348 }, 349 }, 350 }, 351 }, 352 }, 353 }, 354 } 355 356 for name, tc := range tests { 357 t.Run(name, func(t *testing.T) { 358 converted := ConfigSchemaToProto(tc.Block) 359 if !cmp.Equal(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported) { 360 t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported)) 361 } 362 }) 363 } 364 }