| // Copyright (c) HashiCorp, Inc. |
| // SPDX-License-Identifier: BUSL-1.1 |
| |
| package moduletest |
| |
| import ( |
| "testing" |
| |
| "github.com/google/go-cmp/cmp" |
| "github.com/hashicorp/hcl/v2" |
| "github.com/hashicorp/hcl/v2/hclsyntax" |
| |
| "github.com/hashicorp/terraform/internal/addrs" |
| "github.com/hashicorp/terraform/internal/configs" |
| "github.com/hashicorp/terraform/internal/tfdiags" |
| ) |
| |
| func TestRun_ValidateExpectedFailures(t *testing.T) { |
| |
| type output struct { |
| Description tfdiags.Description |
| Severity tfdiags.Severity |
| } |
| |
| tcs := map[string]struct { |
| ExpectedFailures []string |
| Input tfdiags.Diagnostics |
| Output []output |
| }{ |
| "empty": { |
| ExpectedFailures: nil, |
| Input: nil, |
| Output: nil, |
| }, |
| "carries through simple diags": { |
| Input: createDiagnostics(func(diags tfdiags.Diagnostics) tfdiags.Diagnostics { |
| |
| diags = diags.Append(&hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "simple error", |
| Detail: "want to see this in the returned set", |
| }) |
| |
| diags = diags.Append(&hcl.Diagnostic{ |
| Severity: hcl.DiagWarning, |
| Summary: "simple warning", |
| Detail: "want to see this in the returned set", |
| }) |
| |
| return diags |
| }), |
| Output: []output{ |
| { |
| Description: tfdiags.Description{ |
| Summary: "simple error", |
| Detail: "want to see this in the returned set", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "simple warning", |
| Detail: "want to see this in the returned set", |
| }, |
| Severity: tfdiags.Warning, |
| }, |
| }, |
| }, |
| "expected failures did not fail": { |
| ExpectedFailures: []string{ |
| "check.example", |
| }, |
| Input: nil, |
| Output: []output{ |
| { |
| Description: tfdiags.Description{ |
| Summary: "Missing expected failure", |
| Detail: "The checkable object, check.example, was expected to report an error but did not.", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| }, |
| }, |
| "outputs": { |
| ExpectedFailures: []string{ |
| "output.expected_one", |
| "output.expected_two", |
| }, |
| Input: createDiagnostics(func(diags tfdiags.Diagnostics) tfdiags.Diagnostics { |
| |
| // First, let's create an output that failed that isn't |
| // expected. This should be unaffected by our function. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "unexpected failure", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsOutputValue{ |
| Module: addrs.RootModuleInstance, |
| OutputValue: addrs.OutputValue{Name: "unexpected"}, |
| }, addrs.OutputPrecondition, 0), |
| }, |
| }) |
| |
| // Second, let's create an output that failed but is expected. |
| // Our function should remove this from the set of diags. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsOutputValue{ |
| Module: addrs.RootModuleInstance, |
| OutputValue: addrs.OutputValue{Name: "expected_one"}, |
| }, addrs.OutputPrecondition, 0), |
| }, |
| }) |
| |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagWarning, |
| Summary: "expected warning", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsOutputValue{ |
| Module: addrs.RootModuleInstance, |
| OutputValue: addrs.OutputValue{Name: "expected_one"}, |
| }, addrs.OutputPrecondition, 0), |
| }, |
| }) |
| |
| // The error we are adding here is for expected_two but in a |
| // child module. We expect that this diagnostic shouldn't |
| // trigger our expected failure, and that an extra diagnostic |
| // should be created complaining that the output wasn't actually |
| // triggered. |
| |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "error in child module", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsOutputValue{ |
| Module: []addrs.ModuleInstanceStep{ |
| { |
| Name: "child_module", |
| }, |
| }, |
| OutputValue: addrs.OutputValue{Name: "expected_two"}, |
| }, addrs.OutputPrecondition, 0), |
| }, |
| }) |
| |
| return diags |
| }), |
| Output: []output{ |
| { |
| Description: tfdiags.Description{ |
| Summary: "unexpected failure", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "expected warning", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Warning, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "error in child module", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "Missing expected failure", |
| Detail: "The checkable object, output.expected_two, was expected to report an error but did not.", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| }, |
| }, |
| "variables": { |
| ExpectedFailures: []string{ |
| "var.expected_one", |
| "var.expected_two", |
| }, |
| Input: createDiagnostics(func(diags tfdiags.Diagnostics) tfdiags.Diagnostics { |
| |
| // First, let's create an input that failed that isn't |
| // expected. This should be unaffected by our function. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "unexpected failure", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsInputVariableInstance{ |
| Module: addrs.RootModuleInstance, |
| Variable: addrs.InputVariable{Name: "unexpected"}, |
| }, addrs.InputValidation, 0), |
| }, |
| }) |
| |
| // Second, let's create an input that failed but is expected. |
| // Our function should remove this from the set of diags. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsInputVariableInstance{ |
| Module: addrs.RootModuleInstance, |
| Variable: addrs.InputVariable{Name: "expected_one"}, |
| }, addrs.InputValidation, 0), |
| }, |
| }) |
| |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagWarning, |
| Summary: "expected warning", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsInputVariableInstance{ |
| Module: addrs.RootModuleInstance, |
| Variable: addrs.InputVariable{Name: "expected_one"}, |
| }, addrs.InputValidation, 0), |
| }, |
| }) |
| |
| // The error we are adding here is for expected_two but in a |
| // child module. We expect that this diagnostic shouldn't |
| // trigger our expected failure, and that an extra diagnostic |
| // should be created complaining that the output wasn't actually |
| // triggered. |
| |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "error in child module", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsInputVariableInstance{ |
| Module: []addrs.ModuleInstanceStep{ |
| { |
| Name: "child_module", |
| }, |
| }, |
| Variable: addrs.InputVariable{Name: "expected_two"}, |
| }, addrs.InputValidation, 0), |
| }, |
| }) |
| |
| return diags |
| }), |
| Output: []output{ |
| { |
| Description: tfdiags.Description{ |
| Summary: "unexpected failure", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "expected warning", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Warning, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "error in child module", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "Missing expected failure", |
| Detail: "The checkable object, var.expected_two, was expected to report an error but did not.", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| }, |
| }, |
| "resources": { |
| ExpectedFailures: []string{ |
| "test_instance.single", |
| "test_instance.all_instances", |
| "test_instance.instance[0]", |
| "test_instance.instance[2]", |
| "test_instance.missing", |
| }, |
| Input: createDiagnostics(func(diags tfdiags.Diagnostics) tfdiags.Diagnostics { |
| // First, we'll create an unexpected failure that should be |
| // carried through untouched. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "unexpected failure", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "unexpected", |
| }, |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| |
| // Second, we'll create a failure from our test_instance.single |
| // resource that should be removed. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure in test_instance.single", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "single", |
| }, |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| |
| // Third, we'll create a warning from our test_instance.single |
| // resource that should be propagated as it is only a warning. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagWarning, |
| Summary: "expected warning in test_instance.single", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "single", |
| }, |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| |
| // Fourth, we'll create diagnostics from several instances of |
| // the test_instance.all_instances which should all be removed. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure in test_instance.all_instances[0]", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "all_instances", |
| }, |
| Key: addrs.IntKey(0), |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure in test_instance.all_instances[1]", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "all_instances", |
| }, |
| Key: addrs.IntKey(1), |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure in test_instance.all_instances[2]", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "all_instances", |
| }, |
| Key: addrs.IntKey(2), |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| |
| // Fifth, we'll create diagnostics for several instances of |
| // the test_instance.instance resource, only some of which |
| // should be removed. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure in test_instance.instance[0]", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "instance", |
| }, |
| Key: addrs.IntKey(0), |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure in test_instance.instance[1]", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "instance", |
| }, |
| Key: addrs.IntKey(1), |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "expected failure in test_instance.instance[2]", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: addrs.RootModuleInstance, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "instance", |
| }, |
| Key: addrs.IntKey(2), |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| |
| // Finally, we'll create an error that originated from |
| // test_instance.missing but in a child module which shouldn't |
| // be removed. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagError, |
| Summary: "failure in child module", |
| Detail: "this should not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsResourceInstance{ |
| Module: []addrs.ModuleInstanceStep{ |
| { |
| Name: "child_module", |
| }, |
| }, |
| Resource: addrs.ResourceInstance{ |
| Resource: addrs.Resource{ |
| Mode: addrs.ManagedResourceMode, |
| Type: "test_instance", |
| Name: "missing", |
| }, |
| }, |
| }, addrs.ResourcePrecondition, 0), |
| }, |
| }) |
| |
| return diags |
| }), |
| Output: []output{ |
| { |
| Description: tfdiags.Description{ |
| Summary: "unexpected failure", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "expected warning in test_instance.single", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Warning, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "expected failure in test_instance.instance[1]", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "failure in child module", |
| Detail: "this should not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "Missing expected failure", |
| Detail: "The checkable object, test_instance.missing, was expected to report an error but did not.", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| }, |
| }, |
| "check_assertions": { |
| ExpectedFailures: []string{ |
| "check.expected", |
| "check.missing", |
| }, |
| Input: createDiagnostics(func(diags tfdiags.Diagnostics) tfdiags.Diagnostics { |
| // First, we'll add an unexpected warning from a check block |
| // assertion that should get upgraded to an error. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagWarning, |
| Summary: "unexpected failure", |
| Detail: "this should upgrade and not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsCheck{ |
| Module: addrs.RootModuleInstance, |
| Check: addrs.Check{ |
| Name: "unexpected", |
| }, |
| }, addrs.CheckAssertion, 0), |
| }, |
| }) |
| |
| // Second, we'll add an unexpected warning from a check block |
| // in a child module that should get upgrade to error. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagWarning, |
| Summary: "expected failure in child module", |
| Detail: "this should upgrade and not be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsCheck{ |
| Module: []addrs.ModuleInstanceStep{ |
| { |
| Name: "child_module", |
| }, |
| }, |
| Check: addrs.Check{ |
| Name: "expected", |
| }, |
| }, addrs.CheckAssertion, 0), |
| }, |
| }) |
| |
| // Third, we'll add an expected warning from a check block |
| // assertion that should be removed. |
| diags = diags.Append( |
| &hcl.Diagnostic{ |
| Severity: hcl.DiagWarning, |
| Summary: "expected failure", |
| Detail: "this should be removed", |
| Extra: &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsCheck{ |
| Module: addrs.RootModuleInstance, |
| Check: addrs.Check{ |
| Name: "expected", |
| }, |
| }, addrs.CheckAssertion, 0), |
| }, |
| }) |
| |
| // The second expected failure has no diagnostics, we just want |
| // to make sure that a new diagnostic is added for this case. |
| |
| return diags |
| }), |
| Output: []output{ |
| { |
| Description: tfdiags.Description{ |
| Summary: "unexpected failure", |
| Detail: "this should upgrade and not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "expected failure in child module", |
| Detail: "this should upgrade and not be removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "Missing expected failure", |
| Detail: "The checkable object, check.missing, was expected to report an error but did not.", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| }, |
| }, |
| "check_data_sources": { |
| ExpectedFailures: []string{ |
| "check.expected", |
| }, |
| Input: createDiagnostics(func(diags tfdiags.Diagnostics) tfdiags.Diagnostics { |
| // First, we'll add an unexpected warning from a check block |
| // assertion that should be propagated as an error. |
| diags = diags.Append( |
| tfdiags.Override( |
| tfdiags.Sourceless(tfdiags.Error, "unexpected failure", "this should be an error and not removed"), |
| tfdiags.Warning, |
| func() tfdiags.DiagnosticExtraWrapper { |
| return &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsCheck{ |
| Module: addrs.RootModuleInstance, |
| Check: addrs.Check{ |
| Name: "unexpected", |
| }, |
| }, addrs.CheckDataResource, 0), |
| } |
| })) |
| |
| // Second, we'll add an unexpected warning from a check block |
| // assertion that should remain as a warning. |
| diags = diags.Append( |
| tfdiags.Override( |
| tfdiags.Sourceless(tfdiags.Warning, "unexpected warning", "this should be a warning and not removed"), |
| tfdiags.Warning, |
| func() tfdiags.DiagnosticExtraWrapper { |
| return &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsCheck{ |
| Module: addrs.RootModuleInstance, |
| Check: addrs.Check{ |
| Name: "unexpected", |
| }, |
| }, addrs.CheckDataResource, 0), |
| } |
| })) |
| |
| // Third, we'll add an unexpected warning from a check block |
| // in a child module that should be propagated as an error. |
| diags = diags.Append( |
| tfdiags.Override( |
| tfdiags.Sourceless(tfdiags.Error, "expected failure from child module", "this should be an error and not removed"), |
| tfdiags.Warning, |
| func() tfdiags.DiagnosticExtraWrapper { |
| return &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsCheck{ |
| Module: []addrs.ModuleInstanceStep{ |
| { |
| Name: "child_module", |
| }, |
| }, |
| Check: addrs.Check{ |
| Name: "expected", |
| }, |
| }, addrs.CheckDataResource, 0), |
| } |
| })) |
| |
| // Fourth, we'll add an expected warning that should be removed. |
| diags = diags.Append( |
| tfdiags.Override( |
| tfdiags.Sourceless(tfdiags.Error, "expected failure", "this should be removed"), |
| tfdiags.Warning, |
| func() tfdiags.DiagnosticExtraWrapper { |
| return &addrs.CheckRuleDiagnosticExtra{ |
| CheckRule: addrs.NewCheckRule(addrs.AbsCheck{ |
| Module: addrs.RootModuleInstance, |
| Check: addrs.Check{ |
| Name: "expected", |
| }, |
| }, addrs.CheckDataResource, 0), |
| } |
| })) |
| |
| return diags |
| }), |
| Output: []output{ |
| { |
| Description: tfdiags.Description{ |
| Summary: "unexpected failure", |
| Detail: "this should be an error and not removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "unexpected warning", |
| Detail: "this should be a warning and not removed", |
| }, |
| Severity: tfdiags.Warning, |
| }, |
| { |
| Description: tfdiags.Description{ |
| Summary: "expected failure from child module", |
| Detail: "this should be an error and not removed", |
| }, |
| Severity: tfdiags.Error, |
| }, |
| }, |
| }, |
| } |
| for name, tc := range tcs { |
| t.Run(name, func(t *testing.T) { |
| var traversals []hcl.Traversal |
| for _, ef := range tc.ExpectedFailures { |
| traversal, diags := hclsyntax.ParseTraversalAbs([]byte(ef), "foo.tf", hcl.Pos{Line: 1, Column: 1}) |
| if diags.HasErrors() { |
| t.Errorf("invalid expected failure %s: %v", ef, diags.Error()) |
| } |
| traversals = append(traversals, traversal) |
| } |
| |
| if t.Failed() { |
| return |
| } |
| |
| run := Run{ |
| Config: &configs.TestRun{ |
| ExpectFailures: traversals, |
| }, |
| } |
| |
| out := run.ValidateExpectedFailures(tc.Input) |
| ix := 0 |
| for ; ix < len(tc.Output); ix++ { |
| expected := tc.Output[ix] |
| |
| if ix >= len(out) { |
| t.Errorf("missing diagnostic at %d, expected: [%s] %s, %s", ix, expected.Severity, expected.Description.Summary, expected.Description.Detail) |
| continue |
| } |
| |
| actual := output{ |
| Description: out[ix].Description(), |
| Severity: out[ix].Severity(), |
| } |
| |
| if diff := cmp.Diff(expected, actual); len(diff) > 0 { |
| t.Errorf("mismatched diagnostic at %d:\n%s", ix, diff) |
| } |
| } |
| |
| for ; ix < len(out); ix++ { |
| actual := out[ix] |
| t.Errorf("additional diagnostic at %d: [%s] %s, %s", ix, actual.Severity(), actual.Description().Summary, actual.Description().Detail) |
| } |
| }) |
| } |
| } |
| |
| func createDiagnostics(populate func(diags tfdiags.Diagnostics) tfdiags.Diagnostics) tfdiags.Diagnostics { |
| var diags tfdiags.Diagnostics |
| diags = populate(diags) |
| return diags |
| } |