Skip to content

test: Add a shared framework for reproducible fuzz tests - #27048

Merged
2010YOUY01 merged 9 commits into
apache:mainfrom
2010YOUY01:fuzz-ut-framework
Nov 7, 2026
Merged

2010YOUY01 merged 9 commits into
apache:mainfrom
2010YOUY01:fuzz-ut-framework

Conversation

@2010YOUY01

@2010YOUY01 2010YOUY01 commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Important

Fork CI setup: For pull requests from a fork to main, enable workflows in your fork's Actions tab before you push.
See the fork CI setup guide.

Which issue does this PR close?

  • Closes #.

Rationale for this change

Fuzz tests should follow these conventions:

  • Time budgets are configurable: each test case takes several milliseconds, and
    the driver can run on a best-effort basis within a budget such as one minute.
  • Each test case can be reproduced from a seed.
  • The starting seed varies across runs to broaden coverage over time.

Most of the existing implementations don't follow all of these principles, or implemented it with unnecessary complexity:

  • Some individual fuzz unit tests take five minutes to run.
  • Some use environment variables for configuration.
  • Some use fixed seeds across runs.
  • Failures are hard to reproduce.

Refactoring to a shared trait can prevent these issues in the future.

This PR introduces a trait to enforce these conventions and migrates one fuzz unit test to use it. Other existing fuzzers remain available for later migration.

Demo

-- Runs all fuzzing UTs (now only 1 test refactored in this PR)
cargo xtask ci step test fuzz

What changes are included in this PR?

Read the key changes in the following order; the remaining changes are minor.

  1. FuzzTest in test-utils/src/fuzz.rs: a trait that ensures all fuzz tests
    follow the intended conventions.
  2. Suite in datafusion/fuzz/tests/fuzz.rs: a single entry point for all fuzz
    unit tests in DataFusion.
  3. SpillPoolFuzzer in datafusion/fuzz/tests/suites/spill_pool.rs: the first unit
    test migrated to the centralized FuzzTest trait and unified runner.
  4. Update CI to run this fuzz test suite separately.

The key API is introduced in step 1. After implementing several fuzz tests in datafusion, I came up with this design to capture their common patterns. I also asked Codex to check whether all existing fuzz tests can be migrated to this trait.

Step 2: using a unified test entry point make it easier to configure fuzzing time in the future. For example it's possible to deploy a long-running background fuzzing job.

What is the testing strategy for this PR?

Are there any user-facing changes?

let suites = [Suite::new(
&spill_pool,
RunConfig {
run_seed: Some(0),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the existing fuzz config, probably we can use rotating seed (timestamp), and time limit instead of 1000 cases.

@github-actions github-actions Bot added development-process Related to development process of DataFusion physical-plan Changes to the physical-plan crate labels Nov 3, 2026

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The basic idea looks pretty good to me -- thank you @2010YOUY01

What I don't understand is the new crate structure and then the need to partially expose some of the existing testing code from the physical expr crate

- name: Run fuzzers with more iterations
- name: Run fuzz tests
run: cargo xtask ci step test fuzz
# Migrate it to the above unified fuzz runner over time

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please file a ticket that explains the migration plan and has a checklist of tests to run and link it here? So we have the context in the future?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, done in e205a1b


mod suites;

/// The single registration point for project-wide fuzz campaigns.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is a fuzz campaign? I am not familar with the campaign terminology

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed it to run in dd6f892

Comment thread datafusion/fuzz/Cargo.toml Resolved
Comment thread test-utils/src/fuzz.rs Outdated
use datafusion_common::instant::Instant;
use datafusion_common::{Result, exec_err};

/// A component's fuzz experiment, run by the centralized driver.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may help to add a link here to the centralized driver

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@2010YOUY01

2010YOUY01 commented Nov 4, 2026 •

Copy link
Copy Markdown
Member Author

@alamb THanks for the review!

What I don't understand is the new crate structure and then the need to partially expose some of the existing testing code from the physical expr crate

Exposing some testing util was intended to keep the PR small, but this make the structure confusing.

This is fixed in dd6f892: the idea is the fuzzing implementation all lives in datafusion-fuzz crate, and since the testing target should be public interface (SpillPool in this case), so no extra public API change would be needed, only need to move the fuzzing implementation.

RE another major concern for this PR:

why did you make a new crate? Why not just a module in the existing datafusion crate?

I think this structure is clearer. Otherwise, integration tests would include regular, extended (slow), and fuzzing tests, making it awkward to maintain or run only a subset of them.

Since splitting them doesn't seem to introduce any other issues, I went with the clearer structure.

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @2010YOUY01 -- looks good to me

I wonder if we should (as a follow on PR) add a note about fuzz testing to https://datafusion.apache.org/contributor-guide/testing.html

Specifically lay out the rationale / goal of in-project fuzz testing in an attempt to keep the implementations consistent

@2010YOUY01

Copy link
Copy Markdown
Member Author

Thanks @2010YOUY01 -- looks good to me

I wonder if we should (as a follow on PR) add a note about fuzz testing to https://datafusion.apache.org/contributor-guide/testing.html

Specifically lay out the rationale / goal of in-project fuzz testing in an attempt to keep the implementations consistent

I'll do it soon, thanks again.

@2010YOUY01
2010YOUY01 added this pull request to the merge queue Nov 7, 2026
Merged via the queue into apache:main with commit c3eeb47 Nov 7, 2026
45 checks passed
@2010YOUY01
2010YOUY01 deleted the fuzz-ut-framework branch November 7, 2026 04:04
killme2008 pushed a commit to killme2008/datafusion that referenced this pull request Nov 9, 2026
> [!IMPORTANT]
>
> **Fork CI setup:** For pull requests from a fork to `main`, enable
workflows in your fork's **Actions** tab before you push.
> See the [fork CI setup
guide](https://datafusion.apache.org/contributor-guide/#pull-requests-from-forks).

## Which issue does this PR close?

<!--
We generally require a GitHub issue to be filed for all bug fixes and
enhancements and this helps us generate change logs for our releases.
You can link an issue to this PR using the GitHub syntax. For example
`Closes apache#123` indicates that this PR will close issue apache#123.
-->

part of  apache#27082
Follow up: apache#27048

## Rationale for this change

<!--
Why are you proposing this change? If this is already explained clearly
in the issue then this section is not needed.
Explaining clearly why changes are proposed helps reviewers understand
your changes and offer better suggestions for fixes.

Please explain the problem you are trying to solve in terms of the
user-visible
behavior, rather than the implementation.

For example, "The code in `foo.rs` doesn't handle nulls" is a symptom of
the
implementation. "COUNT(DISTINCT) returns wrong results when the column
contains
nulls" is the user-visible problem.
-->
apache#27048 introduced a trait for implementing fuzzing UTs, this PR adds
documentation for it.

## What changes are included in this PR?

<!--
There is no need to duplicate the description in the issue here, but it
is sometimes worth providing a summary of the individual changes in this
PR.
-->

## What is the testing strategy for this PR?

<!--
We typically require tests for all PRs in order to:
1. Prevent the code from being accidentally broken by subsequent changes
2. Serve as another way to document the expected behavior of the code

Briefly describe how this PR is tested, and point to the specific tests
you added. For example: 'This new feature is covered by the
`sqllogictest` cases added in `foo.slt`'.

If this PR does not add tests, explain why. For example, if the change
is already covered by existing tests, please mention it.

You should also check the `codecov` bot reply on this PR to confirm the
changed code is exercised.
-->

## Are there any user-facing changes?

<!--
If there are user-facing changes then we may require documentation to be
updated before approving the PR.

If there are any breaking changes to public APIs, please add the `api
change` label.
-->
philippemnoel pushed a commit to paradedb/datafusion that referenced this pull request Nov 14, 2026
…ache#27258)

## Which issue does this PR close?

Part of apache#27082.

## Rationale for this change

The `union_fuzz` test in `key_range_bitmap.rs` previously ran as a
standalone `#[test]` using environment variables
(`DATAFUSION_KEY_RANGE_UNION_FUZZ_ITERATIONS` and
`DATAFUSION_KEY_RANGE_UNION_FUZZ_SEED`) without standardized budget
controls or centralized failure reporting.

Migrating this suite to the `FuzzTest` framework introduced in apache#27048
makes failures reproducible via seed reporting, connects it to the
unified runner in `datafusion-fuzz`, and aligns it with project-wide
fuzz testing conventions.

## What changes are included in this PR?

- **`datafusion-physical-plan`**:
- Expose `KeyRangePart` and `KeyRangeBitmap::union` so `datafusion-fuzz`
can construct partitions and test union behavior.
- Expose `offset(&self)`, `span(&self)`, `shift(&self)`, and
`bits(&self)` getter accessors on `KeyRangeBitmap` for internal
invariant checking.
- Remove legacy `union_fuzz` and `run_union_scenario` test functions
from `key_range_bitmap.rs`.
- **`datafusion-fuzz`**:
- Implement `KeyRangeBitmapFuzzer` in `tests/suites/key_range_bitmap.rs`
implementing the `FuzzTest` trait.
- Register `KeyRangeBitmapFuzzer` in `tests/fuzz.rs` and
`tests/suites/mod.rs`.
- **`xtask`**:
- Remove `union_fuzz` from `LEGACY_FUZZ_TESTS` in `ci_steps.rs` and
clean up legacy runner configuration and snapshots.

## What is the testing strategy for this PR?

- Validated `datafusion-physical-plan` unit tests:
- `cargo test -p datafusion-physical-plan --lib --
joins::key_range_bitmap` (all 4 unit tests pass)
- Validated unified fuzz runner:
- `cargo test -p datafusion-fuzz --test fuzz --features extended_tests`
(256 cases pass)
- Validated `xtask` legacy fuzz test verification:
  - `cargo test -p datafusion-xtask -- legacy_fuzz_tests_exist`

## Are there any user-facing changes?

No user-facing changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

development-process Related to development process of DataFusion physical-plan Changes to the physical-plan crate v57.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants