Skip to content

Commit 207fb01

Browse files
committed
plancheck: Include known value in error message when asserting an unknown value
1 parent b940385 commit 207fb01

6 files changed

+448
-20
lines changed

plancheck/expect_unknown_output_value.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,15 @@ func (e expectUnknownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRe
3737
}
3838

3939
result, err := tfjsonpath.Traverse(change.AfterUnknown, tfjsonpath.Path{})
40-
4140
if err != nil {
42-
resp.Error = err
41+
// If we find the output in the known values, return a more explicit message
42+
knownVal, knownErr := tfjsonpath.Traverse(change.After, tfjsonpath.Path{})
43+
if knownErr == nil {
44+
resp.Error = fmt.Errorf("Expected unknown value at output %q, but found known value: \"%v\"", e.outputAddress, knownVal)
45+
return
46+
}
4347

48+
resp.Error = err
4449
return
4550
}
4651

@@ -53,7 +58,13 @@ func (e expectUnknownOutputValue) CheckPlan(ctx context.Context, req CheckPlanRe
5358
}
5459

5560
if !isUnknown {
56-
resp.Error = fmt.Errorf("attribute at path is known")
61+
// The output should have a known value, look first to return a more explicit message
62+
knownVal, knownErr := tfjsonpath.Traverse(change.After, tfjsonpath.Path{})
63+
if knownErr == nil {
64+
resp.Error = fmt.Errorf("Expected unknown value at output %q, but found known value: \"%v\"", e.outputAddress, knownVal)
65+
return
66+
}
67+
resp.Error = fmt.Errorf("Expected unknown value at output %q, but found known value", e.outputAddress)
5768

5869
return
5970
}

plancheck/expect_unknown_output_value_at_path.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,14 @@ func (e expectUnknownOutputValueAtPath) CheckPlan(ctx context.Context, req Check
3838
}
3939

4040
result, err := tfjsonpath.Traverse(change.AfterUnknown, e.valuePath)
41-
4241
if err != nil {
42+
// If we find the output in the known values, return a more explicit message
43+
knownVal, knownErr := tfjsonpath.Traverse(change.After, e.valuePath)
44+
if knownErr == nil {
45+
resp.Error = fmt.Errorf("Expected unknown value at output %q path %q, but found known value: \"%v\"", e.outputAddress, e.valuePath.String(), knownVal)
46+
return
47+
}
48+
4349
resp.Error = err
4450

4551
return
@@ -54,7 +60,13 @@ func (e expectUnknownOutputValueAtPath) CheckPlan(ctx context.Context, req Check
5460
}
5561

5662
if !isUnknown {
57-
resp.Error = fmt.Errorf("attribute at path is known")
63+
// The output should have a known value, look first to return a more explicit message
64+
knownVal, knownErr := tfjsonpath.Traverse(change.After, e.valuePath)
65+
if knownErr == nil {
66+
resp.Error = fmt.Errorf("Expected unknown value at output %q path %q, but found known value: \"%v\"", e.outputAddress, e.valuePath.String(), knownVal)
67+
return
68+
}
69+
resp.Error = fmt.Errorf("Expected unknown value at output %q path %q, but found known value", e.outputAddress, e.valuePath.String())
5870

5971
return
6072
}

plancheck/expect_unknown_output_value_at_path_test.go

Lines changed: 158 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ func Test_ExpectUnknownOutputValueAtPath_SetNestedBlock_Object(t *testing.T) {
361361
})
362362
}
363363

364-
func Test_ExpectUnknownOutputValueAtPath_ExpectError_KnownValue(t *testing.T) {
364+
func Test_ExpectUnknownOutputValueAtPath_ExpectError_KnownValue_ListAttribute(t *testing.T) {
365365
t.Parallel()
366366

367367
r.UnitTest(t, r.TestCase{
@@ -381,7 +381,161 @@ func Test_ExpectUnknownOutputValueAtPath_ExpectError_KnownValue(t *testing.T) {
381381
{
382382
Config: `
383383
resource "test_resource" "one" {
384-
set_attribute = ["value1"]
384+
list_attribute = ["value1"]
385+
}
386+
387+
output "resource" {
388+
value = test_resource.one
389+
}
390+
`,
391+
ConfigPlanChecks: r.ConfigPlanChecks{
392+
PreApply: []plancheck.PlanCheck{
393+
plancheck.ExpectUnknownOutputValueAtPath("resource", tfjsonpath.New("list_attribute").AtSliceIndex(0)),
394+
},
395+
},
396+
ExpectError: regexp.MustCompile(`Expected unknown value at output "resource" path "list_attribute.0", but found known value: "value1"`),
397+
},
398+
},
399+
})
400+
}
401+
402+
func Test_ExpectUnknownOutputValueAtPath_ExpectError_KnownValue_StringAttribute(t *testing.T) {
403+
t.Parallel()
404+
405+
r.UnitTest(t, r.TestCase{
406+
ProviderFactories: map[string]func() (*schema.Provider, error){
407+
"test": func() (*schema.Provider, error) { //nolint:unparam // required signature
408+
return testProvider(), nil
409+
},
410+
},
411+
// Prior to Terraform v1.3.0 a planned output is marked as fully unknown
412+
// if any attribute is unknown. The id attribute within the test provider
413+
// is unknown.
414+
// Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022
415+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
416+
tfversion.SkipBelow(tfversion.Version1_3_0),
417+
},
418+
Steps: []r.TestStep{
419+
{
420+
Config: `
421+
resource "test_resource" "one" {
422+
string_attribute = "hello world!"
423+
}
424+
425+
output "resource" {
426+
value = test_resource.one
427+
}
428+
`,
429+
ConfigPlanChecks: r.ConfigPlanChecks{
430+
PreApply: []plancheck.PlanCheck{
431+
plancheck.ExpectUnknownOutputValueAtPath("resource", tfjsonpath.New("string_attribute")),
432+
},
433+
},
434+
ExpectError: regexp.MustCompile(`Expected unknown value at output "resource" path "string_attribute", but found known value: "hello world!"`),
435+
},
436+
},
437+
})
438+
}
439+
440+
func Test_ExpectUnknownOutputValueAtPath_ExpectError_KnownValue_BoolAttribute(t *testing.T) {
441+
t.Parallel()
442+
443+
r.UnitTest(t, r.TestCase{
444+
ProviderFactories: map[string]func() (*schema.Provider, error){
445+
"test": func() (*schema.Provider, error) { //nolint:unparam // required signature
446+
return testProvider(), nil
447+
},
448+
},
449+
// Prior to Terraform v1.3.0 a planned output is marked as fully unknown
450+
// if any attribute is unknown. The id attribute within the test provider
451+
// is unknown.
452+
// Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022
453+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
454+
tfversion.SkipBelow(tfversion.Version1_3_0),
455+
},
456+
Steps: []r.TestStep{
457+
{
458+
Config: `
459+
resource "test_resource" "one" {
460+
bool_attribute = true
461+
}
462+
463+
output "resource" {
464+
value = test_resource.one
465+
}
466+
`,
467+
ConfigPlanChecks: r.ConfigPlanChecks{
468+
PreApply: []plancheck.PlanCheck{
469+
plancheck.ExpectUnknownOutputValueAtPath("resource", tfjsonpath.New("bool_attribute")),
470+
},
471+
},
472+
ExpectError: regexp.MustCompile(`Expected unknown value at output "resource" path "bool_attribute", but found known value: "true"`),
473+
},
474+
},
475+
})
476+
}
477+
478+
func Test_ExpectUnknownOutputValueAtPath_ExpectError_KnownValue_FloatAttribute(t *testing.T) {
479+
t.Parallel()
480+
481+
r.UnitTest(t, r.TestCase{
482+
ProviderFactories: map[string]func() (*schema.Provider, error){
483+
"test": func() (*schema.Provider, error) { //nolint:unparam // required signature
484+
return testProvider(), nil
485+
},
486+
},
487+
// Prior to Terraform v1.3.0 a planned output is marked as fully unknown
488+
// if any attribute is unknown. The id attribute within the test provider
489+
// is unknown.
490+
// Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022
491+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
492+
tfversion.SkipBelow(tfversion.Version1_3_0),
493+
},
494+
Steps: []r.TestStep{
495+
{
496+
Config: `
497+
resource "test_resource" "one" {
498+
float_attribute = 1.234
499+
}
500+
501+
output "resource" {
502+
value = test_resource.one
503+
}
504+
`,
505+
ConfigPlanChecks: r.ConfigPlanChecks{
506+
PreApply: []plancheck.PlanCheck{
507+
plancheck.ExpectUnknownOutputValueAtPath("resource", tfjsonpath.New("float_attribute")),
508+
},
509+
},
510+
ExpectError: regexp.MustCompile(`Expected unknown value at output "resource" path "float_attribute", but found known value: "1.234"`),
511+
},
512+
},
513+
})
514+
}
515+
516+
func Test_ExpectUnknownOutputValueAtPath_ExpectError_KnownValue_ListNestedBlock(t *testing.T) {
517+
t.Parallel()
518+
519+
r.UnitTest(t, r.TestCase{
520+
ProviderFactories: map[string]func() (*schema.Provider, error){
521+
"test": func() (*schema.Provider, error) { //nolint:unparam // required signature
522+
return testProvider(), nil
523+
},
524+
},
525+
// Prior to Terraform v1.3.0 a planned output is marked as fully unknown
526+
// if any attribute is unknown. The id attribute within the test provider
527+
// is unknown.
528+
// Reference: https://github.com/hashicorp/terraform/blob/v1.3/CHANGELOG.md#130-september-21-2022
529+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
530+
tfversion.SkipBelow(tfversion.Version1_3_0),
531+
},
532+
Steps: []r.TestStep{
533+
{
534+
Config: `
535+
resource "test_resource" "one" {
536+
list_nested_block {
537+
list_nested_block_attribute = "value 1"
538+
}
385539
}
386540
387541
output "resource" {
@@ -390,10 +544,10 @@ func Test_ExpectUnknownOutputValueAtPath_ExpectError_KnownValue(t *testing.T) {
390544
`,
391545
ConfigPlanChecks: r.ConfigPlanChecks{
392546
PreApply: []plancheck.PlanCheck{
393-
plancheck.ExpectUnknownOutputValueAtPath("resource", tfjsonpath.New("set_attribute").AtSliceIndex(0)),
547+
plancheck.ExpectUnknownOutputValueAtPath("resource", tfjsonpath.New("list_nested_block").AtSliceIndex(0).AtMapKey("list_nested_block_attribute")),
394548
},
395549
},
396-
ExpectError: regexp.MustCompile(`attribute at path is known`),
550+
ExpectError: regexp.MustCompile(`Expected unknown value at output "resource" path "list_nested_block.0.list_nested_block_attribute", but found known value: "value 1"`),
397551
},
398552
},
399553
})

0 commit comments

Comments
 (0)