From 5ef215a4fcc48625423d9a5655e1cb2da7532f9b Mon Sep 17 00:00:00 2001 From: Dmitry Shlagoff Date: Thu, 20 Jul 2023 12:18:04 +0200 Subject: [PATCH] Add tests --- Cargo.lock | 154 +++++++++++++++--------------------- Cargo.toml | 10 +-- src/app/context.rs | 8 +- src/app/stage/mod.rs | 81 +++++++++++++++++++ src/test_helpers/context.rs | 44 +++-------- 5 files changed, 163 insertions(+), 134 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d516b66f..8c75e04a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -91,26 +91,25 @@ dependencies = [ [[package]] name = "async-nats" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1174495e436c928905018f10a36160f7a8a6786450f50f4ce7fba05d1539704c" +checksum = "94e3e851ddf3b62be8a8085e1e453968df9cdbf990a37bbb589b5b4f587c68d7" dependencies = [ - "async-nats-tokio-rustls-deps", - "base64 0.13.1", - "base64-url", + "base64 0.21.2", "bytes", "futures", "http", "itoa 1.0.8", "memchr", "nkeys", - "nuid", + "nuid 0.3.2", "once_cell", "rand", "regex", "ring", "rustls-native-certs", "rustls-pemfile", + "rustls-webpki", "serde", "serde_json", "serde_nanos", @@ -119,21 +118,11 @@ dependencies = [ "time 0.3.22", "tokio", "tokio-retry", + "tokio-rustls 0.24.1", "tracing", "url", ] -[[package]] -name = "async-nats-tokio-rustls-deps" -version = "0.24.0-ALPHA.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cdefe54cd7867d937c0a507d2a3a830af410044282cd3e4002b5b7860e1892e" -dependencies = [ - "rustls 0.21.2", - "tokio", - "webpki 0.22.0", -] - [[package]] name = "async-trait" version = "0.1.70" @@ -264,15 +253,6 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" -[[package]] -name = "base64-url" -version = "1.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a99c239d0c7e77c85dddfa9cebce48704b3c49550fcd3b84dd637e4484899f" -dependencies = [ - "base64 0.13.1", -] - [[package]] name = "base64ct" version = "1.1.1" @@ -337,6 +317,9 @@ name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] [[package]] name = "cc" @@ -571,29 +554,6 @@ dependencies = [ "const-oid", ] -[[package]] -name = "diesel" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" -dependencies = [ - "bitflags 1.3.2", - "byteorder", - "diesel_derives", - "pq-sys", -] - -[[package]] -name = "diesel_derives" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "difflib" version = "0.4.0" @@ -813,7 +773,7 @@ dependencies = [ "svc-agent", "svc-authn", "svc-authz", - "svc-error", + "svc-error 0.6.0", "svc-events", "svc-nats-client", "svc-utils", @@ -1552,9 +1512,9 @@ dependencies = [ [[package]] name = "nkeys" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e66a7cd1358277b2a6f77078e70aea7315ff2f20db969cc61153103ec162594" +checksum = "c2d151f6ece2f3d1077f6c779268de2516653d8344ddde65addd785cce764fe5" dependencies = [ "byteorder", "data-encoding", @@ -1601,6 +1561,16 @@ dependencies = [ "rand", ] +[[package]] +name = "nuid" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b61b1710432e483e6a67b20b6c60c6afe0e2fad67aabba3bdb912f3f70ff6ae" +dependencies = [ + "once_cell", + "rand", +] + [[package]] name = "num-bigint" version = "0.2.6" @@ -1947,15 +1917,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pq-sys" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0052426df997c0cbd30789eb44ca097e3541717a7b8fa36b1c464ee7edebd" -dependencies = [ - "vcpkg", -] - [[package]] name = "predicates" version = "2.1.5" @@ -2247,8 +2208,8 @@ dependencies = [ "pollster", "thiserror", "tokio", - "tokio-rustls", - "webpki 0.21.4", + "tokio-rustls 0.22.0", + "webpki", ] [[package]] @@ -2397,14 +2358,14 @@ dependencies = [ "log", "ring", "sct 0.6.1", - "webpki 0.21.4", + "webpki", ] [[package]] name = "rustls" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" dependencies = [ "log", "ring", @@ -2435,9 +2396,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.100.1" +version = "0.101.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e" dependencies = [ "ring", "untrusted", @@ -3064,9 +3025,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "svc-agent" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c90205083c87c6bc25990d5cdd26f98d8c431441e86dbd4e7421b28c428e04d" +checksum = "bef9c610b65f24bab61b52f5a7264983d0e014858e8496282aec7d688baf7869" dependencies = [ "async-channel", "base64 0.21.2", @@ -3089,7 +3050,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb5cf659f78c8fff863c17ac4e674829517919716eeecab602e8d2941e89c111" dependencies = [ "chrono", - "diesel", "http", "jsonwebtoken", "serde", @@ -3123,6 +3083,19 @@ name = "svc-error" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f841d7fd45d6f179e9f3765491fcb5eea100a5bbe50ea47faf3f262031966d9" +dependencies = [ + "anyhow", + "crossbeam-channel", + "http", + "serde", + "serde_derive", +] + +[[package]] +name = "svc-error" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad220c6bc89bc2e7b8af01db6dcfa4a513e18d78e7cf2f778e623ac22577eadf" dependencies = [ "anyhow", "crossbeam-channel", @@ -3140,9 +3113,9 @@ dependencies = [ [[package]] name = "svc-events" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a30b9e3f342270165a9e7543f9ba85a45bff586cc04f4d495ffd8b4a44447974" +checksum = "3ad84bd15a598b693df7dd08ca832c3414d59d6847f134f479ff547264669735" dependencies = [ "serde", "serde_json", @@ -3154,9 +3127,9 @@ dependencies = [ [[package]] name = "svc-nats-client" -version = "0.5.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35276c77ae7ff528a5fb243f16bf95065a3ac8c91837356f2ee797c9a697203" +checksum = "cf7705838936003cae1b79e726be255ea9702b8aad516dec9c998c7c93ef6f8d" dependencies = [ "anyhow", "async-nats", @@ -3164,10 +3137,11 @@ dependencies = [ "futures", "futures-util", "humantime-serde", + "nuid 0.4.1", "reqwest", "serde", "svc-agent", - "svc-error", + "svc-error 0.6.0", "svc-events", "thiserror", "tokio", @@ -3177,9 +3151,9 @@ dependencies = [ [[package]] name = "svc-utils" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb63daf177825295faa99773d6fb6de26be0d3e9fbe427e3cac794358c000e99" +checksum = "b8443737f4d2444dc9e6a140a83d720685290d1ad763e75b59421958fa4a1a96" dependencies = [ "axum", "futures", @@ -3188,7 +3162,7 @@ dependencies = [ "prometheus", "svc-agent", "svc-authn", - "svc-error", + "svc-error 0.5.0", "tokio", "tower", "tower-http", @@ -3386,7 +3360,17 @@ checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ "rustls 0.19.1", "tokio", - "webpki 0.21.4", + "webpki", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.5", + "tokio", ] [[package]] @@ -3803,16 +3787,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "whoami" version = "1.4.1" diff --git a/Cargo.toml b/Cargo.toml index b76d0dbe..76741829 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,13 +34,13 @@ serde_qs = "0.12" signal-hook = "0.3" signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } sqlx = { version = "0.6", features = ["offline", "postgres", "macros", "uuid", "chrono", "json", "bigdecimal", "runtime-tokio-native-tls"] } -svc-agent = { version = "0.20", features = ["sqlx", "queue-counter"] } +svc-agent = { version = "0.21", features = ["sqlx", "queue-counter"] } svc-authn = { version = "0.8", features = ["jose", "sqlx"] } svc-authz = { version = "0.12" } -svc-error = { version = "0.5", features = ["sqlx", "svc-agent", "svc-authn", "svc-authz", "sentry-extension"] } -svc-utils = { version = "0.7", features = ["authn-extractor", "cors-middleware", "log-middleware"] } -svc-nats-client = "0.5" -svc-events = "0.9" +svc-error = { version = "0.6", features = ["sqlx", "svc-agent", "svc-authn", "svc-authz", "sentry-extension"] } +svc-utils = { version = "0.8", features = ["authn-extractor", "cors-middleware", "log-middleware"] } +svc-nats-client = "0.8" +svc-events = "0.11" tokio = { version = "1.28", features = ["full"] } tower = "0.4" tower-http = { version = "0.4", features = ["trace", "cors"] } diff --git a/src/app/context.rs b/src/app/context.rs index 8b02f462..d5bdbbaf 100644 --- a/src/app/context.rs +++ b/src/app/context.rs @@ -34,7 +34,7 @@ pub trait GlobalContext { fn metrics(&self) -> Arc; fn s3_client(&self) -> Option; fn broker_client(&self) -> &dyn BrokerClient; - fn nats_client(&self) -> Option<&dyn NatsClient>; + fn nats_client(&self) -> Option>; async fn get_conn(&self) -> Result, AppError> { self.db() @@ -121,8 +121,8 @@ impl GlobalContext for AppContext { self.broker_client.as_ref() } - fn nats_client(&self) -> Option<&dyn NatsClient> { - self.nats_client.as_deref() + fn nats_client(&self) -> Option> { + self.nats_client.clone() } } @@ -183,7 +183,7 @@ impl<'a, C: GlobalContext> GlobalContext for AppMessageContext<'a, C> { self.global_context.broker_client() } - fn nats_client(&self) -> Option<&dyn NatsClient> { + fn nats_client(&self) -> Option> { self.global_context.nats_client() } } diff --git a/src/app/stage/mod.rs b/src/app/stage/mod.rs index 14cdebb2..958a337c 100644 --- a/src/app/stage/mod.rs +++ b/src/app/stage/mod.rs @@ -205,3 +205,84 @@ async fn handle_ban_accepted( Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::test_helpers::prelude::*; + + #[tokio::test] + async fn ban_accepted_handler_enables_disables_ban() { + let db = TestDb::new().await; + let agent = TestAgent::new("web", "user", USR_AUDIENCE); + + let mut conn = db.get_conn().await; + let room = shared_helpers::insert_room(&mut conn).await; + + let subject = Subject::new("test".to_string(), room.classroom_id(), "ban".to_string()); + let event_id: EventId = ("ban".to_string(), "accepted".to_string(), 0).into(); + let headers = + svc_nats_client::test_helpers::HeadersBuilder::new(event_id, agent.agent_id().clone()) + .build(); + let e = BanAcceptedV1 { + ban: true, + classroom_id: room.classroom_id(), + target_account: agent.account_id().clone(), + operation_id: 0, + }; + + let ctx = TestContext::new(db, TestAuthz::new()); + + handle_ban_accepted(&ctx, e, &room, subject, &headers) + .await + .expect("handler failed"); + + let pub_reqs = ctx.inspect_nats_client().get_publish_requests(); + assert_eq!(pub_reqs.len(), 1); + + let payload = + serde_json::from_slice::(&pub_reqs[0].payload).expect("failed to parse event"); + assert!(matches!( + payload, + Event::V1(EventV1::BanCollaborationCompleted(..)) + )); + + let room_bans = db::room_ban::ListQuery::new(room.id()) + .execute(&mut conn) + .await + .expect("failed to list room bans"); + + assert_eq!(room_bans.len(), 1); + assert_eq!(room_bans[0].account_id(), agent.account_id()); + + let subject = Subject::new("test".to_string(), room.classroom_id(), "ban".to_string()); + let e: BanAcceptedV1 = BanAcceptedV1 { + ban: false, + classroom_id: room.classroom_id(), + target_account: agent.account_id().clone(), + operation_id: 0, + }; + + handle_ban_accepted(&ctx, e, &room, subject, &headers) + .await + .expect("handler failed"); + + let pub_reqs = ctx.inspect_nats_client().get_publish_requests(); + assert_eq!(pub_reqs.len(), 1); + + let payload = + serde_json::from_slice::(&pub_reqs[0].payload).expect("failed to parse event"); + assert!(matches!( + payload, + Event::V1(EventV1::BanCollaborationCompleted(..)) + )); + + let room_bans = db::room_ban::ListQuery::new(room.id()) + .execute(&mut conn) + .await + .expect("failed to list room bans"); + + assert_eq!(room_bans.len(), 0); + } +} diff --git a/src/test_helpers/context.rs b/src/test_helpers/context.rs index 1db2b249..adad0abe 100644 --- a/src/test_helpers/context.rs +++ b/src/test_helpers/context.rs @@ -1,16 +1,12 @@ use std::sync::Arc; -use async_trait::async_trait; use chrono::{DateTime, Utc}; use prometheus::Registry; use serde_json::json; use sqlx::postgres::PgPool as Db; use svc_agent::{queue_counter::QueueCounterHandle, AgentId}; use svc_authz::cache::ConnectionPool as RedisConnectionPool; -use svc_nats_client::{ - AckPolicy, DeliverPolicy, Event, Message, MessageStream, Messages, NatsClient, PublishError, - Subject, SubscribeError, TermMessageError, -}; +use svc_nats_client::{test_helpers::TestNatsClient, NatsClient}; use crate::{ app::{ @@ -74,7 +70,7 @@ pub struct TestContext { start_timestamp: DateTime, s3_client: Option, broker_client: Arc, - nats_client: Option>, + nats_client: Arc, } impl TestContext { @@ -92,7 +88,7 @@ impl TestContext { start_timestamp: Utc::now(), s3_client: None, broker_client: Arc::new(MockBrokerClient::new()), - nats_client: Some(Arc::new(TestNatsClient {}) as Arc), + nats_client: Arc::new(TestNatsClient::new()), } } @@ -110,7 +106,7 @@ impl TestContext { start_timestamp: Utc::now(), s3_client: None, broker_client: Arc::new(MockBrokerClient::new()), - nats_client: Some(Arc::new(TestNatsClient {}) as Arc), + nats_client: Arc::new(TestNatsClient::new()), } } @@ -128,7 +124,7 @@ impl TestContext { start_timestamp: Utc::now(), s3_client: None, broker_client: Arc::new(MockBrokerClient::new()), - nats_client: Some(Arc::new(TestNatsClient {}) as Arc), + nats_client: Arc::new(TestNatsClient::new()), } } @@ -139,31 +135,9 @@ impl TestContext { pub fn broker_client_mock(&mut self) -> &mut MockBrokerClient { Arc::get_mut(&mut self.broker_client).expect("Failed to get broker client mock") } -} - -struct TestNatsClient; - -#[async_trait] -impl NatsClient for TestNatsClient { - async fn publish(&self, _event: &Event) -> Result<(), PublishError> { - Ok(()) - } - - async fn subscribe_durable(&self) -> Result { - unimplemented!() - } - - async fn subscribe_ephemeral( - &self, - _subject: Subject, - _deliver_policy: DeliverPolicy, - _ack_policy: AckPolicy, - ) -> Result { - unimplemented!() - } - async fn terminate(&self, _message: &Message) -> Result<(), TermMessageError> { - unimplemented!() + pub fn inspect_nats_client(&self) -> &TestNatsClient { + &self.nats_client } } @@ -208,8 +182,8 @@ impl GlobalContext for TestContext { self.broker_client.as_ref() } - fn nats_client(&self) -> Option<&dyn NatsClient> { - self.nats_client.as_deref() + fn nats_client(&self) -> Option> { + Some(self.nats_client.clone() as Arc) } }