feat: add timeouts to fuzz testing#9394
Conversation
Adds --fuzz-timeout-secs to fuzz tests which will cause a property test to timeout after a certain number of seconds. Also adds --fuzz-allow-timeouts so that timeouts are optionally not considered to be failures.
|
Thank you! Supportive for such, let's have this
[fuzz]
timeout=60which would be applied to all fuzz tests (I don't think the allow time is needed, just consider that if
/// forge-config: default.fuzz.timeout=60
function test_function_with_timeout(uint256 x) public {...}
Same configs could be applied for invariants too, e.g. [invariant]
timeout=60and /// forge-config: default.invariant.timeout=60Lmk if you have issues implementing these, can provide more details / help with |
|
@grandizzy cool, will start making these changes! Regarding allowing timeouts, it might be worth considering that some people may want some way to detect that a fuzz run took too long and timed out. For now I would just allow timeouts by default and if someone asks for the feature we can add |
23c9395 to
b2a5f8d
Compare
|
Ok @grandizzy went ahead and made various changes. Please note the change to use |
the problem with /// forge-config: default.fuzz.runs = 4294967295
/// forge-config: default.fuzz.timeout = 60
function testFuzz_SetNumber(uint256 x) public {the test still loops / consume cpu cycles for way more than 1 minute and don't think that's desired |
Ah yeah you're right, ok, will fix! |
75b81e0 to
b704851
Compare
|
@grandizzy I'm back to failing for timeouts, thanks for the tip there. I believe the PR works as-is, not exactly sure where I should be adding tests but happy to do so if you could point me to the test file I should modify! |
Awesome, could you please make sure are passing, CI is failing now. Re tests, let's add one similar with foundry/crates/forge/tests/it/fuzz.rs Lines 213 to 215 in 31dd1f7 that set inline config for a big number of runs and a timeout of 5 seconds and we assert test is passing. you can test it as |
grandizzy
left a comment
There was a problem hiding this comment.
Last nit re invariant impl, let's fix clippy and format too
grandizzy
left a comment
There was a problem hiding this comment.
lgtm, thank you! I made couple of changes as
- move logic to interrupt invariant test in depth loop
- add and reuse start_timer fn and TEST_TIMEOUT constant
- add fuzz and invariant tests
- fix failing test
Pending other reviews before merging
|
@grandizzy sweet! Let me know if I can help in any way. Thanks for all your review here, very much appreciated 🙏 |
| if let Some((start_time, timeout)) = start_time { | ||
| if start_time.elapsed() > timeout { |
There was a problem hiding this comment.
I guess since this is opt-in, checking via elapsed for now is fine, and we can track improvements separately, but I'd suggest to wrap this if let Some into a helper type like Timeout(Option<Instant>) and an is_timed_out then this becomes easier to change
ac33250 to
da87095
Compare
* feat: add timeouts to fuzz testing Adds --fuzz-timeout-secs to fuzz tests which will cause a property test to timeout after a certain number of seconds. Also adds --fuzz-allow-timeouts so that timeouts are optionally not considered to be failures. * simplify timeout implementation * use u32 for timeout * switch back to failing for timeouts * clippy * Nits: - move logic to interrupt invariant test in depth loop - add and reuse start_timer fn and TEST_TIMEOUT constant - add fuzz and invariant tests - fix failing test * Fix fmt * Changes after review: introduce FuzzTestTimer --------- Co-authored-by: grandizzy <grandizzy.the.egg@gmail.com>
Adds
--fuzz-timeout-secsto fuzz tests which will cause a property test to timeout after a certain number of seconds. Also adds--fuzz-allow-timeoutsso that timeouts are optionally not considered to be failures.First time writing Rust so I have no idea if this is the idiomatic way of doing things, happy to change anything based on suggestions! Would also be great to understand where the best place is to add tests for this sort of PR.
Keeping this as a draft for now. I want to add support for the same feature within invariant tests but I couldn't easily understand how
FOUNDRY_INVARIANT_RUNSactually gets parsed from the environment. ApparentlyFOUNDRY_INVARIANT_RUNScan't be set in the CLI (there's no--invariant-runsflag). Any pointers here would be much appreciated.This is sketch for #9393