Skip to content

Commit

Permalink
Adding functions for copying files and directories when EnvTfAccPersi…
Browse files Browse the repository at this point in the history
…stWorkingDir env var is set (#18)
  • Loading branch information
bendbennett committed Jan 17, 2023
1 parent 04e9a2c commit 47f2592
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 13 deletions.
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ require (
require (
github.com/agext/levenshtein v1.2.2 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
Expand Down
69 changes: 69 additions & 0 deletions helper/resource/copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package resource

import (
"io"
"os"
"path"
)

// CopyFile copies a single file from src to dest.
func CopyFile(src, dest string) error {
var srcFileInfo os.FileInfo

srcFile, err := os.Open(src)
if err != nil {
return err
}
defer srcFile.Close()

destFile, err := os.Create(dest)
if err != nil {
return err
}
defer destFile.Close()

if _, err = io.Copy(destFile, srcFile); err != nil {
return err
}

if srcFileInfo, err = os.Stat(src); err != nil {
return err
}

return os.Chmod(dest, srcFileInfo.Mode())
}

// CopyDir recursively copies directories and files
// from src to dest.
func CopyDir(src string, dest string) error {
srcInfo, err := os.Stat(src)
if err != nil {
return err
}

if err = os.MkdirAll(dest, srcInfo.Mode()); err != nil {
return err
}

dirEntries, err := os.ReadDir(src)
if err != nil {
return err
}

for _, dirEntry := range dirEntries {
srcFilepath := path.Join(src, dirEntry.Name())
destFilepath := path.Join(dest, dirEntry.Name())

if dirEntry.IsDir() {
if err = CopyDir(srcFilepath, destFilepath); err != nil {
return err
}
} else {
if err = CopyFile(srcFilepath, destFilepath); err != nil {
return err
}
}
}

return nil
}
110 changes: 110 additions & 0 deletions helper/resource/copy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package resource

import (
"os"
"path/filepath"
"testing"
)

func TestCopyFile(t *testing.T) {
srcDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatalf("cannot create src dir: %s", err)
}
defer os.RemoveAll(srcDir)

_, err = os.Create(filepath.Join(srcDir, "src.txt"))
if err != nil {
t.Fatalf("cannot create src file: %s", err)
}

destDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatalf("cannot create dest dir: %s", err)
}
defer os.RemoveAll(destDir)

err = CopyFile(filepath.Join(srcDir, "src.txt"), filepath.Join(destDir, "src.txt"))
if err != nil {
t.Fatalf("cannot copy src file: %s", err)
}

srcDirEntries, err := os.ReadDir(srcDir)
if err != nil {
t.Fatalf("cannot read src dir: %s", srcDir)
}

destDirEntries, err := os.ReadDir(srcDir)
if err != nil {
t.Fatalf("cannot read dest dir: %s", srcDir)
}

if !Equal(t, srcDirEntries, destDirEntries) {
t.Fatalf("dir entries differ: %v, %v", srcDirEntries, destDirEntries)
}
}

func TestCopyDir(t *testing.T) {
srcDir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatalf("cannot create src dir: %s", err)
}
defer os.RemoveAll(srcDir)

_, err = os.Create(filepath.Join(srcDir, "src.txt"))
if err != nil {
t.Fatalf("cannot create src file: %s", err)
}

err = CopyDir(srcDir, srcDir+"_1")
if err != nil {
t.Fatalf("cannot copy dir: %s", err)
}
defer os.RemoveAll(srcDir + "_1")

srcDirEntries, err := os.ReadDir(srcDir)
if err != nil {
t.Fatalf("cannot read src dir: %s", srcDir)
}

destDirEntries, err := os.ReadDir(srcDir)
if err != nil {
t.Fatalf("cannot read dest dir: %s", srcDir)
}

if !Equal(t, srcDirEntries, destDirEntries) {
t.Fatalf("dir entries differ: %v, %v", srcDirEntries, destDirEntries)
}
}

func Equal(t *testing.T, a, b []os.DirEntry) bool {
if len(a) != len(b) {
return false
}

for i, v := range a {
if v.Type() != b[i].Type() {
return false
}

if v.Name() != b[i].Name() {
return false
}

aInfo, err := v.Info()
if err != nil {
t.Fatalf("cannot get file info: %s", err)
}

bInfo, err := b[i].Info()
if err != nil {
t.Fatalf("cannot get file info: %s", err)
}

if aInfo.Mode() != bInfo.Mode() {
return false
}
}

return true
}
44 changes: 36 additions & 8 deletions helper/resource/testing_new.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import (
"fmt"
"os"
"reflect"
"strconv"
"strings"

"github.com/google/go-cmp/cmp"
tfjson "github.com/hashicorp/terraform-json"
"github.com/mitchellh/go-testing-interface"

"github.com/hashicorp/terraform-plugin-testing/terraform"

"github.com/hashicorp/terraform-plugin-testing/internal/logging"
"github.com/hashicorp/terraform-plugin-testing/internal/plugintest"
"github.com/hashicorp/terraform-plugin-testing/terraform"
)

func runPostTestDestroy(ctx context.Context, t testing.T, c TestCase, wd *plugintest.WorkingDir, providers *providerFactories, statePreDestroy *terraform.State) error {
Expand Down Expand Up @@ -85,11 +85,6 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest
}
}

if v := os.Getenv(plugintest.EnvTfAccPersistWorkingDir); v != "" {
t.Log(fmt.Sprintf("Working directory and files have been persisted in: %s", wd.GetHelper().WorkingDirectory()))
return
}

wd.Close()
}()

Expand Down Expand Up @@ -122,9 +117,14 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest
// use this to track last step successfully applied
// acts as default for import tests
var appliedCfg string
var stepNumber int

for stepIndex, step := range c.Steps {
stepNumber := stepIndex + 1 // 1-based indexing for humans
if stepNumber > 0 {
copyWorkingDir(ctx, t, stepNumber, wd)
}

stepNumber = stepIndex + 1 // 1-based indexing for humans
ctx = logging.TestStepNumberContext(ctx, stepNumber)

logging.HelperResourceDebug(ctx, "Starting TestStep")
Expand Down Expand Up @@ -331,6 +331,10 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest

t.Fatalf("Step %d/%d, unsupported test mode", stepNumber, len(c.Steps))
}

if stepNumber > 0 {
copyWorkingDir(ctx, t, stepNumber, wd)
}
}

func getState(ctx context.Context, t testing.T, wd *plugintest.WorkingDir) (*terraform.State, error) {
Expand Down Expand Up @@ -445,3 +449,27 @@ func testIDRefresh(ctx context.Context, t testing.T, c TestCase, wd *plugintest.

return nil
}

func copyWorkingDir(ctx context.Context, t testing.T, stepNumber int, wd *plugintest.WorkingDir) {
if v := os.Getenv(plugintest.EnvTfAccPersistWorkingDir); v != "" {
dest := wd.GetHelper().WorkingDirectory() + "_" + strconv.Itoa(stepNumber)

err := os.Setenv(plugintest.EnvTfAccPersistWorkingDirPath, wd.GetHelper().WorkingDirectory())
if err != nil {
t.Log(fmt.Sprintf("could not set %s env var: %s", plugintest.EnvTfAccPersistWorkingDirPath, err))
}

err = CopyDir(wd.GetHelper().WorkingDirectory(), dest)
if err != nil {
logging.HelperResourceError(ctx,
"Unexpected error copying working directory files",
map[string]interface{}{logging.KeyError: err},
)
t.Fatalf("TestStep %d/%d error copying working directory files: %s", stepNumber, err)
}

t.Log(fmt.Sprintf("Working directory and files have been copied to: %s", dest))

return
}
}
67 changes: 67 additions & 0 deletions helper/resource/teststep_providers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package resource
import (
"context"
"fmt"
"os"
"strconv"
"strings"
"testing"
"time"
Expand All @@ -16,6 +18,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/hashicorp/terraform-plugin-testing/internal/plugintest"
"github.com/hashicorp/terraform-plugin-testing/terraform"
)

Expand Down Expand Up @@ -1868,6 +1871,70 @@ func TestTest_TestStep_ProviderFactories_Refresh_Inline(t *testing.T) {
})
}

func TestTest_TestStep_ProviderFactories_CopyWorkingDir_EachTestStep(t *testing.T) {
t.Parallel()

err := os.Setenv(plugintest.EnvTfAccPersistWorkingDir, "1")
if err != nil {
t.Fatalf("cannot set %s env var: %s", plugintest.EnvTfAccPersistWorkingDir, err)
}

testSteps := []TestStep{
{
Config: `resource "random_password" "test" { }`,
},
{
Config: `resource "random_password" "test" { }`,
},
}

Test(t, TestCase{
ProviderFactories: map[string]func() (*schema.Provider, error){
"random": func() (*schema.Provider, error) { //nolint:unparam // required signature
return &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
"random_password": {
CreateContext: func(ctx context.Context, d *schema.ResourceData, i interface{}) diag.Diagnostics {
d.SetId("id")
return nil
},
DeleteContext: func(_ context.Context, _ *schema.ResourceData, _ interface{}) diag.Diagnostics {
return nil
},
ReadContext: func(_ context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics {
return nil
},
Schema: map[string]*schema.Schema{
"id": {
Computed: true,
Type: schema.TypeString,
},
},
},
},
}, nil
},
},
Steps: testSteps,
})

workingDirPath := os.Getenv(plugintest.EnvTfAccPersistWorkingDirPath)

for k := range testSteps {
dir := workingDirPath + "_" + strconv.Itoa(k+1)

_, err := os.ReadDir(dir)
if err != nil {
t.Fatalf("cannot read dir: %s", dir)
}
}

err = os.Unsetenv(plugintest.EnvTfAccPersistWorkingDir)
if err != nil {
t.Fatalf("cannot unset %s env var: %s", plugintest.EnvTfAccPersistWorkingDir, err)
}
}

func TestTest_TestStep_ProviderFactories_RefreshWithPlanModifier_Inline(t *testing.T) {
t.Parallel()

Expand Down
4 changes: 4 additions & 0 deletions internal/plugintest/environment_variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,8 @@ const (
// test. Can be set to any value to persist the working directory and
// its contents, however "1" is conventional.
EnvTfAccPersistWorkingDir = "TF_ACC_PERSIST_WORKING_DIR"

// EnvTfAccPersistWorkingDirPath environment variable is populated
// with the working directory path for the current test step.
EnvTfAccPersistWorkingDirPath = "TF_ACC_PERSIST_WORKING_DIR_PATH"
)
4 changes: 0 additions & 4 deletions internal/plugintest/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,6 @@ func (h *Helper) Close() error {
}
}

if v := os.Getenv(EnvTfAccPersistWorkingDir); v != "" {
return nil
}

return os.RemoveAll(h.baseDir)
}

Expand Down

0 comments on commit 47f2592

Please # to comment.