Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions test/integration/awsconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,6 @@ func TestStartNonInteractiveEmitsNoteWhenAWSProfileMissing(t *testing.T) {
"start",
)
require.NoError(t, err)
requireExitCode(t, 0, err)
assert.Contains(t, stdout, "No complete LocalStack AWS profile found")
}
8 changes: 8 additions & 0 deletions test/integration/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestConfigFileCreatedOnStartup(t *testing.T) {
e := testEnvWithHome(tmpHome, xdgOverride)
_, stderr, err := runLstk(t, testContext(t), workDir, e, "logout")
require.NoError(t, err, stderr)
requireExitCode(t, 0, err)

expectedConfigFile := filepath.Join(tmpHome, ".config", "lstk", "config.toml")
assert.FileExists(t, expectedConfigFile)
Expand All @@ -36,6 +37,7 @@ func TestConfigFileCreatedOnStartup(t *testing.T) {
e := testEnvWithHome(tmpHome, xdgOverride)
_, stderr, err := runLstk(t, testContext(t), workDir, e, "logout")
require.NoError(t, err, stderr)
requireExitCode(t, 0, err)

expectedConfigFile := filepath.Join(expectedOSConfigDir(tmpHome, xdgOverride), "config.toml")
assert.FileExists(t, expectedConfigFile)
Expand Down Expand Up @@ -69,6 +71,7 @@ IAM_SOFT_MODE = "1"
ctx := testContext(t)
_, stderr, err := runLstk(t, ctx, "", env.With(env.APIEndpoint, mockServer.URL), "--config", configFile, "start")
require.NoError(t, err, "lstk start failed: %s", stderr)
requireExitCode(t, 0, err)

inspect, err := dockerClient.ContainerInspect(ctx, containerName)
require.NoError(t, err, "failed to inspect container")
Expand All @@ -81,6 +84,7 @@ func TestConfigFlagOverridesConfigPath(t *testing.T) {

stdout, stderr, err := runLstk(t, testContext(t), t.TempDir(), os.Environ(), "--config", customConfig, "config", "path")
require.NoError(t, err, stderr)
requireExitCode(t, 0, err)

assertSamePath(t, customConfig, stdout)
}
Expand All @@ -98,6 +102,7 @@ func TestLocalConfigTakesPrecedence(t *testing.T) {
e := testEnvWithHome(tmpHome, xdgOverride)
stdout, stderr, err := runLstk(t, testContext(t), workDir, e, "config", "path")
require.NoError(t, err, stderr)
requireExitCode(t, 0, err)

expectedLocalPath, err := filepath.Abs(localConfigFile)
require.NoError(t, err)
Expand All @@ -117,6 +122,7 @@ func TestXDGConfigTakesPrecedence(t *testing.T) {
e := testEnvWithHome(tmpHome, xdgOverride)
stdout, stderr, err := runLstk(t, testContext(t), workDir, e, "config", "path")
require.NoError(t, err, stderr)
requireExitCode(t, 0, err)

assertSamePath(t, xdgConfigFile, stdout)
}
Expand All @@ -130,6 +136,7 @@ func TestConfigPathCommand(t *testing.T) {
e := testEnvWithHome(tmpHome, filepath.Join(tmpHome, "xdg-config-home"))
stdout, stderr, err := runLstk(t, testContext(t), workDir, e, "config", "path")
require.NoError(t, err, stderr)
requireExitCode(t, 0, err)

assertSamePath(t, xdgConfigFile, stdout)
}
Expand All @@ -143,6 +150,7 @@ func TestConfigPathCommandDoesNotCreateConfig(t *testing.T) {
e := testEnvWithHome(tmpHome, xdgOverride)
stdout, stderr, err := runLstk(t, testContext(t), workDir, e, "config", "path")
require.NoError(t, err, stderr)
requireExitCode(t, 0, err)

assertSamePath(t, expectedConfigFile, stdout)
assert.NoFileExists(t, expectedConfigFile)
Expand Down
2 changes: 2 additions & 0 deletions test/integration/license_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func TestLicenseValidationSuccess(t *testing.T) {
}

require.NoError(t, err, "lstk start failed: %s", stderr)
requireExitCode(t, 0, err)

inspect, err := dockerClient.ContainerInspect(ctx, containerName)
require.NoError(t, err, "failed to inspect container")
Expand All @@ -82,6 +83,7 @@ func TestLicenseValidationFailure(t *testing.T) {
ctx := testContext(t)
_, stderr, err := runLstk(t, ctx, "", env.With(env.APIEndpoint, mockServer.URL).With(env.AuthToken, "test-token-for-license-validation"), "start")
require.Error(t, err, "expected lstk start to fail with forbidden license")
requireExitCode(t, 1, err)
assert.Contains(t, stderr, "license validation failed")
assert.Contains(t, stderr, "invalid, inactive, or expired")

Expand Down
2 changes: 2 additions & 0 deletions test/integration/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func TestDeviceFlowSuccess(t *testing.T) {

out := output.String()
require.NoError(t, err, "login should succeed: %s", out)
requireExitCode(t, 0, err)
assert.Contains(t, out, "Opening browser to login...")
assert.Contains(t, out, "Browser didn't open? Visit")
assert.Contains(t, out, "/auth/request/test-auth-req-id?code=TEST123")
Expand Down Expand Up @@ -176,6 +177,7 @@ func TestDeviceFlowFailure_RequestNotConfirmed(t *testing.T) {

out := output.String()
require.Error(t, err, "expected login to fail when request not confirmed")
requireExitCode(t, 1, err)
assert.Contains(t, out, "Opening browser to login...")
assert.Contains(t, out, "Browser didn't open? Visit")
assert.Contains(t, out, "/auth/request/test-auth-req-id?code=TEST123")
Expand Down
4 changes: 4 additions & 0 deletions test/integration/logout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func TestLogoutCommandRemovesToken(t *testing.T) {

stdout, stderr, err := runLstk(t, testContext(t), "", nil, "logout")
require.NoError(t, err, "lstk logout failed: %s", stderr)
requireExitCode(t, 0, err)
assert.Contains(t, stdout, "Logged out successfully")

_, err = GetAuthTokenFromKeyring()
Expand All @@ -30,6 +31,7 @@ func TestLogoutCommandSucceedsWhenNoToken(t *testing.T) {

stdout, stderr, err := runLstk(t, testContext(t), "", env.Without(env.AuthToken), "logout")
require.NoError(t, err, "lstk logout should succeed even with no token: %s", stderr)
requireExitCode(t, 0, err)
assert.Contains(t, stdout, "Not currently logged in")
}

Expand All @@ -38,6 +40,7 @@ func TestLogoutCommandWithEnvVarToken(t *testing.T) {

stdout, stderr, err := runLstk(t, testContext(t), "", env.Without(env.AuthToken).With(env.AuthToken, "test-env-token"), "logout")
require.NoError(t, err, "lstk logout should succeed: %s", stderr)
requireExitCode(t, 0, err)
assert.Contains(t, stdout, "LOCALSTACK_AUTH_TOKEN")
}

Expand All @@ -57,5 +60,6 @@ func TestLogoutCommandNotesWhenEmulatorStillRunning(t *testing.T) {

stdout, stderr, err := runLstk(t, ctx, "", nil, "logout")
require.NoError(t, err, "lstk logout failed: %s", stderr)
requireExitCode(t, 0, err)
assert.Contains(t, stdout, "LocalStack is still running in the background")
}
2 changes: 2 additions & 0 deletions test/integration/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestLogsExitsByDefault(t *testing.T) {

_, _, err := runLstk(t, ctx, "", nil, "logs")
require.NoError(t, err, "lstk logs should exit cleanly when container is running")
requireExitCode(t, 0, err)
}

func TestLogsCommandFailsWhenNotRunning(t *testing.T) {
Expand All @@ -31,6 +32,7 @@ func TestLogsCommandFailsWhenNotRunning(t *testing.T) {

_, stderr, err := runLstk(t, testContext(t), "", nil, "logs", "--follow")
require.Error(t, err, "expected lstk logs --follow to fail when container not running")
requireExitCode(t, 1, err)
assert.Contains(t, stderr, "emulator is not running")
}

Expand Down
11 changes: 11 additions & 0 deletions test/integration/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,17 @@ func runLstkInPTY(t *testing.T, ctx context.Context, environ []string, args ...s
return strings.TrimSpace(out.String()), err
}

func requireExitCode(t *testing.T, expected int, err error) {
t.Helper()
if expected == 0 {
require.NoError(t, err)
return
}
var exitErr *exec.ExitError
require.ErrorAs(t, err, &exitErr)
require.Equal(t, expected, exitErr.ExitCode())
}

func createMockLicenseServer(success bool) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" && r.URL.Path == "/v1/license/request" {
Expand Down
3 changes: 3 additions & 0 deletions test/integration/non_interactive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
func TestNonInteractiveFlagBlocksLogin(t *testing.T) {
out, err := runLstkInPTY(t, testContext(t), nil, "login", "--non-interactive")
require.Error(t, err, "expected login --non-interactive to fail")
requireExitCode(t, 1, err)
assert.Contains(t, out, "login requires an interactive terminal")
}

Expand All @@ -24,6 +25,7 @@ func TestNonInteractiveFlagFailsWithoutToken(t *testing.T) {

out, err := runLstkInPTY(t, testContext(t), env.Without(env.AuthToken).With(env.APIEndpoint, mockServer.URL), "start", "--non-interactive")
require.Error(t, err, "expected start --non-interactive to fail with no auth token")
requireExitCode(t, 1, err)
assert.Contains(t, out, "authentication required: set LOCALSTACK_AUTH_TOKEN or run in interactive mode")
}

Expand All @@ -37,5 +39,6 @@ func TestRootNonInteractiveFlagFailsWithoutToken(t *testing.T) {

out, err := runLstkInPTY(t, testContext(t), env.Without(env.AuthToken).With(env.APIEndpoint, mockServer.URL), "--non-interactive")
require.Error(t, err, "expected lstk --non-interactive to fail with no auth token")
requireExitCode(t, 1, err)
assert.Contains(t, out, "authentication required: set LOCALSTACK_AUTH_TOKEN or run in interactive mode")
}
5 changes: 5 additions & 0 deletions test/integration/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func TestStartCommandSucceedsWithValidToken(t *testing.T) {
ctx := testContext(t)
_, stderr, err := runLstk(t, ctx, "", env.With(env.APIEndpoint, mockServer.URL), "start")
require.NoError(t, err, "lstk start failed: %s", stderr)
requireExitCode(t, 0, err)

inspect, err := dockerClient.ContainerInspect(ctx, containerName)
require.NoError(t, err, "failed to inspect container")
Expand All @@ -47,6 +48,7 @@ func TestStartCommandSucceedsWithKeyringToken(t *testing.T) {
// Run without LOCALSTACK_AUTH_TOKEN should use keyring
_, stderr, err := runLstk(t, ctx, "", env.Without(env.AuthToken).With(env.APIEndpoint, mockServer.URL), "start")
require.NoError(t, err, "lstk start failed: %s", stderr)
requireExitCode(t, 0, err)

inspect, err := dockerClient.ContainerInspect(ctx, containerName)
require.NoError(t, err, "failed to inspect container")
Expand All @@ -63,6 +65,7 @@ func TestStartCommandFailsWithInvalidToken(t *testing.T) {

_, stderr, err := runLstk(t, testContext(t), "", env.With(env.AuthToken, "invalid-token").With(env.APIEndpoint, mockServer.URL), "start")
require.Error(t, err, "expected lstk start to fail with invalid token")
requireExitCode(t, 1, err)
assert.Contains(t, stderr, "license validation failed")
}

Expand All @@ -76,6 +79,7 @@ func TestStartCommandDoesNothingWhenAlreadyRunning(t *testing.T) {

stdout, stderr, err := runLstk(t, ctx, "", env.With(env.AuthToken, "fake-token"), "start")
require.NoError(t, err, "lstk start should succeed when container is already running: %s", stderr)
requireExitCode(t, 0, err)
assert.Contains(t, stdout, "already running")
}

Expand All @@ -90,6 +94,7 @@ func TestStartCommandFailsWhenPortInUse(t *testing.T) {

stdout, _, err := runLstk(t, testContext(t), "", env.With(env.AuthToken, "fake-token"), "start")
require.Error(t, err, "expected lstk start to fail when port is in use")
requireExitCode(t, 1, err)
assert.Contains(t, stdout, "Port 4566 already in use")
assert.Contains(t, stdout, "LocalStack may already be running.")
assert.Contains(t, stdout, "lstk stop")
Expand Down
4 changes: 4 additions & 0 deletions test/integration/stop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func TestStopCommandSucceeds(t *testing.T) {

stdout, stderr, err := runLstk(t, ctx, "", nil, "stop")
require.NoError(t, err, "lstk stop failed: %s", stderr)
requireExitCode(t, 0, err)
assert.Contains(t, stdout, "Stopping", "should show stopping message")
assert.Contains(t, stdout, "stopped", "should show stopped message")

Expand All @@ -31,6 +32,7 @@ func TestStopCommandFailsWhenNotRunning(t *testing.T) {

_, stderr, err := runLstk(t, testContext(t), "", nil, "stop")
require.Error(t, err, "expected lstk stop to fail when container not running")
requireExitCode(t, 1, err)
assert.Contains(t, stderr, "is not running")
}

Expand All @@ -44,10 +46,12 @@ func TestStopCommandIsIdempotent(t *testing.T) {

_, stderr, err := runLstk(t, ctx, "", nil, "stop")
require.NoError(t, err, "first lstk stop failed: %s", stderr)
requireExitCode(t, 0, err)

_, err = dockerClient.ContainerInspect(ctx, containerName)
require.Error(t, err, "container should not exist after first stop")

_, _, err = runLstk(t, ctx, "", nil, "stop")
assert.Error(t, err, "second lstk stop should fail since container already removed")
requireExitCode(t, 1, err)
}
3 changes: 3 additions & 0 deletions test/integration/telemetry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func TestStartCommandSendsTelemetryEvent(t *testing.T) {
With(env.AnalyticsEndpoint, analyticsSrv.URL)
out, err := cmd.CombinedOutput()
require.NoError(t, err, "lstk start failed: %s", out)
requireExitCode(t, 0, err)

// The telemetry goroutine is async; wait up to 3s for the event to arrive.
select {
Expand Down Expand Up @@ -106,6 +107,7 @@ func TestStartCommandSucceedsWhenAnalyticsEndpointUnreachable(t *testing.T) {
out, err := cmd.CombinedOutput()

require.NoError(t, err, "lstk start should succeed even when analytics endpoint is unreachable: %s", out)
requireExitCode(t, 0, err)
}

func TestStartCommandDoesNotSendTelemetryWhenDisabled(t *testing.T) {
Expand All @@ -126,6 +128,7 @@ func TestStartCommandDoesNotSendTelemetryWhenDisabled(t *testing.T) {
With(env.DisableEvents, "1")
out, err := cmd.CombinedOutput()
require.NoError(t, err, "lstk start failed: %s", out)
requireExitCode(t, 0, err)

// Wait long enough that a goroutine would have fired if enabled.
select {
Expand Down
5 changes: 5 additions & 0 deletions test/integration/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func TestUpdateCheckCommand(t *testing.T) {

stdout, stderr, err := runLstk(t, ctx, "", nil, "update", "--check")
require.NoError(t, err, "lstk update --check failed: %s", stderr)
requireExitCode(t, 0, err)

// Dev builds report a note about skipping update check
assert.Contains(t, stdout, "Note:", "should show a note (dev build or up-to-date)")
Expand All @@ -27,6 +28,7 @@ func TestUpdateCheckCommandNonInteractive(t *testing.T) {

stdout, stderr, err := runLstk(t, ctx, "", nil, "update", "--check", "--non-interactive")
require.NoError(t, err, "lstk update --check --non-interactive failed: %s", stderr)
requireExitCode(t, 0, err)
assert.Contains(t, stdout, "Note:", "should show a note in non-interactive mode")
}

Expand Down Expand Up @@ -90,6 +92,7 @@ func TestUpdateNPMLocalInstall(t *testing.T) {
stdoutStr := string(stdout)

require.NoError(t, err, "lstk update failed: %s", stdoutStr)
requireExitCode(t, 0, err)
assert.Contains(t, stdoutStr, "npm (local)", "should detect local npm install")
assert.Contains(t, stdoutStr, projectDir, "should show the project directory")
assert.Contains(t, stdoutStr, "Updated to", "should complete the update")
Expand Down Expand Up @@ -127,6 +130,7 @@ func TestUpdateBinaryInPlace(t *testing.T) {
updateOut, err := updateCmd.CombinedOutput()
updateStr := string(updateOut)
require.NoError(t, err, "lstk update failed: %s", updateStr)
requireExitCode(t, 0, err)
assert.Contains(t, updateStr, "Update available: 0.0.1", "should detect update")
assert.Contains(t, updateStr, "Downloading update", "should download binary")
assert.Contains(t, updateStr, "Updated to", "should complete the update")
Expand Down Expand Up @@ -196,6 +200,7 @@ func TestUpdateHomebrew(t *testing.T) {
updateOut, err := updateCmd.CombinedOutput()
updateStr := string(updateOut)
require.NoError(t, err, "lstk update failed: %s", updateStr)
requireExitCode(t, 0, err)
assert.Contains(t, updateStr, "Homebrew", "should detect Homebrew install")
assert.Contains(t, updateStr, "brew upgrade", "should mention brew upgrade")
}
Expand Down
Loading