Skip to content

Commit e3c4ced

Browse files
Integration tests parallelism - CI sharding (#213)
1 parent f9d80fd commit e3c4ced

3 files changed

Lines changed: 95 additions & 10 deletions

File tree

.github/workflows/ci.yml

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,26 @@ jobs:
8181
reporter: java-junit
8282

8383
test-integration:
84-
name: Integration Tests (${{ matrix.os }})
84+
name: Integration Tests (${{ matrix.os }}${{ matrix.shard && format(' shard {0}/{1}', matrix.shard, matrix.shard_total) || '' }})
8585
runs-on: ${{ matrix.os }}
8686
strategy:
8787
fail-fast: false
8888
matrix:
89-
os: [ubuntu-latest, macos-latest, windows-latest]
89+
include:
90+
- os: ubuntu-latest
91+
shard: 1
92+
shard_total: 4
93+
- os: ubuntu-latest
94+
shard: 2
95+
shard_total: 4
96+
- os: ubuntu-latest
97+
shard: 3
98+
shard_total: 4
99+
- os: ubuntu-latest
100+
shard: 4
101+
shard_total: 4
102+
- os: macos-latest
103+
- os: windows-latest
90104
steps:
91105
- name: Checkout code
92106
uses: actions/checkout@v6
@@ -112,22 +126,39 @@ jobs:
112126
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
113127
LSTK_TEST_HOMEBREW: ${{ matrix.os == 'macos-latest' && '1' || '0' }}
114128
LSTK_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
129+
SHARD_INDEX: ${{ matrix.shard }}
130+
SHARD_TOTAL: ${{ matrix.shard_total }}
115131

116132
- name: Upload test results
117133
uses: actions/upload-artifact@v7
118134
if: always()
119135
with:
120-
name: integration-test-results-${{ matrix.os }}
136+
name: integration-test-results-${{ matrix.os }}${{ matrix.shard && format('-{0}', matrix.shard) || '' }}
121137
path: test-integration-results.xml
122138

123139
- name: Test report
124140
uses: dorny/test-reporter@v3
125141
if: always()
126142
with:
127-
name: Integration Test Results (${{ matrix.os }})
143+
name: Integration Test Results (${{ matrix.os }}${{ matrix.shard && format(' shard {0}/{1}', matrix.shard, matrix.shard_total) || '' }})
128144
path: test-integration-results.xml
129145
reporter: java-junit
130146

147+
# Aggregator job under a stable name so branch ruleset can require a single
148+
# status check regardless of how many shards the integration matrix uses.
149+
test-integration-summary:
150+
name: Integration Tests (ubuntu-latest)
151+
runs-on: ubuntu-latest
152+
needs: test-integration
153+
if: always()
154+
steps:
155+
- name: Verify integration matrix succeeded
156+
run: |
157+
if [ "${{ needs.test-integration.result }}" != "success" ]; then
158+
echo "test-integration matrix result: ${{ needs.test-integration.result }}"
159+
exit 1
160+
fi
161+
131162
release:
132163
name: Build and Publish Release
133164
if: startsWith(github.ref, 'refs/tags/')

Makefile

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@ test:
2020
go run gotest.tools/gotestsum@latest --format testname $$JUNIT -- ./cmd/... ./internal/...
2121

2222
test-integration: $(BUILD_DIR)/$(BINARY_NAME)
23-
@JUNIT=""; [ -n "$$CREATE_JUNIT_REPORT" ] && JUNIT="--junitfile ../../test-integration-results.xml"; \
24-
if [ "$$(uname)" = "Darwin" ]; then \
25-
cd test/integration && LSTK_KEYRING=file go run gotest.tools/gotestsum@latest --format testname $$JUNIT -- -count=1 -timeout 15m $(if $(RUN),-run $(RUN)) ./...; \
26-
else \
27-
cd test/integration && go run gotest.tools/gotestsum@latest --format testname $$JUNIT -- -count=1 -timeout 15m $(if $(RUN),-run $(RUN)) ./...; \
28-
fi
23+
@RUN="$(RUN)" ./scripts/test-integration.sh
2924

3025
otel:
3126
docker compose -f docker-compose.tracing.yaml up -d

scripts/test-integration.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env bash
2+
# Run integration tests, optionally sharded across CI runners.
3+
#
4+
# Honors:
5+
# CREATE_JUNIT_REPORT Emit JUnit XML when set.
6+
# SHARD_INDEX 1-based shard index (used with SHARD_TOTAL).
7+
# SHARD_TOTAL Total number of shards. When set, this run executes
8+
# only the tests assigned to SHARD_INDEX (round-robin
9+
# partition by sorted test name).
10+
# RUN Override: pass directly to `go test -run`.
11+
#
12+
# Sharding is disabled when SHARD_TOTAL is unset or empty, so the script also
13+
# acts as a drop-in replacement for the unsharded `go test ./...` invocation.
14+
15+
set -euo pipefail
16+
17+
cd "$(dirname "$0")/../test/integration"
18+
19+
JUNIT_FLAG=()
20+
if [ -n "${CREATE_JUNIT_REPORT:-}" ]; then
21+
JUNIT_FLAG=(--junitfile ../../test-integration-results.xml)
22+
fi
23+
24+
if [ "$(uname)" = "Darwin" ]; then
25+
export LSTK_KEYRING=file
26+
fi
27+
28+
RUN_FLAG=()
29+
if [ -n "${SHARD_TOTAL:-}" ]; then
30+
IDX="${SHARD_INDEX:-1}"
31+
# `go test -list` enumerates top-level tests in each package. Run it as a
32+
# standalone step (no stderr suppression) so compile errors surface loudly
33+
# under `set -e` instead of being swallowed into an empty test list. The
34+
# subsequent `go test -run` reuses the compiled test binary from Go's build
35+
# cache, so this isn't a duplicate compile.
36+
LIST_OUTPUT=$(go test -list '.*' ./...)
37+
# Filter to lines matching /^Test/ to drop the trailing "ok pkg" summary
38+
# lines, sort for stable partitioning, and pick every N-th entry.
39+
# SHARD_INDEX is 1-based for human-friendly CI labels (shard 1/4, 2/4, ...).
40+
TESTS=$(echo "$LIST_OUTPUT" | awk '/^Test/' | sort \
41+
| awk -v idx="$IDX" -v total="$SHARD_TOTAL" '((NR-1) % total) + 1 == idx')
42+
if [ -z "$TESTS" ]; then
43+
echo "no tests for shard $IDX/$SHARD_TOTAL — skipping"
44+
exit 0
45+
fi
46+
REGEX="^($(echo "$TESTS" | paste -sd '|' -))\$"
47+
RUN_FLAG=(-run "$REGEX")
48+
elif [ -n "${RUN:-}" ]; then
49+
RUN_FLAG=(-run "$RUN")
50+
fi
51+
52+
# Bash 3 (macOS default) treats `${arr[@]}` on an empty array as unbound under
53+
# `set -u`. The `${arr[@]+"${arr[@]}"}` idiom expands to nothing when the
54+
# array is empty and to the array's contents otherwise.
55+
exec go run gotest.tools/gotestsum@latest --format testname \
56+
${JUNIT_FLAG[@]+"${JUNIT_FLAG[@]}"} \
57+
-- -count=1 -timeout 15m \
58+
${RUN_FLAG[@]+"${RUN_FLAG[@]}"} \
59+
./...

0 commit comments

Comments
 (0)