Files
fips/.config/nextest.toml
Johnathan Corgan 78956e869b Serialize only the node tests that need it under nextest
Every node::tests:: test ran in one one-at-a-time group, because the
synthetic-mesh tests once dropped one-shot UDP handshakes under load. The
default test node has since moved to the in-process loopback transport, so
most node tests touch no socket, yet the group still put about 13 minutes
of serialized tests on each GitHub unit-test job.

Split the group in two. node-synthetic now holds only the test modules
that open a real socket (a UDP, TCP, Ethernet or BLE transport, an OS
socket, or a node's start() or rx loop, which bind through its Config and
include the control socket's shared default path), directly or through a
helper. node-large holds the tests that take lock_large_network_test(), the
100-node tests, so they stay mutually exclusive across processes; its
override comes first in both profiles so the 100-node session test, which
sits in a socket module, lands there.

The filters are anchored and package-scoped. The old substring filter also
caught fifteen config::node::tests:: tests. The module list is the union
of what maint, master and next need, so the file merges up unchanged; a
name a branch lacks matches nothing there.

Pin every install step to nextest 0.9.143 and require at least that version
in the config, so the filters are parsed the same way on every runner and a
local host with an older nextest fails loudly. 0.9.143 is the newest release
the pinned install-action carries, so no runner falls back to cargo-binstall.
2026-10-21 16:58:16 +00:00

79 lines
4.8 KiB
TOML

# The nextest version every GitHub runner installs, and the oldest a local host
# may run (`required` is a minimum). The install-action steps in
# .github/workflows/ci.yml pin exactly this version, the newest the pinned
# install-action ships, so no runner falls back to building or fetching another;
# testing/check-node-test-groups.py fails when the two differ.
nextest-version = { required = "0.9.143" }
[profile.ci]
junit = { path = "junit.xml" }
# Synthetic node tests build 250-edge meshes with one-shot UDP
# handshakes; on shared CI runners the localhost stack still drops the
# occasional msg1 under burst load even with the per-edge repair loop.
# Allow a retry rather than failing the whole CI run on a single
# dropped packet.
#
# Deliberately scoped to [profile.ci] and NOT applied locally, which makes
# the two gates disagree: the hosted runner retries a flaky test twice, the
# local sweep fails on the first failure. The asymmetry is intended and this
# is the record of why, since an undocumented one is indistinguishable from
# an oversight.
#
# It is here for shared-runner packet loss, a property of the hosted
# environment and not of the code. Applying it locally would suppress a real
# local flake, and a failure that only reproduces under load is a robustness
# bug to fix rather than to retry past. Keeping the local sweep strict is
# what makes it the sharper of the two gates.
#
# The cost, stated rather than hidden: a test that fails once and passes on
# retry is reported green here with no separate signal, so a genuine
# intermittent failure can be absorbed. If that starts mattering, the fix is
# to surface retried-but-passed tests, not to drop the retries.
retries = 2
# nextest runs each test in its own process, so an in-process Tokio mutex
# cannot keep two tests apart. These two groups do it instead, each running
# one test at a time; the two groups run alongside each other and alongside
# every other test.
#
# node-large the tests that take lock_large_network_test(): the
# 100-node tests, compute-bound and mutually exclusive.
# node-synthetic the node test modules that open a real socket (a UDP, TCP,
# Ethernet or BLE transport, an OS socket, or a node's
# start() or rx loop, which bind through its Config and
# include the control socket's shared default path). Under
# load the loopback stack can drop a lone one-shot msg1 when
# several such tests flood it at once.
#
# The other node tests use the in-process loopback transport and run in
# parallel. The node-large override comes first in both profiles: nextest
# takes the group from the first override that matches, so
# session::test_session_100_nodes, which sits in a socket module, stays in
# node-large.
#
# The module list is the union of what maint, master and next need; a name a
# branch lacks matches nothing there. testing/check-node-test-groups.py
# recomputes the membership from the source (ci-parity job and local CI's
# guards) and fails when a socket module or a lock holder is missing, so add a
# module here when it starts opening a socket. Filters stay in the one shape
# it parses: anchored, package-scoped, one alternation.
[test-groups]
node-large = { max-threads = 1 }
node-synthetic = { max-threads = 1 }
[[profile.default.overrides]]
filter = 'package(fips-mesh) & test(/^node::tests::(bloom::test_bloom_filter_convergence_100_nodes|discovery::test_discovery_100_nodes|routing::test_routing_reachability_100_nodes|routing::test_routing_source_only_coords_100_nodes|session::test_session_100_nodes|spanning_tree::test_spanning_tree_convergence_100_nodes)$/)'
test-group = 'node-large'
[[profile.default.overrides]]
filter = 'package(fips-mesh) & test(/^node::tests::(acl|app_tun|ble|bootstrap|claim_dials|claim_slots|connected_udp|control|decrypt_forged|dial_origin|establish_chartests|handshake|handshake_lines|lan_label|link_setup_diag|netmon|rx_stall|second_path_msg1|session|silent_backoff|silent_replay|tcp|udp_dns|unit|update_peers)::/)'
test-group = 'node-synthetic'
[[profile.ci.overrides]]
filter = 'package(fips-mesh) & test(/^node::tests::(bloom::test_bloom_filter_convergence_100_nodes|discovery::test_discovery_100_nodes|routing::test_routing_reachability_100_nodes|routing::test_routing_source_only_coords_100_nodes|session::test_session_100_nodes|spanning_tree::test_spanning_tree_convergence_100_nodes)$/)'
test-group = 'node-large'
[[profile.ci.overrides]]
filter = 'package(fips-mesh) & test(/^node::tests::(acl|app_tun|ble|bootstrap|claim_dials|claim_slots|connected_udp|control|decrypt_forged|dial_origin|establish_chartests|handshake|handshake_lines|lan_label|link_setup_diag|netmon|rx_stall|second_path_msg1|session|silent_backoff|silent_replay|tcp|udp_dns|unit|update_peers)::/)'
test-group = 'node-synthetic'