Skip to content

Commit 6cd2ba7

Browse files
committed
test: add cross-stack E2E tests
1 parent 4b85ba0 commit 6cd2ba7

2 files changed

Lines changed: 124 additions & 0 deletions

File tree

stacks-test-e2e.sh

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env bash
2+
3+
# Run full e2e tests operating on the example/ directory
4+
5+
set_up() {
6+
cd example
7+
export MAKE="make -f ../stacks.mk ENV=dev-eu CLICOLOR_FORCE=0"
8+
}
9+
10+
tear_down() {
11+
$MAKE deepclean && rm -rf ../registry.opentofu.org
12+
}
13+
14+
test_plan_apply_refresh_destroy_clean() {
15+
# Run an initial full plan and apply to have a clean state
16+
output="$($MAKE plan)"
17+
assert_matches '\[network/vpc.*Plan.*0 to destroy' "$output"
18+
assert_matches '\[instances.*Plan.*0 to destroy' "$output"
19+
assert_matches '\[org.*Plan.*0 to destroy' "$output"
20+
output="$($MAKE plan)"
21+
assert_matches 'Nothing to be done for.*plan' "$output"
22+
touch instances/main.tf
23+
output="$($MAKE plan)"
24+
assert_not_matches '\[network/vpc' "$output"
25+
assert_matches '\[instances.*Plan.*0 to destroy' "$output"
26+
assert_not_matches '\[org' "$output"
27+
output=$($MAKE apply)
28+
assert_matches '\[network/vpc.*Apply complete' "$output"
29+
assert_matches '\[instances.*Apply complete' "$output"
30+
assert_matches '\[org.*Apply complete' "$output"
31+
output=$($MAKE refresh)
32+
assert_matches '\[network/vpc.*Outputs:' "$output"
33+
assert_matches '\[instances.*Outputs:' "$output"
34+
assert_matches '\[org.*Outputs:' "$output"
35+
output=$($MAKE plan)
36+
assert_matches '\[network/vpc.*No changes' "$output"
37+
assert_matches '\[instances.*No changes' "$output"
38+
assert_matches '\[org.*No changes' "$output"
39+
output=$($MAKE plan)
40+
assert_matches 'Nothing to be done for.*plan' "$output"
41+
output=$(TF_CLI_ARGS='-auto-approve' $MAKE destroy)
42+
assert_matches '\[network/vpc.*Destroy complete' "$output"
43+
assert_matches '\[instances.*Destroy complete' "$output"
44+
assert_matches '\[org.*Destroy complete' "$output"
45+
output=$($MAKE clean)
46+
assert_contains "network/vpc/$ENV" "$output"
47+
assert_contains "instances/$ENV" "$output"
48+
assert_contains "org/$ENV" "$output"
49+
50+
# cleanup
51+
rm .terraform.lock.hcl
52+
assert_empty "$(git status --porcelain -- .)"
53+
}
54+
55+
test_plan_changed() {
56+
# Run an initial full plan and apply to have a clean state
57+
$MAKE plan >/dev/null 2>&1
58+
$MAKE apply >/dev/null 2>&1
59+
60+
# test dynamic skipping
61+
echo '# change' >> network/vpc/main.tf
62+
output=$($MAKE plan-changed DIFF_BASE=HEAD)
63+
assert_matches '\[network/vpc.*No changes' "$output"
64+
assert_matches 'Skip.*instances' "$output"
65+
assert_not_matches '\[org' "$output"
66+
# test downstream dependencies of changed stacks
67+
echo 'output "new" { value = 123 }' >> network/vpc/main.tf
68+
output=$($MAKE plan-changed DIFF_BASE=HEAD)
69+
assert_matches '\[network/vpc.*Plan.*0 to destroy' "$output"
70+
assert_matches '\[instances.*Plan.*0 to destroy' "$output"
71+
assert_not_matches '\[org.*Plan' "$output"
72+
output=$($MAKE apply-changed DIFF_BASE=HEAD)
73+
assert_matches '\[network/vpc.*Apply complete' "$output"
74+
assert_matches '\[instances.*Apply complete' "$output"
75+
assert_not_matches '\[org.*Apply' "$output"
76+
77+
# cleanup
78+
$MAKE clean >/dev/null 2>&1
79+
rm .terraform.lock.hcl
80+
git checkout network/vpc/main.tf
81+
assert_empty "$(git status --porcelain -- .)"
82+
}
83+
84+
test_failed_apply_stale_plan() {
85+
$MAKE plan >/dev/null 2>&1
86+
# break 'instances' main.tf to fail during apply
87+
echo -e 'resource "terraform_data" "fail" {\nprovisioner "local-exec" {\n command = "exit 1"\n}\n}' >> instances/main.tf
88+
output=$($MAKE plan)
89+
assert_not_matches '\[network/vpc' "$output"
90+
assert_matches '\[instances.*Plan.*0 to destroy' "$output"
91+
assert_not_matches '\[org' "$output"
92+
# The apply should fail
93+
! $MAKE apply >/dev/null 2>&1
94+
# plan should be stale and get replanned
95+
output=$($MAKE plan)
96+
assert_matches 'terraform_data.*fail.*is tainted' "$output"
97+
assert_matches '\[network/vpc.*No changes' "$output" # replans prerequisites
98+
assert_matches '\[instances.*Plan.*1 to destroy' "$output"
99+
assert_not_matches '\[org' "$output"
100+
101+
# cleanup
102+
$MAKE clean >/dev/null 2>&1
103+
rm .terraform.lock.hcl
104+
git checkout instances/main.tf
105+
assert_empty "$(git status --porcelain -- .)"
106+
}

stacks-test.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,21 @@ test_tfvars_precedence() {
5858
assert_contains '/network_2-dev-eu-.auto.tfvars: network/dev-eu.tfvars' "$output"
5959
}
6060

61+
62+
test_cross_stack_dependencies() {
63+
# Run the script to test cross-stack dependency extraction
64+
cd example/
65+
output=$(bash ../stacks-gen-deps.sh dev-eu 2 network/vpc instances network/vpc/main.tf instances/main.tf)
66+
67+
# Check for downstream/upstream mapping
68+
assert_contains 'DOWNSTREAMS_network/vpc += instances' "$output"
69+
assert_contains 'UPSTREAMS_instances += network/vpc' "$output"
70+
71+
# Check for plan and outputs dependencies
72+
assert_matches 'instances/[^/]+/tfplan.json: .*network/vpc/[^/]+/tfplan.json' "$output"
73+
assert_matches 'instances/[^/]+/outputs.json: .*network/vpc/[^/]+/outputs.json' "$output"
74+
75+
# Check for destroy and refresh dependencies
76+
assert_matches 'network/vpc/[^/]+/.destroy: destroy-instances' "$output"
77+
assert_matches 'instances/[^/]+/.refresh: refresh-network/vpc' "$output"
78+
}

0 commit comments

Comments
 (0)