Sail’s promise is compatibility with Spark-facing behavior, not merely successful Rust compilation. Testing therefore has to compare Sail against Spark semantics: SQL output, DataFrame behavior, functions, errors, type coercion, schema names, streaming state, and protocol responses.
This chapter gives contributors a testing map.
| Concern | File or directory |
|---|---|
| Gold test crate | crates/sail-gold-test/ |
| Spark gold data scripts | scripts/spark-gold-data/ |
| Common gold report scripts | scripts/common-gold-data/ |
| PySpark tests | python/pysail/tests/spark/ |
| Flight tests | python/pysail/tests/flight/ |
| Streaming tests | python/pysail/tests/spark/streaming/ |
| SQL docs and feature docs | docs/guide/sql/ |
| Spark test recipes | docs/development/spark-tests/ |
| Function support utilities | python/pysail/spark/utils/ |
Sail has several useful test layers:
| Layer | What it catches |
|---|---|
| Rust unit tests | local invariants, parser behavior, optimizer rewrites, codecs |
| Gold tests | Spark SQL/function output compatibility |
| PySpark integration tests | DataFrame API, Connect behavior, Python UDFs |
| Flight tests | Flight SQL protocol and Arrow transport |
| Feature files | behavior-oriented execution scenarios |
| Manual plan inspection | logical/physical plan regressions |
No single layer is enough. A function can pass unit tests and still fail Spark compatibility because Spark’s null handling, string formatting, overflow behavior, or timestamp display rules differ from DataFusion defaults.
Gold tests are the strongest compatibility signal. The workflow is:
The point is not only “does this expression run?” The point is “does this expression behave like Spark?”
This is especially important for:
The SQL parser has a second testing dimension: syntax preservation.
TreeText lets tests parse SQL and unparse it back to
normalized text.
Round-trip tests catch grammar regressions that a semantic query test might miss. For example, a parser can still produce a plan for a common query while losing support for a rare Spark syntax form.
Use parser round trips for:
The Python tests exercise the surface users actually touch. They are especially important for:
When a test failure shows up here, debug the path in layers:
PySpark call
-> Spark Connect protobuf
-> proto-to-spec conversion
-> PlanResolver
-> DataFusion plan
-> JobRunner
-> Arrow IPC response
-> PySpark decoding
Do not assume the bug is in the final function implementation. Many compatibility bugs are conversion or type-resolution bugs.
Flight SQL tests should verify:
GetFlightInfo schema,DoGet fetch behavior,Flight SQL enters through SQL, so it shares parser/analyzer coverage with Spark SQL. Its unique risk is protocol handling and Arrow Flight framing.
Sail records plan strings for explain output:
Plan inspection is useful when the output is wrong but no panic occurs. Ask:
spec?Plan bugs often look like data bugs until you inspect the tree.
Local mode is necessary but not sufficient. Cluster mode adds:
Any feature that creates a custom physical operator, UDF, UDAF, table format, or shuffle-sensitive distribution should be tested in cluster mode before being treated as complete.
For a new Spark function:
Spark compatibility failures tend to hide in boring edge cases. That is where the tests earn their keep.
For storage work, test both metadata and execution:
Catalog code can be correct while the resulting
TableProvider is wrong. Table format code can scan
correctly while catalog metadata is wrong. Test both sides of the
boundary.
An extension test matrix should include:
| Extension contribution | Required tests |
|---|---|
| Scalar function | SQL, DataFrame, local, cluster if encoded |
| Aggregate/window function | partial aggregation and cluster merge |
| Logical optimizer rule | before/after logical plan |
| Physical planner | local physical execution and cluster codec |
| Table format | read/write plus catalog integration |
| Python discovery | package import and registration |
An extension that only works in a custom local binary has not met Sail’s likely extension bar.
Testing Sail means testing conversions. Every query crosses protocol, spec, planning, execution, Arrow, and client boundaries. Good tests identify which boundary failed.
Navigation: Previous: Chapter 16, Local And Streaming Execution | Next: Chapter 18, Feature Playbooks | Reader Guide