terraform-provider-gitea/vendor/github.com/hashicorp/terraform-plugin-sdk/v2/internal/plugintest/helper.go
dependabot[bot] 282cd097f9
Bump github.com/hashicorp/terraform-plugin-sdk/v2 from 2.20.0 to 2.24.1
Bumps [github.com/hashicorp/terraform-plugin-sdk/v2](https://github.com/hashicorp/terraform-plugin-sdk) from 2.20.0 to 2.24.1.
- [Release notes](https://github.com/hashicorp/terraform-plugin-sdk/releases)
- [Changelog](https://github.com/hashicorp/terraform-plugin-sdk/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/terraform-plugin-sdk/compare/v2.20.0...v2.24.1)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/terraform-plugin-sdk/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-24 18:04:13 +01:00

288 lines
9.1 KiB
Go

package plugintest
import (
"context"
"errors"
"fmt"
"os"
"strings"
"github.com/hashicorp/terraform-exec/tfexec"
"github.com/hashicorp/terraform-plugin-sdk/v2/internal/logging"
)
// AutoInitProviderHelper is the main entrypoint for testing provider plugins
// using this package. It is intended to be called during TestMain to prepare
// for provider testing.
//
// AutoInitProviderHelper will discover the location of a current Terraform CLI
// executable to test against, detect whether a prior version of the plugin is
// available for upgrade tests, and then will return an object containing the
// results of that initialization which can then be stored in a global variable
// for use in other tests.
func AutoInitProviderHelper(ctx context.Context, sourceDir string) *Helper {
helper, err := AutoInitHelper(ctx, sourceDir)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot run Terraform provider tests: %s\n", err)
os.Exit(1)
}
return helper
}
// Helper is intended as a per-package singleton created in TestMain which
// other tests in a package can use to create Terraform execution contexts
type Helper struct {
baseDir string
// sourceDir is the dir containing the provider source code, needed
// for tests that use fixture files.
sourceDir string
terraformExec string
// execTempDir is created during DiscoverConfig to store any downloaded
// binaries
execTempDir string
}
// AutoInitHelper uses the auto-discovery behavior of DiscoverConfig to prepare
// a configuration and then calls InitHelper with it. This is a convenient
// way to get the standard init behavior based on environment variables, and
// callers should use this unless they have an unusual requirement that calls
// for constructing a config in a different way.
func AutoInitHelper(ctx context.Context, sourceDir string) (*Helper, error) {
config, err := DiscoverConfig(ctx, sourceDir)
if err != nil {
return nil, err
}
return InitHelper(ctx, config)
}
// InitHelper prepares a testing helper with the given configuration.
//
// For most callers it is sufficient to call AutoInitHelper instead, which
// will construct a configuration automatically based on certain environment
// variables.
//
// If this function returns an error then it may have left some temporary files
// behind in the system's temporary directory. There is currently no way to
// automatically clean those up.
func InitHelper(ctx context.Context, config *Config) (*Helper, error) {
tempDir := os.Getenv(EnvTfAccTempDir)
baseDir, err := os.MkdirTemp(tempDir, "plugintest")
if err != nil {
return nil, fmt.Errorf("failed to create temporary directory for test helper: %s", err)
}
return &Helper{
baseDir: baseDir,
sourceDir: config.SourceDir,
terraformExec: config.TerraformExec,
execTempDir: config.execTempDir,
}, nil
}
// Close cleans up temporary files and directories created to support this
// helper, returning an error if any of the cleanup fails.
//
// Call this before returning from TestMain to minimize the amount of detritus
// left behind in the filesystem after the tests complete.
func (h *Helper) Close() error {
if h.execTempDir != "" {
err := os.RemoveAll(h.execTempDir)
if err != nil {
return err
}
}
return os.RemoveAll(h.baseDir)
}
// NewWorkingDir creates a new working directory for use in the implementation
// of a single test, returning a WorkingDir object representing that directory.
//
// If the working directory object is not itself closed by the time the test
// program exits, the Close method on the helper itself will attempt to
// delete it.
func (h *Helper) NewWorkingDir(ctx context.Context, t TestControl) (*WorkingDir, error) {
dir, err := os.MkdirTemp(h.baseDir, "work")
if err != nil {
return nil, err
}
ctx = logging.TestWorkingDirectoryContext(ctx, dir)
// symlink the provider source files into the config directory
// e.g. testdata
logging.HelperResourceTrace(ctx, "Symlinking source directories to work directory")
err = symlinkDirectoriesOnly(h.sourceDir, dir)
if err != nil {
return nil, err
}
tf, err := tfexec.NewTerraform(dir, h.terraformExec)
if err != nil {
return nil, fmt.Errorf("unable to create terraform-exec instance: %w", err)
}
err = tf.SetDisablePluginTLS(true)
if err != nil {
return nil, fmt.Errorf("unable to disable terraform-exec plugin TLS: %w", err)
}
err = tf.SetSkipProviderVerify(true) // Only required for Terraform CLI 0.12.x
var mismatch *tfexec.ErrVersionMismatch
if err != nil && !errors.As(err, &mismatch) {
return nil, fmt.Errorf("unable to disable terraform-exec provider verification: %w", err)
}
tfAccLog := os.Getenv(EnvTfAccLog)
tfAccLogPath := os.Getenv(EnvTfAccLogPath)
tfLogCore := os.Getenv(EnvTfLogCore)
tfLogPathMask := os.Getenv(EnvTfLogPathMask)
tfLogProvider := os.Getenv(EnvTfLogProvider)
if tfAccLog != "" && tfLogCore != "" {
err = fmt.Errorf(
"Invalid environment variable configuration. Cannot set both TF_ACC_LOG and TF_LOG_CORE. " +
"Use TF_LOG_CORE and TF_LOG_PROVIDER to separately control the Terraform CLI logging subsystems. " +
"To control the Go standard library log package for the provider under test, use TF_LOG.",
)
logging.HelperResourceError(ctx, err.Error())
return nil, err
}
if tfAccLog != "" {
logging.HelperResourceTrace(
ctx,
fmt.Sprintf("Setting terraform-exec log level via %s environment variable, if Terraform CLI is version 0.15 or later", EnvTfAccLog),
map[string]interface{}{logging.KeyTestTerraformLogLevel: tfAccLog},
)
err := tf.SetLog(tfAccLog)
if err != nil {
if !errors.As(err, new(*tfexec.ErrVersionMismatch)) {
logging.HelperResourceError(
ctx,
"Unable to set terraform-exec log level",
map[string]interface{}{logging.KeyError: err.Error()},
)
return nil, fmt.Errorf("unable to set terraform-exec log level (%s): %w", tfAccLog, err)
}
logging.HelperResourceWarn(
ctx,
fmt.Sprintf("Unable to set terraform-exec log level via %s environment variable, as Terraform CLI is version 0.14 or earlier. It will default to TRACE.", EnvTfAccLog),
map[string]interface{}{logging.KeyTestTerraformLogLevel: "TRACE"},
)
}
}
if tfLogCore != "" {
logging.HelperResourceTrace(
ctx,
fmt.Sprintf("Setting terraform-exec core log level via %s environment variable, if Terraform CLI is version 0.15 or later", EnvTfLogCore),
map[string]interface{}{
logging.KeyTestTerraformLogCoreLevel: tfLogCore,
},
)
err := tf.SetLogCore(tfLogCore)
if err != nil {
logging.HelperResourceError(
ctx,
"Unable to set terraform-exec core log level",
map[string]interface{}{logging.KeyError: err.Error()},
)
return nil, fmt.Errorf("unable to set terraform-exec core log level (%s): %w", tfLogCore, err)
}
}
if tfLogProvider != "" {
logging.HelperResourceTrace(
ctx,
fmt.Sprintf("Setting terraform-exec provider log level via %s environment variable, if Terraform CLI is version 0.15 or later", EnvTfLogProvider),
map[string]interface{}{
logging.KeyTestTerraformLogCoreLevel: tfLogProvider,
},
)
err := tf.SetLogProvider(tfLogProvider)
if err != nil {
logging.HelperResourceError(
ctx,
"Unable to set terraform-exec provider log level",
map[string]interface{}{logging.KeyError: err.Error()},
)
return nil, fmt.Errorf("unable to set terraform-exec provider log level (%s): %w", tfLogProvider, err)
}
}
var logPath, logPathEnvVar string
if tfAccLogPath != "" {
logPath = tfAccLogPath
logPathEnvVar = EnvTfAccLogPath
}
// Similar to helper/logging.LogOutput() and
// terraform-plugin-log/tfsdklog.RegisterTestSink(), the TF_LOG_PATH_MASK
// environment variable should take precedence over TF_ACC_LOG_PATH.
if tfLogPathMask != "" {
// Escape special characters which may appear if we have subtests
testName := strings.Replace(t.Name(), "/", "__", -1)
logPath = fmt.Sprintf(tfLogPathMask, testName)
logPathEnvVar = EnvTfLogPathMask
}
if logPath != "" {
logging.HelperResourceTrace(
ctx,
fmt.Sprintf("Setting terraform-exec log path via %s environment variable", logPathEnvVar),
map[string]interface{}{logging.KeyTestTerraformLogPath: logPath},
)
if err := tf.SetLogPath(logPath); err != nil {
return nil, fmt.Errorf("unable to set terraform-exec log path (%s): %w", logPath, err)
}
}
return &WorkingDir{
h: h,
tf: tf,
baseDir: dir,
terraformExec: h.terraformExec,
}, nil
}
// RequireNewWorkingDir is a variant of NewWorkingDir that takes a TestControl
// object and will immediately fail the running test if the creation of the
// working directory fails.
func (h *Helper) RequireNewWorkingDir(ctx context.Context, t TestControl) *WorkingDir {
t.Helper()
wd, err := h.NewWorkingDir(ctx, t)
if err != nil {
t := testingT{t}
t.Fatalf("failed to create new working directory: %s", err)
return nil
}
return wd
}
// WorkingDirectory returns the working directory being used when running tests.
func (h *Helper) WorkingDirectory() string {
return h.baseDir
}
// TerraformExecPath returns the location of the Terraform CLI executable that
// should be used when running tests.
func (h *Helper) TerraformExecPath() string {
return h.terraformExec
}