Skip to content

Commit

Permalink
remove individual config dirs
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kmoe committed Feb 10, 2021
1 parent 782c7c1 commit 961d313
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 46 deletions.
15 changes: 15 additions & 0 deletions internal/plugintest/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"io/ioutil"
"os"

"github.com/hashicorp/terraform-exec/tfexec"
)

const subprocessCurrentSigil = "4acd63807899403ca4859f5bb948d2c6"
Expand Down Expand Up @@ -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
Expand Down
68 changes: 22 additions & 46 deletions internal/plugintest/working_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
Expand All @@ -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
}

Expand All @@ -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...)
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 961d313

Please sign in to comment.