From 961d313119a6629a6780633dfbf96632587e9e00 Mon Sep 17 00:00:00 2001 From: Katy Moe Date: Tue, 9 Feb 2021 15:28:34 +0000 Subject: [PATCH] remove individual config dirs The test framework no longer creates a wd.configDir whenever new test config is set. This change simplifies the test directory structure and allows state to persist from one test step to the next, a fundamental assumption of the test framework. --- internal/plugintest/helper.go | 15 +++++++ internal/plugintest/working_dir.go | 68 ++++++++++-------------------- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/internal/plugintest/helper.go b/internal/plugintest/helper.go index 45a4efc4f67..4b130b499dd 100644 --- a/internal/plugintest/helper.go +++ b/internal/plugintest/helper.go @@ -4,6 +4,8 @@ import ( "fmt" "io/ioutil" "os" + + "github.com/hashicorp/terraform-exec/tfexec" ) const subprocessCurrentSigil = "4acd63807899403ca4859f5bb948d2c6" @@ -107,8 +109,21 @@ func (h *Helper) NewWorkingDir() (*WorkingDir, error) { return nil, err } + // symlink the provider source files into the config directory + // e.g. testdata + err = symlinkDirectoriesOnly(h.sourceDir, dir) + if err != nil { + return nil, err + } + + tf, err := tfexec.NewTerraform(dir, h.terraformExec) + if err != nil { + return nil, err + } + return &WorkingDir{ h: h, + tf: tf, baseDir: dir, terraformExec: h.terraformExec, }, nil diff --git a/internal/plugintest/working_dir.go b/internal/plugintest/working_dir.go index 06ea6a5ee43..1faeb5c7a71 100644 --- a/internal/plugintest/working_dir.go +++ b/internal/plugintest/working_dir.go @@ -13,6 +13,11 @@ import ( tfjson "github.com/hashicorp/terraform-json" ) +const ( + ConfigFileName = "terraform_plugin_test.tf" + PlanFileName = "tfplan" +) + // WorkingDir represents a distinct working directory that can be used for // running tests. Each test should construct its own WorkingDir by calling // NewWorkingDir or RequireNewWorkingDir on its package's singleton @@ -26,9 +31,6 @@ type WorkingDir struct { // baseArgs is arguments that should be appended to all commands baseArgs []string - // configDir contains the singular config file generated for each test - configDir string - // tf is the instance of tfexec.Terraform used for running Terraform commands tf *tfexec.Terraform @@ -75,62 +77,32 @@ func (wd *WorkingDir) GetHelper() *Helper { return wd.h } -func (wd *WorkingDir) relativeConfigDir() (string, error) { - relPath, err := filepath.Rel(wd.baseDir, wd.configDir) - if err != nil { - return "", fmt.Errorf("Error determining relative path of configuration directory: %w", err) - } - return relPath, nil -} - // SetConfig sets a new configuration for the working directory. // // This must be called at least once before any call to Init, Plan, Apply, or // Destroy to establish the configuration. Any previously-set configuration is // discarded and any saved plan is cleared. func (wd *WorkingDir) SetConfig(cfg string) error { - // Each call to SetConfig creates a new directory under our baseDir. - // We create them within so that our final cleanup step will delete them - // automatically without any additional tracking. - configDir, err := ioutil.TempDir(wd.baseDir, "config") - if err != nil { - return err - } - configFilename := filepath.Join(configDir, "terraform_plugin_test.tf") - err = ioutil.WriteFile(configFilename, []byte(cfg), 0700) - if err != nil { - return err - } - - // symlink the provider source files into the config directory - // e.g. testdata - err = symlinkDirectoriesOnly(wd.h.sourceDir, configDir) - if err != nil { - return err - } - - tf, err := tfexec.NewTerraform(configDir, wd.terraformExec) + configFilename := filepath.Join(wd.baseDir, ConfigFileName) + err := ioutil.WriteFile(configFilename, []byte(cfg), 0700) if err != nil { return err } var mismatch *tfexec.ErrVersionMismatch - err = tf.SetDisablePluginTLS(true) + err = wd.tf.SetDisablePluginTLS(true) if err != nil && !errors.As(err, &mismatch) { return err } - err = tf.SetSkipProviderVerify(true) + err = wd.tf.SetSkipProviderVerify(true) if err != nil && !errors.As(err, &mismatch) { return err } if p := os.Getenv("TF_ACC_LOG_PATH"); p != "" { - tf.SetLogPath(p) + wd.tf.SetLogPath(p) } - wd.configDir = configDir - wd.tf = tf - // Changing configuration invalidates any saved plan. err = wd.ClearPlan() if err != nil { @@ -144,7 +116,7 @@ func (wd *WorkingDir) SetConfig(cfg string) error { // Any remote objects tracked by the state are not destroyed first, so this // will leave them dangling in the remote system. func (wd *WorkingDir) ClearState() error { - err := os.Remove(filepath.Join(wd.configDir, "terraform.tfstate")) + err := os.Remove(filepath.Join(wd.baseDir, "terraform.tfstate")) if os.IsNotExist(err) { return nil } @@ -163,28 +135,32 @@ func (wd *WorkingDir) ClearPlan() error { // Init runs "terraform init" for the given working directory, forcing Terraform // to use the current version of the plugin under test. func (wd *WorkingDir) Init() error { - if wd.configDir == "" { + if _, err := os.Stat(wd.configFilename()); err != nil { return fmt.Errorf("must call SetConfig before Init") } return wd.tf.Init(context.Background(), tfexec.Reattach(wd.reattachInfo)) } +func (wd *WorkingDir) configFilename() string { + return filepath.Join(wd.baseDir, ConfigFileName) +} + func (wd *WorkingDir) planFilename() string { - return filepath.Join(wd.configDir, "tfplan") + return filepath.Join(wd.baseDir, PlanFileName) } // CreatePlan runs "terraform plan" to create a saved plan file, which if successful // will then be used for the next call to Apply. func (wd *WorkingDir) CreatePlan() error { - _, err := wd.tf.Plan(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false), tfexec.Out("tfplan")) + _, err := wd.tf.Plan(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false), tfexec.Out(PlanFileName)) return err } // CreateDestroyPlan runs "terraform plan -destroy" to create a saved plan // file, which if successful will then be used for the next call to Apply. func (wd *WorkingDir) CreateDestroyPlan() error { - _, err := wd.tf.Plan(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false), tfexec.Out("tfplan"), tfexec.Destroy(true)) + _, err := wd.tf.Plan(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false), tfexec.Out(PlanFileName), tfexec.Destroy(true)) return err } @@ -195,7 +171,7 @@ func (wd *WorkingDir) CreateDestroyPlan() error { func (wd *WorkingDir) Apply() error { args := []tfexec.ApplyOption{tfexec.Reattach(wd.reattachInfo), tfexec.Refresh(false)} if wd.HasSavedPlan() { - args = append(args, tfexec.DirOrPlan("tfplan")) + args = append(args, tfexec.DirOrPlan(PlanFileName)) } return wd.tf.Apply(context.Background(), args...) @@ -260,12 +236,12 @@ func (wd *WorkingDir) State() (*tfjson.State, error) { // Import runs terraform import func (wd *WorkingDir) Import(resource, id string) error { - return wd.tf.Import(context.Background(), resource, id, tfexec.Config(wd.configDir), tfexec.Reattach(wd.reattachInfo)) + return wd.tf.Import(context.Background(), resource, id, tfexec.Config(wd.baseDir), tfexec.Reattach(wd.reattachInfo)) } // Refresh runs terraform refresh func (wd *WorkingDir) Refresh() error { - return wd.tf.Refresh(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.State(filepath.Join(wd.configDir, "terraform.tfstate"))) + return wd.tf.Refresh(context.Background(), tfexec.Reattach(wd.reattachInfo), tfexec.State(filepath.Join(wd.baseDir, "terraform.tfstate"))) } // Schemas returns an object describing the provider schemas.