github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/cloud/e2e/main_test.go (about)

     1  package main
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"log"
     8  	"os"
     9  	"os/exec"
    10  	"strings"
    11  	"testing"
    12  
    13  	expect "github.com/Netflix/go-expect"
    14  	tfe "github.com/hashicorp/go-tfe"
    15  	"github.com/cycloidio/terraform/e2e"
    16  	tfversion "github.com/cycloidio/terraform/version"
    17  )
    18  
    19  var terraformBin string
    20  var cliConfigFileEnv string
    21  
    22  var tfeClient *tfe.Client
    23  var tfeHostname string
    24  var tfeToken string
    25  var verboseMode bool
    26  
    27  func TestMain(m *testing.M) {
    28  	teardown := setup()
    29  	code := m.Run()
    30  	teardown()
    31  
    32  	os.Exit(code)
    33  }
    34  
    35  func accTest() bool {
    36  	// TF_ACC is set when we want to run acceptance tests, meaning it relies on
    37  	// network access.
    38  	return os.Getenv("TF_ACC") != ""
    39  }
    40  
    41  func hasHostname() bool {
    42  	return os.Getenv("TFE_HOSTNAME") != ""
    43  }
    44  
    45  func hasToken() bool {
    46  	return os.Getenv("TFE_TOKEN") != ""
    47  }
    48  
    49  func hasRequiredEnvVars() bool {
    50  	return accTest() && hasHostname() && hasToken()
    51  }
    52  
    53  func skipIfMissingEnvVar(t *testing.T) {
    54  	if !hasRequiredEnvVars() {
    55  		t.Skip("Skipping test, required environment variables missing. Use `TF_ACC`, `TFE_HOSTNAME`, `TFE_TOKEN`")
    56  	}
    57  }
    58  
    59  func setup() func() {
    60  	tfOutput := flag.Bool("tfoutput", false, "This flag produces the terraform output from tests.")
    61  	flag.Parse()
    62  	verboseMode = *tfOutput
    63  
    64  	setTfeClient()
    65  	teardown := setupBinary()
    66  
    67  	return func() {
    68  		teardown()
    69  	}
    70  }
    71  func testRunner(t *testing.T, cases testCases, orgCount int, tfEnvFlags ...string) {
    72  	for name, tc := range cases {
    73  		tc := tc // rebind tc into this lexical scope
    74  		t.Run(name, func(subtest *testing.T) {
    75  			subtest.Parallel()
    76  
    77  			orgNames := []string{}
    78  			for i := 0; i < orgCount; i++ {
    79  				organization, cleanup := createOrganization(t)
    80  				t.Cleanup(cleanup)
    81  				orgNames = append(orgNames, organization.Name)
    82  			}
    83  
    84  			exp, err := expect.NewConsole(defaultOpts()...)
    85  			if err != nil {
    86  				subtest.Fatal(err)
    87  			}
    88  			defer exp.Close()
    89  
    90  			tmpDir, err := ioutil.TempDir("", "terraform-test")
    91  			if err != nil {
    92  				subtest.Fatal(err)
    93  			}
    94  			defer os.RemoveAll(tmpDir)
    95  
    96  			tf := e2e.NewBinary(terraformBin, tmpDir)
    97  			tfEnvFlags = append(tfEnvFlags, "TF_LOG=INFO")
    98  			tfEnvFlags = append(tfEnvFlags, cliConfigFileEnv)
    99  			for _, env := range tfEnvFlags {
   100  				tf.AddEnv(env)
   101  			}
   102  			defer tf.Close()
   103  
   104  			var orgName string
   105  			for index, op := range tc.operations {
   106  				if orgCount == 1 {
   107  					orgName = orgNames[0]
   108  				} else {
   109  					orgName = orgNames[index]
   110  				}
   111  				op.prep(t, orgName, tf.WorkDir())
   112  				for _, tfCmd := range op.commands {
   113  					cmd := tf.Cmd(tfCmd.command...)
   114  					cmd.Stdin = exp.Tty()
   115  					cmd.Stdout = exp.Tty()
   116  					cmd.Stderr = exp.Tty()
   117  
   118  					err = cmd.Start()
   119  					if err != nil {
   120  						subtest.Fatal(err)
   121  					}
   122  
   123  					if tfCmd.expectedCmdOutput != "" {
   124  						got, err := exp.ExpectString(tfCmd.expectedCmdOutput)
   125  						if err != nil {
   126  							subtest.Fatalf("error while waiting for output\nwant: %s\nerror: %s\noutput\n%s", tfCmd.expectedCmdOutput, err, got)
   127  						}
   128  					}
   129  
   130  					lenInput := len(tfCmd.userInput)
   131  					lenInputOutput := len(tfCmd.postInputOutput)
   132  					if lenInput > 0 {
   133  						for i := 0; i < lenInput; i++ {
   134  							input := tfCmd.userInput[i]
   135  							exp.SendLine(input)
   136  							// use the index to find the corresponding
   137  							// output that matches the input.
   138  							if lenInputOutput-1 >= i {
   139  								output := tfCmd.postInputOutput[i]
   140  								_, err := exp.ExpectString(output)
   141  								if err != nil {
   142  									subtest.Fatal(err)
   143  								}
   144  							}
   145  						}
   146  					}
   147  
   148  					err = cmd.Wait()
   149  					if err != nil && !tfCmd.expectError {
   150  						subtest.Fatal(err)
   151  					}
   152  				}
   153  			}
   154  
   155  			if tc.validations != nil {
   156  				tc.validations(t, orgName)
   157  			}
   158  		})
   159  	}
   160  }
   161  
   162  func setTfeClient() {
   163  	tfeHostname = os.Getenv("TFE_HOSTNAME")
   164  	tfeToken = os.Getenv("TFE_TOKEN")
   165  
   166  	cfg := &tfe.Config{
   167  		Address: fmt.Sprintf("https://%s", tfeHostname),
   168  		Token:   tfeToken,
   169  	}
   170  
   171  	if tfeHostname != "" && tfeToken != "" {
   172  		// Create a new TFE client.
   173  		client, err := tfe.NewClient(cfg)
   174  		if err != nil {
   175  			fmt.Printf("Could not create new tfe client: %v\n", err)
   176  			os.Exit(1)
   177  		}
   178  		tfeClient = client
   179  	}
   180  }
   181  
   182  func setupBinary() func() {
   183  	log.Println("Setting up terraform binary")
   184  	tmpTerraformBinaryDir, err := ioutil.TempDir("", "terraform-test")
   185  	if err != nil {
   186  		fmt.Printf("Could not create temp directory: %v\n", err)
   187  		os.Exit(1)
   188  	}
   189  	log.Println(tmpTerraformBinaryDir)
   190  	currentDir, err := os.Getwd()
   191  	defer os.Chdir(currentDir)
   192  	if err != nil {
   193  		fmt.Printf("Could not change directories: %v\n", err)
   194  		os.Exit(1)
   195  	}
   196  	// Getting top level dir
   197  	dirPaths := strings.Split(currentDir, "/")
   198  	log.Println(currentDir)
   199  	topLevel := len(dirPaths) - 3
   200  	topDir := strings.Join(dirPaths[0:topLevel], "/")
   201  
   202  	if err := os.Chdir(topDir); err != nil {
   203  		fmt.Printf("Could not change directories: %v\n", err)
   204  		os.Exit(1)
   205  	}
   206  
   207  	cmd := exec.Command(
   208  		"go",
   209  		"build",
   210  		"-o", tmpTerraformBinaryDir,
   211  		"-ldflags", fmt.Sprintf("-X \"github.com/cycloidio/terraform/version.Prerelease=%s\"", tfversion.Prerelease),
   212  	)
   213  	err = cmd.Run()
   214  	if err != nil {
   215  		fmt.Printf("Could not run exec command: %v\n", err)
   216  		os.Exit(1)
   217  	}
   218  
   219  	credFile := fmt.Sprintf("%s/dev.tfrc", tmpTerraformBinaryDir)
   220  	writeCredRC(credFile)
   221  
   222  	terraformBin = fmt.Sprintf("%s/terraform", tmpTerraformBinaryDir)
   223  	cliConfigFileEnv = fmt.Sprintf("TF_CLI_CONFIG_FILE=%s", credFile)
   224  
   225  	return func() {
   226  		os.RemoveAll(tmpTerraformBinaryDir)
   227  	}
   228  }
   229  
   230  func writeCredRC(file string) {
   231  	creds := credentialBlock()
   232  	f, err := os.Create(file)
   233  	if err != nil {
   234  		fmt.Printf("Could not create file: %v\n", err)
   235  		os.Exit(1)
   236  	}
   237  	_, err = f.WriteString(creds)
   238  	if err != nil {
   239  		fmt.Printf("Could not write credentials: %v\n", err)
   240  		os.Exit(1)
   241  	}
   242  	f.Close()
   243  }
   244  
   245  func credentialBlock() string {
   246  	return fmt.Sprintf(`
   247  credentials "%s" {
   248    token = "%s"
   249  }`, tfeHostname, tfeToken)
   250  }