From d196d2870a2e77f4ec65efe2359ed0d6919b10f7 Mon Sep 17 00:00:00 2001 From: Barrett Clark Date: Thu, 16 Dec 2021 14:23:42 -0600 Subject: [PATCH] Refactor cloud table test runs As the cloud e2e tests evolved some common patters became apparent. This standardizes and consolidates the patterns into a common test runner that takes the table tests and runs them in parallel. Some tests also needed to be converted to utilize table tests. --- internal/cloud/e2e/apply_auto_approve_test.go | 81 +- .../e2e/backend_apply_before_init_test.go | 78 +- internal/cloud/e2e/helper_test.go | 4 +- .../cloud/e2e/init_with_empty_tags_test.go | 77 +- internal/cloud/e2e/main_test.go | 92 + .../e2e/migrate_state_multi_to_tfc_test.go | 158 +- ...igrate_state_remote_backend_to_tfc_test.go | 1531 ++++++----------- .../e2e/migrate_state_single_to_tfc_test.go | 82 +- .../e2e/migrate_state_tfc_to_other_test.go | 77 +- .../e2e/migrate_state_tfc_to_tfc_test.go | 182 +- internal/cloud/e2e/run_variables_test.go | 79 +- 11 files changed, 594 insertions(+), 1847 deletions(-) diff --git a/internal/cloud/e2e/apply_auto_approve_test.go b/internal/cloud/e2e/apply_auto_approve_test.go index 45afeaeb7..816e70035 100644 --- a/internal/cloud/e2e/apply_auto_approve_test.go +++ b/internal/cloud/e2e/apply_auto_approve_test.go @@ -2,13 +2,9 @@ package main import ( "context" - "io/ioutil" - "os" "testing" - expect "github.com/Netflix/go-expect" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/e2e" tfversion "github.com/hashicorp/terraform/version" ) @@ -19,10 +15,7 @@ func Test_terraform_apply_autoApprove(t *testing.T) { ctx := context.Background() - cases := map[string]struct { - operations []operationSets - validations func(t *testing.T, orgName string) - }{ + cases := testCases{ "workspace manual apply, terraform apply without auto-approve, expect prompt": { operations: []operationSets{ { @@ -180,76 +173,6 @@ func Test_terraform_apply_autoApprove(t *testing.T) { }, }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - organization, cleanup := createOrganization(t) - defer cleanup() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - for _, op := range tc.operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil && !tfCmd.expectError { - subtest.Fatal(err) - } - } - } - - if tc.validations != nil { - tc.validations(t, organization.Name) - } - }) - } + testRunner(t, cases, 1) } diff --git a/internal/cloud/e2e/backend_apply_before_init_test.go b/internal/cloud/e2e/backend_apply_before_init_test.go index b44354b91..390e54a42 100644 --- a/internal/cloud/e2e/backend_apply_before_init_test.go +++ b/internal/cloud/e2e/backend_apply_before_init_test.go @@ -1,12 +1,7 @@ package main import ( - "io/ioutil" - "os" "testing" - - expect "github.com/Netflix/go-expect" - "github.com/hashicorp/terraform/internal/e2e" ) func Test_backend_apply_before_init(t *testing.T) { @@ -14,9 +9,7 @@ func Test_backend_apply_before_init(t *testing.T) { skipIfMissingEnvVar(t) skipWithoutRemoteTerraformVersion(t) - cases := map[string]struct { - operations []operationSets - }{ + cases := testCases{ "terraform apply with cloud block - blank state": { operations: []operationSets{ { @@ -71,72 +64,5 @@ func Test_backend_apply_before_init(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - organization, cleanup := createOrganization(t) - defer cleanup() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - for _, op := range tc.operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil && !tfCmd.expectError { - subtest.Fatal(err) - } - } - } - }) - } + testRunner(t, cases, 1) } diff --git a/internal/cloud/e2e/helper_test.go b/internal/cloud/e2e/helper_test.go index 9abfa9c30..eb464cdb1 100644 --- a/internal/cloud/e2e/helper_test.go +++ b/internal/cloud/e2e/helper_test.go @@ -15,7 +15,9 @@ import ( ) const ( - expectConsoleTimeout = 60 * time.Second * 3 + // We need to give the console enough time to hear back. + // 1 minute was too short in some cases, so this gives it ample time. + expectConsoleTimeout = 3 * time.Minute ) type tfCommand struct { diff --git a/internal/cloud/e2e/init_with_empty_tags_test.go b/internal/cloud/e2e/init_with_empty_tags_test.go index 5683363b8..016aad50c 100644 --- a/internal/cloud/e2e/init_with_empty_tags_test.go +++ b/internal/cloud/e2e/init_with_empty_tags_test.go @@ -1,12 +1,7 @@ package main import ( - "io/ioutil" - "os" "testing" - - expect "github.com/Netflix/go-expect" - "github.com/hashicorp/terraform/internal/e2e" ) func Test_init_with_empty_tags(t *testing.T) { @@ -14,9 +9,7 @@ func Test_init_with_empty_tags(t *testing.T) { skipIfMissingEnvVar(t) skipWithoutRemoteTerraformVersion(t) - cases := map[string]struct { - operations []operationSets - }{ + cases := testCases{ "terraform init with cloud block - no tagged workspaces exist yet": { operations: []operationSets{ { @@ -38,71 +31,5 @@ func Test_init_with_empty_tags(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - organization, cleanup := createOrganization(t) - defer cleanup() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - for _, op := range tc.operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - err = cmd.Wait() - if err != nil && !tfCmd.expectError { - subtest.Fatal(err) - } - } - } - }) - } + testRunner(t, cases, 1) } diff --git a/internal/cloud/e2e/main_test.go b/internal/cloud/e2e/main_test.go index d758eb65d..4bfe61429 100644 --- a/internal/cloud/e2e/main_test.go +++ b/internal/cloud/e2e/main_test.go @@ -10,7 +10,9 @@ import ( "strings" "testing" + expect "github.com/Netflix/go-expect" tfe "github.com/hashicorp/go-tfe" + "github.com/hashicorp/terraform/internal/e2e" tfversion "github.com/hashicorp/terraform/version" ) @@ -66,6 +68,96 @@ func setup() func() { teardown() } } +func testRunner(t *testing.T, cases testCases, orgCount int, tfEnvFlags ...string) { + for name, tc := range cases { + tc := tc // rebind tc into this lexical scope + t.Run(name, func(subtest *testing.T) { + subtest.Parallel() + + orgNames := []string{} + for i := 0; i < orgCount; i++ { + organization, cleanup := createOrganization(t) + t.Cleanup(cleanup) + orgNames = append(orgNames, organization.Name) + } + + exp, err := expect.NewConsole(defaultOpts()...) + if err != nil { + subtest.Fatal(err) + } + defer exp.Close() + + tmpDir, err := ioutil.TempDir("", "terraform-test") + if err != nil { + subtest.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + tf := e2e.NewBinary(terraformBin, tmpDir) + tfEnvFlags = append(tfEnvFlags, "TF_LOG=INFO") + tfEnvFlags = append(tfEnvFlags, cliConfigFileEnv) + for _, env := range tfEnvFlags { + tf.AddEnv(env) + } + defer tf.Close() + + var orgName string + for index, op := range tc.operations { + if orgCount == 1 { + orgName = orgNames[0] + } else { + orgName = orgNames[index] + } + op.prep(t, orgName, tf.WorkDir()) + for _, tfCmd := range op.commands { + cmd := tf.Cmd(tfCmd.command...) + cmd.Stdin = exp.Tty() + cmd.Stdout = exp.Tty() + cmd.Stderr = exp.Tty() + + err = cmd.Start() + if err != nil { + subtest.Fatal(err) + } + + if tfCmd.expectedCmdOutput != "" { + got, err := exp.ExpectString(tfCmd.expectedCmdOutput) + if err != nil { + subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) + } + } + + lenInput := len(tfCmd.userInput) + lenInputOutput := len(tfCmd.postInputOutput) + if lenInput > 0 { + for i := 0; i < lenInput; i++ { + input := tfCmd.userInput[i] + exp.SendLine(input) + // use the index to find the corresponding + // output that matches the input. + if lenInputOutput-1 >= i { + output := tfCmd.postInputOutput[i] + _, err := exp.ExpectString(output) + if err != nil { + subtest.Fatal(err) + } + } + } + } + + err = cmd.Wait() + if err != nil && !tfCmd.expectError { + subtest.Fatal(err) + } + } + } + + if tc.validations != nil { + tc.validations(t, orgName) + } + }) + } +} func setTfeClient() { tfeHostname = os.Getenv("TFE_HOSTNAME") diff --git a/internal/cloud/e2e/migrate_state_multi_to_tfc_test.go b/internal/cloud/e2e/migrate_state_multi_to_tfc_test.go index 943da4ccd..b2f4ed0c5 100644 --- a/internal/cloud/e2e/migrate_state_multi_to_tfc_test.go +++ b/internal/cloud/e2e/migrate_state_multi_to_tfc_test.go @@ -2,13 +2,9 @@ package main import ( "context" - "io/ioutil" - "os" "testing" - expect "github.com/Netflix/go-expect" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/e2e" tfversion "github.com/hashicorp/terraform/version" ) @@ -19,10 +15,7 @@ func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) { ctx := context.Background() - cases := map[string]struct { - operations []operationSets - validations func(t *testing.T, orgName string) - }{ + cases := testCases{ "migrating multiple workspaces to cloud using name strategy; current workspace is 'default'": { operations: []operationSets{ { @@ -225,78 +218,7 @@ func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - organization, cleanup := createOrganization(t) - defer cleanup() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - defer tf.Close() - tf.AddEnv(cliConfigFileEnv) - - for _, op := range tc.operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil && !tfCmd.expectError { - subtest.Fatal(err) - } - } - } - - if tc.validations != nil { - tc.validations(t, organization.Name) - } - }) - } + testRunner(t, cases, 1) } func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) { @@ -514,79 +436,5 @@ func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - organization, cleanup := createOrganization(t) - defer cleanup() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - defer tf.Close() - tf.AddEnv(cliConfigFileEnv) - - for _, op := range tc.operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - if output == "" { - continue - } - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil { - subtest.Fatal(err) - } - } - } - - if tc.validations != nil { - tc.validations(t, organization.Name) - } - }) - } + testRunner(t, cases, 1) } diff --git a/internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go b/internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go index 831a716a0..2ae9345e2 100644 --- a/internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go +++ b/internal/cloud/e2e/migrate_state_remote_backend_to_tfc_test.go @@ -2,1091 +2,522 @@ package main import ( "context" - "io/ioutil" - "os" "testing" - expect "github.com/Netflix/go-expect" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/e2e" ) -func Test_migrate_remote_backend_name_to_tfc_name(t *testing.T) { +func Test_migrate_remote_backend_single_org(t *testing.T) { t.Parallel() skipIfMissingEnvVar(t) skipWithoutRemoteTerraformVersion(t) ctx := context.Background() - operations := []operationSets{ - { - prep: func(t *testing.T, orgName, dir string) { - remoteWorkspace := "remote-workspace" - tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ + cases := testCases{ + "migrate remote backend name to tfc name": { + operations: []operationSets{ { - command: []string{"init"}, - expectedCmdOutput: `Successfully configured the backend "remote"!`, + prep: func(t *testing.T, orgName, dir string) { + remoteWorkspace := "remote-workspace" + tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `Successfully configured the backend "remote"!`, + }, + { + command: []string{"apply", "-auto-approve"}, + expectedCmdOutput: `Apply complete!`, + }, + }, }, { - command: []string{"apply", "-auto-approve"}, - expectedCmdOutput: `Apply complete!`, + prep: func(t *testing.T, orgName, dir string) { + wsName := "cloud-workspace" + tfBlock := terraformConfigCloudBackendName(orgName, wsName) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-ignore-remote-version"}, + expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, + userInput: []string{"yes", "yes"}, + postInputOutput: []string{ + `Should Terraform migrate your existing state?`, + `Terraform Cloud has been successfully initialized!`}, + }, + { + command: []string{"workspace", "show"}, + expectedCmdOutput: `cloud-workspace`, + }, + }, }, }, - }, - { - prep: func(t *testing.T, orgName, dir string) { - wsName := "cloud-workspace" - tfBlock := terraformConfigCloudBackendName(orgName, wsName) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init", "-ignore-remote-version"}, - expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, - userInput: []string{"yes", "yes"}, - postInputOutput: []string{ - `Should Terraform migrate your existing state?`, - `Terraform Cloud has been successfully initialized!`}, - }, - { - command: []string{"workspace", "show"}, - expectedCmdOutput: `cloud-workspace`, - }, - }, - }, - } - validations := func(t *testing.T, orgName string) { - expectedName := "cloud-workspace" - ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) - if err != nil { - t.Fatal(err) - } - if ws == nil { - t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) - } - } - - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - t.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - organization, cleanup := createOrganization(t) - defer cleanup() - for _, op := range operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) + validations: func(t *testing.T, orgName string) { + expectedName := "cloud-workspace" + ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) + t.Fatal(err) } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - t.Fatal(err) - } - } + if ws == nil { + t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) } - } - - err = cmd.Wait() - if err != nil { - t.Fatal(err) - } - } + }, + }, + "migrate remote backend name to tfc same name": { + operations: []operationSets{ + { + prep: func(t *testing.T, orgName, dir string) { + remoteWorkspace := "remote-workspace" + tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `Successfully configured the backend "remote"!`, + }, + { + command: []string{"apply", "-auto-approve"}, + postInputOutput: []string{`Apply complete!`}, + }, + }, + }, + { + prep: func(t *testing.T, orgName, dir string) { + wsName := "remote-workspace" + tfBlock := terraformConfigCloudBackendName(orgName, wsName) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-ignore-remote-version"}, + expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, + userInput: []string{"yes", "yes"}, + postInputOutput: []string{ + `Should Terraform migrate your existing state?`, + `Terraform Cloud has been successfully initialized!`}, + }, + { + command: []string{"workspace", "show"}, + expectedCmdOutput: `remote-workspace`, + }, + }, + }, + }, + validations: func(t *testing.T, orgName string) { + expectedName := "remote-workspace" + ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) + if err != nil { + t.Fatal(err) + } + if ws == nil { + t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) + } + }, + }, + "migrate remote backend name to tfc tags": { + operations: []operationSets{ + { + prep: func(t *testing.T, orgName, dir string) { + remoteWorkspace := "remote-workspace" + tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `Successfully configured the backend "remote"!`, + }, + { + command: []string{"apply", "-auto-approve"}, + postInputOutput: []string{`Apply complete!`}, + }, + { + command: []string{"workspace", "show"}, + expectedCmdOutput: `default`, + }, + }, + }, + { + prep: func(t *testing.T, orgName, dir string) { + tag := "app" + tfBlock := terraformConfigCloudBackendTags(orgName, tag) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-ignore-remote-version"}, + expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, + userInput: []string{"yes", "cloud-workspace", "yes"}, + postInputOutput: []string{ + `Should Terraform migrate your existing state?`, + `Terraform Cloud requires all workspaces to be given an explicit name.`, + `Terraform Cloud has been successfully initialized!`}, + }, + { + command: []string{"workspace", "show"}, + expectedCmdOutput: `cloud-workspace`, + }, + }, + }, + }, + validations: func(t *testing.T, orgName string) { + wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{ + Tags: tfe.String("app"), + }) + if err != nil { + t.Fatal(err) + } + if len(wsList.Items) != 1 { + t.Fatalf("Expected number of workspaces to be 1, but got %d", len(wsList.Items)) + } + ws := wsList.Items[0] + if ws.Name != "cloud-workspace" { + t.Fatalf("Expected workspace to be `cloud-workspace`, but is %s", ws.Name) + } + }, + }, + "migrate remote backend prefix to tfc name strategy single workspace": { + operations: []operationSets{ + { + prep: func(t *testing.T, orgName, dir string) { + _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) + prefix := "app-" + tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `Terraform has been successfully initialized!`, + }, + { + command: []string{"apply", "-auto-approve"}, + postInputOutput: []string{`Apply complete!`}, + }, + }, + }, + { + prep: func(t *testing.T, orgName, dir string) { + wsName := "cloud-workspace" + tfBlock := terraformConfigCloudBackendName(orgName, wsName) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-ignore-remote-version"}, + expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, + userInput: []string{"yes", "yes"}, + postInputOutput: []string{ + `Should Terraform migrate your existing state?`, + `Terraform Cloud has been successfully initialized!`}, + }, + { + command: []string{"workspace", "show"}, + expectedCmdOutput: `cloud-workspace`, + }, + }, + }, + }, + validations: func(t *testing.T, orgName string) { + expectedName := "cloud-workspace" + ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) + if err != nil { + t.Fatal(err) + } + if ws == nil { + t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) + } + }, + }, + "migrate remote backend prefix to tfc name strategy multi workspace": { + operations: []operationSets{ + { + prep: func(t *testing.T, orgName, dir string) { + _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) + _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")}) + prefix := "app-" + tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `The currently selected workspace (default) does not exist.`, + userInput: []string{"1"}, + postInputOutput: []string{`Terraform has been successfully initialized!`}, + }, + { + command: []string{"apply", "-auto-approve"}, + postInputOutput: []string{`Apply complete!`}, + }, + { + command: []string{"workspace", "list"}, + expectedCmdOutput: "* one", // app name retrieved via prefix + }, + { + command: []string{"workspace", "select", "two"}, + expectedCmdOutput: `Switched to workspace "two".`, // app name retrieved via prefix + }, + }, + }, + { + prep: func(t *testing.T, orgName, dir string) { + wsName := "cloud-workspace" + tfBlock := terraformConfigCloudBackendName(orgName, wsName) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-ignore-remote-version"}, + expectedCmdOutput: `Do you want to copy only your current workspace?`, + userInput: []string{"yes"}, + postInputOutput: []string{ + `Terraform Cloud has been successfully initialized!`}, + }, + { + command: []string{"workspace", "show"}, + expectedCmdOutput: `cloud-workspace`, + }, + }, + }, + }, + validations: func(t *testing.T, orgName string) { + expectedName := "cloud-workspace" + ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) + if err != nil { + t.Fatal(err) + } + if ws == nil { + t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) + } + wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{}) + if err != nil { + t.Fatal(err) + } + if len(wsList.Items) != 3 { + t.Fatalf("expected number of workspaces in this org to be 3, but got %d", len(wsList.Items)) + } + _, empty := getWorkspace(wsList.Items, "cloud-workspace") + if empty { + t.Fatalf("expected workspaces to include 'cloud-workspace' but didn't.") + } + _, empty = getWorkspace(wsList.Items, "app-one") + if empty { + t.Fatalf("expected workspaces to include 'app-one' but didn't.") + } + _, empty = getWorkspace(wsList.Items, "app-two") + if empty { + t.Fatalf("expected workspaces to include 'app-two' but didn't.") + } + }, + }, + "migrate remote backend prefix to tfc tags strategy single workspace": { + operations: []operationSets{ + { + prep: func(t *testing.T, orgName, dir string) { + _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) + prefix := "app-" + tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `Terraform has been successfully initialized!`, + }, + { + command: []string{"apply", "-auto-approve"}, + postInputOutput: []string{`Apply complete!`}, + }, + }, + }, + { + prep: func(t *testing.T, orgName, dir string) { + tag := "app" + tfBlock := terraformConfigCloudBackendTags(orgName, tag) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-ignore-remote-version"}, + expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, + userInput: []string{"yes", "cloud-workspace", "yes"}, + postInputOutput: []string{ + `Should Terraform migrate your existing state?`, + `Terraform Cloud requires all workspaces to be given an explicit name.`, + `Terraform Cloud has been successfully initialized!`}, + }, + { + command: []string{"workspace", "list"}, + expectedCmdOutput: `cloud-workspace`, + }, + }, + }, + }, + validations: func(t *testing.T, orgName string) { + expectedName := "cloud-workspace" + ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) + if err != nil { + t.Fatal(err) + } + if ws == nil { + t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) + } + }, + }, + "migrate remote backend prefix to tfc tags strategy multi workspace": { + operations: []operationSets{ + { + prep: func(t *testing.T, orgName, dir string) { + _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) + _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")}) + prefix := "app-" + tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `The currently selected workspace (default) does not exist.`, + userInput: []string{"1"}, + postInputOutput: []string{`Terraform has been successfully initialized!`}, + }, + { + command: []string{"apply"}, + expectedCmdOutput: `Do you want to perform these actions in workspace "app-one"?`, + userInput: []string{"yes"}, + postInputOutput: []string{`Apply complete!`}, + }, + { + command: []string{"workspace", "select", "two"}, + }, + { + command: []string{"apply"}, + expectedCmdOutput: `Do you want to perform these actions in workspace "app-two"?`, + userInput: []string{"yes"}, + postInputOutput: []string{`Apply complete!`}, + }, + }, + }, + { + prep: func(t *testing.T, orgName, dir string) { + tag := "app" + tfBlock := terraformConfigCloudBackendTags(orgName, tag) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-ignore-remote-version"}, + expectedCmdOutput: `Do you wish to proceed?`, + userInput: []string{"yes"}, + postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, + }, + { + command: []string{"workspace", "show"}, + expectedCmdOutput: "app-two", + }, + { + command: []string{"workspace", "select", "app-one"}, + expectedCmdOutput: `Switched to workspace "app-one".`, + }, + }, + }, + }, + validations: func(t *testing.T, orgName string) { + wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{ + Tags: tfe.String("app"), + }) + if err != nil { + t.Fatal(err) + } + if len(wsList.Items) != 2 { + t.Logf("Expected the number of workspaces to be 2, but got %d", len(wsList.Items)) + } + ws, empty := getWorkspace(wsList.Items, "app-one") + if empty { + t.Fatalf("expected workspaces to include 'app-one' but didn't.") + } + if len(ws.TagNames) == 0 { + t.Fatalf("expected workspaces 'one' to have tags.") + } + ws, empty = getWorkspace(wsList.Items, "app-two") + if empty { + t.Fatalf("expected workspaces to include 'app-two' but didn't.") + } + if len(ws.TagNames) == 0 { + t.Fatalf("expected workspaces 'app-two' to have tags.") + } + }, + }, } - if validations != nil { - validations(t, organization.Name) - } + testRunner(t, cases, 1) } -func Test_migrate_remote_backend_name_to_tfc_same_name(t *testing.T) { +func Test_migrate_remote_backend_multi_org(t *testing.T) { t.Parallel() skipIfMissingEnvVar(t) skipWithoutRemoteTerraformVersion(t) ctx := context.Background() - operations := []operationSets{ - { - prep: func(t *testing.T, orgName, dir string) { - remoteWorkspace := "remote-workspace" - tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ + cases := testCases{ + "migrate remote backend name to tfc name": { + operations: []operationSets{ { - command: []string{"init"}, - expectedCmdOutput: `Successfully configured the backend "remote"!`, + prep: func(t *testing.T, orgName, dir string) { + remoteWorkspace := "remote-workspace" + tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `Successfully configured the backend "remote"!`, + }, + { + command: []string{"apply", "-auto-approve"}, + postInputOutput: []string{`Apply complete!`}, + }, + }, }, { - command: []string{"apply", "-auto-approve"}, - postInputOutput: []string{`Apply complete!`}, + prep: func(t *testing.T, orgName, dir string) { + wsName := "remote-workspace" + tfBlock := terraformConfigCloudBackendName(orgName, wsName) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-ignore-remote-version"}, + expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, + userInput: []string{"yes", "yes"}, + postInputOutput: []string{ + `Should Terraform migrate your existing state?`, + `Terraform Cloud has been successfully initialized!`}, + }, + { + command: []string{"workspace", "show"}, + expectedCmdOutput: `remote-workspace`, + }, + }, }, }, - }, - { - prep: func(t *testing.T, orgName, dir string) { - wsName := "remote-workspace" - tfBlock := terraformConfigCloudBackendName(orgName, wsName) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init", "-ignore-remote-version"}, - expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, - userInput: []string{"yes", "yes"}, - postInputOutput: []string{ - `Should Terraform migrate your existing state?`, - `Terraform Cloud has been successfully initialized!`}, - }, - { - command: []string{"workspace", "show"}, - expectedCmdOutput: `remote-workspace`, - }, - }, - }, - } - validations := func(t *testing.T, orgName string) { - expectedName := "remote-workspace" - ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) - if err != nil { - t.Fatal(err) - } - if ws == nil { - t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) - } - } - - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - t.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - organization, cleanup := createOrganization(t) - defer cleanup() - for _, op := range operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) + validations: func(t *testing.T, orgName string) { + expectedName := "remote-workspace" + ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) + t.Fatal(err) } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - t.Fatal(err) - } - } + if ws == nil { + t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) } - } - - err = cmd.Wait() - if err != nil { - t.Fatal(err) - } - } + }, + }, } - if validations != nil { - validations(t, organization.Name) - } -} - -func Test_migrate_remote_backend_name_to_tfc_name_different_org(t *testing.T) { - t.Parallel() - skipIfMissingEnvVar(t) - skipWithoutRemoteTerraformVersion(t) - - ctx := context.Background() - operations := []operationSets{ - { - prep: func(t *testing.T, orgName, dir string) { - remoteWorkspace := "remote-workspace" - tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init"}, - expectedCmdOutput: `Successfully configured the backend "remote"!`, - }, - { - command: []string{"apply", "-auto-approve"}, - postInputOutput: []string{`Apply complete!`}, - }, - }, - }, - { - prep: func(t *testing.T, orgName, dir string) { - wsName := "remote-workspace" - tfBlock := terraformConfigCloudBackendName(orgName, wsName) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init", "-ignore-remote-version"}, - expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, - userInput: []string{"yes", "yes"}, - postInputOutput: []string{ - `Should Terraform migrate your existing state?`, - `Terraform Cloud has been successfully initialized!`}, - }, - { - command: []string{"workspace", "show"}, - expectedCmdOutput: `remote-workspace`, - }, - }, - }, - } - validations := func(t *testing.T, orgName string) { - expectedName := "remote-workspace" - ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) - if err != nil { - t.Fatal(err) - } - if ws == nil { - t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) - } - } - - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - t.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - orgOne, cleanupOne := createOrganization(t) - orgTwo, cleanupTwo := createOrganization(t) - defer cleanupOne() - defer cleanupTwo() - orgs := []string{orgOne.Name, orgTwo.Name} - var orgName string - for index, op := range operations { - orgName = orgs[index] - op.prep(t, orgName, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - t.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil { - t.Fatal(err) - } - } - } - - if validations != nil { - validations(t, orgName) - } -} - -func Test_migrate_remote_backend_name_to_tfc_tags(t *testing.T) { - t.Parallel() - skipIfMissingEnvVar(t) - skipWithoutRemoteTerraformVersion(t) - - ctx := context.Background() - operations := []operationSets{ - { - prep: func(t *testing.T, orgName, dir string) { - remoteWorkspace := "remote-workspace" - tfBlock := terraformConfigRemoteBackendName(orgName, remoteWorkspace) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init"}, - expectedCmdOutput: `Successfully configured the backend "remote"!`, - }, - { - command: []string{"apply", "-auto-approve"}, - postInputOutput: []string{`Apply complete!`}, - }, - { - command: []string{"workspace", "show"}, - expectedCmdOutput: `default`, - }, - }, - }, - { - prep: func(t *testing.T, orgName, dir string) { - tag := "app" - tfBlock := terraformConfigCloudBackendTags(orgName, tag) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init", "-ignore-remote-version"}, - expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, - userInput: []string{"yes", "cloud-workspace", "yes"}, - postInputOutput: []string{ - `Should Terraform migrate your existing state?`, - `Terraform Cloud requires all workspaces to be given an explicit name.`, - `Terraform Cloud has been successfully initialized!`}, - }, - { - command: []string{"workspace", "show"}, - expectedCmdOutput: `cloud-workspace`, - }, - }, - }, - } - validations := func(t *testing.T, orgName string) { - wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{ - Tags: tfe.String("app"), - }) - if err != nil { - t.Fatal(err) - } - if len(wsList.Items) != 1 { - t.Fatalf("Expected number of workspaces to be 1, but got %d", len(wsList.Items)) - } - ws := wsList.Items[0] - if ws.Name != "cloud-workspace" { - t.Fatalf("Expected workspace to be `cloud-workspace`, but is %s", ws.Name) - } - } - - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - t.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - organization, cleanup := createOrganization(t) - defer cleanup() - for _, op := range operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - t.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil { - t.Fatal(err) - } - } - } - - if validations != nil { - validations(t, organization.Name) - } -} - -func Test_migrate_remote_backend_prefix_to_tfc_name_strategy_single_workspace(t *testing.T) { - t.Parallel() - skipIfMissingEnvVar(t) - skipWithoutRemoteTerraformVersion(t) - - ctx := context.Background() - operations := []operationSets{ - { - prep: func(t *testing.T, orgName, dir string) { - _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) - prefix := "app-" - tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init"}, - expectedCmdOutput: `Terraform has been successfully initialized!`, - }, - { - command: []string{"apply", "-auto-approve"}, - postInputOutput: []string{`Apply complete!`}, - }, - }, - }, - { - prep: func(t *testing.T, orgName, dir string) { - wsName := "cloud-workspace" - tfBlock := terraformConfigCloudBackendName(orgName, wsName) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init", "-ignore-remote-version"}, - expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, - userInput: []string{"yes", "yes"}, - postInputOutput: []string{ - `Should Terraform migrate your existing state?`, - `Terraform Cloud has been successfully initialized!`}, - }, - { - command: []string{"workspace", "show"}, - expectedCmdOutput: `cloud-workspace`, - }, - }, - }, - } - validations := func(t *testing.T, orgName string) { - expectedName := "cloud-workspace" - ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) - if err != nil { - t.Fatal(err) - } - if ws == nil { - t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) - } - } - - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - t.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - organization, cleanup := createOrganization(t) - defer cleanup() - for _, op := range operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - got, err := exp.ExpectString(output) - if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", output, err, got) - } - } - } - } - - err = cmd.Wait() - if err != nil { - t.Fatal(err) - } - } - } - - if validations != nil { - validations(t, organization.Name) - } -} - -func Test_migrate_remote_backend_prefix_to_tfc_name_strategy_multi_workspace(t *testing.T) { - t.Parallel() - skipIfMissingEnvVar(t) - skipWithoutRemoteTerraformVersion(t) - - ctx := context.Background() - operations := []operationSets{ - { - prep: func(t *testing.T, orgName, dir string) { - _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) - _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")}) - prefix := "app-" - tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init"}, - expectedCmdOutput: `The currently selected workspace (default) does not exist.`, - userInput: []string{"1"}, - postInputOutput: []string{`Terraform has been successfully initialized!`}, - }, - { - command: []string{"apply", "-auto-approve"}, - postInputOutput: []string{`Apply complete!`}, - }, - { - command: []string{"workspace", "list"}, - expectedCmdOutput: "* one", // app name retrieved via prefix - }, - { - command: []string{"workspace", "select", "two"}, - expectedCmdOutput: `Switched to workspace "two".`, // app name retrieved via prefix - }, - }, - }, - { - prep: func(t *testing.T, orgName, dir string) { - wsName := "cloud-workspace" - tfBlock := terraformConfigCloudBackendName(orgName, wsName) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init", "-ignore-remote-version"}, - expectedCmdOutput: `Do you want to copy only your current workspace?`, - userInput: []string{"yes"}, - postInputOutput: []string{ - `Terraform Cloud has been successfully initialized!`}, - }, - { - command: []string{"workspace", "show"}, - expectedCmdOutput: `cloud-workspace`, - }, - }, - }, - } - validations := func(t *testing.T, orgName string) { - expectedName := "cloud-workspace" - ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) - if err != nil { - t.Fatal(err) - } - if ws == nil { - t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) - } - wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{}) - if err != nil { - t.Fatal(err) - } - if len(wsList.Items) != 3 { - t.Fatalf("expected number of workspaces in this org to be 3, but got %d", len(wsList.Items)) - } - _, empty := getWorkspace(wsList.Items, "cloud-workspace") - if empty { - t.Fatalf("expected workspaces to include 'cloud-workspace' but didn't.") - } - _, empty = getWorkspace(wsList.Items, "app-one") - if empty { - t.Fatalf("expected workspaces to include 'app-one' but didn't.") - } - _, empty = getWorkspace(wsList.Items, "app-two") - if empty { - t.Fatalf("expected workspaces to include 'app-two' but didn't.") - } - } - - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - t.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - organization, cleanup := createOrganization(t) - defer cleanup() - for _, op := range operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - t.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil { - t.Fatal(err) - } - } - } - - if validations != nil { - validations(t, organization.Name) - } -} - -func Test_migrate_remote_backend_prefix_to_tfc_tags_strategy_single_workspace(t *testing.T) { - t.Parallel() - skipIfMissingEnvVar(t) - skipWithoutRemoteTerraformVersion(t) - - ctx := context.Background() - operations := []operationSets{ - { - prep: func(t *testing.T, orgName, dir string) { - _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) - prefix := "app-" - tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init"}, - expectedCmdOutput: `Terraform has been successfully initialized!`, - }, - { - command: []string{"apply", "-auto-approve"}, - postInputOutput: []string{`Apply complete!`}, - }, - }, - }, - { - prep: func(t *testing.T, orgName, dir string) { - tag := "app" - tfBlock := terraformConfigCloudBackendTags(orgName, tag) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init", "-ignore-remote-version"}, - expectedCmdOutput: `Migrating from backend "remote" to Terraform Cloud.`, - userInput: []string{"yes", "cloud-workspace", "yes"}, - postInputOutput: []string{ - `Should Terraform migrate your existing state?`, - `Terraform Cloud requires all workspaces to be given an explicit name.`, - `Terraform Cloud has been successfully initialized!`}, - }, - { - command: []string{"workspace", "list"}, - expectedCmdOutput: `cloud-workspace`, - }, - }, - }, - } - validations := func(t *testing.T, orgName string) { - expectedName := "cloud-workspace" - ws, err := tfeClient.Workspaces.Read(ctx, orgName, expectedName) - if err != nil { - t.Fatal(err) - } - if ws == nil { - t.Fatalf("Expected workspace %s to be present, but is not.", expectedName) - } - } - - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - t.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - organization, cleanup := createOrganization(t) - defer cleanup() - for _, op := range operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - t.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil { - t.Fatal(err) - } - } - } - - if validations != nil { - validations(t, organization.Name) - } -} - -func Test_migrate_remote_backend_prefix_to_tfc_tags_strategy_multi_workspace(t *testing.T) { - t.Parallel() - skipIfMissingEnvVar(t) - skipWithoutRemoteTerraformVersion(t) - - ctx := context.Background() - operations := []operationSets{ - { - prep: func(t *testing.T, orgName, dir string) { - _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-one")}) - _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{Name: tfe.String("app-two")}) - prefix := "app-" - tfBlock := terraformConfigRemoteBackendPrefix(orgName, prefix) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init"}, - expectedCmdOutput: `The currently selected workspace (default) does not exist.`, - userInput: []string{"1"}, - postInputOutput: []string{`Terraform has been successfully initialized!`}, - }, - { - command: []string{"apply"}, - expectedCmdOutput: `Do you want to perform these actions in workspace "app-one"?`, - userInput: []string{"yes"}, - postInputOutput: []string{`Apply complete!`}, - }, - { - command: []string{"workspace", "select", "two"}, - }, - { - command: []string{"apply"}, - expectedCmdOutput: `Do you want to perform these actions in workspace "app-two"?`, - userInput: []string{"yes"}, - postInputOutput: []string{`Apply complete!`}, - }, - }, - }, - { - prep: func(t *testing.T, orgName, dir string) { - tag := "app" - tfBlock := terraformConfigCloudBackendTags(orgName, tag) - writeMainTF(t, tfBlock, dir) - }, - commands: []tfCommand{ - { - command: []string{"init", "-ignore-remote-version"}, - expectedCmdOutput: `Do you wish to proceed?`, - userInput: []string{"yes"}, - postInputOutput: []string{`Terraform Cloud has been successfully initialized!`}, - }, - { - command: []string{"workspace", "show"}, - expectedCmdOutput: "app-two", - }, - { - command: []string{"workspace", "select", "app-one"}, - expectedCmdOutput: `Switched to workspace "app-one".`, - }, - }, - }, - } - validations := func(t *testing.T, orgName string) { - wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{ - Tags: tfe.String("app"), - }) - if err != nil { - t.Fatal(err) - } - if len(wsList.Items) != 2 { - t.Logf("Expected the number of workspaces to be 2, but got %d", len(wsList.Items)) - } - ws, empty := getWorkspace(wsList.Items, "app-one") - if empty { - t.Fatalf("expected workspaces to include 'app-one' but didn't.") - } - if len(ws.TagNames) == 0 { - t.Fatalf("expected workspaces 'one' to have tags.") - } - ws, empty = getWorkspace(wsList.Items, "app-two") - if empty { - t.Fatalf("expected workspaces to include 'app-two' but didn't.") - } - if len(ws.TagNames) == 0 { - t.Fatalf("expected workspaces 'app-two' to have tags.") - } - } - - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - t.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - organization, cleanup := createOrganization(t) - defer cleanup() - for _, op := range operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - t.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - t.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - t.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil { - t.Fatal(err) - } - } - } - - if validations != nil { - validations(t, organization.Name) - } + testRunner(t, cases, 2) } diff --git a/internal/cloud/e2e/migrate_state_single_to_tfc_test.go b/internal/cloud/e2e/migrate_state_single_to_tfc_test.go index edf0c0376..ff386cc93 100644 --- a/internal/cloud/e2e/migrate_state_single_to_tfc_test.go +++ b/internal/cloud/e2e/migrate_state_single_to_tfc_test.go @@ -2,13 +2,9 @@ package main import ( "context" - "io/ioutil" - "os" "testing" - expect "github.com/Netflix/go-expect" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/e2e" ) func Test_migrate_single_to_tfc(t *testing.T) { @@ -18,10 +14,7 @@ func Test_migrate_single_to_tfc(t *testing.T) { ctx := context.Background() - cases := map[string]struct { - operations []operationSets - validations func(t *testing.T, orgName string) - }{ + cases := testCases{ "migrate using cloud workspace name strategy": { operations: []operationSets{ { @@ -129,76 +122,5 @@ func Test_migrate_single_to_tfc(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - organization, cleanup := createOrganization(t) - defer cleanup() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - for _, op := range tc.operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil { - subtest.Fatal(err) - } - } - } - - if tc.validations != nil { - tc.validations(t, organization.Name) - } - }) - } + testRunner(t, cases, 1) } diff --git a/internal/cloud/e2e/migrate_state_tfc_to_other_test.go b/internal/cloud/e2e/migrate_state_tfc_to_other_test.go index 3e0be6894..4029ba5b4 100644 --- a/internal/cloud/e2e/migrate_state_tfc_to_other_test.go +++ b/internal/cloud/e2e/migrate_state_tfc_to_other_test.go @@ -1,21 +1,14 @@ package main import ( - "io/ioutil" - "os" "testing" - - expect "github.com/Netflix/go-expect" - "github.com/hashicorp/terraform/internal/e2e" ) func Test_migrate_tfc_to_other(t *testing.T) { t.Parallel() skipIfMissingEnvVar(t) - cases := map[string]struct { - operations []operationSets - }{ + cases := testCases{ "migrate from cloud to local backend": { operations: []operationSets{ { @@ -48,71 +41,5 @@ func Test_migrate_tfc_to_other(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - organization, cleanup := createOrganization(t) - defer cleanup() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - for _, op := range tc.operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - err = cmd.Wait() - if err != nil && !tfCmd.expectError { - subtest.Fatal(err) - } - } - } - }) - } + testRunner(t, cases, 1) } diff --git a/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go b/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go index 123534a95..d5c7113b9 100644 --- a/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go +++ b/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go @@ -2,13 +2,9 @@ package main import ( "context" - "io/ioutil" - "os" "testing" - expect "github.com/Netflix/go-expect" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/e2e" tfversion "github.com/hashicorp/terraform/version" ) @@ -19,16 +15,8 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { ctx := context.Background() - cases := map[string]struct { - setup func(t *testing.T) (string, func()) - operations []operationSets - validations func(t *testing.T, orgName string) - }{ + cases := testCases{ "migrating from name to name": { - setup: func(t *testing.T) (string, func()) { - organization, cleanup := createOrganization(t) - return organization.Name, cleanup - }, operations: []operationSets{ { prep: func(t *testing.T, orgName, dir string) { @@ -93,10 +81,6 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { }, }, "migrating from name to tags": { - setup: func(t *testing.T) (string, func()) { - organization, cleanup := createOrganization(t) - return organization.Name, cleanup - }, operations: []operationSets{ { prep: func(t *testing.T, orgName, dir string) { @@ -155,10 +139,6 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { }, }, "migrating from name to tags without ignore-version flag": { - setup: func(t *testing.T) (string, func()) { - organization, cleanup := createOrganization(t) - return organization.Name, cleanup - }, operations: []operationSets{ { prep: func(t *testing.T, orgName, dir string) { @@ -220,78 +200,7 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - defer tf.Close() - tf.AddEnv(cliConfigFileEnv) - - orgName, cleanup := tc.setup(t) - defer cleanup() - for _, op := range tc.operations { - op.prep(t, orgName, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil && !tfCmd.expectError { - subtest.Fatal(err.Error()) - } - } - } - - if tc.validations != nil { - tc.validations(t, orgName) - } - }) - } + testRunner(t, cases, 1) } func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) { @@ -301,16 +210,8 @@ func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) { ctx := context.Background() - cases := map[string]struct { - setup func(t *testing.T) (string, func()) - operations []operationSets - validations func(t *testing.T, orgName string) - }{ + cases := testCases{ "migrating from multiple workspaces via tags to name": { - setup: func(t *testing.T) (string, func()) { - organization, cleanup := createOrganization(t) - return organization.Name, cleanup - }, operations: []operationSets{ { prep: func(t *testing.T, orgName, dir string) { @@ -392,10 +293,6 @@ func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) { }, }, "migrating from multiple workspaces via tags to other tags": { - setup: func(t *testing.T) (string, func()) { - organization, cleanup := createOrganization(t) - return organization.Name, cleanup - }, operations: []operationSets{ { prep: func(t *testing.T, orgName, dir string) { @@ -468,76 +365,5 @@ func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - defer tf.Close() - tf.AddEnv(cliConfigFileEnv) - - orgName, cleanup := tc.setup(t) - defer cleanup() - for _, op := range tc.operations { - op.prep(t, orgName, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatal(err) - } - } - } - } - - err = cmd.Wait() - if err != nil { - subtest.Fatal(err.Error()) - } - } - } - - if tc.validations != nil { - tc.validations(t, orgName) - } - }) - } + testRunner(t, cases, 1) } diff --git a/internal/cloud/e2e/run_variables_test.go b/internal/cloud/e2e/run_variables_test.go index 54fcb38a6..ee1f66eeb 100644 --- a/internal/cloud/e2e/run_variables_test.go +++ b/internal/cloud/e2e/run_variables_test.go @@ -2,13 +2,9 @@ package main import ( "fmt" - "io/ioutil" - "os" "testing" - expect "github.com/Netflix/go-expect" tfe "github.com/hashicorp/go-tfe" - "github.com/hashicorp/terraform/internal/e2e" tfversion "github.com/hashicorp/terraform/version" ) @@ -81,78 +77,5 @@ func Test_cloud_run_variables(t *testing.T) { }, } - for name, tc := range cases { - tc := tc // rebind tc into this lexical scope - t.Run(name, func(subtest *testing.T) { - subtest.Parallel() - organization, cleanup := createOrganization(t) - defer cleanup() - exp, err := expect.NewConsole(defaultOpts()...) - if err != nil { - subtest.Fatal(err) - } - defer exp.Close() - - tmpDir, err := ioutil.TempDir("", "terraform-test") - if err != nil { - subtest.Fatal(err) - } - defer os.RemoveAll(tmpDir) - - tf := e2e.NewBinary(terraformBin, tmpDir) - tf.AddEnv("TF_CLI_ARGS=-no-color") - tf.AddEnv("TF_VAR_baz=qux") - tf.AddEnv(cliConfigFileEnv) - defer tf.Close() - - for _, op := range tc.operations { - op.prep(t, organization.Name, tf.WorkDir()) - for _, tfCmd := range op.commands { - cmd := tf.Cmd(tfCmd.command...) - cmd.Stdin = exp.Tty() - cmd.Stdout = exp.Tty() - cmd.Stderr = exp.Tty() - - err = cmd.Start() - if err != nil { - subtest.Fatal(err) - } - - if tfCmd.expectedCmdOutput != "" { - got, err := exp.ExpectString(tfCmd.expectedCmdOutput) - if err != nil { - subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got) - } - } - - lenInput := len(tfCmd.userInput) - lenInputOutput := len(tfCmd.postInputOutput) - if lenInput > 0 { - for i := 0; i < lenInput; i++ { - input := tfCmd.userInput[i] - exp.SendLine(input) - // use the index to find the corresponding - // output that matches the input. - if lenInputOutput-1 >= i { - output := tfCmd.postInputOutput[i] - _, err := exp.ExpectString(output) - if err != nil { - subtest.Fatalf(`Expected command output "%s", but got %v `, tfCmd.expectedCmdOutput, err) - } - } - } - } - - err = cmd.Wait() - if err != nil && !tfCmd.expectError { - subtest.Fatal(err) - } - } - - if tc.validations != nil { - tc.validations(t, organization.Name) - } - } - }) - } + testRunner(t, cases, 1, "TF_CLI_ARGS=-no-color", "TF_VAR_baz=qux") }