From cb1a4af5dddede72376ab75fac0a769206292f30 Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Fri, 28 Mar 2025 10:25:13 -0400 Subject: [PATCH 1/3] packer_test: fix crash detection checker When running a black-box Packer test, crashes were to be detected automatically so that tests that crash are always reported as a failure. However, the match for detecting that Packer crashed was incorrectly formed, so those weren't detected. --- packer_test/common/check/gadgets.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packer_test/common/check/gadgets.go b/packer_test/common/check/gadgets.go index 9eecc57cf..14761d98c 100644 --- a/packer_test/common/check/gadgets.go +++ b/packer_test/common/check/gadgets.go @@ -198,7 +198,7 @@ func (d dump) Check(stdout, stderr string, err error) error { type PanicCheck struct{} func (_ PanicCheck) Check(stdout, stderr string, _ error) error { - if strings.Contains(stdout, "= PACKER CRASH =") || strings.Contains(stderr, "= PACKER CRASH =") { + if strings.Contains(stdout, "! PACKER CRASH !") || strings.Contains(stderr, "! PACKER CRASH !") { return fmt.Errorf("packer has crashed: this is never normal and should be investigated") } return nil From 3289540c902148a9f285aa182bfff92a990184dc Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Fri, 28 Mar 2025 10:26:50 -0400 Subject: [PATCH 2/3] packer_test: add `Dump' function to packerCommand Previous versions of the packerCommand implementation for wrapping a freshly compiled Packer binary to run tests with were a bit opaque, and printing out the logs from a run was defined in `Assert` as a plain checker, using a bit of a clumsy call that repeats already known information like `testing.T`. This commit changes the implementation so that `Dump` becomes a function call akin to the others, which doesn't need any parameter, instead it leverages what if already kept within the packerCommand structure. --- packer_test/common/commands.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packer_test/common/commands.go b/packer_test/common/commands.go index 869a6b278..c0c043674 100644 --- a/packer_test/common/commands.go +++ b/packer_test/common/commands.go @@ -22,6 +22,7 @@ type packerCommand struct { err error t *testing.T fatalfAssert bool + dump bool } // PackerCommand creates a skeleton of packer command with the ability to execute gadgets on the outputs of the command. @@ -125,6 +126,15 @@ func (pc *packerCommand) SetAssertFatal() *packerCommand { return pc } +// Dump enables a verbose mode for the test, when Assert is called, the test +// proceeds normally, and the command-line that was invoked, along with the +// contents of stdout/stderr will also be output in addition to the test +// results. This is mostly useful for debugging a test. +func (pc *packerCommand) Dump() *packerCommand { + pc.dump = true + return pc +} + // Run executes the packer command with the args/env requested and returns the // output streams (stdout, stderr) // @@ -182,6 +192,14 @@ func (pc *packerCommand) Output() (string, string, error) { } func (pc *packerCommand) Assert(checks ...check.Checker) { + if pc.dump { + tmpChecks := []check.Checker{ + check.Dump(pc.t), + } + + checks = append(tmpChecks, checks...) + } + attempt := 0 for pc.runs > 0 { attempt++ From 7e1ddca0ec493a4d9f4a834bf55903ee4e34b42f Mon Sep 17 00:00:00 2001 From: Lucas Bajolet Date: Fri, 28 Mar 2025 10:31:32 -0400 Subject: [PATCH 3/3] common: add DumpCommand check to packerCommand In addition to dumping the results of a command, we also now dump the command itself, so we know exactly which command was invoked to produce the result we got. --- packer_test/common/check/gadgets.go | 14 ++++++++++++++ packer_test/common/commands.go | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/packer_test/common/check/gadgets.go b/packer_test/common/check/gadgets.go index 14761d98c..ec8e53fd3 100644 --- a/packer_test/common/check/gadgets.go +++ b/packer_test/common/check/gadgets.go @@ -195,6 +195,20 @@ func (d dump) Check(stdout, stderr string, err error) error { return nil } +func DumpCommand(t *testing.T, command string) Checker { + return &dumpCommand{t, command} +} + +type dumpCommand struct { + t *testing.T + command string +} + +func (d dumpCommand) Check(_, _ string, _ error) error { + d.t.Logf("ran command %s", d.command) + return nil +} + type PanicCheck struct{} func (_ PanicCheck) Check(stdout, stderr string, _ error) error { diff --git a/packer_test/common/commands.go b/packer_test/common/commands.go index c0c043674..c9bfd3119 100644 --- a/packer_test/common/commands.go +++ b/packer_test/common/commands.go @@ -135,6 +135,17 @@ func (pc *packerCommand) Dump() *packerCommand { return pc } +func (pc *packerCommand) commandString() string { + buf := &strings.Builder{} + + fmt.Fprintf(buf, "%q", pc.packerPath) + for _, arg := range pc.args { + fmt.Fprintf(buf, " %q", arg) + } + + return buf.String() +} + // Run executes the packer command with the args/env requested and returns the // output streams (stdout, stderr) // @@ -194,6 +205,7 @@ func (pc *packerCommand) Output() (string, string, error) { func (pc *packerCommand) Assert(checks ...check.Checker) { if pc.dump { tmpChecks := []check.Checker{ + check.DumpCommand(pc.t, pc.commandString()), check.Dump(pc.t), }