//! The composition root assembles on a fresh database, with every adapter real. mod support; #[tokio::test] async fn server_builds_on_a_fresh_database() { let pool = support::memory_pool().await; let router = bootstrap::build_server_on(&support::test_config(), pool) .await .expect("server builds"); let (status, _, _) = support::send(&router, support::get("/health", None)).await; assert_eq!(status, 200); } #[tokio::test] async fn worker_builds_on_a_fresh_database() { let pool = support::memory_pool().await; bootstrap::build_worker_on(&support::test_config(), pool) .await .expect("worker builds"); } /// Without the federation feature, following another local user still works /// (the request lands as pending for the target): /// the local social ports are wired in place of the ActivityPub ones. #[cfg(not(feature = "federation"))] #[tokio::test] async fn federation_off_build_wires_local_social() { use axum::http::Method; let (router, _pool) = support::server().await; let alice = support::register(&router, "alice", "alice@example.com").await; let bob = support::register(&router, "bob", "bob@example.com").await; let (status, _, body) = support::send( &router, support::json_request( Method::POST, "/api/v1/social/follow", Some(&alice.token), serde_json::json!({ "handle": "bob@localhost:3000" }), ), ) .await; assert_eq!(status, 200, "follow: {body}"); let (status, _, body) = support::send( &router, axum::http::Request::builder() .uri("/api/v1/social/followers/pending") .header("authorization", format!("Bearer {}", bob.token)) .body(axum::body::Body::empty()) .unwrap(), ) .await; assert_eq!(status, 200, "pending followers: {body}"); let followers: serde_json::Value = serde_json::from_str(&body).unwrap(); let actors = followers["actors"].as_array().unwrap(); assert_eq!( actors.len(), 1, "bob should have one pending follower: {body}" ); assert!( body.contains(&alice.user_id) || body.contains("alice"), "follower should be alice: {body}" ); } /// The server never talks to the bus: whatever `EVENT_BUS_BACKEND` says, a /// change and its event land in the outbox table. No NATS server is reachable here. #[tokio::test] async fn server_publishes_to_the_outbox_even_when_bus_is_nats() { let pool = support::memory_pool().await; let mut config = support::test_config(); config.events.bus_backend = "nats".into(); config.nats.url = Some("nats://127.0.0.1:1".into()); let router = bootstrap::build_server_on(&config, pool.clone()) .await .expect("server builds without a reachable NATS"); let session = support::register(&router, "alice", "alice@example.com").await; let (status, _, body) = support::send( &router, support::json_request( axum::http::Method::POST, "/api/v1/reviews", Some(&session.token), serde_json::json!({ "manual_title": "Outbox", "manual_release_year": 2001, "rating": 4, "comment": "queued", "watched_at": "2024-01-01" }), ), ) .await; assert_eq!(status, 201, "log review: {body}"); let queued: i64 = sqlx::query_scalar( "SELECT COUNT(*) FROM event_queue WHERE event_type = 'ReviewLogged' AND event_id IS NOT NULL", ) .fetch_one(&pool) .await .unwrap(); assert_eq!(queued, 1); }