mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-18 04:32:59 -06:00
d196d2870a
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.
257 lines
5.5 KiB
Go
257 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
expect "github.com/Netflix/go-expect"
|
|
tfe "github.com/hashicorp/go-tfe"
|
|
"github.com/hashicorp/go-uuid"
|
|
goversion "github.com/hashicorp/go-version"
|
|
tfversion "github.com/hashicorp/terraform/version"
|
|
)
|
|
|
|
const (
|
|
// 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 {
|
|
command []string
|
|
expectedCmdOutput string
|
|
expectError bool
|
|
userInput []string
|
|
postInputOutput []string
|
|
}
|
|
|
|
type operationSets struct {
|
|
commands []tfCommand
|
|
prep func(t *testing.T, orgName, dir string)
|
|
}
|
|
|
|
type testCases map[string]struct {
|
|
operations []operationSets
|
|
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()) {
|
|
ctx := context.Background()
|
|
org, err := tfeClient.Organizations.Create(ctx, tfe.OrganizationCreateOptions{
|
|
Name: tfe.String("tst-" + randomString(t)),
|
|
Email: tfe.String(fmt.Sprintf("%s@tfe.local", randomString(t))),
|
|
CostEstimationEnabled: tfe.Bool(false),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = tfeClient.Admin.Organizations.Update(ctx, org.Name, tfe.AdminOrganizationUpdateOptions{
|
|
AccessBetaTools: tfe.Bool(true),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return org, func() {
|
|
if err := tfeClient.Organizations.Delete(ctx, org.Name); err != nil {
|
|
t.Errorf("Error destroying organization! WARNING: Dangling resources\n"+
|
|
"may exist! The full error is shown below.\n\n"+
|
|
"Organization: %s\nError: %s", org.Name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func createWorkspace(t *testing.T, orgName string, wOpts tfe.WorkspaceCreateOptions) *tfe.Workspace {
|
|
ctx := context.Background()
|
|
w, err := tfeClient.Workspaces.Create(ctx, orgName, wOpts)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return w
|
|
}
|
|
|
|
func getWorkspace(workspaces []*tfe.Workspace, workspace string) (*tfe.Workspace, bool) {
|
|
for _, ws := range workspaces {
|
|
if ws.Name == workspace {
|
|
return ws, false
|
|
}
|
|
}
|
|
return nil, true
|
|
}
|
|
|
|
func randomString(t *testing.T) string {
|
|
v, err := uuid.GenerateUUID()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return v
|
|
}
|
|
|
|
func terraformConfigLocalBackend() string {
|
|
return `
|
|
terraform {
|
|
backend "local" {
|
|
}
|
|
}
|
|
|
|
output "val" {
|
|
value = "${terraform.workspace}"
|
|
}
|
|
`
|
|
}
|
|
|
|
func terraformConfigRemoteBackendName(org, name string) string {
|
|
return fmt.Sprintf(`
|
|
terraform {
|
|
backend "remote" {
|
|
hostname = "%s"
|
|
organization = "%s"
|
|
|
|
workspaces {
|
|
name = "%s"
|
|
}
|
|
}
|
|
}
|
|
|
|
output "val" {
|
|
value = "${terraform.workspace}"
|
|
}
|
|
`, tfeHostname, org, name)
|
|
}
|
|
|
|
func terraformConfigRemoteBackendPrefix(org, prefix string) string {
|
|
return fmt.Sprintf(`
|
|
terraform {
|
|
backend "remote" {
|
|
hostname = "%s"
|
|
organization = "%s"
|
|
|
|
workspaces {
|
|
prefix = "%s"
|
|
}
|
|
}
|
|
}
|
|
|
|
output "val" {
|
|
value = "${terraform.workspace}"
|
|
}
|
|
`, tfeHostname, org, prefix)
|
|
}
|
|
|
|
func terraformConfigCloudBackendTags(org, tag string) string {
|
|
return fmt.Sprintf(`
|
|
terraform {
|
|
cloud {
|
|
hostname = "%s"
|
|
organization = "%s"
|
|
|
|
workspaces {
|
|
tags = ["%s"]
|
|
}
|
|
}
|
|
}
|
|
|
|
output "tag_val" {
|
|
value = "%s"
|
|
}
|
|
`, tfeHostname, org, tag, tag)
|
|
}
|
|
|
|
func terraformConfigCloudBackendName(org, name string) string {
|
|
return fmt.Sprintf(`
|
|
terraform {
|
|
cloud {
|
|
hostname = "%s"
|
|
organization = "%s"
|
|
|
|
workspaces {
|
|
name = "%s"
|
|
}
|
|
}
|
|
}
|
|
|
|
output "val" {
|
|
value = "${terraform.workspace}"
|
|
}
|
|
`, tfeHostname, org, name)
|
|
}
|
|
|
|
func writeMainTF(t *testing.T, block string, dir string) {
|
|
f, err := os.Create(fmt.Sprintf("%s/main.tf", dir))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = f.WriteString(block)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
}
|
|
|
|
// 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) {
|
|
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{
|
|
ListOptions: tfe.ListOptions{
|
|
PageNumber: 1,
|
|
PageSize: 100,
|
|
},
|
|
}
|
|
hasVersion := false
|
|
|
|
findTfVersion:
|
|
for {
|
|
// TODO: update go-tfe Read() to retrieve a terraform version by name.
|
|
// Currently you can only retrieve by ID.
|
|
tfVersionList, err := tfeClient.Admin.TerraformVersions.List(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("Could not retrieve list of terraform versions: %v", err)
|
|
}
|
|
for _, item := range tfVersionList.Items {
|
|
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
|
|
break findTfVersion
|
|
}
|
|
}
|
|
|
|
// Exit the loop when we've seen all pages.
|
|
if tfVersionList.CurrentPage >= tfVersionList.TotalPages {
|
|
break
|
|
}
|
|
|
|
// Update the page number to get the next page.
|
|
opts.PageNumber = tfVersionList.NextPage
|
|
}
|
|
|
|
if !hasVersion {
|
|
t.Skip(fmt.Sprintf("Skipping test because TFC/E does not have current Terraform version to test with (%s)", version))
|
|
}
|
|
}
|