//go:build !race // This test is excluded from the race detector because the underlying // hc-install library makes massive allocations and can take 1-2 minutes // to complete. package terraform_test import ( "context" "os" "sync" "testing" "time" "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/coder/coder/v2/provisioner/terraform" "github.com/coder/coder/v2/testutil" ) func TestInstall(t *testing.T) { t.Parallel() if testing.Short() { t.SkipNow() } ctx := context.Background() dir := t.TempDir() log := testutil.Logger(t) // Install spins off 8 installs with Version and waits for them all // to complete. The locking mechanism within Install should // prevent multiple binaries from being installed, so the function // should perform like a single install. install := func(version *version.Version) string { var wg sync.WaitGroup paths := make(chan string, 8) for i := 0; i < 8; i++ { wg.Add(1) go func() { defer wg.Done() p, err := terraform.Install(ctx, log, false, dir, version) assert.NoError(t, err) paths <- p }() } go func() { wg.Wait() close(paths) }() var firstPath string for p := range paths { if firstPath == "" { firstPath = p } else { require.Equal(t, firstPath, p, "installs returned different paths") } } return firstPath } version1 := terraform.TerraformVersion binPath := install(version1) checkBinModTime := func() time.Time { binInfo, err := os.Stat(binPath) require.NoError(t, err) require.Greater(t, binInfo.Size(), int64(0)) return binInfo.ModTime() } modTime1 := checkBinModTime() // Since we're using the same version the install should be idempotent. install(terraform.TerraformVersion) modTime2 := checkBinModTime() require.Equal(t, modTime1, modTime2) // Ensure a new install happens when version changes version2 := version.Must(version.NewVersion("1.2.0")) // Sanity-check require.NotEqual(t, version2.String(), version1.String()) install(version2) modTime3 := checkBinModTime() require.Greater(t, modTime3, modTime2) }