Skip to content

Commit 339adea

Browse files
committed
chore: Comprehensive randomized fuzzy mutation testing
It's such a shame that we keep commiting regressions that are leading ot the missed events from the file watcher. I want to minimize this to 0.
1 parent c16de19 commit 339adea

12 files changed

Lines changed: 1972 additions & 103 deletions

File tree

.github/workflows/rust.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,76 @@ jobs:
3939
- name: Run tests
4040
run: cargo test --features zlob --workspace --exclude fff-nvim
4141

42+
stress-test:
43+
name: Stress Test (Watcher + Git)
44+
# Cross-platform: macOS uses FSEvents, Ubuntu uses inotify — different
45+
# backends with different debouncer quirks and race windows, so
46+
# running the same fuzz suite on both is the whole point. A job
47+
# failure on either platform fails the CI gate.
48+
#
49+
# Matches the `test` job matrix above; Windows is not exercised
50+
# anywhere else in CI, so wiring it up here would be asymmetric and
51+
# would surface `ReadDirectoryChangesW`-specific noise without a
52+
# corresponding signal. Add it when the rest of CI does.
53+
runs-on: ${{ matrix.os }}
54+
strategy:
55+
# Keep going after one OS fails so we can see whether a bug
56+
# reproduces everywhere or is platform-specific.
57+
fail-fast: false
58+
matrix:
59+
os: [ubuntu-latest, macos-latest]
60+
# Long-running; don't let a stuck watcher thread burn a full CI
61+
# timeout. Two scenarios should finish well under this limit.
62+
timeout-minutes: 20
63+
steps:
64+
- uses: actions/checkout@v5
65+
66+
- name: Install Zig
67+
uses: goto-bus-stop/setup-zig@v2
68+
with:
69+
version: 0.16.0
70+
71+
- name: Install Rust
72+
uses: actions-rust-lang/setup-rust-toolchain@v1.15.4
73+
with:
74+
cache: true
75+
cache-on-failure: true
76+
cache-key: "v1-rust-stress-${{ matrix.os }}"
77+
components: rustfmt, clippy
78+
79+
# Run 1: deterministic. Pins a regression surface that must not
80+
# regress between builds. Seed is hard-coded in the Makefile; if
81+
# you need to replay a different seed locally, prefix with
82+
# `FFF_STRESS_SEED=<u64|0xHEX>`.
83+
- name: Stress test (seeded / deterministic)
84+
shell: bash
85+
run: make test-stress-seeded
86+
env:
87+
FFF_STRESS_CASES: "3"
88+
FFF_STRESS_MIN_OPS: "30"
89+
FFF_STRESS_MAX_OPS: "50"
90+
91+
# Run 2: random. Every CI build explores a fresh slice of the op
92+
# space. If this ever goes red, proptest persists the failing seed
93+
# to `crates/fff-core/tests/fuzz_git_watcher_stress.proptest-regressions`;
94+
# that file gets uploaded as an artifact so the failure is
95+
# reproducible locally.
96+
- name: Stress test (random / proptest)
97+
shell: bash
98+
run: make test-stress-random
99+
env:
100+
FFF_STRESS_CASES: "5"
101+
FFF_STRESS_MIN_OPS: "30"
102+
FFF_STRESS_MAX_OPS: "60"
103+
104+
- name: Upload proptest regressions on failure
105+
if: failure()
106+
uses: actions/upload-artifact@v4
107+
with:
108+
name: proptest-regressions-${{ matrix.os }}
109+
path: crates/fff-core/tests/fuzz_git_watcher_stress.proptest-regressions
110+
if-no-files-found: ignore
111+
42112
fmt:
43113
name: cargo fmt
44114
runs-on: ubuntu-latest

Cargo.lock

Lines changed: 91 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@ PREFIX ?= /usr/local
44
LIBDIR ?= $(PREFIX)/lib
55
INCLUDEDIR ?= $(PREFIX)/include
66

7-
.PHONY: build build-c-lib install uninstall test test-rust test-lua test-version test-bun test-node prepare-bun prepare-node set-npm-version header
7+
# Compile-time cfg that gates the watcher + git-status fuzz stress test.
8+
# Always set on `test-stress*` targets via RUSTFLAGS.
9+
STRESS_RUSTFLAGS := --cfg stress
10+
11+
# Pinned seed for the deterministic stress run. Changing this value is
12+
# equivalent to picking a new regression surface, so keep it stable —
13+
# that's the whole point. Override ad-hoc on the command line via
14+
# `FFF_STRESS_SEED=<u64|0xhex> make test-stress-seeded`.
15+
FFF_STRESS_DEFAULT_SEED ?= 0xDEADBEEFCAFEBABE
16+
17+
.PHONY: build build-c-lib install uninstall test test-rust test-lua test-version test-bun test-node prepare-bun prepare-node set-npm-version header test-stress test-stress-seeded test-stress-random
818

919
all: format test lint
1020

@@ -85,6 +95,26 @@ test-node: prepare-node
8595

8696
test: test-rust test-lua test-version test-bun test-node
8797

98+
99+
test-stress-seeded:
100+
FFF_STRESS_SEED="$${FFF_STRESS_SEED:-$(FFF_STRESS_DEFAULT_SEED)}" \
101+
RUSTFLAGS="$(STRESS_RUSTFLAGS)" \
102+
cargo test \
103+
-p fff-search \
104+
--test fuzz_git_watcher_stress \
105+
--features zlob \
106+
-- --nocapture stress_seeded
107+
108+
test-stress-random:
109+
RUSTFLAGS="$(STRESS_RUSTFLAGS)" \
110+
cargo test \
111+
-p fff-search \
112+
--test fuzz_git_watcher_stress \
113+
--features zlob \
114+
-- --nocapture stress_random
115+
116+
test-stress: test-stress-seeded test-stress-random
117+
88118
# Update version in a package.json, including optionalDependencies.
89119
# Usage: make set-npm-version PKG=packages/fff-bun VERSION=1.0.0-nightly.abc1234
90120
set-npm-version:

crates/fff-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,6 @@ dunce = { workspace = true }
7979

8080
[dev-dependencies]
8181
criterion = { version = "0.5", features = ["html_reports"] }
82+
proptest = { version = "1", default-features = false, features = ["std", "fork"] }
8283
rand = { version = "0.8", features = ["small_rng"] }
8384
tempfile = "3.8"

crates/fff-core/benches/bigram_bench.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,7 @@ fn bench_bigram_build(c: &mut Criterion) {
127127
));
128128
s.push_str(" let parsed = ctx.parse()?;\n");
129129
s.push_str(" let validated = parsed.validate()?;\n");
130-
s.push_str(&format!(
131-
" ctx.respond(validated, {}).await\n"
132-
, j));
130+
s.push_str(&format!(" ctx.respond(validated, {}).await\n", j));
133131
s.push_str("}\n\n");
134132
}
135133
s

crates/fff-core/build.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
fn main() {
2+
// Opt-in cfg for the long-running randomized stress tests
3+
// used by tests/fuzz_git_watcher_stress.rs
4+
println!("cargo::rustc-check-cfg=cfg(stress)");
5+
6+
// When the `zlob` feature is enabled (Zig-compiled C library):
7+
// On Windows MSVC, explicitly link the C runtime libraries.
8+
// Zig-compiled static libraries don't emit /DEFAULTLIB directives for the
9+
// MSVC CRT, so symbols like strcmp, memcpy etc. would be unresolved.
210
if std::env::var("CARGO_FEATURE_ZLOB").is_ok() {
311
if !zig_available() {
412
panic!(

0 commit comments

Comments
 (0)