Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d5150e2
updates
aknysh Jan 16, 2026
f4b5e55
updates
aknysh Jan 16, 2026
5605dd0
updates
aknysh Jan 16, 2026
cef361f
updates
aknysh Jan 16, 2026
09701fb
updates
aknysh Jan 16, 2026
5956d3d
updates
aknysh Jan 16, 2026
7c7abd4
docs: Add Packer directory-based templates milestone to roadmap
aknysh Jan 16, 2026
c4f4713
fix: Address CodeRabbit feedback on Packer directory-based templates PR
aknysh Jan 16, 2026
edfa5dc
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 16, 2026
5e51dfa
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Jan 16, 2026
86c01ea
address comments, add tests
aknysh Jan 16, 2026
1adc64a
address comments, add tests
aknysh Jan 17, 2026
060ad99
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 17, 2026
5aebafb
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Jan 17, 2026
aca64a0
[autofix.ci] apply automated fixes (attempt 3/3)
autofix-ci[bot] Jan 17, 2026
d4a3c5b
address comments, add tests
aknysh Jan 17, 2026
712487a
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 17, 2026
7be5f7f
[autofix.ci] apply automated fixes (attempt 2/3)
autofix-ci[bot] Jan 17, 2026
9ffdfc3
[autofix.ci] apply automated fixes (attempt 3/3)
autofix-ci[bot] Jan 17, 2026
276f15b
update NOTICE
aknysh Jan 17, 2026
1f20a83
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 17, 2026
78356ee
address comments
aknysh Jan 17, 2026
3df5833
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 17, 2026
7c6ab65
address comments
aknysh Jan 17, 2026
2dd84a8
Merge remote-tracking branch 'origin/aknysh/update-packer-2' into akn…
aknysh Jan 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 231 additions & 0 deletions cmd/packer_build_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package cmd

import (
"bytes"
"os"
"strings"
"testing"

"github.com/stretchr/testify/assert"

log "github.com/cloudposse/atmos/pkg/logger"
)

// TestPackerBuildCmd tests the packer build command execution.
// This test verifies that packer build executes correctly.
// The actual packer execution may fail due to missing AWS credentials.
// The test verifies command arguments are parsed correctly, component and stack are resolved,
// the variable file is generated, and packer is invoked with correct arguments.
func TestPackerBuildCmd(t *testing.T) {
_ = NewTestKit(t)

skipIfPackerNotInstalled(t)

workDir := "../tests/fixtures/scenarios/packer"
t.Setenv("ATMOS_CLI_CONFIG_PATH", workDir)
t.Setenv("ATMOS_LOGS_LEVEL", "Warning")
log.SetLevel(log.WarnLevel)

// Ensure plugins are installed so build errors are about credentials, not init.
RootCmd.SetArgs([]string{"packer", "init", "aws/bastion", "-s", "nonprod"})
if initErr := Execute(); initErr != nil {
t.Skipf("Skipping test: packer init failed (may require network access): %v", initErr)
}

// Reset for actual test.
_ = NewTestKit(t)

oldStdout := os.Stdout
oldStderr := os.Stderr
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("failed to create pipe for stdout capture: %v", err)
}
os.Stdout = w
os.Stderr = w
log.SetOutput(w)

// Ensure cleanup happens before any reads.
defer func() {
os.Stdout = oldStdout
os.Stderr = oldStderr
log.SetOutput(os.Stderr)
}()

// Run packer build. It will fail due to missing AWS credentials.
// We verify that Atmos correctly processes the command.
RootCmd.SetArgs([]string{"packer", "build", "aws/bastion", "-s", "nonprod"})
err = Execute()

// Close write end after Execute.
_ = w.Close()

// Read the captured output.
var buf bytes.Buffer
_, _ = buf.ReadFrom(r)
output := buf.String()

// The command may fail due to AWS credentials.
// The output should contain packer-specific content, indicating that Atmos invoked packer correctly.
if err == nil {
t.Logf("TestPackerBuildCmd completed successfully (unexpected in test environment)")
return
}

// Skip if plugins are still missing despite init attempt.
if strings.Contains(output, "Missing plugins") {
t.Skipf("Skipping test: packer plugins missing (run packer init): %v", err)
}

// If packer ran and failed due to credentials, that's expected.
// Check that packer actually ran (output contains packer-specific content).
packerRan := strings.Contains(output, "amazon-ebs") ||
strings.Contains(output, "Build") ||
strings.Contains(output, "credential") ||
strings.Contains(output, "Packer")

if packerRan {
t.Logf("Packer build executed but failed (likely due to missing credentials): %v", err)
// Test passes - packer was correctly invoked.
return
}

// If the error is from Atmos (not packer), that's a real failure.
t.Logf("TestPackerBuildCmd output: %s", output)
t.Errorf("Packer build failed unexpectedly: %v", err)
}

func TestPackerBuildCmdInvalidComponent(t *testing.T) {
_ = NewTestKit(t)

skipIfPackerNotInstalled(t)

workDir := "../tests/fixtures/scenarios/packer"
t.Setenv("ATMOS_CLI_CONFIG_PATH", workDir)
t.Setenv("ATMOS_LOGS_LEVEL", "Warning")
log.SetLevel(log.WarnLevel)

// Capture stderr for error messages.
oldStderr := os.Stderr
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("failed to create pipe for stderr capture: %v", err)
}
os.Stderr = w
log.SetOutput(w)

defer func() {
os.Stderr = oldStderr
log.SetOutput(os.Stderr)
}()

RootCmd.SetArgs([]string{"packer", "build", "invalid/component", "-s", "nonprod"})
err = Execute()

// Close write end after Execute.
_ = w.Close()

// Read the captured output.
var buf bytes.Buffer
_, _ = buf.ReadFrom(r)
output := buf.String()

// Should fail with invalid component error.
assert.Error(t, err, "'TestPackerBuildCmdInvalidComponent' should fail for invalid component")

// Log the error for debugging.
t.Logf("TestPackerBuildCmdInvalidComponent error: %v", err)
t.Logf("TestPackerBuildCmdInvalidComponent output: %s", output)
}

func TestPackerBuildCmdMissingStack(t *testing.T) {
_ = NewTestKit(t)

skipIfPackerNotInstalled(t)

workDir := "../tests/fixtures/scenarios/packer"
t.Setenv("ATMOS_CLI_CONFIG_PATH", workDir)
t.Setenv("ATMOS_LOGS_LEVEL", "Warning")
log.SetLevel(log.WarnLevel)

RootCmd.SetArgs([]string{"packer", "build", "aws/bastion"})
err := Execute()

// The command should fail either with "stack is required" or with a packer execution error.
// Both indicate the command was processed.
assert.Error(t, err, "'TestPackerBuildCmdMissingStack' should fail when stack is not specified")
t.Logf("TestPackerBuildCmdMissingStack error: %v", err)
}

func TestPackerBuildCmdWithDirectoryTemplate(t *testing.T) {
_ = NewTestKit(t)

skipIfPackerNotInstalled(t)

workDir := "../tests/fixtures/scenarios/packer"
t.Setenv("ATMOS_CLI_CONFIG_PATH", workDir)
t.Setenv("ATMOS_LOGS_LEVEL", "Warning")
log.SetLevel(log.WarnLevel)

// Ensure plugins are installed so build errors are about credentials, not init.
RootCmd.SetArgs([]string{"packer", "init", "aws/multi-file", "-s", "nonprod"})
if initErr := Execute(); initErr != nil {
t.Skipf("Skipping test: packer init failed (may require network access): %v", initErr)
}

// Reset for actual test.
_ = NewTestKit(t)

oldStdout := os.Stdout
oldStderr := os.Stderr
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("failed to create pipe for stdout capture: %v", err)
}
os.Stdout = w
os.Stderr = w
log.SetOutput(w)

defer func() {
os.Stdout = oldStdout
os.Stderr = oldStderr
log.SetOutput(os.Stderr)
}()

// Test with explicit directory template flag (directory mode).
// This uses "." to load all *.pkr.hcl files from the component directory.
RootCmd.SetArgs([]string{"packer", "build", "aws/multi-file", "-s", "nonprod", "--template", "."})
err = Execute()

// Close write end after Execute.
_ = w.Close()

// Read the captured output.
var buf bytes.Buffer
_, _ = buf.ReadFrom(r)
output := buf.String()

// The command may fail due to AWS credentials, but verify packer was invoked.
if err == nil {
return
}

// Skip if plugins are still missing despite init attempt.
if strings.Contains(output, "Missing plugins") {
t.Skipf("Skipping test: packer plugins missing (run packer init): %v", err)
}

packerRan := strings.Contains(output, "amazon-ebs") ||
strings.Contains(output, "Build") ||
strings.Contains(output, "credential") ||
strings.Contains(output, "Packer")

if packerRan {
t.Logf("Packer build with directory template executed (failed due to credentials): %v", err)
// Test passes.
return
}

t.Logf("TestPackerBuildCmdWithDirectoryTemplate output: %s", output)
t.Errorf("Packer build with directory template failed unexpectedly: %v", err)
}
Loading
Loading