From 1e8537b8d4c838c4469c9425f0ce817dcf2abde4 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Mon, 30 Nov 2020 17:48:02 -0500 Subject: [PATCH] remove unused --- terraform/context.go | 43 ---- terraform/context_apply_test.go | 8 +- terraform/context_import_test.go | 11 -- terraform/context_plan_test.go | 2 - terraform/context_test.go | 12 -- terraform/eval_context_builtin.go | 1 - terraform/graph.go | 3 +- terraform/graph_dot.go | 9 + terraform/graph_dot_test.go | 313 ++++++++++++++++++++++++++++++ terraform/terraform_test.go | 6 - 10 files changed, 327 insertions(+), 81 deletions(-) create mode 100644 terraform/graph_dot.go create mode 100644 terraform/graph_dot_test.go diff --git a/terraform/context.go b/terraform/context.go index c44fda7d4..7e24de341 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -37,17 +37,6 @@ const ( InputModeStd = InputModeProvider ) -var ( - // contextFailOnShadowError will cause Context operations to return - // errors when shadow operations fail. This is only used for testing. - contextFailOnShadowError = false - - // contextTestDeepCopyOnPlan will perform a Diff DeepCopy on every - // Plan operation, effectively testing the Diff DeepCopy whenever - // a Plan occurs. This is enabled for tests. - contextTestDeepCopyOnPlan = false -) - // ContextOpts are the user-configurable options to create a context with // NewContext. type ContextOpts struct { @@ -125,11 +114,9 @@ type Context struct { parallelSem Semaphore providerInputConfig map[string]map[string]cty.Value providerSHA256s map[string][]byte - runLock sync.Mutex runCond *sync.Cond runContext context.Context runContextCancel context.CancelFunc - shadowErr error } // (additional methods on Context can be found in context_*.go files.) @@ -383,33 +370,6 @@ func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, tfdiags. } } -// ShadowError returns any errors caught during a shadow operation. -// -// A shadow operation is an operation run in parallel to a real operation -// that performs the same tasks using new logic on copied state. The results -// are compared to ensure that the new logic works the same as the old logic. -// The shadow never affects the real operation or return values. -// -// The result of the shadow operation are only available through this function -// call after a real operation is complete. -// -// For API consumers of Context, you can safely ignore this function -// completely if you have no interest in helping report experimental feature -// errors to Terraform maintainers. Otherwise, please call this function -// after every operation and report this to the user. -// -// IMPORTANT: Shadow errors are _never_ critical: they _never_ affect -// the real state or result of a real operation. They are purely informational -// to assist in future Terraform versions being more stable. Please message -// this effectively to the end user. -// -// This must be called only when no other operation is running (refresh, -// plan, etc.). The result can be used in parallel to any other operation -// running. -func (c *Context) ShadowError() error { - return c.shadowErr -} - // State returns a copy of the current state associated with this context. // // This cannot safely be called in parallel with any other Context function. @@ -748,9 +708,6 @@ func (c *Context) acquireRun(phase string) func() { // Reset the stop hook so we're not stopped c.sh.Reset() - // Reset the shadow errors - c.shadowErr = nil - return c.releaseRun } diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 2256b1c5b..a4acd0085 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -5700,7 +5700,7 @@ func TestContext2Apply_destroyModulePrefix(t *testing.T) { t.Fatalf("plan errors: %s", diags.Err()) } - state, diags = ctx.Apply() + _, diags = ctx.Apply() if diags.HasErrors() { t.Fatalf("diags: %s", diags.Err()) } @@ -8049,7 +8049,7 @@ func TestContext2Apply_singleDestroy(t *testing.T) { } h.Active = true - state, diags := ctx.Apply() + _, diags := ctx.Apply() if diags.HasErrors() { t.Fatalf("diags: %s", diags.Err()) } @@ -8141,7 +8141,7 @@ func TestContext2Apply_issue5254(t *testing.T) { }, }) - plan, diags := ctx.Plan() + _, diags := ctx.Plan() if diags.HasErrors() { t.Fatalf("err: %s", diags.Err()) } @@ -8162,7 +8162,7 @@ func TestContext2Apply_issue5254(t *testing.T) { }, }) - plan, diags = ctx.Plan() + plan, diags := ctx.Plan() if diags.HasErrors() { t.Fatalf("err: %s", diags.Err()) } diff --git a/terraform/context_import_test.go b/terraform/context_import_test.go index a7db88e06..f8679620f 100644 --- a/terraform/context_import_test.go +++ b/terraform/context_import_test.go @@ -921,17 +921,6 @@ module.child[0].nested: provider = provider["registry.terraform.io/hashicorp/aws"] ` -const testImportModuleExistingStr = ` - -module.foo: - aws_instance.bar: - ID = bar - provider = provider["registry.terraform.io/hashicorp/aws"] - aws_instance.foo: - ID = foo - provider = provider["registry.terraform.io/hashicorp/aws"] -` - const testImportMultiStr = ` aws_instance.foo: ID = foo diff --git a/terraform/context_plan_test.go b/terraform/context_plan_test.go index 25c38bba3..b7d05b418 100644 --- a/terraform/context_plan_test.go +++ b/terraform/context_plan_test.go @@ -4389,7 +4389,6 @@ func TestContext2Plan_targetedOverTen(t *testing.T) { state := states.NewState() root := state.EnsureModule(addrs.RootModuleInstance) - var expectedState []string for i := 0; i < 13; i++ { key := fmt.Sprintf("aws_instance.foo[%d]", i) id := fmt.Sprintf("i-abc%d", i) @@ -4403,7 +4402,6 @@ func TestContext2Plan_targetedOverTen(t *testing.T) { }, mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), ) - expectedState = append(expectedState, fmt.Sprintf("%s:\n ID = %s\n", key, id)) } ctx := testContext2(t, &ContextOpts{ diff --git a/terraform/context_test.go b/terraform/context_test.go index 2c8ae3474..b19ac3681 100644 --- a/terraform/context_test.go +++ b/terraform/context_test.go @@ -1054,18 +1054,6 @@ func logDiagnostics(t *testing.T, diags tfdiags.Diagnostics) { } } -const testContextGraph = ` -root: root -aws_instance.bar - aws_instance.bar -> provider.aws -aws_instance.foo - aws_instance.foo -> provider.aws -provider.aws -root - root -> aws_instance.bar - root -> aws_instance.foo -` - const testContextRefreshModuleStr = ` aws_instance.web: (tainted) ID = bar diff --git a/terraform/eval_context_builtin.go b/terraform/eval_context_builtin.go index ae4d16d2a..97d2ff6ef 100644 --- a/terraform/eval_context_builtin.go +++ b/terraform/eval_context_builtin.go @@ -332,7 +332,6 @@ func (ctx *BuiltinEvalContext) SetModuleCallArguments(n addrs.ModuleCallInstance args := ctx.VariableValues[key] if args == nil { - args = make(map[string]cty.Value) ctx.VariableValues[key] = vals return } diff --git a/terraform/graph.go b/terraform/graph.go index c690b356b..5fa1ff283 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -38,8 +38,7 @@ func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics { ctx := walker.EvalContext() // Walk the graph. - var walkFn dag.WalkFunc - walkFn = func(v dag.Vertex) (diags tfdiags.Diagnostics) { + walkFn := func(v dag.Vertex) (diags tfdiags.Diagnostics) { log.Printf("[TRACE] vertex %q: starting visit (%T)", dag.VertexName(v), v) defer func() { diff --git a/terraform/graph_dot.go b/terraform/graph_dot.go new file mode 100644 index 000000000..73e3821fb --- /dev/null +++ b/terraform/graph_dot.go @@ -0,0 +1,9 @@ +package terraform + +import "github.com/hashicorp/terraform/dag" + +// GraphDot returns the dot formatting of a visual representation of +// the given Terraform graph. +func GraphDot(g *Graph, opts *dag.DotOpts) (string, error) { + return string(g.Dot(opts)), nil +} diff --git a/terraform/graph_dot_test.go b/terraform/graph_dot_test.go new file mode 100644 index 000000000..c204424d9 --- /dev/null +++ b/terraform/graph_dot_test.go @@ -0,0 +1,313 @@ +package terraform + +import ( + "strings" + "testing" + + "github.com/hashicorp/terraform/dag" +) + +func TestGraphDot(t *testing.T) { + cases := []struct { + Name string + Graph testGraphFunc + Opts dag.DotOpts + Expect string + Error string + }{ + { + Name: "empty", + Graph: func() *Graph { return &Graph{} }, + Expect: ` +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + } +}`, + }, + { + Name: "three-level", + Graph: func() *Graph { + var g Graph + root := &testDrawableOrigin{"root"} + g.Add(root) + + levelOne := []interface{}{"foo", "bar"} + for i, s := range levelOne { + levelOne[i] = &testDrawable{ + VertexName: s.(string), + } + v := levelOne[i] + + g.Add(v) + g.Connect(dag.BasicEdge(v, root)) + } + + levelTwo := []string{"baz", "qux"} + for i, s := range levelTwo { + v := &testDrawable{ + VertexName: s, + } + + g.Add(v) + g.Connect(dag.BasicEdge(v, levelOne[i])) + } + + return &g + }, + Expect: ` +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] bar" + "[root] baz" + "[root] foo" + "[root] qux" + "[root] root" + "[root] bar" -> "[root] root" + "[root] baz" -> "[root] foo" + "[root] foo" -> "[root] root" + "[root] qux" -> "[root] bar" + } +} + `, + }, + + { + Name: "cycle", + Opts: dag.DotOpts{ + DrawCycles: true, + }, + Graph: func() *Graph { + var g Graph + root := &testDrawableOrigin{"root"} + g.Add(root) + + vA := g.Add(&testDrawable{ + VertexName: "A", + }) + + vB := g.Add(&testDrawable{ + VertexName: "B", + }) + + vC := g.Add(&testDrawable{ + VertexName: "C", + }) + + g.Connect(dag.BasicEdge(vA, root)) + g.Connect(dag.BasicEdge(vA, vC)) + g.Connect(dag.BasicEdge(vB, vA)) + g.Connect(dag.BasicEdge(vC, vB)) + + return &g + }, + Expect: ` +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] A" + "[root] B" + "[root] C" + "[root] root" + "[root] A" -> "[root] B" [color = "red", penwidth = "2.0"] + "[root] A" -> "[root] C" + "[root] A" -> "[root] root" + "[root] B" -> "[root] A" + "[root] B" -> "[root] C" [color = "red", penwidth = "2.0"] + "[root] C" -> "[root] A" [color = "red", penwidth = "2.0"] + "[root] C" -> "[root] B" + } +} + `, + }, + + { + Name: "subgraphs, no depth restriction", + Opts: dag.DotOpts{ + MaxDepth: -1, + }, + Graph: func() *Graph { + var g Graph + root := &testDrawableOrigin{"root"} + g.Add(root) + + var sub Graph + vSubRoot := sub.Add(&testDrawableOrigin{"sub_root"}) + + var subsub Graph + subsub.Add(&testDrawableOrigin{"subsub_root"}) + vSubV := sub.Add(&testDrawableSubgraph{ + VertexName: "subsub", + SubgraphMock: &subsub, + }) + + vSub := g.Add(&testDrawableSubgraph{ + VertexName: "sub", + SubgraphMock: &sub, + }) + + g.Connect(dag.BasicEdge(vSub, root)) + sub.Connect(dag.BasicEdge(vSubV, vSubRoot)) + + return &g + }, + Expect: ` +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] root" + "[root] sub" + "[root] sub" -> "[root] root" + } + subgraph "cluster_sub" { + label = "sub" + "[sub] sub_root" + "[sub] subsub" + "[sub] subsub" -> "[sub] sub_root" + } + subgraph "cluster_subsub" { + label = "subsub" + "[subsub] subsub_root" + } +} + `, + }, + + { + Name: "subgraphs, with depth restriction", + Opts: dag.DotOpts{ + MaxDepth: 1, + }, + Graph: func() *Graph { + var g Graph + root := &testDrawableOrigin{"root"} + g.Add(root) + + var sub Graph + rootSub := sub.Add(&testDrawableOrigin{"sub_root"}) + + var subsub Graph + subsub.Add(&testDrawableOrigin{"subsub_root"}) + + subV := sub.Add(&testDrawableSubgraph{ + VertexName: "subsub", + SubgraphMock: &subsub, + }) + vSub := g.Add(&testDrawableSubgraph{ + VertexName: "sub", + SubgraphMock: &sub, + }) + + g.Connect(dag.BasicEdge(vSub, root)) + sub.Connect(dag.BasicEdge(subV, rootSub)) + return &g + }, + Expect: ` +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] root" + "[root] sub" + "[root] sub" -> "[root] root" + } + subgraph "cluster_sub" { + label = "sub" + "[sub] sub_root" + "[sub] subsub" + "[sub] subsub" -> "[sub] sub_root" + } +} + `, + }, + } + + for _, tc := range cases { + tn := tc.Name + t.Run(tn, func(t *testing.T) { + g := tc.Graph() + var err error + //actual, err := GraphDot(g, &tc.Opts) + actual := string(g.Dot(&tc.Opts)) + + if err == nil && tc.Error != "" { + t.Fatalf("%s: expected err: %s, got none", tn, tc.Error) + } + if err != nil && tc.Error == "" { + t.Fatalf("%s: unexpected err: %s", tn, err) + } + if err != nil && tc.Error != "" { + if !strings.Contains(err.Error(), tc.Error) { + t.Fatalf("%s: expected err: %s\nto contain: %s", tn, err, tc.Error) + } + return + } + + expected := strings.TrimSpace(tc.Expect) + "\n" + if actual != expected { + t.Fatalf("%s:\n\nexpected:\n%s\n\ngot:\n%s", tn, expected, actual) + } + }) + } +} + +type testGraphFunc func() *Graph + +type testDrawable struct { + VertexName string + DependentOnMock []string +} + +func (node *testDrawable) Name() string { + return node.VertexName +} +func (node *testDrawable) DotNode(n string, opts *dag.DotOpts) *dag.DotNode { + return &dag.DotNode{Name: n, Attrs: map[string]string{}} +} +func (node *testDrawable) DependableName() []string { + return []string{node.VertexName} +} +func (node *testDrawable) DependentOn() []string { + return node.DependentOnMock +} + +type testDrawableOrigin struct { + VertexName string +} + +func (node *testDrawableOrigin) Name() string { + return node.VertexName +} +func (node *testDrawableOrigin) DotNode(n string, opts *dag.DotOpts) *dag.DotNode { + return &dag.DotNode{Name: n, Attrs: map[string]string{}} +} +func (node *testDrawableOrigin) DotOrigin() bool { + return true +} +func (node *testDrawableOrigin) DependableName() []string { + return []string{node.VertexName} +} + +type testDrawableSubgraph struct { + VertexName string + SubgraphMock *Graph + DependentOnMock []string +} + +func (node *testDrawableSubgraph) Name() string { + return node.VertexName +} +func (node *testDrawableSubgraph) Subgraph() dag.Grapher { + return node.SubgraphMock +} +func (node *testDrawableSubgraph) DotNode(n string, opts *dag.DotOpts) *dag.DotNode { + return &dag.DotNode{Name: n, Attrs: map[string]string{}} +} +func (node *testDrawableSubgraph) DependentOn() []string { + return node.DependentOnMock +} diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 4475619af..019f47f94 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -38,12 +38,6 @@ func TestMain(m *testing.M) { experiment.Flag(flag.CommandLine) flag.Parse() - // Make sure shadow operations fail our real tests - contextFailOnShadowError = true - - // Always DeepCopy the Diff on every Plan during a test - contextTestDeepCopyOnPlan = true - // We have fmt.Stringer implementations on lots of objects that hide // details that we very often want to see in tests, so we just disable // spew's use of String methods globally on the assumption that spew