Skip to content

Commit

Permalink
chore(tests): allow running tests with different version of Terrafor…
Browse files Browse the repository at this point in the history
…m. (#1185)

# Reason for This Change

Add support for running e2e tests with a different version of Terraform
when exporting the `TM_TEST_TERRAFORM_REQUIRED_VERSION` environment
variable.

Additionally, the tests now detect if Terraform is already installed and
then the detected version is used. If the detected version does not
match the version provided in the environment variable, then it's
installed as before.

Usage example:

```
$ which terraform
/usr/bin/terraform
$ terraform version
Terraform v1.5.0

# Run tests with existing Terraform
$ go test -v ./cmd/terramate/e2etests

# Run tests with a different version of Terraform
$ TM_TEST_TERRAFORM_REQUIRED_VERSION=1.3.0 go test ./cmd/terramate/e2etests
```

## Description of Changes

The e2etest setup was updated to support a configurable Terraform
version and tests were updated to be independent of the Terraform
version.
  • Loading branch information
i4k-tm committed Oct 20, 2023
2 parents cead9ef + 26ddfd1 commit 7104be0
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"format_version":"1.2","terraform_version":"1.5.0","variables":{"content":{"value":"REDACTED_SENSITIVE"}},"planned_values":{"root_module":{"resources":[{"address":"local_file.foo","mode":"managed","type":"local_file","name":"foo","provider_name":"registry.terraform.io/hashicorp/local","schema_version":0,"values":{"content":"REDACTED_SENSITIVE","content_base64":null,"directory_permission":"0777","file_permission":"0777","filename":"./foo.bar","sensitive_content":"REDACTED_SENSITIVE","source":null},"sensitive_values":{"content":true}}]}},"resource_changes":[{"address":"local_file.foo","mode":"managed","type":"local_file","name":"foo","provider_name":"registry.terraform.io/hashicorp/local","change":{"actions":["create"],"before":null,"after":{"content":"REDACTED_SENSITIVE","content_base64":null,"directory_permission":"0777","file_permission":"0777","filename":"./foo.bar","sensitive_content":"REDACTED_SENSITIVE","source":null},"after_unknown":{"content_base64sha256":true,"content_base64sha512":true,"content_md5":true,"content_sha1":true,"content_sha256":true,"content_sha512":true,"id":true},"before_sensitive":false,"after_sensitive":{"content":true,"sensitive_content":true}}}],"configuration":{"provider_config":{"local":{"name":"local","full_name":"registry.terraform.io/hashicorp/local"}},"root_module":{"resources":[{"address":"local_file.foo","mode":"managed","type":"local_file","name":"foo","provider_config_key":"local","expressions":{"content":{"references":["var.content"]},"filename":{"references":["path.module"]}},"schema_version":0}],"variables":{"content":{"sensitive":true}}}},"timestamp":"2023-10-12T14:03:39Z"}
{"format_version":"1.2","terraform_version":"__terraform_version__","variables":{"content":{"value":"REDACTED_SENSITIVE"}},"planned_values":{"root_module":{"resources":[{"address":"local_file.foo","mode":"managed","type":"local_file","name":"foo","provider_name":"registry.terraform.io/hashicorp/local","schema_version":0,"values":{"content":"REDACTED_SENSITIVE","content_base64":null,"directory_permission":"0777","file_permission":"0777","filename":"./foo.bar","sensitive_content":"REDACTED_SENSITIVE","source":null},"sensitive_values":{"content":true}}]}},"resource_changes":[{"address":"local_file.foo","mode":"managed","type":"local_file","name":"foo","provider_name":"registry.terraform.io/hashicorp/local","change":{"actions":["create"],"before":null,"after":{"content":"REDACTED_SENSITIVE","content_base64":null,"directory_permission":"0777","file_permission":"0777","filename":"./foo.bar","sensitive_content":"REDACTED_SENSITIVE","source":null},"after_unknown":{"content_base64sha256":true,"content_base64sha512":true,"content_md5":true,"content_sha1":true,"content_sha256":true,"content_sha512":true,"id":true},"before_sensitive":false,"after_sensitive":{"content":true,"sensitive_content":true}}}],"configuration":{"provider_config":{"local":{"name":"local","full_name":"registry.terraform.io/hashicorp/local"}},"root_module":{"resources":[{"address":"local_file.foo","mode":"managed","type":"local_file","name":"foo","provider_config_key":"local","expressions":{"content":{"references":["var.content"]},"filename":{"references":["path.module"]}},"schema_version":0}],"variables":{"content":{"sensitive":true}}}},"timestamp":"2023-10-12T14:03:39Z"}
51 changes: 38 additions & 13 deletions cmd/terramate/e2etests/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"

Expand All @@ -22,14 +23,17 @@ import (
"github.com/terramate-io/terramate/errors"
)

const terraformVersion = "1.5.0"
const terraformInstallVersion = "1.5.0"

// terramateTestBin is the path to the terramate binary we compiled for test purposes
var terramateTestBin string

// terraformTestBin is the path to the installed terraform binary.
var terraformTestBin string

// terraformVersion is the detected or installed Terraform version.
var terraformVersion string

// testHelperBin is the path to the test binary we compiled for test purposes
var testHelperBin string

Expand Down Expand Up @@ -89,21 +93,14 @@ func setupAndRunTests(m *testing.M) (status int) {
EOF
)}`, testHelperBin)

tfExecPath, installer, err := installTerraform()
tfExecPath, cleanup, err := installTerraform()
if err != nil {
log.Printf("failed to setup Terraform binary")
return 1
}

defer cleanup()
terraformTestBin = tfExecPath

defer func() {
err := installer.Remove(context.Background())
if err != nil {
log.Printf("failed to remove terraform installation")
}
}()

return m.Run()
}

Expand Down Expand Up @@ -146,12 +143,33 @@ func buildTerramate(goBin, projectRoot, binDir string) (string, error) {
return outBinPath, nil
}

func installTerraform() (string, *install.Installer, error) {
func installTerraform() (string, func(), error) {
requireVersion := os.Getenv("TM_TEST_TERRAFORM_REQUIRED_VERSION")
tfExecPath, err := exec.LookPath("terraform")
if err == nil {
cmd := exec.Command("terraform", "version")
output, err := cmd.Output()
if err == nil && len(output) > 0 {
lines := strings.Split(string(output), "\n")
terraformVersion = strings.TrimPrefix(strings.TrimSpace(lines[0]), "Terraform v")

if requireVersion == "" || terraformVersion == requireVersion {
log.Printf("Terraform detected version: %s", terraformVersion)
return tfExecPath, func() {}, nil
}
}
}

installVersion := terraformInstallVersion
if requireVersion != "" {
installVersion = requireVersion
}

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()

installer := install.NewInstaller()
version := version.Must(version.NewVersion(terraformVersion))
version := version.Must(version.NewVersion(installVersion))

execPath, err := installer.Install(ctx, []src.Installable{
&releases.ExactVersion{
Expand All @@ -162,7 +180,14 @@ func installTerraform() (string, *install.Installer, error) {
if err != nil {
return "", nil, errors.E(err, "installing Terraform")
}
return execPath, installer, nil
terraformVersion = installVersion
log.Printf("Terraform installed version: %s", terraformVersion)
return execPath, func() {
err := installer.Remove(context.Background())
if err != nil {
log.Printf("failed to remove terraform installation")
}
}, nil
}

func lookupGoBin() (string, error) {
Expand Down
17 changes: 14 additions & 3 deletions cmd/terramate/e2etests/run_cloud_drift_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ func TestCLIRunWithCloudSyncDriftStatus(t *testing.T) {
Status: stack.Drifted,
Details: &cloud.DriftDetails{
Provisioner: "terraform",
ChangesetJSON: string(test.ReadFile(t, "_testdata/cloud-sync-drift-plan-file", "sanitized.plan.json")),
ChangesetJSON: loadJSONPlan(t, "_testdata/cloud-sync-drift-plan-file/sanitized.plan.json"),
},
},
ChangesetASCIIRegexes: []string{
Expand All @@ -414,7 +414,7 @@ func TestCLIRunWithCloudSyncDriftStatus(t *testing.T) {
Status: stack.Drifted,
Details: &cloud.DriftDetails{
Provisioner: "terraform",
ChangesetJSON: string(test.ReadFile(t, "_testdata/cloud-sync-drift-plan-file", "sanitized.plan.json")),
ChangesetJSON: loadJSONPlan(t, "_testdata/cloud-sync-drift-plan-file/sanitized.plan.json"),
},
},
ChangesetASCIIRegexes: []string{
Expand Down Expand Up @@ -570,10 +570,21 @@ func assertRunDrifts(t *testing.T, expectedDrifts expectedDriftStackPayloadReque
assert.NoError(t, json.Unmarshal([]byte(got.Details.ChangesetJSON), &gotPlan))
assert.NoError(t, json.Unmarshal([]byte(expected.Details.ChangesetJSON), &wantPlan))

if diff := cmp.Diff(gotPlan, wantPlan, cmpopts.IgnoreFields(tfjson.Plan{}, "Timestamp")); diff != "" {
if diff := cmp.Diff(gotPlan, wantPlan, cmpopts.IgnoreFields(tfjson.Plan{}, "Timestamp", "FormatVersion")); diff != "" {
t.Logf("want: %+v", expected.Details.ChangesetJSON)
t.Logf("got: %+v", got.Details.ChangesetJSON)
t.Fatal(diff)
}
}
}

func loadJSONPlan(t *testing.T, fname string) string {
fname = filepath.FromSlash(fname)
jsonBytes := test.ReadFile(t, filepath.Dir(fname), filepath.Base(fname))
var plan tfjson.Plan
assert.NoError(t, json.Unmarshal(jsonBytes, &plan))
plan.TerraformVersion = terraformVersion
jsonNewBytes, err := json.Marshal(&plan)
assert.NoError(t, err)
return string(jsonNewBytes)
}

0 comments on commit 7104be0

Please sign in to comment.