Skip to content

Commit d5d7a29

Browse files
chore: make smoketests faster via test.concurrent, no sharding, 800% workers (#773)
Co-authored-by: codeant-ai[bot] <151821869+codeant-ai[bot]@users.noreply.github.com>
1 parent 5997824 commit d5d7a29

20 files changed

Lines changed: 185 additions & 262 deletions

.github/workflows/sdk-coverage.yml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ jobs:
5353
5454
- name: Run smoke tests with coverage
5555
id: tests
56-
continue-on-error: true
5756
run: |
5857
set -o pipefail
59-
yarn test:objects-coverage 2>&1 | tee test-output.log
58+
yarn test:objects-coverage --maxWorkers=800% --color 2>&1 | \
59+
tee -i test-output.log
6060
6161
- name: Upload coverage report
6262
uses: runloopai/upload-artifact@main
@@ -73,7 +73,7 @@ jobs:
7373
script: |
7474
const fs = require('fs');
7575
const testsPassed = '${{ steps.tests.outcome }}' === 'success';
76-
const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
76+
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
7777
const COMMENT_MARKER = '<!-- sdk-coverage-report -->';
7878
7979
let lines = [COMMENT_MARKER];
@@ -197,8 +197,3 @@ jobs:
197197
});
198198
}
199199
200-
- name: Fail if tests failed
201-
if: steps.tests.outcome != 'success'
202-
run: |
203-
echo "Smoke tests failed. See PR comment for details."
204-
exit 1

.github/workflows/smoke-tests.yml

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ jobs:
2727
smoke-tests:
2828
runs-on: ubuntu-latest
2929
timeout-minutes: 60
30-
strategy:
31-
fail-fast: false
32-
matrix:
33-
shard: [1, 2, 3, 4]
3430
steps:
3531
- name: Checkout
3632
uses: runloopai/checkout@main
@@ -41,6 +37,7 @@ jobs:
4137
uses: runloopai/setup-node@main
4238
with:
4339
node-version: '20'
40+
cache: yarn
4441

4542
- name: Install dependencies
4643
run: yarn --frozen-lockfile
@@ -67,74 +64,5 @@ jobs:
6764
- name: Verify generated example artifacts
6865
run: yarn check:examples-md
6966

70-
- name: Run smoke tests (Shard ${{ matrix.shard }}/4)
71-
id: tests
72-
shell: python
73-
run: |
74-
from subprocess import Popen, PIPE
75-
import sys
76-
77-
proc = Popen(["yarn", "test:smoke", "--shard=${{ matrix.shard }}/4", "--color"], stderr=PIPE)
78-
zstd = Popen(["zstd", "-q", "-5", "-o", "smoke-tests-shard-${{ matrix.shard }}.zst"], stdin=PIPE)
79-
tee = Popen(["tee", "-i", "/dev/stderr"], stdin=proc.stderr, stdout=zstd.stdin)
80-
proc.stderr.close()
81-
sys.exit(proc.wait())
82-
83-
- name: Upload test output
84-
if: always()
85-
uses: runloopai/upload-artifact@main
86-
with:
87-
path: smoke-tests-shard-${{ matrix.shard }}.zst
88-
if-no-files-found: error
89-
retention-days: 1
90-
archive: false
91-
92-
smoke-tests-results:
93-
runs-on: ubuntu-slim
94-
needs: smoke-tests
95-
if: always()
96-
steps:
97-
- name: Download all test output artifacts
98-
uses: runloopai/download-artifact@main
99-
with:
100-
pattern: smoke-tests-shard-*.zst
101-
path: all-output
102-
103-
- name: Decompress and display logs
104-
run: |
105-
# Decompress all files
106-
zstd -q --rm -d all-output/*/*.zst
107-
108-
BOLD=$'\033[1m'
109-
RESET=$'\033[22m'
110-
# Extract and display failed tests from each shard
111-
for output_file in all-output/*/*; do
112-
shard_name=$(basename "$output_file")
113-
# Check if this shard has failures
114-
if grep -q "FAIL\|✕" "$output_file" 2>/dev/null; then
115-
echo "$BOLD$shard_name had test failures$RESET"
116-
# Filter output to show only failures:
117-
# - Skip PASS suites entirely (from PASS to next FAIL or "Test Suites:")
118-
# - Within FAIL suites, skip individual passing tests (✓) but show failures (● and ✕)
119-
awk '
120-
{ line=$0; gsub(/\x1b\[[0-9;]*m/, "") }
121-
/^[[:space:]]*PASS[[:space:]]/ { in_pass_suite=1; in_fail_suite=0; next }
122-
/^[[:space:]]*FAIL[[:space:]]/ { in_pass_suite=0; in_fail_suite=1; print line; next }
123-
/^Test Suites:/ { in_pass_suite=0; in_fail_suite=0; print line; next }
124-
in_pass_suite { next }
125-
in_fail_suite && /^[[:space:]]*✓/ { next }
126-
in_fail_suite { print line; next }
127-
{ print line }
128-
' "$output_file"
129-
fi
130-
done
131-
132-
# Aggregate all output in a collapsed group
133-
echo "::group::Full output from all shards"
134-
for output_file in all-output/*/*; do
135-
shard_name=$(basename "$output_file")
136-
echo "$BOLD=== $shard_name ===$RESET"
137-
cat "$output_file"
138-
echo ""
139-
done
140-
echo "::endgroup::"
67+
- name: Run smoke tests
68+
run: yarn test:smoke --maxWorkers=800% --color

tests/smoketests/blueprints.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ describe('smoketest: blueprints', () => {
8686
(process.env['RUN_SMOKETESTS'] ? describe : describe.skip)('blueprint secrets', () => {
8787
const secretsBlueprintName = uniqueName('bp-secrets');
8888

89-
test(
89+
test.concurrent(
9090
'create blueprint with secret in Dockerfile and await build',
9191
async () => {
9292
let bpt: BlueprintView | undefined;

tests/smoketests/devboxes.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describe('smoketest: devboxes', () => {
88
* Test V2 tunnel functionality.
99
*/
1010
describe('devbox tunnels', () => {
11-
test(
11+
test.concurrent(
1212
'create devbox with tunnel in create params',
1313
async () => {
1414
let devbox: DevboxView | undefined;
@@ -39,7 +39,7 @@ describe('smoketest: devboxes', () => {
3939
SHORT_TIMEOUT,
4040
);
4141

42-
test(
42+
test.concurrent(
4343
'create devbox with authenticated tunnel in create params (deprecated polling path)',
4444
async () => {
4545
let devbox: DevboxView | undefined;
@@ -71,7 +71,7 @@ describe('smoketest: devboxes', () => {
7171
SHORT_TIMEOUT,
7272
);
7373

74-
test(
74+
test.concurrent(
7575
'create devbox then enable tunnel',
7676
async () => {
7777
let devbox: DevboxView | undefined;
@@ -110,7 +110,7 @@ describe('smoketest: devboxes', () => {
110110
SHORT_TIMEOUT,
111111
);
112112

113-
test(
113+
test.concurrent(
114114
'create devbox then enable authenticated tunnel',
115115
async () => {
116116
let devbox: DevboxView | undefined;
@@ -158,7 +158,7 @@ describe('smoketest: devboxes', () => {
158158
}
159159
});
160160

161-
test(
161+
test.concurrent(
162162
'create devbox',
163163
async () => {
164164
let devbox: DevboxView | undefined;
@@ -211,7 +211,7 @@ describe('smoketest: devboxes', () => {
211211
});
212212
});
213213

214-
test(
214+
test.concurrent(
215215
'createAndAwaitRunning long set up',
216216
async () => {
217217
// createAndAwaitRunning should poll until devbox is running
@@ -229,7 +229,7 @@ describe('smoketest: devboxes', () => {
229229
SHORT_TIMEOUT * 4,
230230
);
231231

232-
test(
232+
test.concurrent(
233233
'createAndAwaitRunning timeout (deprecated polling path)',
234234
async () => {
235235
await expect(

tests/smoketests/examples/examples.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ describe('smoketest: examples', () => {
77
for (const entry of exampleRegistry) {
88
const hasRequiredEnv = entry.requiredEnv.every((name) => Boolean(process.env[name]));
99
const runLiveExample = hasLiveFlag && hasRequiredEnv;
10-
const itLive = runLiveExample ? test : test.skip;
10+
const itLive = runLiveExample ? test.concurrent : test.concurrent.skip;
1111

1212
itLive(
1313
`${entry.slug} example runs with successful checks and cleanup`,

tests/smoketests/object-oriented/agent.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const runloop = makeClientSDK();
55

66
describe('smoketest: object-oriented agent', () => {
77
describe('agent lifecycle', () => {
8-
test(
8+
test.concurrent(
99
'create agent basic',
1010
async () => {
1111
const name = uniqueName('sdk-agent-test-basic');
@@ -37,7 +37,7 @@ describe('smoketest: object-oriented agent', () => {
3737
SHORT_TIMEOUT,
3838
);
3939

40-
test(
40+
test.concurrent(
4141
'get agent info',
4242
async () => {
4343
const name = uniqueName('sdk-agent-test-info');
@@ -68,7 +68,7 @@ describe('smoketest: object-oriented agent', () => {
6868
});
6969

7070
describe('agent listing', () => {
71-
test(
71+
test.concurrent(
7272
'list agents',
7373
async () => {
7474
const agents = await runloop.agent.list({ limit: 10 });
@@ -80,7 +80,7 @@ describe('smoketest: object-oriented agent', () => {
8080
SHORT_TIMEOUT,
8181
);
8282

83-
test(
83+
test.concurrent(
8484
'get agent by ID',
8585
async () => {
8686
// Create an agent
@@ -110,7 +110,7 @@ describe('smoketest: object-oriented agent', () => {
110110
SHORT_TIMEOUT,
111111
);
112112

113-
test(
113+
test.concurrent(
114114
'list multiple agents',
115115
async () => {
116116
const sourceConfig = {
@@ -159,7 +159,7 @@ describe('smoketest: object-oriented agent', () => {
159159
});
160160

161161
describe('agent creation variations', () => {
162-
test(
162+
test.concurrent(
163163
'agent with source npm',
164164
async () => {
165165
const name = uniqueName('sdk-agent-test-npm');
@@ -188,7 +188,7 @@ describe('smoketest: object-oriented agent', () => {
188188
SHORT_TIMEOUT,
189189
);
190190

191-
test(
191+
test.concurrent(
192192
'agent with source git',
193193
async () => {
194194
const name = uniqueName('sdk-agent-test-git');
@@ -220,7 +220,7 @@ describe('smoketest: object-oriented agent', () => {
220220
});
221221

222222
describe('agent convenience methods', () => {
223-
test(
223+
test.concurrent(
224224
'createFromNpm',
225225
async () => {
226226
const name = uniqueName('sdk-agent-from-npm');
@@ -243,7 +243,7 @@ describe('smoketest: object-oriented agent', () => {
243243
SHORT_TIMEOUT,
244244
);
245245

246-
test(
246+
test.concurrent(
247247
'createFromPip',
248248
async () => {
249249
const name = uniqueName('sdk-agent-from-pip');
@@ -266,7 +266,7 @@ describe('smoketest: object-oriented agent', () => {
266266
SHORT_TIMEOUT,
267267
);
268268

269-
test(
269+
test.concurrent(
270270
'createFromGit',
271271
async () => {
272272
const name = uniqueName('sdk-agent-from-git');
@@ -290,7 +290,7 @@ describe('smoketest: object-oriented agent', () => {
290290
SHORT_TIMEOUT,
291291
);
292292

293-
test(
293+
test.concurrent(
294294
'createFromObject with storage object',
295295
async () => {
296296
let storageObject: StorageObject | undefined;
@@ -332,7 +332,7 @@ describe('smoketest: object-oriented agent', () => {
332332
});
333333

334334
describe('agent with devbox mounting', () => {
335-
test(
335+
test.concurrent(
336336
'mount agent from storage object into devbox',
337337
async () => {
338338
let storageObject: StorageObject | undefined;

0 commit comments

Comments
 (0)