mirror of https://github.com/hashicorp/packer
Having only one test suite for the whole of Packer makes it harder to segregate between test types, and makes for a longer runtime as no tests run in parallel by default. This commit splits the packer_test suite into several components in order to make extension easier. First we have `lib`: this package embeds the core for running Packer test suites. This ships facilities to build your own test suite for Packer core, and exposes convenience methods and structures for building plugins, packer core, and use it to run a test suite in a temporary directory. Then we have two separate test suites: one for plugins, and one for core itself, the latter of which does not depend on plugins being compiled at all. This sets the stage for more specialised test suites in the future, each of which can run in parallel on different parts of the code.protobuf_testing
parent
a1caaad47d
commit
47a4ad201b
@ -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)
|
||||
defer cleanup()
|
||||
|
||||
ts := &PackerCoreTestSuite{
|
||||
baseSuite,
|
||||
}
|
||||
|
||||
suite.Run(t, ts)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package packer_test
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -0,0 +1,142 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type PackerTestSuite struct {
|
||||
suite.Suite
|
||||
// pluginsDirectory is the directory in which plugins are compiled.
|
||||
//
|
||||
// Those binaries are not necessarily meant to be used as-is, but
|
||||
// instead should be used for composing plugin installation directories.
|
||||
pluginsDirectory string
|
||||
// packerPath is the location in which the Packer executable is compiled
|
||||
//
|
||||
// Since we don't necessarily want to manually compile Packer beforehand,
|
||||
// we compile it on demand, and use this executable for the tests.
|
||||
packerPath string
|
||||
}
|
||||
|
||||
func (ts *PackerTestSuite) buildPluginVersion(waitgroup *sync.WaitGroup, versionString string, t *testing.T) {
|
||||
waitgroup.Add(1)
|
||||
go func() {
|
||||
defer waitgroup.Done()
|
||||
ts.BuildSimplePlugin(versionString, t)
|
||||
}()
|
||||
}
|
||||
|
||||
func (ts *PackerTestSuite) CompileTestPluginVersions(t *testing.T, versions ...string) {
|
||||
wg := &sync.WaitGroup{}
|
||||
|
||||
for _, ver := range versions {
|
||||
ts.buildPluginVersion(wg, ver, t)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// BuildSimplePlugin creates a plugin that essentially does nothing.
|
||||
//
|
||||
// The plugin's code is contained in a subdirectory of this, and lets us
|
||||
// change the attributes of the plugin binary itself, like the SDK version,
|
||||
// the plugin's version, etc.
|
||||
//
|
||||
// The plugin is functional, and can be used to run builds with.
|
||||
// There won't be anything substantial created though, its goal is only
|
||||
// to validate the core functionality of Packer.
|
||||
//
|
||||
// The path to the plugin is returned, it won't be removed automatically
|
||||
// though, deletion is the caller's responsibility.
|
||||
func (ts *PackerTestSuite) BuildSimplePlugin(versionString string, t *testing.T) string {
|
||||
// Only build plugin binary if not already done beforehand
|
||||
path, ok := LoadPluginVersion(versionString)
|
||||
if ok {
|
||||
return path
|
||||
}
|
||||
|
||||
v := version.Must(version.NewSemver(versionString))
|
||||
|
||||
t.Logf("Building plugin in version %v", v)
|
||||
|
||||
testDir, err := currentDir()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to compile plugin binary: %s", err)
|
||||
}
|
||||
|
||||
testerPluginDir := filepath.Join(testDir, "plugin_tester")
|
||||
outBin := filepath.Join(ts.pluginsDirectory, BinaryName(v))
|
||||
|
||||
compileCommand := exec.Command("go", "build", "-C", testerPluginDir, "-o", outBin, "-ldflags", LDFlags(v), ".")
|
||||
logs, err := compileCommand.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to compile plugin binary: %s\ncompiler logs: %s", err, logs)
|
||||
}
|
||||
|
||||
StorePluginVersion(v.String(), outBin)
|
||||
|
||||
return outBin
|
||||
}
|
||||
|
||||
// SkipNoAcc is a pre-condition that skips the test if the PACKER_ACC environment
|
||||
// variable is unset, or set to "0".
|
||||
//
|
||||
// This allows us to build tests with a potential for long runs (or errors like
|
||||
// rate-limiting), so we can still test them, but only in a longer timeouted
|
||||
// context.
|
||||
func (ts *PackerTestSuite) SkipNoAcc() {
|
||||
acc := os.Getenv("PACKER_ACC")
|
||||
if acc == "" || acc == "0" {
|
||||
ts.T().Logf("Skipping test as `PACKER_ACC` is unset.")
|
||||
ts.T().Skip()
|
||||
}
|
||||
}
|
||||
|
||||
func PackerCoreSuite(t *testing.T) (*PackerTestSuite, func()) {
|
||||
ts := &PackerTestSuite{}
|
||||
|
||||
tempDir, err := os.MkdirTemp("", "packer-core-acc-test-")
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to create temporary directory for compiled plugins: %s", err))
|
||||
}
|
||||
ts.pluginsDirectory = tempDir
|
||||
|
||||
defer func() {
|
||||
}()
|
||||
|
||||
packerPath := os.Getenv("PACKER_CUSTOM_PATH")
|
||||
if packerPath == "" {
|
||||
var err error
|
||||
t.Logf("Building test packer binary...")
|
||||
packerPath, err = BuildTestPacker(t)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to build Packer binary: %s", err)
|
||||
}
|
||||
}
|
||||
ts.packerPath = packerPath
|
||||
t.Logf("Done")
|
||||
|
||||
return ts, func() {
|
||||
err := os.RemoveAll(ts.pluginsDirectory)
|
||||
if err != nil {
|
||||
t.Logf("failed to cleanup directory %q: %s. This will need manual action", ts.pluginsDirectory, err)
|
||||
}
|
||||
|
||||
if os.Getenv("PACKER_CUSTOM_PATH") != "" {
|
||||
return
|
||||
}
|
||||
|
||||
err = os.Remove(ts.packerPath)
|
||||
if err != nil {
|
||||
t.Logf("failed to cleanup compiled packer binary %q: %s. This will need manual action", packerPath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package plugin_tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/packer_test/lib"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type PackerPluginTestSuite struct {
|
||||
*lib.PackerTestSuite
|
||||
}
|
||||
|
||||
func Test_PackerPluginSuite(t *testing.T) {
|
||||
baseSuite, cleanup := lib.PackerCoreSuite(t)
|
||||
defer cleanup()
|
||||
|
||||
ts := &PackerPluginTestSuite{
|
||||
baseSuite,
|
||||
}
|
||||
ts.PackerTestSuite.CompileTestPluginVersions(t,
|
||||
"1.0.0",
|
||||
"1.0.0",
|
||||
"1.0.0+metadata",
|
||||
"1.0.1-alpha1",
|
||||
"1.0.9",
|
||||
"1.0.10",
|
||||
"1.0.0-dev",
|
||||
"1.0.0-dev+metadata",
|
||||
"1.0.10+metadata",
|
||||
"1.0.1-dev",
|
||||
"2.0.0",
|
||||
)
|
||||
|
||||
suite.Run(t, ts)
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
package packer_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type PackerTestSuite struct {
|
||||
suite.Suite
|
||||
// pluginsDirectory is the directory in which plugins are compiled.
|
||||
//
|
||||
// Those binaries are not necessarily meant to be used as-is, but
|
||||
// instead should be used for composing plugin installation directories.
|
||||
pluginsDirectory string
|
||||
// packerPath is the location in which the Packer executable is compiled
|
||||
//
|
||||
// Since we don't necessarily want to manually compile Packer beforehand,
|
||||
// we compile it on demand, and use this executable for the tests.
|
||||
packerPath string
|
||||
}
|
||||
|
||||
func buildPluginVersion(waitgroup *sync.WaitGroup, versionString string, t *testing.T) {
|
||||
waitgroup.Add(1)
|
||||
go func() {
|
||||
defer waitgroup.Done()
|
||||
BuildSimplePlugin(versionString, t)
|
||||
}()
|
||||
}
|
||||
|
||||
func (ts *PackerTestSuite) buildPluginBinaries(t *testing.T) {
|
||||
wg := &sync.WaitGroup{}
|
||||
|
||||
buildPluginVersion(wg, "1.0.0", t)
|
||||
buildPluginVersion(wg, "1.0.0+metadata", t)
|
||||
buildPluginVersion(wg, "1.0.1-alpha1", t)
|
||||
buildPluginVersion(wg, "1.0.9", t)
|
||||
buildPluginVersion(wg, "1.0.10", t)
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// SkipNoAcc is a pre-condition that skips the test if the PACKER_ACC environment
|
||||
// variable is unset, or set to "0".
|
||||
//
|
||||
// This allows us to build tests with a potential for long runs (or errors like
|
||||
// rate-limiting), so we can still test them, but only in a longer timeouted
|
||||
// context.
|
||||
func (ts *PackerTestSuite) SkipNoAcc() {
|
||||
acc := os.Getenv("PACKER_ACC")
|
||||
if acc == "" || acc == "0" {
|
||||
ts.T().Logf("Skipping test as `PACKER_ACC` is unset.")
|
||||
ts.T().Skip()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PackerCoreSuite(t *testing.T) {
|
||||
ts := &PackerTestSuite{}
|
||||
|
||||
pluginsDirectory := PluginBinaryDir()
|
||||
defer func() {
|
||||
err := os.RemoveAll(pluginsDirectory)
|
||||
if err != nil {
|
||||
t.Logf("failed to cleanup directory %q: %s. This will need manual action", pluginsDirectory, err)
|
||||
}
|
||||
}()
|
||||
|
||||
ts.pluginsDirectory = pluginsDirectory
|
||||
ts.buildPluginBinaries(t)
|
||||
|
||||
packerPath := os.Getenv("PACKER_CUSTOM_PATH")
|
||||
if packerPath == "" {
|
||||
var err error
|
||||
t.Logf("Building test packer binary...")
|
||||
packerPath, err = BuildTestPacker(t)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to build Packer binary: %s", err)
|
||||
}
|
||||
}
|
||||
ts.packerPath = packerPath
|
||||
t.Logf("Done")
|
||||
|
||||
defer func() {
|
||||
if os.Getenv("PACKER_CUSTOM_PATH") != "" {
|
||||
return
|
||||
}
|
||||
|
||||
err := os.Remove(ts.packerPath)
|
||||
if err != nil {
|
||||
t.Logf("failed to cleanup compiled packer binary %q: %s. This will need manual action", packerPath, err)
|
||||
}
|
||||
}()
|
||||
|
||||
suite.Run(t, ts)
|
||||
}
|
||||
Loading…
Reference in new issue