Skip to content

test: Porting over the Cassandra Repo integration suite - #350

Merged
robinnsc merged 2 commits into
feat/storage-cassandra-in-treefrom
feat/cassandra-direct-tests
Sep 19, 2026
Merged

robinnsc merged 2 commits into
feat/storage-cassandra-in-treefrom
feat/cassandra-direct-tests

Conversation

@robinnsc

@robinnsc robinnsc commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

What

Porting over the original extenddb-cassandra-plugin repository's direct integration suit. 136 tests that exercise the storage traits directly against a real Cassandra node (139 ported, minus the four plug-in tag tests deduplicated into the consolidated in-tree lifecycle test when the metadata suite was folded in — see the second commit) — no HTTP server in between — of which the in-tree port had previously picked up only the four tag tests.

Coverage the tree gains: CRUD and key-type handling (decimal, binary), Query/Scan semantics, pagination, segments and index reads, transactions (TransactGet, TransactWrite rollback and idempotency, ledger internals, lock protection), GSI/LSI physical schema and the async propagation workers, streams (write, read, pagination, shards), table lifecycle, and the whole management plane: access keys, accounts, users, groups, roles, policies, admin, settings, backup/restore state. None of that had automated coverage in-tree; the TTL suites use some of these operations but never assert their general semantics.

Structure: one test binary (tests/direct_integration.rs), one module per area under tests/direct/, all sharing tests/common/mod.rs — which is the in-tree descendant of the plug-in's helpers.rs, so the port is mostly mechanical: keyspace-prefix adaptation, two CreateTableInput fields added since the fork, and the skip-without-Cassandra guard on every test so the serviceless workspace cargo test job stays green (same pattern the existing suites use, EXTENDDB_TEST_CASSANDRA=required in the dedicated workflow).

Why

135 of 139 tests had no in-tree equivalent (~8,600 LOC of coverage). This suite is the safety net under everything else the in-tree port changes.

Not copied verbatim

Four tests the porting inventory flagged as weak were strengthened, and one of them promptly caught something:

  • The sync-GSI test's TODO was hiding a real semantic difference. The plug-in engine wrote GSI rows synchronously by default; in-tree the default is 10ms async propagation through the GSI queue, which no test worker drains. The old test "verified the write path executes without crashing" — it would never have caught a lost index write, and when I added the missing assertion it failed immediately. It now pins the index to synchronous propagation (the same catalog knob production routing reads) and asserts the row is visible through the index-scan path.
  • The table-lifecycle and settings tests printed ✓/✗ outcomes instead of asserting them; every outcome is now an assertion. The settings test also mutated control_plane_delay_seconds — a live control-plane knob in the shared catalog — and left the test value behind; it now restores what it found (or the reader default, 0.25, when the key was absent).
  • The pk-only delete-timestamp test carried dead bindings from an inspection it never did; it now verifies the delete actually removed the item, with a comment explaining why the timestamp itself is uninspectable on that table shape.

Parallelism and CI

The suite runs with default parallelism — every test provisions its own account and keyspace. Full run on a local single node: ~17–19 minutes wall, 139/139. Wired into the Cassandra CI workflow as a step after the existing serial suites; this will grow that job's runtime, and if it becomes the long pole the next step is splitting it into its own job in the same workflow.

One observed interaction worth knowing: running the other TTL suite immediately after this one on the same node hit one flaky claim-contention failure while Cassandra was still dropping this suite's 139 keyspaces in the background (test-fixture Drop is async fire-and-forget). It passes reliably in isolation and CI runs the suites in the opposite order, so nothing is changed here — flagging it in case it ever shows up in someone's local run.

Testing done

Real Cassandra 4.1, single node:

  • cargo test -p extenddb-storage-cassandra --test direct_integration — 139 passed, 0 failed (two full runs, plus targeted reruns of every strengthened test)
  • Existing suites unaffected: ttl_integration 26/26 serial, metadata_integration 1/1, lib 43/43
  • cargo clippy --all-targets -- -D warnings — clean (the ported code carried ten lint findings; fixed)
  • cargo fmt --all -- --check — clean
  • Skip-guard behavior inherited from the existing suites' helper (probe 9042, required in CI)

Checklist

  • I have read CONTRIBUTING.md
  • Test-only change; the one non-test file touched is the CI workflow
  • Code is formatted (cargo fmt --all -- --check)
  • No new Clippy warnings (workspace -D warnings clean)
  • No wire, trait, schema, or behavior change

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache License 2.0 and I agree to the Developer Certificate of Origin (DCO). See CONTRIBUTING.md for details.

@robinnsc robinnsc changed the title test: port the plug-in repo's 139-test direct integration suite test: port the plug-in repo's direct integration suite Sep 15, 2026
@robinnsc robinnsc changed the title test: port the plug-in repo's direct integration suite test: Porting over the Cassandra Repo integration suite Sep 15, 2026
@jcshepherd
jcshepherd force-pushed the feat/storage-cassandra-in-tree branch 2 times, most recently from 8151972 to 845f933 Compare September 15, 2026 21:05
The original extenddb-cassandra-plugin repository carried 139 direct
integration tests against the storage traits — real node, no HTTP
server in between — of which the in-tree port had picked up only the
four tag tests. The other 135 covered CRUD, Query/Scan semantics and
pagination, transactions (TransactGet, TransactWrite rollback and
idempotency, ledger operations), GSI/LSI physical schema and the async
propagation workers, streams, access keys, accounts, users, groups,
roles, policies, admin and settings stores, and backup/restore state.
None of that had automated coverage in-tree.

One test binary (direct_integration), one module per area, sharing
tests/common/mod.rs — the in-tree descendant of the plug-in's
helpers.rs, which is why the port is mostly mechanical: keyspace-prefix
adaptation, the two CreateTableInput fields added since the fork, and
the skip-without-Cassandra guard on all 139 tests so the serviceless
workspace test job stays green.

Four tests the inventory flagged as weak were strengthened rather than
copied: the table lifecycle and settings tests printed outcomes instead
of asserting them (the settings test also now restores the live
control-plane knob it mutates, which used to leak past the test run);
the pk-only delete-timestamp test carried dead bindings and now
verifies the delete; and the sync-GSI test's TODO was hiding a real
semantic difference — the plug-in engine wrote GSIs synchronously by
default, in-tree the default is 10ms async propagation via a queue no
test worker drains, so its "verify the write path executes without
crashing" would never have caught a lost index write. It now pins the
index to synchronous propagation (the same knob production routing
reads) and asserts the index row is visible through the index-scan
path.

The suite runs in parallel: every test provisions its own account and
keyspace. Wired into the Cassandra CI workflow after the existing
serial suites.
@robinnsc
robinnsc force-pushed the feat/cassandra-direct-tests branch from 528d049 to fe657a3 Compare September 17, 2026 20:28
@robinnsc

Copy link
Copy Markdown
Collaborator Author

Rebuilt on the current base after the branch reconstruction dropped merged PR #339 (see #349 for the full story; restored as 439ca5b, which this suite depends on for the skip-guard helper and CI workflow). Worth highlighting: this suite already paid for itself before merging — the delete_item tests caught the rebuilt base's OCC delete fast path silently skipping partition_max_delete_timestamp, which disarmed the transaction prepare path's new-item-vs-delete ordering check for plain deletes. Fixed on the base as 0aebbe4; 139/139 green on top of it.


#[tokio::test]
async fn test_create_account() {
if crate::helpers::skip_without_cassandra() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just checking: is this function already pushed?

@jcshepherd jcshepherd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Overall, LGTM. Two questions:

  • is helpers::skip_without_cassandra() already checked in?
  • Do you plan to migrate storage-cassandra/tests/metadata_integration.rs and ttl_integration.rs to this suite?

Review suggestion from jcshepherd. The standalone metadata_integration
binary held one test — the in-tree consolidation of the plug-in repo's
four tag tests — while the ported suite carried those four originals,
so merging the binaries also deduplicates: the consolidated phased
lifecycle test replaces the four in direct/metadata_engine.rs (same
assertions, one engine connection instead of four catalog-migration
setups). It is parallel-safe like the rest of the suite. The TTL suite
stays its own serial binary: its tests drive global sweep, repair, and
audit passes that would see every concurrent test's tables, so the two
binaries have deliberately opposite concurrency contracts. One fewer
test binary to link, one fewer CI step.
@robinnsc
robinnsc merged commit bae4933 into feat/storage-cassandra-in-tree Sep 19, 2026
25 checks passed
@robinnsc
robinnsc deleted the feat/cassandra-direct-tests branch September 19, 2026 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants