diff --git a/packer_test/gob_test/gob_pb_test.go b/packer_test/gob_test/gob_pb_test.go new file mode 100644 index 00000000000..3b86e4b5b88 --- /dev/null +++ b/packer_test/gob_test/gob_pb_test.go @@ -0,0 +1,181 @@ +package gob_test + +import ( + "github.com/hashicorp/packer/packer_test/lib" +) + +const pbPluginName = "github.com/hashicorp/pbtester" + +func CheckPBUsed(expect bool) lib.Checker { + const strToLookFor = "protobuf for communication with plugins" + + var opts []lib.GrepOpts + if !expect { + opts = append(opts, lib.GrepInvert) + } + + return lib.Grep(strToLookFor, opts...) +} + +// Two different plugins installed locally, one with gob, one with protobuf. +// Both should have different sources so Packer will discover and fallback to using only gob. +func (ts *PackerGobTestSuite) TestTwoPluginsDifferentPB() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+gob") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("plugins", "install", "--path", ts.BuildSimplePlugin("1.0.0+pb", ts.T()), pbPluginName). + Assert(lib.MustSucceed()) + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_both_plugins.pkr.hcl"). + Assert(CheckPBUsed(false)) + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_one_plugin.pkr.hcl"). + Assert(CheckPBUsed(false)) +} + +// Two plugins, both with protobuf supported +// Both installed plugins will support protobuf, so Packer will use Protobuf for all its communications. +func (ts *PackerGobTestSuite) TestTwoPluginsBothPB() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+pb") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("plugins", "install", "--path", ts.BuildSimplePlugin("1.0.0+pb", ts.T()), pbPluginName). + Assert(lib.MustSucceed()) + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_both_plugins.pkr.hcl"). + Assert(CheckPBUsed(true)) + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_one_plugin.pkr.hcl"). + Assert(CheckPBUsed(true)) +} + +// Two plugins, both with protobuf supported, force gob +// Both installed plugins support protobuf, but the environment variable PACKER_FORCE_GOB is +// set to 1 (or on), so Packer must use gob despite protobuf being supported all around. +func (ts *PackerGobTestSuite) TestTwoPluginsBothPBForceGob() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+pb") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("plugins", "install", "--path", ts.BuildSimplePlugin("1.0.0+pb", ts.T()), pbPluginName). + Assert(lib.MustSucceed()) + + ts.PackerCommand().UsePluginDir(pluginDir). + AddEnv("PACKER_FORCE_GOB", "1"). + SetArgs("build", "./templates/test_both_plugins.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(false)) + + ts.PackerCommand().UsePluginDir(pluginDir). + AddEnv("PACKER_FORCE_GOB", "1"). + SetArgs("build", "./templates/test_one_plugin.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(false)) +} + +// Two plugins installed, one with two versions: one version supporting pb, +// one older with gob only. The other with only protobuf. +// The template used pins the older version of the first plugin. +// In this case, gob should be the one used, as the selected version supports +// gob only, despite a newer version supporting protobuf, and the other plugin +// also being compatible. +func (ts *PackerGobTestSuite) TestTwoPluginsLatestPBOlderGob_OlderPinned() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+gob", "1.1.0+pb") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("plugins", "install", "--path", ts.BuildSimplePlugin("1.1.0+pb", ts.T()), pbPluginName). + Assert(lib.MustSucceed(), lib.MustSucceed()) + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_one_pinned_plugin.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(false)) +} + +// One plugin installed, one version supporting pb, one older with gob only +// The template used pins the older version. +// In this case, gob should be the one used, as the selected version supports +// gob only, despite a newer version supporting protobuf. +func (ts *PackerGobTestSuite) TestOnePluginLatestPBOlderGob_OlderPinned() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+gob", "1.1.0+pb") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_one_pinned_plugin.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(false)) +} + +// One plugin, with latest version supporting gob, but the older supporting protobuf +// In this case, Packer will default to using the latest version, and should +// default to using gob. +func (ts *PackerGobTestSuite) TestOnePluginWithLatestOnlyGob() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+pb", "1.1.0+gob") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_one_plugin.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(false)) +} + +// One plugin, gob only supported +// Packer will load the only plugin available there, and will use it, and use gob for comms +func (ts PackerGobTestSuite) TestOnePluginWithOnlyGob() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+gob") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_one_plugin.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(false)) +} + +// One plugin, protobuf supported +// Packer will load the only plugin available there, and use protobuf for comms +func (ts PackerGobTestSuite) TestOnePluginWithPB() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+pb") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/test_one_plugin.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(true)) +} + +// No plugin installed, only internal components +// In this test, Packer must use Protobuf for internal components as nothing installed will prevent it. +func (ts PackerGobTestSuite) TestInternalOnly() { + pluginDir, cleanup := ts.MakePluginDir() + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/internal_only.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(true)) +} + +// One plugin with gob only installed, use only internal components +// +// Packer in this case will fallback to Gob, even if the template uses internal +// components only, as this is determined at loading time. +func (ts PackerGobTestSuite) TestInternalOnlyWithGobPluginInstalled() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+gob") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/internal_only.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(false)) +} + +// One plugin with pb support installed, use only internal components +// +// Packer in this case will fallback to Gob, even if the template uses internal +// components only, as this is determined at loading time. +func (ts PackerGobTestSuite) TestInternalOnlyWithPBPluginInstalled() { + pluginDir, cleanup := ts.MakePluginDir("1.0.0+pb") + defer cleanup() + + ts.PackerCommand().UsePluginDir(pluginDir). + SetArgs("build", "./templates/internal_only.pkr.hcl"). + Assert(lib.MustSucceed(), CheckPBUsed(true)) +} diff --git a/packer_test/gob_test/suite_test.go b/packer_test/gob_test/suite_test.go new file mode 100644 index 00000000000..c7f64ab290a --- /dev/null +++ b/packer_test/gob_test/suite_test.go @@ -0,0 +1,34 @@ +package gob_test + +import ( + "testing" + + "github.com/hashicorp/packer/packer_test/lib" + "github.com/stretchr/testify/suite" +) + +type PackerGobTestSuite struct { + *lib.PackerTestSuite +} + +func Test_PackerPluginSuite(t *testing.T) { + baseSuite, cleanup := lib.PackerCoreSuite(t) + defer cleanup() + + ts := &PackerGobTestSuite{ + baseSuite, + } + + // Build two versions of each plugin, one with gob only, one with protobuf only + // + // We'll install them manually in tests, as they'll need to be installed as + // different plugin sources in order for discovery to trigger the + // gob-only/pb-supported behaviours we want to test. + ts.BuildSimplePlugin("1.1.0+pb", t, lib.UseDependency(lib.SDKModule, "grpc_base")) + ts.BuildSimplePlugin("1.0.0+pb", t, lib.UseDependency(lib.SDKModule, "grpc_base")) + + ts.BuildSimplePlugin("1.0.0+gob", t) + ts.BuildSimplePlugin("1.1.0+gob", t) + + suite.Run(t, ts) +} diff --git a/packer_test/gob_test/templates/internal_only.pkr.hcl b/packer_test/gob_test/templates/internal_only.pkr.hcl new file mode 100644 index 00000000000..e005230b49d --- /dev/null +++ b/packer_test/gob_test/templates/internal_only.pkr.hcl @@ -0,0 +1,7 @@ +source "null" "test" { + communicator = "none" +} + +build { + sources = ["null.test"] +} diff --git a/packer_test/gob_test/templates/test_both_plugins.pkr.hcl b/packer_test/gob_test/templates/test_both_plugins.pkr.hcl new file mode 100644 index 00000000000..36c148e4bf1 --- /dev/null +++ b/packer_test/gob_test/templates/test_both_plugins.pkr.hcl @@ -0,0 +1,22 @@ +packer { + required_plugins { + tester = { + source = "github.com/hashicorp/tester", + version = ">= 1.0.0" + } + pbtester = { + source = "github.com/hashicorp/pbtester", + version = ">= 1.0.0" + } + } +} + +source "tester-dynamic" "test" {} +source "pbtester-dynamic" "test" {} + +build { + sources = [ + "tester-dynamic.test", + "pbtester-dynamic.test" + ] +} diff --git a/packer_test/gob_test/templates/test_one_pinned_plugin.pkr.hcl b/packer_test/gob_test/templates/test_one_pinned_plugin.pkr.hcl new file mode 100644 index 00000000000..735c0947c2f --- /dev/null +++ b/packer_test/gob_test/templates/test_one_pinned_plugin.pkr.hcl @@ -0,0 +1,16 @@ +packer { + required_plugins { + tester = { + source = "github.com/hashicorp/tester", + version = "= 1.0.0" + } + } +} + +source "tester-dynamic" "test" {} + +build { + sources = [ + "tester-dynamic.test", + ] +} diff --git a/packer_test/gob_test/templates/test_one_plugin.pkr.hcl b/packer_test/gob_test/templates/test_one_plugin.pkr.hcl new file mode 100644 index 00000000000..1e063e27d34 --- /dev/null +++ b/packer_test/gob_test/templates/test_one_plugin.pkr.hcl @@ -0,0 +1,16 @@ +packer { + required_plugins { + tester = { + source = "github.com/hashicorp/tester", + version = ">= 1.0.0" + } + } +} + +source "tester-dynamic" "test" {} + +build { + sources = [ + "tester-dynamic.test", + ] +}