catalog-tests: the catalog test harness, and flowctl raw test - #3417
Merged
Conversation
This was referenced Aug 27, 2026
jgraettinger
force-pushed
the
johnny/v2-tests-2-runtime-local
branch
from
August 30, 2026 17:56
38a589b to
a2d44ab
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-3-catalog-tests
branch
from
August 30, 2026 17:56
7c143a6 to
db1ce76
Compare
jgraettinger
marked this pull request as draft
August 31, 2026 20:38
jgraettinger
force-pushed
the
johnny/v2-tests-2-runtime-local
branch
2 times, most recently
from
August 31, 2026 22:08
f63e934 to
e392a76
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-3-catalog-tests
branch
from
August 31, 2026 22:08
db1ce76 to
df38483
Compare
jgraettinger
marked this pull request as ready for review
August 31, 2026 22:11
jgraettinger
force-pushed
the
johnny/v2-tests-2-runtime-local
branch
from
August 31, 2026 22:19
e392a76 to
a4ad7c4
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-3-catalog-tests
branch
from
August 31, 2026 22:19
df38483 to
5dd646c
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-2-runtime-local
branch
from
August 31, 2026 22:46
a4ad7c4 to
2d160a7
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-3-catalog-tests
branch
from
August 31, 2026 22:46
5dd646c to
5106b77
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-2-runtime-local
branch
from
September 1, 2026 00:51
2d160a7 to
13ac318
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-3-catalog-tests
branch
from
September 1, 2026 00:51
5106b77 to
0b5782c
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-2-runtime-local
branch
from
September 1, 2026 04:46
13ac318 to
bf1c380
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-3-catalog-tests
branch
from
September 1, 2026 04:46
0b5782c to
dae189d
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-2-runtime-local
branch
from
September 1, 2026 15:34
bf1c380 to
8426df8
Compare
jgraettinger
force-pushed
the
johnny/v2-tests-3-catalog-tests
branch
from
September 1, 2026 15:34
dae189d to
0094e7a
Compare
Reset asks a derivation shard's connector to reset its internal state to an as-just-initialized condition, mapping onto the connector protocol's existing `derive.Request.Reset`. It is the mechanism the catalog-test harness uses to isolate test cases from one another. Reset is deliberately shard-local — Controller → Shard, with ResetDone coming back Shard → Controller. The leader is not in the path: coordinating a common transaction boundary across shards belongs to the caller, and the test harness already has that property because it drives one transaction per stat() and awaits its commit. ResetDone is nonetheless required. A shard receives transaction messages from its leader but Reset from its controller, so ordering within either stream alone cannot establish that the connector observed the reset before the next transaction's reads.
A derivation shard now answers a controller Reset by queueing a `derive::Request.Reset` to its connector and replying ResetDone. This is handled shard-locally; the leader is not involved.
`Opened.runtime_checkpoint` is how a connector tells the runtime that its checkpoint state is remote-authoritative — that the endpoint, not the recovery log, holds the truth. derive-sqlite reported one unconditionally, including for a `:memory:` database whose "truth" does not outlive the session. Introduce `Database` to decide this once, where the URI is chosen: `Durable` for a file-backed database, whose recorded checkpoint is authoritative and is reported; `Ephemeral` for `:memory:`, which reports none. An explicit `:memory:` from `sqlite_vfs_uri` is now recognized as ephemeral rather than taken at face value as a file path. This is a test-only concern in practice: a production task is always threaded a recorded recovery-log VFS URI by the runtime, and `:memory:` arises only where a local drive deliberately wants a stateless connector. What it buys is that such a drive is no longer forced single-shard by an authority claim the database can't back — which is what lets the catalog-test harness run derive-sqlite multi-shard.
New crate holding what a catalog test *means*, layered above runtime-local and runtime-next. `run_tests` starts a resident session per enabled derivation, then runs every case — sorted by first-step scope, so a run is diffable from one invocation to the next — through the scheduler, with a Reset between cases. Which derivations to start is settled synchronously first, so a malformed catalog fails before any connector boots. Every derivation runs multi-shard, whatever its connector. Sessions thread an empty `Task.sqlite_vfs_uri`, so a derive-sqlite shard runs a session-scoped `:memory:` database and claims no checkpoint authority it couldn't back — which is what leaves the leader free to accept the topology. clock / graph / scheduler carry the scheduling semantics that `go/testing/` worked out — writes cascading through a multi-hop chain, self-cycles reaching a fixed point, read delays against a lazily-advanced synthetic clock, verify steps gated on a forward BFS over pending reads — and follow the Go closely, down to its unit tests, rather than re-deriving them. Two deliberate departures: the graph tracks derivations only, since a test never runs a capture or a materialization; and there is no `ErrAdvanceDisabled`, because synthetic time is a counter local to this crate. Everything else that's non-obvious is written up under "Non-obvious details" in the crate README. Tests run over derive-sqlite and need no containers, covering scheduling, Reset isolation, partition selectors, redaction, collection names nested under one another, read delays, diff rendering, and a run dropped mid-flight. Connector death at startup — while handling Open, or racing the leader's startup commit just after Opened — is covered by `tests/fixtures/dying_connector.py`, since no well-behaved connector produces that fault.
`flowctl raw test --source ...` runs a catalog's tests locally on the runtime-next stack, and CI's catalog-test task now uses it instead of `flowctl-go test`. It sits under `raw` beside `raw preview-next`, which drives the same stack: both are local, developer-facing, and tied to a runtime that is still landing, so neither belongs at the top level yet. `flowctl catalog test` — a remote dry-run publish — is a different command and is unaffected. Output is a line per test, keyed by test name: a failure names the source path and JSON pointer of the step it failed at and indents the rendered diff beneath, and a case the run never reached says so. Then a tally. Exits non-zero if any test failed.
jgraettinger
force-pushed
the
johnny/v2-tests-3-catalog-tests
branch
from
September 1, 2026 16:17
0094e7a to
a2e9974
Compare
williamhbaker
approved these changes
Sep 1, 2026
| graph: &mut Graph, | ||
| driver: &mut D, | ||
| test: &TestSpec, | ||
| ) -> anyhow::Result<String> { |
Member
There was a problem hiding this comment.
nit: The comment says that the scope of the last step reached is returned and used for error reporting, but as I understand it the error reporting part happens on the error path, and the string value from the Ok result is never used... in crates/catalog-tests/src/run.rs:192 it is discarded. It seems like LiveDriver::last_scope is actually doing the tracking of error scopes.
Member
Author
There was a problem hiding this comment.
Thanks, I'll address in a next PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description:
Stack 3 of 5, and the core of it: a new
catalog-testscrate, layered aboveruntime-local(#3416) andruntime-next. Plus the one protocol addition it needs, and the CLI that drives it.Five commits:
proto: add derive Reset / ResetDone messages— the mechanism the harness uses to isolate test cases from one another.runtime-next: forward Reset to derive connectors— handled shard-locally; the leader is not involved.derive-sqlite: report no checkpoint for an ephemeral database— a:memory:database is not remote-authoritative, and saying so is what lets the harness run derive-sqlite multi-shard.catalog-tests: the catalog test harness— the crate.flowctl: add the raw test subcommand— and CI'sci:catalog-testtask now uses it instead offlowctl-go test.Workflow steps:
A line per test, keyed by test name. A failure names the source path and JSON pointer of the step it failed at and indents the rendered diff beneath; a case the run never reached says so. Then a tally. Exits non-zero if any test failed.
Documentation links affected:
None user-facing.
crates/catalog-tests/README.mdis new and carries the design.Notes for reviewers:
Stack — each PR is based on the one above it, so review only the top commits of each.
flowctl raw test#3417 — catalog-tests: the harness, andflowctl raw test← you are here