github.com/kevinklinger/open_terraform@v1.3.6/noninternal/cloud/e2e/helper_test.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	expect "github.com/Netflix/go-expect"
    11  	tfe "github.com/hashicorp/go-tfe"
    12  	"github.com/hashicorp/go-uuid"
    13  	goversion "github.com/hashicorp/go-version"
    14  	tfversion "github.com/kevinklinger/open_terraform/version"
    15  )
    16  
    17  const (
    18  	// We need to give the console enough time to hear back.
    19  	// 1 minute was too short in some cases, so this gives it ample time.
    20  	expectConsoleTimeout = 3 * time.Minute
    21  )
    22  
    23  type tfCommand struct {
    24  	command           []string
    25  	expectedCmdOutput string
    26  	expectError       bool
    27  	userInput         []string
    28  	postInputOutput   []string
    29  }
    30  
    31  type operationSets struct {
    32  	commands []tfCommand
    33  	prep     func(t *testing.T, orgName, dir string)
    34  }
    35  
    36  type testCases map[string]struct {
    37  	operations  []operationSets
    38  	validations func(t *testing.T, orgName string)
    39  }
    40  
    41  func defaultOpts() []expect.ConsoleOpt {
    42  	opts := []expect.ConsoleOpt{
    43  		expect.WithDefaultTimeout(expectConsoleTimeout),
    44  	}
    45  	if verboseMode {
    46  		opts = append(opts, expect.WithStdout(os.Stdout))
    47  	}
    48  	return opts
    49  }
    50  
    51  func createOrganization(t *testing.T) (*tfe.Organization, func()) {
    52  	ctx := context.Background()
    53  	org, err := tfeClient.Organizations.Create(ctx, tfe.OrganizationCreateOptions{
    54  		Name:                  tfe.String("tst-" + randomString(t)),
    55  		Email:                 tfe.String(fmt.Sprintf("%s@tfe.local", randomString(t))),
    56  		CostEstimationEnabled: tfe.Bool(false),
    57  	})
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  
    62  	_, err = tfeClient.Admin.Organizations.Update(ctx, org.Name, tfe.AdminOrganizationUpdateOptions{
    63  		AccessBetaTools: tfe.Bool(true),
    64  	})
    65  	if err != nil {
    66  		t.Fatal(err)
    67  	}
    68  
    69  	return org, func() {
    70  		if err := tfeClient.Organizations.Delete(ctx, org.Name); err != nil {
    71  			t.Errorf("Error destroying organization! WARNING: Dangling resources\n"+
    72  				"may exist! The full error is shown below.\n\n"+
    73  				"Organization: %s\nError: %s", org.Name, err)
    74  		}
    75  	}
    76  }
    77  
    78  func createWorkspace(t *testing.T, orgName string, wOpts tfe.WorkspaceCreateOptions) *tfe.Workspace {
    79  	ctx := context.Background()
    80  	w, err := tfeClient.Workspaces.Create(ctx, orgName, wOpts)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	return w
    86  }
    87  
    88  func getWorkspace(workspaces []*tfe.Workspace, workspace string) (*tfe.Workspace, bool) {
    89  	for _, ws := range workspaces {
    90  		if ws.Name == workspace {
    91  			return ws, false
    92  		}
    93  	}
    94  	return nil, true
    95  }
    96  
    97  func randomString(t *testing.T) string {
    98  	v, err := uuid.GenerateUUID()
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	return v
   103  }
   104  
   105  func terraformConfigLocalBackend() string {
   106  	return `
   107  terraform {
   108    backend "local" {
   109    }
   110  }
   111  
   112  output "val" {
   113    value = "${terraform.workspace}"
   114  }
   115  `
   116  }
   117  
   118  func terraformConfigRemoteBackendName(org, name string) string {
   119  	return fmt.Sprintf(`
   120  terraform {
   121    backend "remote" {
   122      hostname = "%s"
   123      organization = "%s"
   124  
   125      workspaces {
   126        name = "%s"
   127      }
   128    }
   129  }
   130  
   131  output "val" {
   132    value = "${terraform.workspace}"
   133  }
   134  `, tfeHostname, org, name)
   135  }
   136  
   137  func terraformConfigRemoteBackendPrefix(org, prefix string) string {
   138  	return fmt.Sprintf(`
   139  terraform {
   140    backend "remote" {
   141      hostname = "%s"
   142      organization = "%s"
   143  
   144      workspaces {
   145        prefix = "%s"
   146      }
   147    }
   148  }
   149  
   150  output "val" {
   151    value = "${terraform.workspace}"
   152  }
   153  `, tfeHostname, org, prefix)
   154  }
   155  
   156  func terraformConfigCloudBackendTags(org, tag string) string {
   157  	return fmt.Sprintf(`
   158  terraform {
   159    cloud {
   160      hostname = "%s"
   161      organization = "%s"
   162  
   163      workspaces {
   164        tags = ["%s"]
   165      }
   166    }
   167  }
   168  
   169  output "tag_val" {
   170    value = "%s"
   171  }
   172  `, tfeHostname, org, tag, tag)
   173  }
   174  
   175  func terraformConfigCloudBackendName(org, name string) string {
   176  	return fmt.Sprintf(`
   177  terraform {
   178    cloud {
   179      hostname = "%s"
   180      organization = "%s"
   181  
   182      workspaces {
   183        name = "%s"
   184      }
   185    }
   186  }
   187  
   188  output "val" {
   189    value = "${terraform.workspace}"
   190  }
   191  `, tfeHostname, org, name)
   192  }
   193  
   194  func terraformConfigCloudBackendOmitOrg(workspaceName string) string {
   195  	return fmt.Sprintf(`
   196  terraform {
   197    cloud {
   198      hostname = "%s"
   199  
   200  	workspaces {
   201  	  name = "%s"
   202  	}
   203    }
   204  }
   205  
   206  output "val" {
   207    value = "${terraform.workspace}"
   208  }
   209  `, tfeHostname, workspaceName)
   210  }
   211  
   212  func terraformConfigCloudBackendOmitWorkspaces(orgName string) string {
   213  	return fmt.Sprintf(`
   214  terraform {
   215    cloud {
   216      hostname = "%s"
   217  	organization = "%s"
   218    }
   219  }
   220  
   221  output "val" {
   222    value = "${terraform.workspace}"
   223  }
   224  `, tfeHostname, orgName)
   225  }
   226  
   227  func terraformConfigCloudBackendOmitConfig() string {
   228  	return `
   229  terraform {
   230    cloud {}
   231  }
   232  
   233  output "val" {
   234    value = "${terraform.workspace}"
   235  }
   236  `
   237  }
   238  
   239  func writeMainTF(t *testing.T, block string, dir string) {
   240  	f, err := os.Create(fmt.Sprintf("%s/main.tf", dir))
   241  	if err != nil {
   242  		t.Fatal(err)
   243  	}
   244  	_, err = f.WriteString(block)
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  	f.Close()
   249  }
   250  
   251  // The e2e tests rely on the fact that the terraform version in TFC/E is able to
   252  // run the `cloud` configuration block, which is available in 1.1 and will
   253  // continue to be available in later versions. So this function checks that
   254  // there is a version that is >= 1.1.
   255  func skipWithoutRemoteTerraformVersion(t *testing.T) {
   256  	version := tfversion.Version
   257  	baseVersion, err := goversion.NewVersion(version)
   258  	if err != nil {
   259  		t.Fatalf(fmt.Sprintf("Error instantiating go-version for %s", version))
   260  	}
   261  	opts := &tfe.AdminTerraformVersionsListOptions{
   262  		ListOptions: tfe.ListOptions{
   263  			PageNumber: 1,
   264  			PageSize:   100,
   265  		},
   266  	}
   267  	hasVersion := false
   268  
   269  findTfVersion:
   270  	for {
   271  		// TODO: update go-tfe Read() to retrieve a terraform version by name.
   272  		// Currently you can only retrieve by ID.
   273  		tfVersionList, err := tfeClient.Admin.TerraformVersions.List(context.Background(), opts)
   274  		if err != nil {
   275  			t.Fatalf("Could not retrieve list of terraform versions: %v", err)
   276  		}
   277  		for _, item := range tfVersionList.Items {
   278  			availableVersion, err := goversion.NewVersion(item.Version)
   279  			if err != nil {
   280  				t.Logf("Error instantiating go-version for %s", item.Version)
   281  				continue
   282  			}
   283  			if availableVersion.Core().GreaterThanOrEqual(baseVersion.Core()) {
   284  				hasVersion = true
   285  				break findTfVersion
   286  			}
   287  		}
   288  
   289  		// Exit the loop when we've seen all pages.
   290  		if tfVersionList.CurrentPage >= tfVersionList.TotalPages {
   291  			break
   292  		}
   293  
   294  		// Update the page number to get the next page.
   295  		opts.PageNumber = tfVersionList.NextPage
   296  	}
   297  
   298  	if !hasVersion {
   299  		t.Skipf("Skipping test because TFC/E does not have current Terraform version to test with (%s)", version)
   300  	}
   301  }