// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package graph import ( "log" "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/backend/backendrun" "github.com/hashicorp/terraform/internal/moduletest" "github.com/hashicorp/terraform/internal/terraform" "github.com/hashicorp/terraform/internal/tfdiags" ) // TestGraphBuilder is a GraphBuilder implementation that builds a graph for // a terraform test file. The file may contain multiple runs, and each run may have // dependencies on other runs. type TestGraphBuilder struct { File *moduletest.File GlobalVars map[string]backendrun.UnparsedVariableValue ContextOpts *terraform.ContextOpts } type graphOptions struct { File *moduletest.File GlobalVars map[string]backendrun.UnparsedVariableValue ContextOpts *terraform.ContextOpts } // See GraphBuilder func (b *TestGraphBuilder) Build() (*terraform.Graph, tfdiags.Diagnostics) { log.Printf("[TRACE] building graph for terraform test") return (&terraform.BasicGraphBuilder{ Steps: b.Steps(), Name: "TestGraphBuilder", }).Build(addrs.RootModuleInstance) } // See GraphBuilder func (b *TestGraphBuilder) Steps() []terraform.GraphTransformer { opts := &graphOptions{ File: b.File, GlobalVars: b.GlobalVars, ContextOpts: b.ContextOpts, } steps := []terraform.GraphTransformer{ &TestRunTransformer{opts}, &TestConfigTransformer{File: b.File}, &TestStateCleanupTransformer{opts}, terraform.DynamicTransformer(validateRunConfigs), &TestProvidersTransformer{}, &CloseTestGraphTransformer{}, &terraform.TransitiveReductionTransformer{}, } return steps } func validateRunConfigs(g *terraform.Graph) error { for _, v := range g.Vertices() { if node, ok := v.(*NodeTestRun); ok { diags := node.run.Config.Validate(node.run.ModuleConfig) node.run.Diagnostics = node.run.Diagnostics.Append(diags) if diags.HasErrors() { node.run.Status = moduletest.Error } } } return nil } // dynamicNode is a helper node which can be added to the graph to execute // a dynamic function at some desired point in the graph. type dynamicNode struct { eval func(*EvalContext) tfdiags.Diagnostics } func (n *dynamicNode) Execute(evalCtx *EvalContext) tfdiags.Diagnostics { return n.eval(evalCtx) }