Expand description
§faucet-conformance
A reusable test battery that any faucet connector can call from its own
tests/ to prove it upholds the connector contract. Passing this battery is
the Tier-1 criterion for a connector — there is no separate tiering
scheme; a connector is “supported” exactly when it invokes and passes these
checks in CI.
use faucet_conformance as conf;
let source = /* your Source */
conf::assert_config_schema_valid(&source);
conf::assert_bounded_memory(&source, 100, 1000).await;The core contract checks:
assert_config_schema_valid— the config schema is a valid JSON Schema.assert_bounded_memory— the source pages instead of buffering.assert_bookmark_roundtrip— an incremental source resumes from its bookmark rather than restarting.assert_idempotent_replay— re-delivering committed rows leaves no duplicates (atomic-watermark or keyed-upsert mechanism).assert_capabilities_truthful— advertised capabilities match real behaviour.assert_errors_not_panics— failures surface as a typedfaucet_core::FaucetError, never a panic.
Capability-demonstration checks — each proves a connector that advertises a
capability actually demonstrates it:
7. assert_write_modes_truthful — a sink advertising Upsert/Delete
genuinely converges by key and removes on delete, and missing/null keys
are reported as failed rather than silently written.
8. assert_schema_evolution_effective — an evolvable sink’s evolve_schema
makes the added column appear in a fresh current_schema().
9. assert_batch_size_zero_single_page — a source built with batch_size = 0 yields the whole result set as one page.
10. assert_connector_name_nonempty — connector_name() is non-empty (an
empty name becomes the "unknown" metric label).
11. assert_preflight_check_wellformed — check() returns Ok(CheckReport)
with well-formed probes; a probe failure is a Fail probe, not an Err.
Integration-level checks — these drive a live backend / the real pipeline,
so they belong in a connector’s testcontainers/tempfile conformance test
(not the synthetic unit doubles):
12. assert_discover_roundtrips — a source’s discover() descriptors are
genuinely selectable: deep-merge each config_patch, rebuild, and read.
13. assert_cancellation_flushes — a mid-run cancel stops at a page
boundary and flushes the sink, so buffered output survives (#146 H16).
Each check has both a passing and a #[should_panic] failing test in this
crate — a check that cannot fail is worthless.
Modules§
- doubles
- Synthetic
Source/Sinkdoubles the battery drives (and that connector authors can reuse in their own tests).
Traits§
- HasConfig
Schema - Anything that can expose a config JSON Schema + a label — blanket-implemented
for every
Sourcesoassert_config_schema_validaccepts a source directly. (Sinks can be checked viaassert_config_schema_valid_value.)
Functions§
- assert_
batch_ size_ zero_ single_ page - Check 9. Drive a source built with
batch_size = 0and assert it yields the entire result set as a singleStreamPage— the documented “no batching” sentinel (small lookup tables, sinks that prefer one large request). - assert_
bookmark_ roundtrip - Check 3. Drive an incremental source to completion, capture the bookmark
it emits, feed it back via
apply_start_bookmark, and assert the second run resumes after that point — strictly fewer records reappear (zero for a fully-consumed static source). - assert_
bounded_ memory - Check 2. Drive
stream_pagesover a source that yieldstotalrecords and assert the consumer never holds more than ~batch_sizerecords live at once (i.e. the source pages instead of buffering everything). - assert_
cancellation_ flushes - Check 13. Assert the flush-completing cancellation contract
(ADR 0011,
#146 H16): a
CancellationTokenfired mid-run stopsrun_streamat the next page boundary, flushes the sink so buffered output is made durable, and returnsOkwith the partial result — as opposed to dropping the run future, which would flush nothing and orphan a buffered sink’s output (a Parquet footer, an S3 multipart). - assert_
capabilities_ truthful - Check 5. Assert a sink’s advertised capabilities match real behaviour:
- assert_
config_ schema_ valid - Check 1. Assert the connector’s
config_schema()is a structurally valid JSON Schema that round-trips throughserde_json. - assert_
config_ schema_ valid_ value - The value-level core of
assert_config_schema_valid— usable for sinks:assert_config_schema_valid_value(&sink.config_schema(), sink.connector_name()). - assert_
connector_ name_ nonempty - Check 10. Assert a source’s
connector_nameis a non-empty string. An empty name is a cardinality-rule violation — the observability layer falls back to the"unknown"metric label, silently merging distinct connectors’ metrics. - assert_
connector_ name_ nonempty_ value - The value-level core of
assert_connector_name_nonempty— usable for sinks. - assert_
discover_ roundtrips - Check 12. For a source that advertises
supports_discover: enumerate its datasets viadiscover, then for each descriptor deep-merge itsconfig_patchonto the base config (via the caller’srebuildclosure) and assert the rebuilt source is actually readable — the dataset the catalog advertised is genuinely selectable end-to-end, not just a name in a list. - assert_
errors_ not_ panics - Check 6. Drive a source configured to fail (unreachable endpoint / bad
config) and assert it surfaces a typed
faucet_core::FaucetErrorwithout unwinding. Catches any panic and re-raises it as a check failure, so a connector thatunwrap()s on bad input is caught rather than crashing the test process silently. - assert_
idempotent_ replay - Check 4. Assert re-delivering already-committed rows leaves no duplicates in the destination — the trust-critical effectively-once check.
- assert_
preflight_ check_ wellformed - Check 11. Assert a source’s
checkreturnsOk(CheckReport)with at least one well-formed probe (non-empty name; aFail/Skipprobe carries a non-empty reason). A connector must surface a probe failure as aProbeStatus::FailinsideOk(report), never as anErrfromcheck()(anErrmeans “no probe could run at all”, whichfaucet doctorrenders differently). - assert_
schema_ evolution_ effective - Check 8. For a sink advertising
supports_schema_evolution: readcurrent_schema, apply a real add-columnSchemaEvolutionviaevolve_schema, and assert the new column appears in a freshcurrent_schema(). Stronger thanassert_capabilities_truthful, which only checks a no-op evolve does not error. - assert_
sink_ preflight_ check_ wellformed - The sink counterpart of
assert_preflight_check_wellformed. - assert_
write_ modes_ truthful - Check 7. Assert a sink advertising
Upsert/Deleteinsupported_write_modesgenuinely upholds those modes: - merge_
config_ patch - Deep-merge a discovery
config_patchonto a base configValueand return the merged config — objects merge recursively, scalars and arrays replace wholesale. This mirrors the deep-merge the CLI applies when it turns aDatasetDescriptorinto a matrix row, so arebuildclosure forassert_discover_roundtripscan compose the patch onto the real base config exactly as production does: