feat(test): add Pact contract tests covering Namespace and Table APIs#341
Closed
XuQianJin-Stars wants to merge 1 commit into
Closed
feat(test): add Pact contract tests covering Namespace and Table APIs#341XuQianJin-Stars wants to merge 1 commit into
XuQianJin-Stars wants to merge 1 commit into
Conversation
… across Java/Python/Rust clients
Introduce a consumer-driven contract testing suite for lance-namespace
based on the Pact framework. The suite covers both Namespace and Table
REST APIs (11 operations × success + error scenarios) and verifies three
language clients (Java / Python / Rust) against the Spring Boot reference
provider.
APIs under contract (success + 4xx error for each):
Namespace API : ListNamespaces, DescribeNamespace, CreateNamespace,
DropNamespace, NamespaceExists
Table API : ListTables, DescribeTable, TableExists, DropTable,
RegisterTable, DeregisterTable
Contract Pack (contract-pack/):
- README.md : contract pack overview
- sample-pacts/ : drop-in folder for pre-built Pact
v3/v4 JSON to enable offline
provider verification without a
live Pact Broker
Consumers:
- Java (java/lance-namespace-pact-tests)
* NamespaceApiPactTest.java : 22 interactions using PactDslJsonRootValue
/ PactDslJsonBody matchers
* ErrorResponseDsl.java : reusable 4-field ErrorResponse body DSL
- Python (python/lance_namespace_pact_tests)
* tests/pact_tests/test_namespace_api_pact.py : 10 interactions
* tests/pact_tests/test_table_api_pact.py : 12 interactions
* error_response_dsl.py / conftest.py : shared fixtures
- Rust (rust/lance-namespace-pact-tests)
* tests/namespace_api_tests.rs : 10 async interactions (tokio)
* tests/table_api_tests.rs : 12 async interactions (tokio)
Provider (java/lance-namespace-pact-tests, provider package):
- PactProviderTest.java : MockMvcTestTarget + @PactFolder offline verify
- PactStateController.java : @State hook endpoints
- InMemoryNamespaceFixtures.java : deterministic in-memory fixtures
- PactNamespaceController.java : pact-profile Namespace REST impl
- PactTableController.java : pact-profile Table REST impl
- PactTestApplication.java : isolated Spring Boot test application
- PactValidationConfig.java : request/response validation beans
- EmptyBodyFilter.java : normalize empty-body edge cases
CI tooling (ci/):
- naming_lint.sh : consumer/provider name whitelist validator
- openapi_pact_diff.py : OpenAPI ↔ Pact field coverage checker
- pact_consistency_check.py : cross-consumer matcher matrix tool
- pact_state_guard.sh : pre-commit @State string whitelist guard
Build & workflow integration:
- .github/workflows/pact.yml : CI pipeline running Java/Python/Rust
consumer tests, provider verification,
and a main-branch can-i-deploy gate
- .pre-commit-config.yaml : wires pact_state_guard into pre-commit
- java/pom.xml + lance-namespace-pact-tests/pom.xml
: new pact-tests Maven module + pact-publish profile
- java/Makefile, python/Makefile, rust/Makefile
: pact targets for each language
- python/lance_namespace_pact_tests/pyproject.toml
: pact-python test package
- rust/lance-namespace-pact-tests/Cargo.toml + src/lib.rs
: pact_consumer-based Rust test crate
- rust/Cargo.toml + Cargo.lock : workspace member registration
Verification:
- Java Consumer + Provider : 22 consumer pacts generated; provider
verification replays 45 interactions, 0 failures
- Python Consumer : 22 tests pass locally (pact-python)
- Rust Consumer : 22 tests pass locally (pact_consumer + tokio)
- Sample pacts can be dropped under contract-pack/sample-pacts/ for
offline provider verification without a live Pact Broker.
25cabda to
f039a88
Compare
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.
Summary
Introduce a consumer-driven contract testing suite for
lance-namespacebased on the Pact framework pact-foundation. The suite covers both
Namespace and Table REST APIs (11 operations × success + 4xx error
scenarios) and verifies three language clients (Java / Python / Rust)
against the Spring Boot reference provider.
Problem
lance-namespaceships an OpenAPI spec plus auto-generated clients in Java,Python and Rust, but so far there is no automated mechanism to guarantee
that:
ErrorResponse) keep a consistent 4-field shape acrosslanguages and versions.
reach downstream consumers (pylance, rust callers, Spark/Ray integrations, …).
Typical symptoms without contract tests:
error, different casing,optional
instance, etc.), making retries / user-facing messages inconsistent.integration environments.
Solution
A complete Pact-based contract test suite, plus a small contract-pack folder
that hosts the generated pact files, plus CI wiring that runs all three
consumer suites and the Spring Boot provider verification on every PR.
APIs under contract (success + 4xx for each)
ListNamespaces,DescribeNamespace,CreateNamespace,DropNamespace,NamespaceExistsListTables,DescribeTable,TableExists,DropTable,RegisterTable,DeregisterTableConsumer interaction count
NamespaceApiPactTest.java@Pact)test_namespace_api_pact.pytest_table_api_pact.pynamespace_api_tests.rstable_api_tests.rsError body DSL
A reusable 4-field
ErrorResponseshape (error,code,type,instance)is enforced for every 4xx interaction, exposed as:
ErrorResponseDsl.javaerror_response_dsl.pytests/Provider verification
PactProviderTestboots an isolatedPactTestApplication(Spring Boot,pactprofile, no external deps) and replays consumer pacts viaMockMvcTestTarget+@PactFolder, with provider states served byPactStateControllerusingInMemoryNamespaceFixtures.CI pipeline (
.github/workflows/pact.yml)5 jobs, triggered on
pushandpull_request:consumer-java— Consumer Contract Tests (Java Apache Client)consumer-python— Consumer Contract Tests (Python urllib3 Client)consumer-rust— Consumer Contract Tests (Rust reqwest Client)provider-verify— Provider Verification Tests (Spring Boot Server),downloads
pact-files-java/python/rustartifacts and replays themcan-i-deploy— Can I Deploy Check (main branch gate).pre-commit-config.yamlwiresci/pact_state_guard.shso any new@State("...")string must be whitelisted before commit.Verification
verification replays all interactions, 0 failures
pact-python)pact_consumer+tokio)contract-pack/sample-pacts/foroffline provider verification without a live Pact Broker.
How to run locally
cd java && make test-pact-consumercd java && make test-pact-providercd python && make test-pact-testscd rust && make test-pact-testsclose: #340
google doc: https://docs.google.com/document/d/1Wju0Ema10OkuDLs8tYzZ0xXqihX65k-OYabZbnc5NbI/edit?usp=sharing