Skip to content

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

Open
2010YOUY01 wants to merge 9 commits into
apache:mainfrom
2010YOUY01:fuzz-ut-framework
Open

2010YOUY01 wants to merge 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

# specific language governing permissions and limitations
# under the License.

# A private crate providing a single entry point for all fuzz tests.

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.

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

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.

see the longer comment below

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.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants