Skip to content

Commit 40e25e6

Browse files
committed
list: validate empty config
1 parent df11348 commit 40e25e6

File tree

1 file changed

+105
-1
lines changed

1 file changed

+105
-1
lines changed

internal/terraform/context_plan_query_test.go

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,104 @@ func TestContext2Plan_queryList(t *testing.T) {
261261
}
262262
},
263263
},
264+
{
265+
name: "valid list with empty config",
266+
mainConfig: `
267+
terraform {
268+
required_providers {
269+
test = {
270+
source = "hashicorp/test"
271+
version = "1.0.0"
272+
}
273+
}
274+
}
275+
`,
276+
queryConfig: `
277+
variable "input" {
278+
type = string
279+
default = "foo"
280+
}
281+
282+
list "test_resource" "test" {
283+
count = 1
284+
provider = test
285+
include_resource = true
286+
}
287+
`,
288+
listResourceFn: func(request providers.ListResourceRequest) providers.ListResourceResponse {
289+
madeUp := []cty.Value{
290+
cty.ObjectVal(map[string]cty.Value{"instance_type": cty.StringVal("ami-123456")}),
291+
cty.ObjectVal(map[string]cty.Value{"instance_type": cty.StringVal("ami-654321")}),
292+
}
293+
ids := []cty.Value{}
294+
for i := range madeUp {
295+
ids = append(ids, cty.ObjectVal(map[string]cty.Value{
296+
"id": cty.StringVal(fmt.Sprintf("i-v%d", i+1)),
297+
}))
298+
}
299+
300+
resp := []cty.Value{}
301+
for i, v := range madeUp {
302+
resp = append(resp, cty.ObjectVal(map[string]cty.Value{
303+
"state": v,
304+
"identity": ids[i],
305+
"display_name": cty.StringVal(fmt.Sprintf("Instance %d", i+1)),
306+
}))
307+
}
308+
309+
ret := map[string]cty.Value{
310+
"data": cty.TupleVal(resp),
311+
}
312+
for k, v := range request.Config.AsValueMap() {
313+
if k != "data" {
314+
ret[k] = v
315+
}
316+
}
317+
318+
return providers.ListResourceResponse{Result: cty.ObjectVal(ret)}
319+
},
320+
assertChanges: func(sch providers.ProviderSchema, changes *plans.ChangesSrc) {
321+
expectedResources := []string{"list.test_resource.test[0]"}
322+
actualResources := make([]string, 0)
323+
for _, change := range changes.Queries {
324+
actualResources = append(actualResources, change.Addr.String())
325+
schema := sch.ListResourceTypes[change.Addr.Resource.Resource.Type]
326+
cs, err := change.Decode(schema)
327+
if err != nil {
328+
t.Fatalf("failed to decode change: %s", err)
329+
}
330+
331+
// Verify instance types
332+
expectedTypes := []string{"ami-123456", "ami-654321"}
333+
actualTypes := make([]string, 0)
334+
obj := cs.Results.Value.GetAttr("data")
335+
if obj.IsNull() {
336+
t.Fatalf("Expected 'data' attribute to be present, but it is null")
337+
}
338+
obj.ForEachElement(func(key cty.Value, val cty.Value) bool {
339+
val = val.GetAttr("state")
340+
if val.IsNull() {
341+
t.Fatalf("Expected 'state' attribute to be present, but it is null")
342+
}
343+
if val.GetAttr("instance_type").IsNull() {
344+
t.Fatalf("Expected 'instance_type' attribute to be present, but it is missing")
345+
}
346+
actualTypes = append(actualTypes, val.GetAttr("instance_type").AsString())
347+
return false
348+
})
349+
sort.Strings(actualTypes)
350+
sort.Strings(expectedTypes)
351+
if diff := cmp.Diff(expectedTypes, actualTypes); diff != "" {
352+
t.Fatalf("Expected instance types to match, but they differ: %s", diff)
353+
}
354+
}
355+
sort.Strings(actualResources)
356+
sort.Strings(expectedResources)
357+
if diff := cmp.Diff(expectedResources, actualResources); diff != "" {
358+
t.Fatalf("Expected resources to match, but they differ: %s", diff)
359+
}
360+
},
361+
},
264362
{
265363
name: "invalid list result's attribute reference",
266364
mainConfig: `
@@ -690,6 +788,9 @@ func TestContext2Plan_queryList(t *testing.T) {
690788
provider.GetProviderSchemaResponse = getListProviderSchemaResp()
691789
var requestConfigs = make(map[string]cty.Value)
692790
provider.ListResourceFn = func(request providers.ListResourceRequest) providers.ListResourceResponse {
791+
if request.Config.IsNull() || request.Config.GetAttr("config").IsNull() {
792+
t.Fatalf("config should never be null, got null for %s", request.TypeName)
793+
}
693794
requestConfigs[request.TypeName] = request.Config
694795
fn := tc.listResourceFn
695796
if fn == nil {
@@ -837,6 +938,9 @@ func TestContext2Plan_queryListArgs(t *testing.T) {
837938
provider.GetProviderSchemaResponse = getListProviderSchemaResp()
838939
var recordedRequest providers.ListResourceRequest
839940
provider.ListResourceFn = func(request providers.ListResourceRequest) providers.ListResourceResponse {
941+
if request.Config.IsNull() || request.Config.GetAttr("config").IsNull() {
942+
t.Fatalf("config should never be null, got null for %s", request.TypeName)
943+
}
840944
recordedRequest = request
841945
return provider.ListResourceResponse
842946
}
@@ -902,7 +1006,7 @@ func getListProviderSchemaResp() *providers.GetProviderSchemaResponse {
9021006
},
9031007
},
9041008
},
905-
Nesting: configschema.NestingSingle,
1009+
Nesting: configschema.NestingGroup,
9061010
},
9071011
},
9081012
}

0 commit comments

Comments
 (0)