Skip to main content

cratefield_testing/
lib.rs

1//! `cratefield-testing`: the conformance kit every Factory Zero module runs
2//! against (issue #9) — fake ports, an in-memory SQLite `Database`, and
3//! request helpers over the axum router with **no network**.
4//!
5//! ```no_run
6//! use cratefield_testing::{conformance, TestHarness, request};
7//!
8//! #[test]
9//! fn my_module_conforms() {
10//!     conformance(Box::new(my_module::MyModule::new()));
11//! }
12//!
13//! #[pollster::test]
14//! async fn join_returns_202() {
15//!     let kit = TestHarness::new(vec![Box::new(my_module::MyModule::new())]);
16//!     let response = request(&kit.router, http::Method::POST,
17//!         "/v1/my-module/join", Some(r#"{"email":"nick@example.com"}"#)).await;
18//!     assert_eq!(response.status, http::StatusCode::ACCEPTED);
19//! }
20//! ```
21
22#![doc = include_str!("../README.md")]
23#![forbid(unsafe_code)]
24
25// Needs only `cratefield-core`, so it is ungated like `vectors` and
26// `tmp`: a light consumer can assert the batch contract without the
27// harness graph (issues #126, #201).
28mod batch;
29// Byte round-trips (issue #39): ungated for the same reason as `batch`
30// — it binds through sea-query's `From` impls without naming the crate,
31// so it needs nothing beyond `cratefield-core`.
32mod blob;
33#[cfg(feature = "harness")]
34mod conformance;
35#[cfg(feature = "harness")]
36mod dialect;
37#[cfg(feature = "harness")]
38mod fakes;
39#[cfg(feature = "harness")]
40mod harness;
41#[cfg(feature = "postgres")]
42mod pg;
43#[cfg(feature = "port-conformance")]
44mod port;
45#[cfg(feature = "harness")]
46mod request;
47#[cfg(feature = "harness")]
48mod sidecar;
49mod tmp;
50pub mod vectors;
51
52pub use batch::assert_batch_is_atomic;
53pub use blob::assert_blob_round_trips;
54#[cfg(feature = "harness")]
55pub use conformance::{conformance, conformance_in_process_only, full_fake_ports, sidecar_parity};
56#[cfg(feature = "harness")]
57pub use dialect::Dialect;
58#[cfg(feature = "harness")]
59pub use fakes::{
60    Ask, AuthMode, ClassifierMode, EmptyDatabase, FakeAuth, FakeCaptcha, FakeClassifier, FakeDefer,
61    FakeDispatcher, FakeHttpClient, FakeMailer, FakePayments, FakePush, FakeRateLimiter,
62    FakeRealtime, FakeTextModel, FakeTracker, FiledCall, FixedClock, MailerMode, MemoryBlob,
63    MemoryKeyValue, PaymentsCall, PaymentsMode, PushMode, StatusedCall, TextModelMode, TrackerMode,
64};
65#[cfg(feature = "harness")]
66pub use harness::TestHarness;
67#[cfg(feature = "port-conformance")]
68pub use port::{
69    assert_wasm_safe_deps, classifier_conformance, classifier_conformance_questions,
70    classifier_conformance_state, classifier_not_configured,
71    classifier_rejects_malformed_questions, classifier_truncates_long_state,
72    push_recipient_conformance,
73};
74#[cfg(feature = "harness")]
75pub use request::{TestResponse, request, request_as};
76#[cfg(feature = "harness")]
77pub use sidecar::{FakeSidecar, Fault, shared as shared_sidecar};
78pub use tmp::TempDir;
79
80// The fixed test secret for the kit's Signer — an obvious dummy, never real.
81pub const TEST_HARNESS_SECRET: &str = "cratefield-testing-dummy-secret-0123456789";
82
83// Mirrors cratefield-adapter-postgres's integration-test skip reason.
84// The dialect axis (behind `harness`) prints it when the Postgres leg is
85// unavailable, so it exists whenever that axis or the leg itself does.
86#[cfg(any(feature = "harness", feature = "postgres"))]
87const POSTGRES_SKIP_REASON: &str = "start a local postgres:16 \
88     (docker run --rm -e POSTGRES_PASSWORD=postgres -p 5433:5432 postgres:16) \
89     and set FZ_TEST_POSTGRES_URL=postgres://postgres:postgres@127.0.0.1:5433/postgres";