Merge pull request #29883 from hashicorp/barrettclark/cloud-e2e-tests

Cloud: Make e2e Tests Less Chatty, and More Stable
This commit is contained in:
Barrett Clark 2021-11-15 10:45:14 -06:00 committed by GitHub
commit 388c430ece
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1619 additions and 1463 deletions

2
go.mod
View File

@ -43,7 +43,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.0 github.com/hashicorp/go-retryablehttp v0.7.0
github.com/hashicorp/go-tfe v0.20.1-0.20211110172530-c43c6b574caa github.com/hashicorp/go-tfe v0.20.1-0.20211110172530-c43c6b574caa
github.com/hashicorp/go-uuid v1.0.2 github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.2.1 github.com/hashicorp/go-version v1.3.0
github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f
github.com/hashicorp/hcl/v2 v2.10.1 github.com/hashicorp/hcl/v2 v2.10.1
github.com/hashicorp/terraform-config-inspect v0.0.0-20210209133302-4fd17a0faac2 github.com/hashicorp/terraform-config-inspect v0.0.0-20210209133302-4fd17a0faac2

3
go.sum
View File

@ -388,8 +388,9 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw=
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=

View File

@ -0,0 +1,24 @@
# How to run tests
To run them, use:
```
TFE_TOKEN=<token> TFE_HOSTNAME=<hostname> TF_ACC=1 go test ./internal/cloud/e2e/... -ldflags "-X \"github.com/hashicorp/terraform/version.Prerelease=<PRE-RELEASE>\""
```
Required flags
* `TF_ACC=1`. This variable is used as part of terraform for tests that make
external network calls. This is needed to run these tests. Without it, the
tests do not run.
* `TFE_TOKEN=<admin token>` and `TFE_HOSTNAME=<hostname>`. The helpers
for these tests require admin access to a TFC/TFE instance.
* `-timeout=30m`. Some of these tests take longer than the default 10m timeout for `go test`.
### Flags
* Use the `-v` flag for normal verbose mode.
* Use the `-tfoutput` flag to print the terraform output to standard out.
* Use `-ldflags` to change the version Prerelease to match a version
available remotely. Some behaviors rely on the exact local version Terraform
being available in TFC/TFE, and manipulating the Prerelease during build is
often the only way to ensure this.
[(More on `-ldflags`.)](https://www.digitalocean.com/community/tutorials/using-ldflags-to-set-version-information-for-go-applications)

View File

@ -1,12 +1,8 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
"context" "context"
"io/ioutil" "io/ioutil"
"log"
"os" "os"
"testing" "testing"
@ -17,7 +13,7 @@ import (
) )
func Test_terraform_apply_autoApprove(t *testing.T) { func Test_terraform_apply_autoApprove(t *testing.T) {
t.Parallel() skipIfMissingEnvVar(t)
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
ctx := context.Background() ctx := context.Background()
@ -183,12 +179,10 @@ func Test_terraform_apply_autoApprove(t *testing.T) {
}, },
}, },
} }
for name, tc := range cases { for _, tc := range cases {
log.Println("Test: ", name)
organization, cleanup := createOrganization(t) organization, cleanup := createOrganization(t)
defer cleanup() defer cleanup()
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) exp, err := expect.NewConsole(defaultOpts()...)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -201,7 +195,6 @@ func Test_terraform_apply_autoApprove(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
tf.AddEnv("TF_LOG=info")
tf.AddEnv(cliConfigFileEnv) tf.AddEnv(cliConfigFileEnv)
defer tf.Close() defer tf.Close()

View File

@ -1,10 +1,6 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
@ -14,6 +10,7 @@ import (
) )
func Test_backend_apply_before_init(t *testing.T) { func Test_backend_apply_before_init(t *testing.T) {
skipIfMissingEnvVar(t)
t.Parallel() t.Parallel()
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
@ -51,10 +48,8 @@ func Test_backend_apply_before_init(t *testing.T) {
expectedCmdOutput: `Successfully configured the backend "local"!`, expectedCmdOutput: `Successfully configured the backend "local"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
}, },
}, },
@ -77,68 +72,70 @@ func Test_backend_apply_before_init(t *testing.T) {
} }
for name, tc := range cases { for name, tc := range cases {
fmt.Println("Test: ", name) tc := tc
organization, cleanup := createOrganization(t) t.Run(name, func(t *testing.T) {
defer cleanup() t.Parallel()
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) organization, cleanup := createOrganization(t)
if err != nil { defer cleanup()
t.Fatal(err) exp, err := expect.NewConsole(defaultOpts()...)
} if err != nil {
defer exp.Close() t.Fatal(err)
}
defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
tf.AddEnv("TF_LOG=info") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv) defer tf.Close()
defer tf.Close()
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, organization.Name, tf.WorkDir()) op.prep(t, organization.Name, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
cmd := tf.Cmd(tfCmd.command...) cmd := tf.Cmd(tfCmd.command...)
cmd.Stdin = exp.Tty() cmd.Stdin = exp.Tty()
cmd.Stdout = exp.Tty() cmd.Stdout = exp.Tty()
cmd.Stderr = exp.Tty() cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil {
t.Fatal(err)
}
if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
}
lenInput := len(tfCmd.userInput) if tfCmd.expectedCmdOutput != "" {
lenInputOutput := len(tfCmd.postInputOutput) _, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if lenInput > 0 { if err != nil {
for i := 0; i < lenInput; i++ { t.Fatal(err)
input := tfCmd.userInput[i] }
exp.SendLine(input) }
// use the index to find the corresponding
// output that matches the input. lenInput := len(tfCmd.userInput)
if lenInputOutput-1 >= i { lenInputOutput := len(tfCmd.postInputOutput)
output := tfCmd.postInputOutput[i] if lenInput > 0 {
_, err := exp.ExpectString(output) for i := 0; i < lenInput; i++ {
if err != nil { input := tfCmd.userInput[i]
t.Fatal(err) 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()
err = cmd.Wait() if err != nil && !tfCmd.expectError {
if err != nil && !tfCmd.expectError { t.Fatal(err)
t.Fatal(err) }
} }
} }
} })
} }
} }

View File

@ -1,6 +1,3 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
@ -10,8 +7,10 @@ import (
"testing" "testing"
"time" "time"
expect "github.com/Netflix/go-expect"
tfe "github.com/hashicorp/go-tfe" tfe "github.com/hashicorp/go-tfe"
"github.com/hashicorp/go-uuid" "github.com/hashicorp/go-uuid"
goversion "github.com/hashicorp/go-version"
tfversion "github.com/hashicorp/terraform/version" tfversion "github.com/hashicorp/terraform/version"
) )
@ -22,7 +21,6 @@ const (
type tfCommand struct { type tfCommand struct {
command []string command []string
expectedCmdOutput string expectedCmdOutput string
expectedErr string
expectError bool expectError bool
userInput []string userInput []string
postInputOutput []string postInputOutput []string
@ -38,6 +36,16 @@ type testCases map[string]struct {
validations func(t *testing.T, orgName string) validations func(t *testing.T, orgName string)
} }
func defaultOpts() []expect.ConsoleOpt {
opts := []expect.ConsoleOpt{
expect.WithDefaultTimeout(expectConsoleTimeout),
}
if verboseMode {
opts = append(opts, expect.WithStdout(os.Stdout))
}
return opts
}
func createOrganization(t *testing.T) (*tfe.Organization, func()) { func createOrganization(t *testing.T) (*tfe.Organization, func()) {
ctx := context.Background() ctx := context.Background()
org, err := tfeClient.Organizations.Create(ctx, tfe.OrganizationCreateOptions{ org, err := tfeClient.Organizations.Create(ctx, tfe.OrganizationCreateOptions{
@ -93,7 +101,7 @@ func randomString(t *testing.T) string {
} }
func terraformConfigLocalBackend() string { func terraformConfigLocalBackend() string {
return fmt.Sprintf(` return `
terraform { terraform {
backend "local" { backend "local" {
} }
@ -102,7 +110,7 @@ terraform {
output "val" { output "val" {
value = "${terraform.workspace}" value = "${terraform.workspace}"
} }
`) `
} }
func terraformConfigRemoteBackendName(org, name string) string { func terraformConfigRemoteBackendName(org, name string) string {
@ -193,9 +201,16 @@ func writeMainTF(t *testing.T, block string, dir string) {
f.Close() f.Close()
} }
// Ensure that TFC/E has a particular terraform version. // The e2e tests rely on the fact that the terraform version in TFC/E is able to
// run the `cloud` configuration block, which is available in 1.1 and will
// continue to be available in later versions. So this function checks that
// there is a version that is >= 1.1.
func skipWithoutRemoteTerraformVersion(t *testing.T) { func skipWithoutRemoteTerraformVersion(t *testing.T) {
version := tfversion.String() version := tfversion.Version
baseVersion, err := goversion.NewVersion(version)
if err != nil {
t.Fatalf(fmt.Sprintf("Error instantiating go-version for %s", version))
}
opts := tfe.AdminTerraformVersionsListOptions{ opts := tfe.AdminTerraformVersionsListOptions{
ListOptions: tfe.ListOptions{ ListOptions: tfe.ListOptions{
PageNumber: 1, PageNumber: 1,
@ -213,7 +228,12 @@ findTfVersion:
t.Fatalf("Could not retrieve list of terraform versions: %v", err) t.Fatalf("Could not retrieve list of terraform versions: %v", err)
} }
for _, item := range tfVersionList.Items { for _, item := range tfVersionList.Items {
if item.Version == version { availableVersion, err := goversion.NewVersion(item.Version)
if err != nil {
t.Logf("Error instantiating go-version for %s", item.Version)
continue
}
if availableVersion.Core().GreaterThanOrEqual(baseVersion.Core()) {
hasVersion = true hasVersion = true
break findTfVersion break findTfVersion
} }

View File

@ -1,10 +1,6 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
@ -14,6 +10,7 @@ import (
) )
func Test_init_with_empty_tags(t *testing.T) { func Test_init_with_empty_tags(t *testing.T) {
skipIfMissingEnvVar(t)
t.Parallel() t.Parallel()
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
@ -42,68 +39,70 @@ func Test_init_with_empty_tags(t *testing.T) {
} }
for name, tc := range cases { for name, tc := range cases {
fmt.Println("Test: ", name) tc := tc
organization, cleanup := createOrganization(t) t.Run(name, func(t *testing.T) {
defer cleanup() t.Parallel()
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) organization, cleanup := createOrganization(t)
if err != nil { defer cleanup()
t.Fatal(err) exp, err := expect.NewConsole(defaultOpts()...)
} if err != nil {
defer exp.Close() t.Fatal(err)
}
defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
tf.AddEnv("TF_LOG=info") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv) defer tf.Close()
defer tf.Close()
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, organization.Name, tf.WorkDir()) op.prep(t, organization.Name, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
cmd := tf.Cmd(tfCmd.command...) cmd := tf.Cmd(tfCmd.command...)
cmd.Stdin = exp.Tty() cmd.Stdin = exp.Tty()
cmd.Stdout = exp.Tty() cmd.Stdout = exp.Tty()
cmd.Stderr = exp.Tty() cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil {
t.Fatal(err)
}
if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
}
lenInput := len(tfCmd.userInput) if tfCmd.expectedCmdOutput != "" {
lenInputOutput := len(tfCmd.postInputOutput) _, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if lenInput > 0 { if err != nil {
for i := 0; i < lenInput; i++ { t.Fatal(err)
input := tfCmd.userInput[i] }
exp.SendLine(input) }
// use the index to find the corresponding
// output that matches the input. lenInput := len(tfCmd.userInput)
if lenInputOutput-1 >= i { lenInputOutput := len(tfCmd.postInputOutput)
output := tfCmd.postInputOutput[i] if lenInput > 0 {
_, err := exp.ExpectString(output) for i := 0; i < lenInput; i++ {
if err != nil { input := tfCmd.userInput[i]
t.Fatal(err) 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()
err = cmd.Wait() if err != nil && !tfCmd.expectError {
if err != nil && !tfCmd.expectError { t.Fatal(err)
t.Fatal(err) }
} }
} }
} })
} }
} }

View File

@ -1,9 +1,7 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
"flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
@ -22,13 +20,9 @@ var cliConfigFileEnv string
var tfeClient *tfe.Client var tfeClient *tfe.Client
var tfeHostname string var tfeHostname string
var tfeToken string var tfeToken string
var verboseMode bool
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
log.SetFlags(log.LstdFlags | log.Lshortfile)
if !accTest() {
// if TF_ACC is not set, we want to skip all these tests.
return
}
teardown := setup() teardown := setup()
code := m.Run() code := m.Run()
teardown() teardown()
@ -42,7 +36,29 @@ func accTest() bool {
return os.Getenv("TF_ACC") != "" return os.Getenv("TF_ACC") != ""
} }
func hasHostname() bool {
return os.Getenv("TFE_HOSTNAME") != ""
}
func hasToken() bool {
return os.Getenv("TFE_TOKEN") != ""
}
func hasRequiredEnvVars() bool {
return accTest() && hasHostname() && hasToken()
}
func skipIfMissingEnvVar(t *testing.T) {
if !hasRequiredEnvVars() {
t.Skip("Skipping test, required environment variables missing. Use `TF_ACC`, `TFE_HOSTNAME`, `TFE_TOKEN`")
}
}
func setup() func() { func setup() func() {
tfOutput := flag.Bool("tfoutput", false, "This flag produces the terraform output from tests.")
flag.Parse()
verboseMode = *tfOutput
setTfeClient() setTfeClient()
teardown := setupBinary() teardown := setupBinary()
@ -52,41 +68,38 @@ func setup() func() {
} }
func setTfeClient() { func setTfeClient() {
hostname := os.Getenv("TFE_HOSTNAME") tfeHostname = os.Getenv("TFE_HOSTNAME")
token := os.Getenv("TFE_TOKEN") tfeToken = os.Getenv("TFE_TOKEN")
if hostname == "" {
log.Fatal("hostname cannot be empty")
}
if token == "" {
log.Fatal("token cannot be empty")
}
tfeHostname = hostname
tfeToken = token
cfg := &tfe.Config{ cfg := &tfe.Config{
Address: fmt.Sprintf("https://%s", hostname), Address: fmt.Sprintf("https://%s", tfeHostname),
Token: token, Token: tfeToken,
} }
// Create a new TFE client. if tfeHostname != "" && tfeToken != "" {
client, err := tfe.NewClient(cfg) // Create a new TFE client.
if err != nil { client, err := tfe.NewClient(cfg)
log.Fatal(err) if err != nil {
fmt.Printf("Could not create new tfe client: %v\n", err)
os.Exit(1)
}
tfeClient = client
} }
tfeClient = client
} }
func setupBinary() func() { func setupBinary() func() {
log.Println("Setting up terraform binary") log.Println("Setting up terraform binary")
tmpTerraformBinaryDir, err := ioutil.TempDir("", "terraform-test") tmpTerraformBinaryDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
log.Fatal(err) fmt.Printf("Could not create temp directory: %v\n", err)
os.Exit(1)
} }
log.Println(tmpTerraformBinaryDir) log.Println(tmpTerraformBinaryDir)
currentDir, err := os.Getwd() currentDir, err := os.Getwd()
defer os.Chdir(currentDir) defer os.Chdir(currentDir)
if err != nil { if err != nil {
log.Fatal(err) fmt.Printf("Could not change directories: %v\n", err)
os.Exit(1)
} }
// Getting top level dir // Getting top level dir
dirPaths := strings.Split(currentDir, "/") dirPaths := strings.Split(currentDir, "/")
@ -95,7 +108,8 @@ func setupBinary() func() {
topDir := strings.Join(dirPaths[0:topLevel], "/") topDir := strings.Join(dirPaths[0:topLevel], "/")
if err := os.Chdir(topDir); err != nil { if err := os.Chdir(topDir); err != nil {
log.Fatal(err) fmt.Printf("Could not change directories: %v\n", err)
os.Exit(1)
} }
cmd := exec.Command( cmd := exec.Command(
@ -106,7 +120,8 @@ func setupBinary() func() {
) )
err = cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
log.Fatal(err) fmt.Printf("Could not run exec command: %v\n", err)
os.Exit(1)
} }
credFile := fmt.Sprintf("%s/dev.tfrc", tmpTerraformBinaryDir) credFile := fmt.Sprintf("%s/dev.tfrc", tmpTerraformBinaryDir)
@ -124,11 +139,13 @@ func writeCredRC(file string) {
creds := credentialBlock() creds := credentialBlock()
f, err := os.Create(file) f, err := os.Create(file)
if err != nil { if err != nil {
log.Fatal(err) fmt.Printf("Could not create file: %v\n", err)
os.Exit(1)
} }
_, err = f.WriteString(creds) _, err = f.WriteString(creds)
if err != nil { if err != nil {
log.Fatal(err) fmt.Printf("Could not write credentials: %v\n", err)
os.Exit(1)
} }
f.Close() f.Close()
} }

View File

@ -1,6 +1,3 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
@ -16,7 +13,7 @@ import (
) )
func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) { func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) {
t.Parallel() skipIfMissingEnvVar(t)
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
ctx := context.Background() ctx := context.Background()
@ -38,20 +35,16 @@ func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) {
expectedCmdOutput: `Successfully configured the backend "local"!`, expectedCmdOutput: `Successfully configured the backend "local"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
{ {
command: []string{"workspace", "new", "prod"}, command: []string{"workspace", "new", "prod"},
expectedCmdOutput: `Created and switched to workspace "prod"!`, expectedCmdOutput: `Created and switched to workspace "prod"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
{ {
command: []string{"workspace", "select", "default"}, command: []string{"workspace", "select", "default"},
@ -113,20 +106,16 @@ func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) {
expectedCmdOutput: `Successfully configured the backend "local"!`, expectedCmdOutput: `Successfully configured the backend "local"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
{ {
command: []string{"workspace", "new", "prod"}, command: []string{"workspace", "new", "prod"},
expectedCmdOutput: `Created and switched to workspace "prod"!`, expectedCmdOutput: `Created and switched to workspace "prod"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
}, },
}, },
@ -171,82 +160,81 @@ func Test_migrate_multi_to_tfc_cloud_name_strategy(t *testing.T) {
} }
for name, tc := range cases { for name, tc := range cases {
t.Log("Test: ", name) tc := tc
organization, cleanup := createOrganization(t) t.Run(name, func(t *testing.T) {
defer cleanup() t.Parallel()
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) organization, cleanup := createOrganization(t)
if err != nil { defer cleanup()
t.Fatal(err) exp, err := expect.NewConsole(defaultOpts()...)
} if err != nil {
defer exp.Close() t.Fatal(err)
}
defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
defer tf.Close() defer tf.Close()
tf.AddEnv("TF_LOG=INFO") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv)
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, organization.Name, tf.WorkDir()) op.prep(t, organization.Name, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
t.Log("Running commands: ", tfCmd.command) cmd := tf.Cmd(tfCmd.command...)
tfCmd.command = append(tfCmd.command) cmd.Stdin = exp.Tty()
cmd := tf.Cmd(tfCmd.command...) cmd.Stdout = exp.Tty()
cmd.Stdin = exp.Tty() cmd.Stderr = exp.Tty()
cmd.Stdout = exp.Tty()
cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if tfCmd.expectedCmdOutput != "" { if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput) _, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil {
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)
}
}
}
}
err = cmd.Wait()
if err != nil { if err != nil {
t.Fatal(err) 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)
}
}
}
}
err = cmd.Wait()
if err != nil {
t.Fatal(err)
}
} }
}
if tc.validations != nil { if tc.validations != nil {
tc.validations(t, organization.Name) tc.validations(t, organization.Name)
} }
})
} }
} }
func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) { func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) {
t.Parallel() skipIfMissingEnvVar(t)
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
ctx := context.Background() ctx := context.Background()
@ -268,20 +256,16 @@ func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) {
expectedCmdOutput: `Successfully configured the backend "local"!`, expectedCmdOutput: `Successfully configured the backend "local"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
{ {
command: []string{"workspace", "new", "prod"}, command: []string{"workspace", "new", "prod"},
expectedCmdOutput: `Created and switched to workspace "prod"!`, expectedCmdOutput: `Created and switched to workspace "prod"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
{ {
command: []string{"workspace", "select", "default"}, command: []string{"workspace", "select", "default"},
@ -311,21 +295,12 @@ func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) {
{ {
command: []string{"init", "-migrate-state"}, command: []string{"init", "-migrate-state"},
expectedCmdOutput: `Terraform Cloud requires all workspaces to be given an explicit name.`, expectedCmdOutput: `Terraform Cloud requires all workspaces to be given an explicit name.`,
userInput: []string{"dev", "1", "app-*", "1"}, userInput: []string{"dev", "1", "app-*"},
postInputOutput: []string{ postInputOutput: []string{
`Would you like to rename your workspaces?`, `Would you like to rename your workspaces?`,
"What pattern would you like to add to all your workspaces?", "How would you like to rename your workspaces?",
"The currently selected workspace (prod) does not exist.",
"Terraform Cloud has been successfully initialized!"}, "Terraform Cloud has been successfully initialized!"},
}, },
{
command: []string{"workspace", "select", "app-prod"},
expectedCmdOutput: `Switched to workspace "app-prod".`,
},
{
command: []string{"output"},
expectedCmdOutput: `val = "prod"`,
},
{ {
command: []string{"workspace", "select", "app-dev"}, command: []string{"workspace", "select", "app-dev"},
expectedCmdOutput: `Switched to workspace "app-dev".`, expectedCmdOutput: `Switched to workspace "app-dev".`,
@ -334,6 +309,14 @@ func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) {
command: []string{"output"}, command: []string{"output"},
expectedCmdOutput: `val = "default"`, expectedCmdOutput: `val = "default"`,
}, },
{
command: []string{"workspace", "select", "app-prod"},
expectedCmdOutput: `Switched to workspace "app-prod".`,
},
{
command: []string{"output"},
expectedCmdOutput: `val = "prod"`,
},
}, },
}, },
}, },
@ -417,17 +400,12 @@ func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) {
{ {
command: []string{"init", "-migrate-state"}, command: []string{"init", "-migrate-state"},
expectedCmdOutput: `Terraform Cloud requires all workspaces to be given an explicit name.`, expectedCmdOutput: `Terraform Cloud requires all workspaces to be given an explicit name.`,
userInput: []string{"dev", "1", "app-*", "1"}, userInput: []string{"dev", "1", "app-*"},
postInputOutput: []string{ postInputOutput: []string{
`Would you like to rename your workspaces?`, `Would you like to rename your workspaces?`,
"What pattern would you like to add to all your workspaces?", "How would you like to rename your workspaces?",
"The currently selected workspace (default) does not exist.",
"Terraform Cloud has been successfully initialized!"}, "Terraform Cloud has been successfully initialized!"},
}, },
{
command: []string{"workspace", "select", "app-dev"},
expectedCmdOutput: `Switched to workspace "app-dev".`,
},
{ {
command: []string{"workspace", "select", "app-billing"}, command: []string{"workspace", "select", "app-billing"},
expectedCmdOutput: `Switched to workspace "app-billing".`, expectedCmdOutput: `Switched to workspace "app-billing".`,
@ -436,6 +414,10 @@ func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) {
command: []string{"workspace", "select", "app-identity"}, command: []string{"workspace", "select", "app-identity"},
expectedCmdOutput: `Switched to workspace "app-identity".`, expectedCmdOutput: `Switched to workspace "app-identity".`,
}, },
{
command: []string{"workspace", "select", "app-dev"},
expectedCmdOutput: `Switched to workspace "app-dev".`,
},
}, },
}, },
}, },
@ -466,78 +448,78 @@ func Test_migrate_multi_to_tfc_cloud_tags_strategy(t *testing.T) {
} }
for name, tc := range cases { for name, tc := range cases {
t.Log("Test: ", name) tc := tc
organization, cleanup := createOrganization(t) t.Run(name, func(t *testing.T) {
t.Log(organization.Name) t.Parallel()
defer cleanup() organization, cleanup := createOrganization(t)
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) defer cleanup()
if err != nil { exp, err := expect.NewConsole(defaultOpts()...)
t.Fatal(err) if err != nil {
} t.Fatal(err)
defer exp.Close() }
defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
defer tf.Close() defer tf.Close()
tf.AddEnv("TF_LOG=INFO") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv)
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, organization.Name, tf.WorkDir()) op.prep(t, organization.Name, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
t.Log("running commands: ", tfCmd.command) cmd := tf.Cmd(tfCmd.command...)
cmd := tf.Cmd(tfCmd.command...) cmd.Stdin = exp.Tty()
cmd.Stdin = exp.Tty() cmd.Stdout = exp.Tty()
cmd.Stdout = exp.Tty() cmd.Stderr = exp.Tty()
cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if tfCmd.expectedCmdOutput != "" { if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput) _, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil {
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]
if output == "" {
continue
}
_, err := exp.ExpectString(output)
if err != nil {
t.Fatal(err)
}
}
}
}
err = cmd.Wait()
if err != nil { if err != nil {
t.Fatal(err) 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]
if output == "" {
continue
}
_, err := exp.ExpectString(output)
if err != nil {
t.Fatal(err)
}
}
}
}
err = cmd.Wait()
if err != nil {
t.Fatal(err)
}
} }
}
if tc.validations != nil { if tc.validations != nil {
tc.validations(t, organization.Name) tc.validations(t, organization.Name)
} }
})
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,3 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
@ -15,7 +12,7 @@ import (
) )
func Test_migrate_single_to_tfc(t *testing.T) { func Test_migrate_single_to_tfc(t *testing.T) {
t.Parallel() skipIfMissingEnvVar(t)
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
ctx := context.Background() ctx := context.Background()
@ -37,10 +34,8 @@ func Test_migrate_single_to_tfc(t *testing.T) {
expectedCmdOutput: `Successfully configured the backend "local"!`, expectedCmdOutput: `Successfully configured the backend "local"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
}, },
}, },
@ -88,10 +83,8 @@ func Test_migrate_single_to_tfc(t *testing.T) {
expectedCmdOutput: `Successfully configured the backend "local"!`, expectedCmdOutput: `Successfully configured the backend "local"!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
}, },
}, },
@ -133,73 +126,75 @@ func Test_migrate_single_to_tfc(t *testing.T) {
} }
for name, tc := range cases { for name, tc := range cases {
t.Log("Test: ", name) tc := tc
organization, cleanup := createOrganization(t) t.Run(name, func(t *testing.T) {
defer cleanup() t.Parallel()
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) organization, cleanup := createOrganization(t)
if err != nil { defer cleanup()
t.Fatal(err) exp, err := expect.NewConsole(defaultOpts()...)
} if err != nil {
defer exp.Close() t.Fatal(err)
}
defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
tf.AddEnv("TF_LOG=info") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv) defer tf.Close()
defer tf.Close()
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, organization.Name, tf.WorkDir()) op.prep(t, organization.Name, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
cmd := tf.Cmd(tfCmd.command...) cmd := tf.Cmd(tfCmd.command...)
cmd.Stdin = exp.Tty() cmd.Stdin = exp.Tty()
cmd.Stdout = exp.Tty() cmd.Stdout = exp.Tty()
cmd.Stderr = exp.Tty() cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if tfCmd.expectedCmdOutput != "" { if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput) _, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil {
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)
}
}
}
}
err = cmd.Wait()
if err != nil { if err != nil {
t.Fatal(err) 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)
}
}
}
}
err = cmd.Wait()
if err != nil {
t.Fatal(err)
}
} }
}
if tc.validations != nil { if tc.validations != nil {
tc.validations(t, organization.Name) tc.validations(t, organization.Name)
} }
})
} }
} }

View File

@ -1,10 +1,6 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
@ -14,7 +10,7 @@ import (
) )
func Test_migrate_tfc_to_other(t *testing.T) { func Test_migrate_tfc_to_other(t *testing.T) {
t.Parallel() skipIfMissingEnvVar(t)
cases := map[string]struct { cases := map[string]struct {
operations []operationSets operations []operationSets
}{ }{
@ -51,68 +47,70 @@ func Test_migrate_tfc_to_other(t *testing.T) {
} }
for name, tc := range cases { for name, tc := range cases {
fmt.Println("Test: ", name) tc := tc
organization, cleanup := createOrganization(t) t.Run(name, func(t *testing.T) {
defer cleanup() t.Parallel()
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) organization, cleanup := createOrganization(t)
if err != nil { defer cleanup()
t.Fatal(err) exp, err := expect.NewConsole(defaultOpts()...)
} if err != nil {
defer exp.Close() t.Fatal(err)
}
defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
tf.AddEnv("TF_LOG=info") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv) defer tf.Close()
defer tf.Close()
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, organization.Name, tf.WorkDir()) op.prep(t, organization.Name, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
cmd := tf.Cmd(tfCmd.command...) cmd := tf.Cmd(tfCmd.command...)
cmd.Stdin = exp.Tty() cmd.Stdin = exp.Tty()
cmd.Stdout = exp.Tty() cmd.Stdout = exp.Tty()
cmd.Stderr = exp.Tty() cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil {
t.Fatal(err)
}
if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
}
lenInput := len(tfCmd.userInput) if tfCmd.expectedCmdOutput != "" {
lenInputOutput := len(tfCmd.postInputOutput) _, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if lenInput > 0 { if err != nil {
for i := 0; i < lenInput; i++ { t.Fatal(err)
input := tfCmd.userInput[i] }
exp.SendLine(input) }
// use the index to find the corresponding
// output that matches the input. lenInput := len(tfCmd.userInput)
if lenInputOutput-1 >= i { lenInputOutput := len(tfCmd.postInputOutput)
output := tfCmd.postInputOutput[i] if lenInput > 0 {
_, err := exp.ExpectString(output) for i := 0; i < lenInput; i++ {
if err != nil { input := tfCmd.userInput[i]
t.Fatal(err) 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()
err = cmd.Wait() if err != nil && !tfCmd.expectError {
if err != nil && !tfCmd.expectError { t.Fatal(err)
t.Fatal(err) }
} }
} }
} })
} }
} }

View File

@ -1,6 +1,3 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
@ -16,7 +13,7 @@ import (
) )
func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) {
t.Parallel() skipIfMissingEnvVar(t)
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
ctx := context.Background() ctx := context.Background()
@ -55,10 +52,8 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) {
expectedCmdOutput: `prod`, // this comes from the `prep` function expectedCmdOutput: `prod`, // this comes from the `prep` function
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions in workspace "prod"?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
}, },
}, },
@ -119,10 +114,8 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) {
expectedCmdOutput: `Terraform Cloud has been successfully initialized!`, expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions in workspace "prod"?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
}, },
}, },
@ -183,10 +176,8 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) {
expectedCmdOutput: `Terraform Cloud has been successfully initialized!`, expectedCmdOutput: `Terraform Cloud has been successfully initialized!`,
}, },
{ {
command: []string{"apply"}, command: []string{"apply", "-auto-approve"},
expectedCmdOutput: `Do you want to perform these actions in workspace "prod"?`, postInputOutput: []string{`Apply complete!`},
userInput: []string{"yes"},
postInputOutput: []string{`Apply complete!`},
}, },
}, },
}, },
@ -214,95 +205,93 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) {
}, },
}, },
validations: func(t *testing.T, orgName string) { validations: func(t *testing.T, orgName string) {
wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{ // We created the workspace, so it will be there. We could not complete the state migration,
Tags: tfe.String("app"), // though, so the workspace should be empty.
}) ws, err := tfeClient.Workspaces.ReadWithOptions(ctx, orgName, "new-workspace", &tfe.WorkspaceReadOptions{Include: "current_run"})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// The migration never occured, so we have no workspaces with this tag. if ws.CurrentRun != nil {
if len(wsList.Items) != 0 { t.Fatal("Expected to workspace be empty")
t.Fatalf("Expected number of workspaces to be 0, but got %d", len(wsList.Items))
} }
}, },
}, },
} }
for name, tc := range cases { for name, tc := range cases {
t.Log("Test: ", name) t.Run(name, func(t *testing.T) {
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) exp, err := expect.NewConsole(defaultOpts()...)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer exp.Close() defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
defer tf.Close() defer tf.Close()
tf.AddEnv("TF_LOG=INFO") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv)
orgName, cleanup := tc.setup(t) orgName, cleanup := tc.setup(t)
defer cleanup() defer cleanup()
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, orgName, tf.WorkDir()) op.prep(t, orgName, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
t.Log("Running commands: ", tfCmd.command) cmd := tf.Cmd(tfCmd.command...)
cmd := tf.Cmd(tfCmd.command...) cmd.Stdin = exp.Tty()
cmd.Stdin = exp.Tty() cmd.Stdout = exp.Tty()
cmd.Stdout = exp.Tty() cmd.Stderr = exp.Tty()
cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil {
t.Fatal(err)
}
if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
}
lenInput := len(tfCmd.userInput) if tfCmd.expectedCmdOutput != "" {
lenInputOutput := len(tfCmd.postInputOutput) _, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if lenInput > 0 { if err != nil {
for i := 0; i < lenInput; i++ { t.Fatal(err)
input := tfCmd.userInput[i] }
exp.SendLine(input) }
// use the index to find the corresponding
// output that matches the input. lenInput := len(tfCmd.userInput)
if lenInputOutput-1 >= i { lenInputOutput := len(tfCmd.postInputOutput)
output := tfCmd.postInputOutput[i] if lenInput > 0 {
_, err := exp.ExpectString(output) for i := 0; i < lenInput; i++ {
if err != nil { input := tfCmd.userInput[i]
t.Fatal(err) 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() err = cmd.Wait()
if err != nil && !tfCmd.expectError { if err != nil && !tfCmd.expectError {
t.Fatal(err.Error()) t.Fatal(err.Error())
}
} }
} }
}
if tc.validations != nil { if tc.validations != nil {
tc.validations(t, orgName) tc.validations(t, orgName)
} }
})
} }
} }
func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) { func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) {
t.Parallel() skipIfMissingEnvVar(t)
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
ctx := context.Background() ctx := context.Background()
@ -454,7 +443,6 @@ func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) {
tag := "billing" tag := "billing"
tfBlock := terraformConfigCloudBackendTags(orgName, tag) tfBlock := terraformConfigCloudBackendTags(orgName, tag)
writeMainTF(t, tfBlock, dir) writeMainTF(t, tfBlock, dir)
t.Log(orgName)
}, },
commands: []tfCommand{ commands: []tfCommand{
{ {
@ -462,8 +450,7 @@ func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) {
expectedCmdOutput: `Would you like to rename your workspaces?`, expectedCmdOutput: `Would you like to rename your workspaces?`,
userInput: []string{"1", "new-*", "1"}, userInput: []string{"1", "new-*", "1"},
postInputOutput: []string{ postInputOutput: []string{
`What pattern would you like to add to all your workspaces?`, `How would you like to rename your workspaces?`,
`The currently selected workspace (app-staging) does not exist.`,
`Terraform Cloud has been successfully initialized!`}, `Terraform Cloud has been successfully initialized!`},
}, },
}, },
@ -492,75 +479,73 @@ func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) {
} }
for name, tc := range cases { for name, tc := range cases {
t.Log("Test: ", name) t.Run(name, func(t *testing.T) {
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) exp, err := expect.NewConsole(defaultOpts()...)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer exp.Close() defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
defer tf.Close() defer tf.Close()
tf.AddEnv("TF_LOG=INFO") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv)
orgName, cleanup := tc.setup(t) orgName, cleanup := tc.setup(t)
defer cleanup() defer cleanup()
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, orgName, tf.WorkDir()) op.prep(t, orgName, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
t.Log("Running commands: ", tfCmd.command) cmd := tf.Cmd(tfCmd.command...)
cmd := tf.Cmd(tfCmd.command...) cmd.Stdin = exp.Tty()
cmd.Stdin = exp.Tty() cmd.Stdout = exp.Tty()
cmd.Stdout = exp.Tty() cmd.Stderr = exp.Tty()
cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil {
t.Fatal(err)
}
if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
}
lenInput := len(tfCmd.userInput) if tfCmd.expectedCmdOutput != "" {
lenInputOutput := len(tfCmd.postInputOutput) _, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if lenInput > 0 { if err != nil {
for i := 0; i < lenInput; i++ { t.Fatal(err)
input := tfCmd.userInput[i] }
exp.SendLine(input) }
// use the index to find the corresponding
// output that matches the input. lenInput := len(tfCmd.userInput)
if lenInputOutput-1 >= i { lenInputOutput := len(tfCmd.postInputOutput)
output := tfCmd.postInputOutput[i] if lenInput > 0 {
_, err := exp.ExpectString(output) for i := 0; i < lenInput; i++ {
if err != nil { input := tfCmd.userInput[i]
t.Fatal(err) 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)
}
} }
} }
} }
}
t.Log(cmd.Stderr) err = cmd.Wait()
err = cmd.Wait() if err != nil {
if err != nil { t.Fatal(err.Error())
t.Fatal(err.Error()) }
} }
} }
}
if tc.validations != nil { if tc.validations != nil {
tc.validations(t, orgName) tc.validations(t, orgName)
} }
})
} }
} }

View File

@ -1,6 +1,3 @@
//go:build e2e
// +build e2e
package main package main
import ( import (
@ -10,7 +7,9 @@ import (
"testing" "testing"
expect "github.com/Netflix/go-expect" expect "github.com/Netflix/go-expect"
tfe "github.com/hashicorp/go-tfe"
"github.com/hashicorp/terraform/internal/e2e" "github.com/hashicorp/terraform/internal/e2e"
tfversion "github.com/hashicorp/terraform/version"
) )
func terraformConfigRequiredVariable(org, name string) string { func terraformConfigRequiredVariable(org, name string) string {
@ -46,7 +45,7 @@ output "test_env" {
} }
func Test_cloud_run_variables(t *testing.T) { func Test_cloud_run_variables(t *testing.T) {
t.Parallel() skipIfMissingEnvVar(t)
skipWithoutRemoteTerraformVersion(t) skipWithoutRemoteTerraformVersion(t)
cases := testCases{ cases := testCases{
@ -55,6 +54,10 @@ func Test_cloud_run_variables(t *testing.T) {
{ {
prep: func(t *testing.T, orgName, dir string) { prep: func(t *testing.T, orgName, dir string) {
wsName := "new-workspace" wsName := "new-workspace"
_ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{
Name: tfe.String(wsName),
TerraformVersion: tfe.String(tfversion.String()),
})
tfBlock := terraformConfigRequiredVariable(orgName, wsName) tfBlock := terraformConfigRequiredVariable(orgName, wsName)
writeMainTF(t, tfBlock, dir) writeMainTF(t, tfBlock, dir)
}, },
@ -78,75 +81,75 @@ func Test_cloud_run_variables(t *testing.T) {
} }
for name, tc := range cases { for name, tc := range cases {
fmt.Println("Test: ", name) t.Run(name, func(t *testing.T) {
organization, cleanup := createOrganization(t) organization, cleanup := createOrganization(t)
defer cleanup() defer cleanup()
exp, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithDefaultTimeout(expectConsoleTimeout)) exp, err := expect.NewConsole(defaultOpts()...)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer exp.Close() defer exp.Close()
tmpDir, err := ioutil.TempDir("", "terraform-test") tmpDir, err := ioutil.TempDir("", "terraform-test")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
tf := e2e.NewBinary(terraformBin, tmpDir) tf := e2e.NewBinary(terraformBin, tmpDir)
tf.AddEnv("TF_LOG=info") tf.AddEnv("TF_CLI_ARGS=-no-color")
tf.AddEnv("TF_CLI_ARGS=-no-color") tf.AddEnv("TF_VAR_baz=qux")
tf.AddEnv("TF_VAR_baz=qux") tf.AddEnv(cliConfigFileEnv)
tf.AddEnv(cliConfigFileEnv) defer tf.Close()
defer tf.Close()
for _, op := range tc.operations { for _, op := range tc.operations {
op.prep(t, organization.Name, tf.WorkDir()) op.prep(t, organization.Name, tf.WorkDir())
for _, tfCmd := range op.commands { for _, tfCmd := range op.commands {
cmd := tf.Cmd(tfCmd.command...) cmd := tf.Cmd(tfCmd.command...)
cmd.Stdin = exp.Tty() cmd.Stdin = exp.Tty()
cmd.Stdout = exp.Tty() cmd.Stdout = exp.Tty()
cmd.Stderr = exp.Tty() cmd.Stderr = exp.Tty()
err = cmd.Start() err = cmd.Start()
if err != nil {
t.Fatal(err)
}
if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if tfCmd.expectedCmdOutput != "" {
_, err := exp.ExpectString(tfCmd.expectedCmdOutput)
if err != nil {
t.Fatalf(`Expected command output "%s", but got %v `, tfCmd.expectedCmdOutput, 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.Fatalf(`Expected command output "%s", but got %v `, tfCmd.expectedCmdOutput, err)
}
}
}
}
err = cmd.Wait()
if err != nil && !tfCmd.expectError {
t.Fatal(err)
}
} }
lenInput := len(tfCmd.userInput) if tc.validations != nil {
lenInputOutput := len(tfCmd.postInputOutput) tc.validations(t, organization.Name)
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 && !tfCmd.expectError {
t.Fatal(err)
} }
} }
})
if tc.validations != nil {
tc.validations(t, organization.Name)
}
}
} }
} }