summaryrefslogtreecommitdiff
path: root/src/channel/routes/test/on_send.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/channel/routes/test/on_send.rs')
-rw-r--r--src/channel/routes/test/on_send.rs148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/channel/routes/test/on_send.rs b/src/channel/routes/test/on_send.rs
new file mode 100644
index 0000000..eab7c32
--- /dev/null
+++ b/src/channel/routes/test/on_send.rs
@@ -0,0 +1,148 @@
+use axum::{
+ extract::{Json, Path, State},
+ http::StatusCode,
+};
+use futures::stream::StreamExt;
+
+use crate::{
+ channel::{app, routes},
+ repo::channel,
+ test::fixtures::{self, future::Immediately as _},
+};
+
+#[tokio::test]
+async fn channel_exists() {
+ // Set up the environment
+
+ let app = fixtures::scratch_app().await;
+ let sender = fixtures::login::create(&app).await;
+ let channel = fixtures::channel::create(&app).await;
+
+ // Call the endpoint
+
+ let sent_at = fixtures::now();
+ let request = routes::SendRequest {
+ message: fixtures::message::propose(),
+ };
+ let status = routes::on_send(
+ State(app.clone()),
+ Path(channel.id.clone()),
+ sent_at.clone(),
+ sender.clone(),
+ Json(request.clone()),
+ )
+ .await
+ .expect("sending to a valid channel");
+
+ // Verify the structure of the response
+
+ assert_eq!(StatusCode::ACCEPTED, status);
+
+ // Verify the semantics
+
+ let subscribed_at = fixtures::now();
+ let mut events = app
+ .channels()
+ .events(&channel.id, &subscribed_at, None)
+ .await
+ .expect("subscribing to a valid channel");
+
+ let event = events
+ .next()
+ .immediately()
+ .await
+ .expect("event received by subscribers");
+
+ assert_eq!(request.message, event.body);
+ assert_eq!(sender, event.sender);
+ assert_eq!(*sent_at, event.sent_at);
+}
+
+#[tokio::test]
+async fn messages_in_order() {
+ // Set up the environment
+
+ let app = fixtures::scratch_app().await;
+ let sender = fixtures::login::create(&app).await;
+ let channel = fixtures::channel::create(&app).await;
+
+ // Call the endpoint (twice)
+
+ let requests = vec![
+ (
+ fixtures::now(),
+ routes::SendRequest {
+ message: fixtures::message::propose(),
+ },
+ ),
+ (
+ fixtures::now(),
+ routes::SendRequest {
+ message: fixtures::message::propose(),
+ },
+ ),
+ ];
+
+ for (sent_at, request) in &requests {
+ routes::on_send(
+ State(app.clone()),
+ Path(channel.id.clone()),
+ sent_at.clone(),
+ sender.clone(),
+ Json(request.clone()),
+ )
+ .await
+ .expect("sending to a valid channel");
+ }
+
+ // Verify the semantics
+
+ let subscribed_at = fixtures::now();
+ let events = app
+ .channels()
+ .events(&channel.id, &subscribed_at, None)
+ .await
+ .expect("subscribing to a valid channel")
+ .take(requests.len());
+
+ let events = events.collect::<Vec<_>>().immediately().await;
+
+ for ((sent_at, request), event) in requests.into_iter().zip(events) {
+ assert_eq!(request.message, event.body);
+ assert_eq!(sender, event.sender);
+ assert_eq!(*sent_at, event.sent_at);
+ }
+}
+
+#[tokio::test]
+async fn nonexistent_channel() {
+ // Set up the environment
+
+ let app = fixtures::scratch_app().await;
+ let login = fixtures::login::create(&app).await;
+
+ // Call the endpoint
+
+ let sent_at = fixtures::now();
+ let channel = channel::Id::generate();
+ let request = routes::SendRequest {
+ message: fixtures::message::propose(),
+ };
+ let routes::ErrorResponse(error) = routes::on_send(
+ State(app),
+ Path(channel.clone()),
+ sent_at,
+ login,
+ Json(request),
+ )
+ .await
+ .expect_err("sending to a nonexistent channel");
+
+ // Verify the structure of the response
+
+ fixtures::error::expected!(
+ error,
+ app::EventsError::ChannelNotFound(error_channel),
+ assert_eq!(channel, error_channel)
+ );
+}