-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
packer_test: make packer test suite modular #13041
Changes from all commits
23beb0f
759f389
6507866
3afc5d3
47ea17b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,12 @@ | ||
package packer_test | ||
package core_test | ||
|
||
import "fmt" | ||
import ( | ||
"fmt" | ||
|
||
func (ts *PackerTestSuite) TestEvalLocalsOrder() { | ||
"github.com/hashicorp/packer/packer_test/lib" | ||
) | ||
|
||
func (ts *PackerCoreTestSuite) TestEvalLocalsOrder() { | ||
ts.SkipNoAcc() | ||
|
||
pluginDir, cleanup := ts.MakePluginDir() | ||
|
@@ -12,20 +16,21 @@ func (ts *PackerTestSuite) TestEvalLocalsOrder() { | |
Runs(10). | ||
Stdin("local.test_local\n"). | ||
SetArgs("console", "./templates/locals_no_order.pkr.hcl"). | ||
Assert(MustSucceed(), Grep("\\[\\]", grepStdout, grepInvert)) | ||
Assert(lib.MustSucceed(), | ||
lib.Grep("\\[\\]", lib.GrepStdout, lib.GrepInvert)) | ||
} | ||
|
||
func (ts *PackerTestSuite) TestLocalDuplicates() { | ||
func (ts *PackerCoreTestSuite) TestLocalDuplicates() { | ||
pluginDir, cleanup := ts.MakePluginDir() | ||
defer cleanup() | ||
|
||
for _, cmd := range []string{"console", "validate", "build"} { | ||
ts.Run(fmt.Sprintf("duplicate local detection with %s command - expect error", cmd), func() { | ||
ts.PackerCommand().UsePluginDir(pluginDir). | ||
SetArgs(cmd, "./templates/locals_duplicate.pkr.hcl"). | ||
Assert(MustFail(), | ||
Grep("Duplicate local definition"), | ||
Grep("Local variable \"test\" is defined twice")) | ||
Assert(lib.MustFail(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My first question here is what is lib? Why not just What do you think if we renamed Assert to RunAndAssert(
MustFail(),
Grep("Duplicate local definition"),
Grep("Local variable \"test\" is defined twice")) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can name them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As for renaming |
||
lib.Grep("Duplicate local definition"), | ||
lib.Grep("Local variable \"test\" is defined twice")) | ||
}) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package core_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/packer/packer_test/lib" | ||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
type PackerCoreTestSuite struct { | ||
*lib.PackerTestSuite | ||
} | ||
|
||
func Test_PackerPluginSuite(t *testing.T) { | ||
baseSuite, cleanup := lib.PackerCoreSuite(t) | ||
Comment on lines
+10
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand the need for PackerCoreTestSuite over lib.PackerTestSuite and how they relate or differ from lib.PackerCoreSuite(). Is this level of abstraction offering a benefit that may not be immediately noticeable? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So the difference between the two is mostly that the tests run are not the same, being two separate packages/instances of TestSuite means that both can run in parallel. They also may not have the same needs for plugins for example, so one will have to compile a bunch of plugins, and others don't. |
||
defer cleanup() | ||
|
||
ts := &PackerCoreTestSuite{ | ||
baseSuite, | ||
} | ||
|
||
suite.Run(t, ts) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package packer_test | ||
package lib | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have to dive into these changes further. But I hesitate to treat this as a separate package. I changed the name to packer_test, as that is the Go idiom for denoting that this is a test package, which does not have direct access to anything in the Previously, the go files ended with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would think the code will not be part of the final binary still, as it's not transitively imported from |
||
|
||
import ( | ||
"fmt" | ||
|
@@ -19,7 +19,7 @@ func BuildTestPacker(t *testing.T) (string, error) { | |
return "", fmt.Errorf("failed to compile packer binary: %s", err) | ||
} | ||
|
||
packerCoreDir := filepath.Dir(testDir) | ||
packerCoreDir := filepath.Dir(filepath.Dir(testDir)) | ||
|
||
outBin := filepath.Join(os.TempDir(), fmt.Sprintf("packer_core-%d", rand.Int())) | ||
if runtime.GOOS == "windows" { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package packer_test | ||
package lib | ||
|
||
import ( | ||
"fmt" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package lib | ||
|
||
import ( | ||
"crypto/sha256" | ||
"fmt" | ||
"io" | ||
"os" | ||
"path/filepath" | ||
"runtime" | ||
"testing" | ||
) | ||
|
||
// CopyFile essentially replicates the `cp` command, for a file only. | ||
// | ||
// # Permissions are copied over from the source to destination | ||
// | ||
// The function detects if destination is a directory or a file (existent or not). | ||
// | ||
// If this is the former, we append the source file's basename to the | ||
// directory and create the file from that inferred path. | ||
func CopyFile(t *testing.T, dest, src string) { | ||
st, err := os.Stat(src) | ||
if err != nil { | ||
t.Fatalf("failed to stat origin file %q: %s", src, err) | ||
} | ||
|
||
// If the stat call fails, we assume dest is the destination file. | ||
dstStat, err := os.Stat(dest) | ||
if err == nil && dstStat.IsDir() { | ||
dest = filepath.Join(dest, filepath.Base(src)) | ||
} | ||
|
||
destFD, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, st.Mode().Perm()) | ||
if err != nil { | ||
t.Fatalf("failed to create cp destination file %q: %s", dest, err) | ||
} | ||
defer destFD.Close() | ||
|
||
srcFD, err := os.Open(src) | ||
if err != nil { | ||
t.Fatalf("failed to open source file to copy: %s", err) | ||
} | ||
defer srcFD.Close() | ||
|
||
_, err = io.Copy(destFD, srcFD) | ||
if err != nil { | ||
t.Fatalf("failed to copy from %q -> %q: %s", src, dest, err) | ||
} | ||
} | ||
|
||
// WriteFile writes `content` to a file `dest` | ||
// | ||
// The default permissions of that file is 0644 | ||
func WriteFile(t *testing.T, dest string, content string) { | ||
outFile, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) | ||
if err != nil { | ||
t.Fatalf("failed to open/create %q: %s", dest, err) | ||
} | ||
defer outFile.Close() | ||
|
||
_, err = fmt.Fprintf(outFile, content) | ||
if err != nil { | ||
t.Fatalf("failed to write to file %q: %s", dest, err) | ||
} | ||
} | ||
|
||
// TempWorkdir creates a working directory for a Packer test with the list of files | ||
// given as input. | ||
// | ||
// The files should either have a path relative to the test that invokes it, or should | ||
// be absolute. | ||
// Each file will be copied to the root of the workdir being created. | ||
// | ||
// If any file cannot be found, this function will fail | ||
func TempWorkdir(t *testing.T, files ...string) (string, func()) { | ||
var err error | ||
tempDir, err := os.MkdirTemp("", "packer-test-workdir-") | ||
if err != nil { | ||
t.Fatalf("failed to create temporary working directory: %s", err) | ||
} | ||
|
||
defer func() { | ||
if err != nil { | ||
os.RemoveAll(tempDir) | ||
t.Errorf("failed to create temporary workdir: %s", err) | ||
} | ||
}() | ||
|
||
for _, file := range files { | ||
CopyFile(t, tempDir, file) | ||
} | ||
|
||
return tempDir, func() { | ||
err := os.RemoveAll(tempDir) | ||
if err != nil { | ||
t.Logf("failed to remove temporary workdir %q: %s. This will need manual action.", tempDir, err) | ||
} | ||
} | ||
} | ||
|
||
// SHA256Sum computes the SHA256 digest for an input file | ||
// | ||
// The digest is returned as a hexstring | ||
func SHA256Sum(t *testing.T, file string) string { | ||
fl, err := os.ReadFile(file) | ||
if err != nil { | ||
t.Fatalf("failed to compute sha256sum for %q: %s", file, err) | ||
} | ||
sha := sha256.New() | ||
sha.Write(fl) | ||
return fmt.Sprintf("%x", sha.Sum([]byte{})) | ||
} | ||
|
||
// currentDir returns the directory in which the current file is located. | ||
// | ||
// Since we're in tests it's reliable as they're supposed to run on the same | ||
// machine the binary's compiled from, but goes to say it's not meant for use | ||
// in distributed binaries. | ||
func currentDir() (string, error) { | ||
// pc uintptr, file string, line int, ok bool | ||
_, testDir, _, ok := runtime.Caller(0) | ||
if !ok { | ||
return "", fmt.Errorf("couldn't get the location of the test suite file") | ||
} | ||
|
||
return filepath.Dir(testDir), nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why core_test? What information does it provide that packer_test may not?