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 privacy_provider;
47#[cfg(feature = "harness")]
48mod request;
49#[cfg(feature = "harness")]
50mod sidecar;
51// Webhook request signers (issue #666): mint the headers a provider
52// sends, for a test to feed `WebhookVerifier`. Like `batch` and `blob`
53// it is ungated — it needs only `cratefield-core` and the `http`/HMAC
54// crates core already carries, none of the harness graph.
55mod signing;
56mod tmp;
57pub mod vectors;
58
59pub use batch::assert_batch_is_atomic;
60pub use blob::assert_blob_round_trips;
61#[cfg(feature = "harness")]
62pub use conformance::{conformance, conformance_in_process_only, full_fake_ports, sidecar_parity};
63#[cfg(feature = "harness")]
64pub use dialect::Dialect;
65#[cfg(feature = "harness")]
66pub use fakes::{
67    Ask, AuthMode, ClassifierMode, CommentedCall, EmptyDatabase, FAKE_EMBEDDER_DIMENSIONS,
68    FAKE_EMBEDDER_MODEL, FakeAuth, FakeCaptcha, FakeClassifier, FakeCustomHostnames, FakeDefer,
69    FakeDispatcher, FakeEmbedder, FakeHttpClient, FakeMailer, FakePayments, FakePush,
70    FakeRateLimiter, FakeRealtime, FakeTextModel, FakeTracker, FiledCall, FixedClock, MailerMode,
71    MemoryBlob, MemoryKeyValue, PaymentsCall, PaymentsMode, PushMode, StatusedCall, TextModelMode,
72    TrackerMode, error_json, problem_json, with_retry_after,
73};
74#[cfg(feature = "harness")]
75pub use harness::TestHarness;
76#[cfg(feature = "port-conformance")]
77pub use port::{
78    TEXT_MODEL_CONFORMANCE_CACHED_INPUT_TOKENS, TEXT_MODEL_CONFORMANCE_INPUT_TOKENS,
79    TEXT_MODEL_CONFORMANCE_OUTPUT_TOKENS, TEXT_MODEL_CONFORMANCE_REPLY, assert_wasm_safe_deps,
80    classifier_conformance, classifier_conformance_questions, classifier_conformance_state,
81    classifier_not_configured, classifier_rejects_malformed_questions,
82    classifier_truncates_long_state, push_recipient_conformance, text_model_conformance,
83    text_model_conformance_not_configured, text_model_conformance_prompt, vector_index_conformance,
84};
85#[cfg(feature = "harness")]
86pub use privacy_provider::{FakePrivacyProvider, ProviderCall};
87#[cfg(feature = "harness")]
88pub use request::{TestResponse, request, request_as, request_chunks};
89#[cfg(feature = "harness")]
90pub use sidecar::{FakeSidecar, Fault, shared as shared_sidecar};
91pub use signing::{sign_provider_scheme, sign_stripe_style};
92pub use tmp::TempDir;
93
94// The fixed test secret for the kit's Signer — an obvious dummy, never real.
95pub const TEST_HARNESS_SECRET: &str = "cratefield-testing-dummy-secret-0123456789";
96
97// Mirrors cratefield-adapter-postgres's integration-test skip reason.
98// The dialect axis (behind `harness`) prints it when the Postgres leg is
99// unavailable, so it exists whenever that axis or the leg itself does.
100#[cfg(any(feature = "harness", feature = "postgres"))]
101const POSTGRES_SKIP_REASON: &str = "start a local postgres:16 \
102     (docker run --rm -e POSTGRES_PASSWORD=postgres -p 5433:5432 postgres:16) \
103     and set FZ_TEST_POSTGRES_URL=postgres://postgres:postgres@127.0.0.1:5433/postgres";