terraform-module-test-helper/e2etest.go

146 строки
4.3 KiB
Go
Исходник Обычный вид История

package terraform_module_test_helper
import (
"fmt"
"io"
2023-03-14 10:55:08 +03:00
"os"
"path/filepath"
"testing"
"time"
"github.com/gruntwork-io/terratest/modules/files"
"github.com/gruntwork-io/terratest/modules/logger"
"github.com/gruntwork-io/terratest/modules/terraform"
test_structure "github.com/gruntwork-io/terratest/modules/test-structure"
2023-02-21 08:54:55 +03:00
terratest "github.com/gruntwork-io/terratest/modules/testing"
"github.com/stretchr/testify/require"
)
type TestOptions struct {
TerraformOptions terraform.Options
Assertion func(*testing.T, TerraformOutput)
SkipIdempotentCheck bool
}
var copyLock = &KeyedMutex{}
type TerraformOutput = map[string]interface{}
type testExecutor interface {
TearDown(t *testing.T, rootDir string, modulePath string)
Logger() logger.TestLogger
}
var _ testExecutor = e2eTestExecutor{}
type e2eTestExecutor struct{}
func (e2eTestExecutor) TearDown(t *testing.T, rootDir string, modulePath string) {
s := SuccessTestVersionSnapshot(rootDir, modulePath)
if t.Failed() {
s = FailedTestVersionSnapshot(rootDir, modulePath, "")
}
require.NoError(t, s.Save(t))
}
func (e2eTestExecutor) Logger() logger.TestLogger {
l := NewMemoryLogger()
return l
}
func RunE2ETest(t *testing.T, moduleRootPath, exampleRelativePath string, option terraform.Options, assertion func(*testing.T, TerraformOutput)) {
initAndApplyAndIdempotentTest(t, moduleRootPath, exampleRelativePath, option, assertion, true, e2eTestExecutor{})
}
func RunE2ETestWithOption(t *testing.T, moduleRootPath, exampleRelativePath string, testOption TestOptions) {
initAndApplyAndIdempotentTest(t,
moduleRootPath,
exampleRelativePath,
testOption.TerraformOptions,
testOption.Assertion,
testOption.SkipIdempotentCheck,
e2eTestExecutor{})
}
func initAndApplyAndIdempotentTest(t *testing.T, moduleRootPath string, exampleRelativePath string, option terraform.Options, assertion func(*testing.T, TerraformOutput), skipCheckIdempotent bool, executor testExecutor) {
2023-03-08 04:41:23 +03:00
tryParallel(t)
defer executor.TearDown(t, moduleRootPath, exampleRelativePath)
testDir := filepath.Join(moduleRootPath, exampleRelativePath)
logger.Log(t, fmt.Sprintf("===> Starting test for %s, since we're running tests in parallel, the test log will be buffered and output to stdout after the test was finished.", testDir))
tmpDir := copyTerraformFolderToTemp(t, moduleRootPath, exampleRelativePath)
2023-03-14 10:55:08 +03:00
defer func() {
_ = os.RemoveAll(filepath.Clean(tmpDir))
2023-03-14 10:55:08 +03:00
}()
option.TerraformDir = tmpDir
l := executor.Logger()
c, ok := l.(io.Closer)
if ok {
defer func() {
_ = c.Close()
}()
}
option.Logger = logger.New(l)
option = setupRetryLogic(option)
defer destroy(t, option)
initAndApply(t, &option)
var err error
if !skipCheckIdempotent {
err = initAndPlanAndIdempotentAtEasyMode(t, option)
}
if err != nil {
2022-09-06 08:44:32 +03:00
t.Fatalf(err.Error())
}
if assertion != nil {
2022-09-06 08:44:32 +03:00
assertion(t, terraform.OutputAll(t, removeLogger(option)))
}
}
2022-07-06 09:16:29 +03:00
func copyTerraformFolderToTemp(t *testing.T, moduleRootPath string, exampleRelativePath string) string {
unlock := copyLock.Lock(exampleRelativePath)
defer unlock()
tmpDir := test_structure.CopyTerraformFolderToTemp(t, moduleRootPath, exampleRelativePath)
return tmpDir
}
func initAndApply(t terratest.TestingT, options *terraform.Options) string {
2023-02-02 08:45:09 +03:00
tfInit(t, options)
2023-02-02 09:29:01 +03:00
return terraform.Apply(t, options)
2023-02-02 08:45:09 +03:00
}
func tfInit(t terratest.TestingT, options *terraform.Options) {
terraform.Init(t, options)
}
func destroy(t *testing.T, option terraform.Options) {
path := option.TerraformDir
if !files.IsExistingDir(path) || !files.FileExists(filepath.Join(path, "terraform.tfstate")) {
return
}
option.MaxRetries = 5
option.TimeBetweenRetries = time.Minute
option.RetryableTerraformErrors = map[string]string{
".*": "Retry destroy on any error",
}
_, err := terraform.RunTerraformCommandE(t, &option, terraform.FormatArgs(&option, "destroy", "-auto-approve", "-input=false", "-refresh=false")...)
if err != nil {
_, err = terraform.DestroyE(t, &option)
}
2022-12-30 09:13:30 +03:00
require.NoError(t, err)
}
2022-09-06 08:44:32 +03:00
func removeLogger(option terraform.Options) *terraform.Options {
// default logger might leak sensitive data
option.Logger = logger.Discard
return &option
}
2022-07-06 09:16:29 +03:00
func retryableOptions(t *testing.T, options terraform.Options) terraform.Options {
result := terraform.WithDefaultRetryableErrors(t, &options)
2023-01-13 14:30:20 +03:00
result.RetryableTerraformErrors[".*Please try again.*"] = "Service side suggest retry."
2022-07-06 09:16:29 +03:00
return *result
}