@@ -149,14 +149,181 @@ commands:
149149 - checkout
150150 - setup_environment :
151151 cache_key : v4.2.0-rust-1.88.0-<< parameters.workspace_member >><< parameters.cache_key_suffix >>-cache
152+
153+ - run :
154+ name : Install cargo-nextest
155+ command : |
156+ cargo install cargo-nextest --locked || true
157+
152158 - run :
153159 name : " Run Tests"
154160 timeout : << parameters.timeout >>
155161 no_output_timeout : << parameters.no_output_timeout >>
156- command : RUST_MIN_STACK=67108864 cargo test --package=<< parameters.workspace_member >> << parameters.flags >>
162+ command : |
163+ set -euo pipefail
164+ export CARGO_TERM_COLOR=never
165+
166+ # Create artifact + nextest output directories
167+ mkdir -p artifacts target/nextest/ci
168+
169+ # Create artifact + nextest output directories
170+ OUT="artifacts/<< parameters.workspace_member >>-nextest.txt"
171+ CSV="artifacts/<< parameters.workspace_member >>-test-times.csv"
172+ TOP="artifacts/<< parameters.workspace_member >>-slow-tests-top30.csv"
173+ JUNIT="target/nextest/ci/junit.xml"
174+
175+ # Extract and trim flags from parameters
176+ FLAGS_FULL="<< parameters.flags >>"
177+ FLAGS_TRIM="$(printf '%s' "$FLAGS_FULL" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
178+
179+ # Split flags into cargo build flags (before --) and libtest args (after --)
180+ RIGHT_OF_SEP=""
181+ if printf '%s' "$FLAGS_TRIM" | grep -q ' -- '; then
182+ BUILD_FLAGS="${FLAGS_TRIM%% -- *}"
183+ RIGHT_OF_SEP="${FLAGS_TRIM#* -- }"
184+ elif printf '%s' "$FLAGS_TRIM" | grep -Eq '^--[[:space:]]'; then
185+ BUILD_FLAGS=""
186+ RIGHT_OF_SEP="${FLAGS_TRIM#-- }"
187+ else
188+ BUILD_FLAGS="$FLAGS_TRIM"
189+ fi
190+
191+ # Remove any --test target flags,they cause nextest build errors
192+ BUILD_FLAGS_SANITIZED="$(printf '%s' "$BUILD_FLAGS" \
193+ | sed -E "s/(^|[[:space:]])--test[[:space:]]+'[^']*'([[:space:]]|$)/ /g" \
194+ | sed -E 's/(^|[[:space:]])--test[[:space:]]+\"[^\"]*\"([[:space:]]|$)/ /g' \
195+ | sed -E 's/(^|[[:space:]])--test[[:space:]]+[^[:space:]]+([[:space:]]|$)/ /g' \
196+ | tr -s ' ' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' \
197+ )"
198+
199+ # Detect wildcard integration selection: `--test '*'` (with or without quotes)
200+ HAS_TEST_WILDCARD=0
201+ if printf '%s\n' "$BUILD_FLAGS" | grep -Eq -- '--test[[:space:]]+("\*"|'\''\*'\''|\*)'; then
202+ HAS_TEST_WILDCARD=1
203+ fi
204+
205+ # Build nextest filter expression from any --skip <pattern> arguments
206+ FILTER_EXPR=""
207+
208+ WSM="<< parameters.workspace_member >>"
209+ if [ "$WSM" = "snarkvm-synthesizer" ] && [ "$HAS_TEST_WILDCARD" -eq 1 ]; then
210+ FILTER_EXPR='test(/test_command_parse/)+test(/test_instruction_parse/)+test(/test_process_execute/)+test(/test_program_parse/)+test(/test_vm_execute_and_finalize/)'
211+ fi
212+
213+ # Build nextest filter expression from any --skip <pattern> arguments
214+ if [ -z "$FILTER_EXPR" ] && [ -n "$RIGHT_OF_SEP" ]; then
215+ SKIPS="$(printf '%s\n' "$RIGHT_OF_SEP" \
216+ | sed -E 's/[[:space:]]+/ /g' \
217+ | grep -oE -- '--skip[[:space:]]+(\"[^\"]+\"|'\''[^'\'']+'\''|[^[:space:]]+)' || true)"
218+ if [ -n "$SKIPS" ]; then
219+ EXPRS=""
220+ tmpf="$(mktemp)"
221+ printf '%s\n' "$SKIPS" > "$tmpf"
222+ while IFS= read -r line; do
223+ pat="${line#--skip }"
224+ pat="${pat%\"}"; pat="${pat#\"}"
225+ pat="${pat%\'}"; pat="${pat#\'}"
226+ pat_rx="${pat//\//\\/}" # escape forward slashes for regex
227+ if [ -z "$EXPRS" ]; then
228+ EXPRS="test(/$pat_rx/)"
229+ else
230+ EXPRS="$EXPRS or test(/$pat_rx/)"
231+ fi
232+ done < "$tmpf"
233+ rm -f "$tmpf"
234+ if [ -n "$EXPRS" ]; then
235+ FILTER_EXPR="not ($EXPRS)"
236+ fi
237+ fi
238+ fi
239+
240+ # Detect and extract --test-threads value (used to set JOBS)
241+ TEST_THREADS=""
242+ if [ -n "$RIGHT_OF_SEP" ]; then
243+ # form: --test-threads=8
244+ TEST_THREADS="$(printf '%s\n' "$RIGHT_OF_SEP" | sed -nE 's/.*--test-threads=([0-9]+).*/\1/p' | head -n1)"
245+ if [ -z "$TEST_THREADS" ]; then
246+ # form: --test-threads 8
247+ TEST_THREADS="$(printf '%s\n' "$RIGHT_OF_SEP" | sed -nE 's/.*--test-threads[[:space:]]+([0-9]+).*/\1/p' | head -n1)"
248+ fi
249+ fi
250+
251+ DEFAULT_JOBS=12
252+
253+ # Default JOBS, overridden by TEST_THREADS if set
254+ JOBS="${NEXTEST_JOBS:-$DEFAULT_JOBS}"
255+ if [ -n "$TEST_THREADS" ]; then
256+ JOBS="$TEST_THREADS"
257+ fi
258+
259+ # Create nextest config (disable fail-fast, add slow-timeout + JUnit output)
260+ SLOW_PERIOD="${NEXTEST_SLOW_PERIOD:-60s}"
261+ CFG_ARGS=()
262+ TMPD="$(mktemp -d)"
263+ if [ -f ".config/nextest.toml" ]; then
264+ CFG_ARGS+=(--config-file ".config/nextest.toml")
265+ fi
266+ {
267+ printf '%s\n' '[profile.ci]'
268+ printf '%s\n' 'fail-fast = false'
269+ printf '%s\n' "slow-timeout = \"${SLOW_PERIOD}\""
270+ printf '%s\n' ''
271+ printf '%s\n' '[profile.ci.junit]'
272+ printf '%s\n' 'path = "junit.xml"'
273+ } > "$TMPD/nextest-override.toml"
274+ CFG_ARGS+=(--config-file "$TMPD/nextest-override.toml")
275+
276+ # Print configuration summary for debugging
277+ echo "==> nextest package: << parameters.workspace_member >>"
278+ echo "==> build flags (sanitized): '${BUILD_FLAGS_SANITIZED}'"
279+ echo "==> filter-expr: ${FILTER_EXPR:-<none>} (right-of-sep: ${RIGHT_OF_SEP:-<none>})"
280+ echo "==> test-threads override: ${TEST_THREADS:-<none>}"
281+ echo "==> jobs: ${JOBS}"
282+
283+ # Use plain cargo test if --no-run was requested
284+ # Otherwise, run tests with cargo nextest
285+ if printf '%s' " $BUILD_FLAGS_SANITIZED " | grep -q ' --no-run '; then
286+ RUST_MIN_STACK=67108864 cargo test --package="<< parameters.workspace_member >>" $BUILD_FLAGS_SANITIZED | tee "$OUT"
287+ : > "$CSV"; : > "$TOP"
288+ else
289+ RUST_MIN_STACK=67108864 cargo nextest run \
290+ -p "<< parameters.workspace_member >>" $BUILD_FLAGS_SANITIZED \
291+ --profile ci -j "${JOBS}" "${CFG_ARGS[@]}" \
292+ --status-level fail --hide-progress-bar \
293+ --no-tests=pass \
294+ ${FILTER_EXPR:+--filter-expr "$FILTER_EXPR"} \
295+ 2>&1 | tee "$OUT"
296+
297+ # Parse junit.xml to extract test timings
298+ if [ -f "$JUNIT" ]; then
299+ awk -v RS='<testcase ' '
300+ NR>1 {
301+ name=""; classname=""; time="";
302+ start=index($0,"classname=\""); if(start>0){ start+=11; rest=substr($0,start); end=index(rest,"\""); if(end>0) classname=substr(rest,1,end-1) }
303+ start=index($0,"name=\""); if(start>0){ start+=6; rest=substr($0,start); end=index(rest,"\""); if(end>0) name=substr(rest,1,end-1) }
304+ start=index($0,"time=\""); if(start>0){ start+=6; rest=substr($0,start); end=index(rest,"\""); if(end>0) time=substr(rest,1,end-1) }
305+ if(name!="" && time!=""){ full=(classname!=""?classname"::"name:name); printf "%s,%s\n", full, time }
306+ }
307+ ' "$JUNIT" > "$CSV" || true
308+
309+ # Sort and store top 30 slowest tests
310+ sort -t, -k2,2nr "$CSV" | head -n 30 > "$TOP" || true
311+ else
312+ echo "WARN: $JUNIT not found; no timings extracted." >&2
313+ : > "$CSV"; : > "$TOP"
314+ fi
315+ fi
316+
317+ - store_artifacts :
318+ path : artifacts
319+ destination : test-timings/<< parameters.workspace_member >>
320+ - store_test_results :
321+ path : target/nextest/ci
322+
157323 - clear_environment :
158324 cache_key : v4.2.0-rust-1.88.0-<< parameters.workspace_member >><< parameters.cache_key_suffix >>-cache
159325
326+
160327 install_rust_nightly :
161328 description : " Install Rust nightly toolchain"
162329 steps :
@@ -439,14 +606,25 @@ jobs:
439606 - run_test :
440607 workspace_member : snarkvm-ledger
441608
442- ledger-with-rocksdb :
609+ ledger-with-rocksdb-partition1 :
443610 executor : rust-docker
444611 resource_class : << pipeline.parameters.large >>
445612 steps :
446613 - run_test :
447614 workspace_member : snarkvm-ledger
448- flags : --release --features=rocks -- --test-threads=2
449- timeout : 20m
615+ flags : --release --features=rocks --partition count:1/2 -- --test-threads=8
616+ no_output_timeout : 20m
617+ timeout : 30m
618+
619+ ledger-with-rocksdb-partition2 :
620+ executor : rust-docker
621+ resource_class : << pipeline.parameters.large >>
622+ steps :
623+ - run_test :
624+ workspace_member : snarkvm-ledger
625+ flags : --release --features=rocks --partition count:2/2 -- --test-threads=8
626+ no_output_timeout : 20m
627+ timeout : 30m
450628
451629 ledger-with-valid-solutions :
452630 executor : rust-docker
@@ -470,6 +648,8 @@ jobs:
470648 steps :
471649 - run_test :
472650 workspace_member : snarkvm-ledger-block
651+ no_output_timeout : 20m
652+ timeout : 30m
473653
474654 ledger-committee :
475655 executor : rust-docker
@@ -593,24 +773,44 @@ jobs:
593773 workspace_member : snarkvm-parameters
594774 flags : -- --test-threads=2 --ignored test_load_bytes_mini
595775 cache_key_suffix : -v-{{ epoch }}
776+ no_output_timeout : 20m
777+ timeout : 30m
596778
597779 synthesizer :
598780 executor : rust-docker
599781 resource_class : << pipeline.parameters.twoxlarge >>
600782 steps :
601783 - run_test :
602784 workspace_member : snarkvm-synthesizer
603- flags : --lib --bins
604- timeout : 20m
785+ flags : --lib --bins -- --test-threads 16
786+ no_output_timeout : 20m
787+ timeout : 30m
605788
606- synthesizer-test :
789+ synthesizer-test-partition1 :
607790 executor : rust-docker
608791 resource_class : << pipeline.parameters.twoxlarge >>
609792 steps :
610793 - run_test :
611794 workspace_member : snarkvm-synthesizer
612- flags : --lib --bins --features test
613- cache_key_suffix : -test
795+ # nextest args before `--`, libtest args after `--`
796+ flags : >
797+ --lib --bins --features test
798+ --partition count:1/2
799+ -- --test-threads 16
800+ cache_key_suffix : -test1
801+ timeout : 25m
802+
803+ synthesizer-test-partition2 :
804+ executor : rust-docker
805+ resource_class : << pipeline.parameters.twoxlarge >>
806+ steps :
807+ - run_test :
808+ workspace_member : snarkvm-synthesizer
809+ flags : >
810+ --lib --bins --features test
811+ --partition count:2/2
812+ -- --test-threads 16
813+ cache_key_suffix : -test2
614814 timeout : 25m
615815
616816# synthesizer-mem-heavy:
@@ -631,7 +831,7 @@ jobs:
631831 # test_vm_execute_and_finalize can take over 10 minutes in the current setup
632832 no_output_timeout : 20m
633833 workspace_member : snarkvm-synthesizer
634- flags : --test '*' --features test -- --test-threads=4
834+ flags : --test '*' --features test -- --test-threads=4
635835 cache_key_suffix : -integration
636836
637837 synthesizer-process :
@@ -640,15 +840,14 @@ jobs:
640840 steps :
641841 - run_test :
642842 workspace_member : snarkvm-synthesizer-process
643- flags : -- --test-threads=8
644843
645844 synthesizer-process-with-rocksdb :
646845 executor : rust-docker
647846 resource_class : << pipeline.parameters.xlarge >>
648847 steps :
649848 - run_test :
650849 workspace_member : snarkvm-synthesizer-process
651- flags : --features=rocks
850+ flags : --features=rocks -- --test-threads=4
652851 cache_key_suffix : -with-rocksdb
653852
654853 synthesizer-program :
@@ -665,7 +864,7 @@ jobs:
665864 steps :
666865 - run_test :
667866 workspace_member : snarkvm-synthesizer-program
668- flags : -- --skip keccak --skip psd --skip sha --skip instruction::is --skip instruction::equal --skip instruction::commit
867+ flags : -- --skip keccak --skip psd --skip sha --skip instruction::is --skip instruction::equal --skip instruction::commit --test-threads=8
669868 cache_key_suffix : -integration
670869
671870 synthesizer-program-integration-keccak :
@@ -935,7 +1134,8 @@ workflows:
9351134 ledger-workflow :
9361135 jobs :
9371136 - ledger
938- - ledger-with-rocksdb
1137+ - ledger-with-rocksdb-partition1
1138+ - ledger-with-rocksdb-partition2
9391139 - ledger-with-valid-solutions
9401140 - ledger-authority
9411141 - ledger-block
@@ -956,7 +1156,8 @@ workflows:
9561156 synthesizer-workflow :
9571157 jobs :
9581158 - synthesizer
959- - synthesizer-test
1159+ - synthesizer-test-partition1
1160+ - synthesizer-test-partition2
9601161 # - synthesizer-mem-heavy
9611162 - synthesizer-integration
9621163 - synthesizer-process
0 commit comments