From 754bc4e88e19c1b636cc80f1ef50291c3d88dfdf Mon Sep 17 00:00:00 2001 From: Samsondeen Dare Date: Wed, 15 Jan 2025 09:27:57 +0100 Subject: [PATCH] report all deps errors --- internal/backend/local/test.go | 7 +-- internal/command/test_test.go | 1 + internal/terraformtest/node_test_run.go | 6 ++- internal/terraformtest/transform_test_run.go | 56 +++++++++++++++++++- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/internal/backend/local/test.go b/internal/backend/local/test.go index 8be053ff8868..fd8b7b280ae8 100644 --- a/internal/backend/local/test.go +++ b/internal/backend/local/test.go @@ -311,12 +311,13 @@ func (runner *TestFileRunner) Test(file *moduletest.File) { file.Status = file.Status.Merge(moduletest.Pass) } - // Build the graph for the file. Currently, we build this serially to maintain - // the existing sequential functionality of test runs. In the future, we could - // optimize this by parallelizing runs that do not depend on each other. + // Build the graph for the file. b := terraformtest.TestGraphBuilder{File: file} graph, diags := b.Build(addrs.RootModuleInstance) file.Diagnostics = file.Diagnostics.Append(diags) + if diags.HasErrors() { + return + } // walk and execute the graph diags = runner.walkGraph(graph) diff --git a/internal/command/test_test.go b/internal/command/test_test.go index d7678195e189..b07ab97d21ee 100644 --- a/internal/command/test_test.go +++ b/internal/command/test_test.go @@ -294,6 +294,7 @@ func TestTest_Runs(t *testing.T) { expectedOut: []string{"3 passed, 1 failed."}, expectedErr: []string{"Test assertion failed", "resource renamed without moved block"}, code: 1, + }, "simple_testdata": { expectedOut: []string{" passed, 0 failed."}, code: 0, diff --git a/internal/terraformtest/node_test_run.go b/internal/terraformtest/node_test_run.go index 5d218a754020..db605324cdc0 100644 --- a/internal/terraformtest/node_test_run.go +++ b/internal/terraformtest/node_test_run.go @@ -6,12 +6,14 @@ package terraformtest import ( "fmt" + "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/moduletest" ) type NodeTestRun struct { - file *moduletest.File - run *moduletest.Run + file *moduletest.File + run *moduletest.Run + config *configs.Config } func (n *NodeTestRun) Run() *moduletest.Run { diff --git a/internal/terraformtest/transform_test_run.go b/internal/terraformtest/transform_test_run.go index b66f2171b141..6a1cb74522bc 100644 --- a/internal/terraformtest/transform_test_run.go +++ b/internal/terraformtest/transform_test_run.go @@ -4,9 +4,15 @@ package terraformtest import ( + "errors" + "fmt" + "strings" + + "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/backend/backendrun" "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/dag" + "github.com/hashicorp/terraform/internal/lang/langrefs" "github.com/hashicorp/terraform/internal/moduletest" "github.com/hashicorp/terraform/internal/terraform" ) @@ -21,16 +27,62 @@ type TestRunTransformer struct { func (t *TestRunTransformer) Transform(g *terraform.Graph) error { var prev *NodeTestRun + var errs []error + runsSoFar := make(map[string]*NodeTestRun) for _, run := range t.File.Runs { - node := &NodeTestRun{run: run, file: t.File} + // If we're testing a specific configuration, we need to use that + config := t.config + if run.Config.ConfigUnderTest != nil { + config = run.Config.ConfigUnderTest + } + + node := &NodeTestRun{run: run, file: t.File, config: config} g.Add(node) if prev != nil { g.Connect(dag.BasicEdge(node, prev)) } prev = node + + // Connect the run to all the other runs that it depends on + refs, err := getRefs(run) + if err != nil { + return err + } + for _, ref := range refs { + subjectStr := ref.Subject.String() + if !strings.HasPrefix(subjectStr, "run.") { + continue + } + runName := strings.TrimPrefix(subjectStr, "run.") + if runName == "" { + continue + } + dependency, ok := runsSoFar[runName] + if !ok { + errs = append(errs, fmt.Errorf("dependency `run.%s` not found for run %q", runName, run.Name)) + continue + } + g.Connect(dag.BasicEdge(node, dependency)) + } + runsSoFar[run.Name] = node } - return nil + return errors.Join(errs...) +} + +func getRefs(run *moduletest.Run) ([]*addrs.Reference, error) { + refs, refDiags := run.GetReferences() + if refDiags.HasErrors() { + return nil, refDiags.Err() + } + for _, expr := range run.Config.Variables { + moreRefs, moreDiags := langrefs.ReferencesInExpr(addrs.ParseRefFromTestingScope, expr) + if moreDiags.HasErrors() { + return nil, moreDiags.Err() + } + refs = append(refs, moreRefs...) + } + return refs, nil } // -------------------------------------------------------- CloseTestGraphTransformer --------------------------------------------------------