diff --git a/internal/command/e2etest/primary_test.go b/internal/command/e2etest/primary_test.go index ebffa9c37d75..e3eff0903031 100644 --- a/internal/command/e2etest/primary_test.go +++ b/internal/command/e2etest/primary_test.go @@ -149,6 +149,124 @@ func TestPrimarySeparatePlan(t *testing.T) { } +func TestPrimarySeparatePlan_incorrectWorkspace(t *testing.T) { + t.Parallel() + + // This test reaches out to releases.hashicorp.com to download the + // template and null providers, so it can only run if network access is + // allowed. + skipIfCannotAccessNetwork(t) + + fixturePath := filepath.Join("testdata", "full-workflow-null") + tf := e2e.NewBinary(t, terraformBin, fixturePath) + + //// INIT + stdout, stderr, err := tf.Run("init") + if err != nil { + t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr) + } + + // Make sure we actually downloaded the plugins, rather than picking up + // copies that might be already installed globally on the system. + if !strings.Contains(stdout, "Installing hashicorp/template v") { + t.Errorf("template provider download message is missing from init output:\n%s", stdout) + t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)") + } + if !strings.Contains(stdout, "Installing hashicorp/null v") { + t.Errorf("null provider download message is missing from init output:\n%s", stdout) + t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)") + } + + //// PLAN + stdout, stderr, err = tf.Run("plan", "-out=tfplan") + if err != nil { + t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr) + } + + if !strings.Contains(stdout, "1 to add, 0 to change, 0 to destroy") { + t.Errorf("incorrect plan tally; want 1 to add:\n%s", stdout) + } + + if !strings.Contains(stdout, "Saved the plan to: tfplan") { + t.Errorf("missing \"Saved the plan to...\" message in plan output\n%s", stdout) + } + if !strings.Contains(stdout, "terraform apply \"tfplan\"") { + t.Errorf("missing next-step instruction in plan output\n%s", stdout) + } + + plan, err := tf.Plan("tfplan") + if err != nil { + t.Fatalf("failed to read plan file: %s", err) + } + + if plan.Backend.Workspace != "default" { + t.Fatalf("expected plan to contain Workspace %q, got %q", "default", plan.Backend.Workspace) + } + + // Create and select a workspace that doesn't match the plan made above + newWorkspace := "foobar" + stdout, stderr, err = tf.Run("workspace", "new", newWorkspace, "-no-color") + if err != nil { + t.Fatalf("unexpected error: %s\nstderr:\n%s", err, stderr) + } + expectedMsg := fmt.Sprintf("Created and switched to workspace %q!", newWorkspace) + if !strings.Contains(stdout, expectedMsg) { + t.Errorf("unexpected output, expected %q, but got:\n%s", expectedMsg, stdout) + } + + //// APPLY + stdout, stderr, err = tf.Run("apply", "tfplan") + if err != nil { + t.Fatalf("unexpected apply error: %s\nstderr:\n%s", err, stderr) + } + + if !strings.Contains(stdout, "Resources: 1 added, 0 changed, 0 destroyed") { + t.Errorf("incorrect apply tally; want 1 added:\n%s", stdout) + } + + state, err := tf.LocalState() + if err != nil { + t.Fatalf("failed to read state file: %s", err) + } + + stateResources := state.RootModule().Resources + var gotResources []string + for n := range stateResources { + gotResources = append(gotResources, n) + } + sort.Strings(gotResources) + + wantResources := []string{ + "data.template_file.test", + "null_resource.test", + } + + if !reflect.DeepEqual(gotResources, wantResources) { + t.Errorf("wrong resources in state\ngot: %#v\nwant: %#v", gotResources, wantResources) + } + + //// DESTROY + stdout, stderr, err = tf.Run("destroy", "-auto-approve") + if err != nil { + t.Fatalf("unexpected destroy error: %s\nstderr:\n%s", err, stderr) + } + + if !strings.Contains(stdout, "Resources: 1 destroyed") { + t.Errorf("incorrect destroy tally; want 1 destroyed:\n%s", stdout) + } + + state, err = tf.LocalState() + if err != nil { + t.Fatalf("failed to read state file after destroy: %s", err) + } + + stateResources = state.RootModule().Resources + if len(stateResources) != 0 { + t.Errorf("wrong resources in state after destroy; want none, but still have:%s", spew.Sdump(stateResources)) + } + +} + func TestPrimaryChdirOption(t *testing.T) { t.Parallel()