Skip to content

Commit 9bd8b8e

Browse files
committed
Add keep-failed-containers flag for debugging integration tests
Introduces the ability to preserve Docker containers when integration tests fail, making debugging significantly easier. This feature matches the implementation in java-buildpack and php-buildpack. Changes: - Add --keep-failed-containers CLI flag to integration.sh script - Add KeepFailedContainers boolean flag to integration test settings - Update all 12 integration test files with conditional container cleanup - Log failed test container names for easy identification When a test fails with --keep-failed-containers flag enabled, the container is preserved for inspection rather than being automatically deleted. This allows developers to: - Inspect container logs with docker logs - Enter the container with docker exec - Debug the exact state that caused the test failure Usage: ./scripts/integration.sh --github-token <token> --keep-failed-containers
1 parent 4567b7e commit 9bd8b8e

14 files changed

Lines changed: 107 additions & 23 deletions

scripts/integration.sh

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ OPTIONS
2121
--help -h prints the command usage
2222
--github-token <token> GitHub token to use when making API requests
2323
--platform <cf|docker> Switchblade platform to execute the tests against
24+
--keep-failed-containers Preserve failed test containers for debugging (default: false)
2425
USAGE
2526
}
2627

2728
function main() {
28-
local src stack platform token cached parallel
29+
local src stack platform token cached parallel keep_failed
2930
src="$(find "${ROOTDIR}/src" -mindepth 1 -maxdepth 1 -type d )"
3031
stack="${CF_STACK:-$(jq -r -S .stack "${ROOTDIR}/config.json")}"
3132
platform="cf"
33+
keep_failed="false"
3234

3335
while [[ "${#}" != 0 ]]; do
3436
case "${1}" in
@@ -52,6 +54,11 @@ function main() {
5254
shift 2
5355
;;
5456

57+
--keep-failed-containers)
58+
keep_failed="true"
59+
shift 1
60+
;;
61+
5562
--help|-h)
5663
shift 1
5764
usage
@@ -94,24 +101,26 @@ function main() {
94101

95102
echo "Running integration suite (cached: ${cached}, parallel: ${parallel})"
96103

97-
specs::run "${cached}" "${parallel}" "${stack}" "${platform}" "${token:-}"
104+
specs::run "${cached}" "${parallel}" "${stack}" "${platform}" "${token:-}" "${keep_failed}"
98105
done
99106
}
100107

101108
function specs::run() {
102-
local cached parallel stack platform token
109+
local cached parallel stack platform token keep_failed
103110
cached="${1}"
104111
parallel="${2}"
105112
stack="${3}"
106113
platform="${4}"
107114
token="${5}"
115+
keep_failed="${6}"
108116

109-
local nodes cached_flag serial_flag platform_flag stack_flag token_flag
117+
local nodes cached_flag serial_flag platform_flag stack_flag token_flag keep_failed_flag
110118
cached_flag="--cached=${cached}"
111119
serial_flag="--serial=true"
112120
platform_flag="--platform=${platform}"
113121
stack_flag="--stack=${stack}"
114122
token_flag="--github-token=${token}"
123+
keep_failed_flag="--keep-failed-containers=${keep_failed}"
115124
nodes=1
116125

117126
if [[ "${parallel}" == "true" ]]; then
@@ -135,7 +144,8 @@ function specs::run() {
135144
"${platform_flag}" \
136145
"${token_flag}" \
137146
"${stack_flag}" \
138-
"${serial_flag}"
147+
"${serial_flag}" \
148+
"${keep_failed_flag}"
139149
}
140150

141151
function buildpack::package() {

src/staticfile/integration/alternate_root_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ func testAlternateRoot(platform switchblade.Platform, fixtures string) func(*tes
2727
})
2828

2929
it.After(func() {
30-
Expect(platform.Delete.Execute(name)).To(Succeed())
30+
if t.Failed() && name != "" {
31+
t.Logf("❌ FAILED TEST - App/Container: %s", name)
32+
t.Logf(" Platform: %s", settings.Platform)
33+
}
34+
if name != "" && (!settings.KeepFailedContainers || !t.Failed()) {
35+
Expect(platform.Delete.Execute(name)).To(Succeed())
36+
}
3137
})
3238

3339
context("the path is default", func() {

src/staticfile/integration/cache_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ func testCache(platform switchblade.Platform, fixtures string) func(*testing.T,
3636
})
3737

3838
it.After(func() {
39-
Expect(platform.Delete.Execute(name)).To(Succeed())
39+
if t.Failed() && name != "" {
40+
t.Logf("❌ FAILED TEST - App/Container: %s", name)
41+
t.Logf(" Platform: %s", settings.Platform)
42+
}
43+
if name != "" && (!settings.KeepFailedContainers || !t.Failed()) {
44+
Expect(platform.Delete.Execute(name)).To(Succeed())
45+
}
4046
})
4147

4248
it("uses the cache for manifest dependencies", func() {

src/staticfile/integration/default_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ func testDefault(platform switchblade.Platform, fixtures string) func(*testing.T
3232
})
3333

3434
it.After(func() {
35-
Expect(platform.Delete.Execute(name)).To(Succeed())
35+
if t.Failed() && name != "" {
36+
t.Logf("❌ FAILED TEST - App/Container: %s", name)
37+
t.Logf(" Platform: %s", settings.Platform)
38+
}
39+
if name != "" && (!settings.KeepFailedContainers || !t.Failed()) {
40+
Expect(platform.Delete.Execute(name)).To(Succeed())
41+
}
3642
})
3743

3844
it("builds and runs the app", func() {

src/staticfile/integration/dot_files_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ func testDotFiles(platform switchblade.Platform, fixtures string) func(*testing.
3030
})
3131

3232
it.After(func() {
33-
Expect(platform.Delete.Execute(name)).To(Succeed())
33+
if t.Failed() && name != "" {
34+
t.Logf("❌ FAILED TEST - App/Container: %s", name)
35+
t.Logf(" Platform: %s", settings.Platform)
36+
}
37+
if name != "" && (!settings.KeepFailedContainers || !t.Failed()) {
38+
Expect(platform.Delete.Execute(name)).To(Succeed())
39+
}
3440
})
3541

3642
context("when deploying an app it dotfile enabled", func() {

src/staticfile/integration/dynatrace_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ func testDynatrace(platform switchblade.Platform, fixtures, uri string) func(*te
2626
})
2727

2828
it.After(func() {
29-
Expect(platform.Delete.Execute(name)).To(Succeed())
29+
if t.Failed() && name != "" {
30+
t.Logf("❌ FAILED TEST - App/Container: %s", name)
31+
t.Logf(" Platform: %s", settings.Platform)
32+
}
33+
if name != "" && (!settings.KeepFailedContainers || !t.Failed()) {
34+
Expect(platform.Delete.Execute(name)).To(Succeed())
35+
}
3036
})
3137

3238
it("builds the app with a Dynatrace agent", func() {

src/staticfile/integration/https_redirect_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ func testHttpsRedirect(platform switchblade.Platform, fixtures string) func(*tes
3636
})
3737

3838
it.After(func() {
39-
Expect(platform.Delete.Execute(name)).To(Succeed())
39+
if t.Failed() && name != "" {
40+
t.Logf("❌ FAILED TEST - App/Container: %s", name)
41+
t.Logf(" Platform: %s", settings.Platform)
42+
}
43+
if name != "" && (!settings.KeepFailedContainers || !t.Failed()) {
44+
Expect(platform.Delete.Execute(name)).To(Succeed())
45+
}
4046
})
4147

4248
context("with HTTPS redirect set with an environment variable", func() {

src/staticfile/integration/include_headers_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ func testIncludeHeaders(platform switchblade.Platform, fixtures string) func(*te
2929
})
3030

3131
it.After(func() {
32-
Expect(platform.Delete.Execute(name)).To(Succeed())
32+
if t.Failed() && name != "" {
33+
t.Logf("❌ FAILED TEST - App/Container: %s", name)
34+
t.Logf(" Platform: %s", settings.Platform)
35+
}
36+
if name != "" && (!settings.KeepFailedContainers || !t.Failed()) {
37+
Expect(platform.Delete.Execute(name)).To(Succeed())
38+
}
3339
})
3440

3541
context("with a public folder", func() {

src/staticfile/integration/init_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,19 @@ var settings struct {
2424
Path string
2525
}
2626

27-
Cached bool
28-
Serial bool
29-
FixturesPath string
30-
GitHubToken string
31-
Platform string
32-
Stack string
27+
Cached bool
28+
Serial bool
29+
KeepFailedContainers bool
30+
FixturesPath string
31+
GitHubToken string
32+
Platform string
33+
Stack string
3334
}
3435

3536
func init() {
3637
flag.BoolVar(&settings.Cached, "cached", false, "run cached buildpack tests")
3738
flag.BoolVar(&settings.Serial, "serial", false, "run serial buildpack tests")
39+
flag.BoolVar(&settings.KeepFailedContainers, "keep-failed-containers", false, "preserve failed test containers for debugging")
3840
flag.StringVar(&settings.Platform, "platform", "cf", `switchblade platform to test against ("cf" or "docker")`)
3941
flag.StringVar(&settings.GitHubToken, "github-token", "", "use the token to make GitHub API requests")
4042
flag.StringVar(&settings.Stack, "stack", "cflinuxfs4", "stack to use as default when pusing apps")

src/staticfile/integration/multibuildpack_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ func testMultibuildpack(platform switchblade.Platform, fixtures string) func(*te
2727
})
2828

2929
it.After(func() {
30-
Expect(platform.Delete.Execute(name)).To(Succeed())
30+
if t.Failed() && name != "" {
31+
t.Logf("❌ FAILED TEST - App/Container: %s", name)
32+
t.Logf(" Platform: %s", settings.Platform)
33+
}
34+
if name != "" && (!settings.KeepFailedContainers || !t.Failed()) {
35+
Expect(platform.Delete.Execute(name)).To(Succeed())
36+
}
3137
})
3238

3339
it("finds the supplied dependency in the runtime container", func() {

0 commit comments

Comments
 (0)