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