-
-
Notifications
You must be signed in to change notification settings - Fork 153
Expand file tree
/
Copy pathterraform_execute_exit_wrapping_test.go
More file actions
59 lines (51 loc) · 2.49 KB
/
terraform_execute_exit_wrapping_test.go
File metadata and controls
59 lines (51 loc) · 2.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package exec
// terraform_execute_exit_wrapping_test.go is a dedicated contract test for the
// ExitCodeError wrapping guarantee of ExecuteShellCommand.
//
// Contract: whenever the spawned subprocess exits with a non-zero code,
// ExecuteShellCommand must return an error that satisfies errors.As(err, ExitCodeError).
// This guarantee is relied upon by runWorkspaceSetup, executeMainTerraformCommand, and
// any other caller that needs to inspect the subprocess exit code.
//
// Cross-platform approach: uses the test binary (os.Executable) with
// _ATMOS_TEST_EXIT_ONE=1. TestMain in testmain_test.go intercepts that env var
// and calls os.Exit(1) immediately.
import (
"errors"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
errUtils "github.com/cloudposse/atmos/errors"
"github.com/cloudposse/atmos/pkg/schema"
)
// TestExecuteShellCommand_ExitOneWrappedAsExitCodeError verifies the core ExitCodeError
// wrapping contract: a subprocess that exits with code 1 must produce an error that can
// be unwrapped to errUtils.ExitCodeError with Code == 1.
//
// This is the canonical standalone reference test for this contract. The same property
// is exercised indirectly by workspace and pipeline tests that use _ATMOS_TEST_EXIT_ONE,
// but having an explicit dedicated test makes regressions immediately obvious in isolation.
func TestExecuteShellCommand_ExitOneWrappedAsExitCodeError(t *testing.T) {
exePath, err := os.Executable()
require.NoError(t, err, "os.Executable() must succeed")
atmosConfig := schema.AtmosConfiguration{}
execErr := ExecuteShellCommand(
atmosConfig,
exePath,
[]string{"-test.run=^$"}, // no test matches; TestMain exits before any test
"", // dir: current working directory
[]string{"_ATMOS_TEST_EXIT_ONE=1"}, // env: makes TestMain call os.Exit(1)
false, // dryRun: false — actually run the subprocess
"", // redirectStdErr
)
// The subprocess must have exited with code 1.
require.Error(t, execErr, "ExecuteShellCommand must return an error when subprocess exits 1")
// The error must be (or wrap) an ExitCodeError — callers depend on this contract.
var exitCodeErr errUtils.ExitCodeError
require.True(t,
errors.As(execErr, &exitCodeErr),
"error must satisfy errors.As(err, ExitCodeError); got %T: %v", execErr, execErr,
)
assert.Equal(t, 1, exitCodeErr.Code, "ExitCodeError.Code must equal the subprocess exit code (1)")
}