From e7f6a372f0cd50d09d6e96eb7ffb5e22d06de6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Oliveira?= Date: Mon, 6 Apr 2020 04:57:45 +0100 Subject: [PATCH] add initial client tests (#25) --- src/client.rs | 5 +++ src/server.rs | 2 +- tests/client.rs | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 tests/client.rs diff --git a/src/client.rs b/src/client.rs index 812e896..45b7c16 100644 --- a/src/client.rs +++ b/src/client.rs @@ -187,6 +187,11 @@ pub struct Subscriber { impl Subscriber { + /// get the list of subscribed channels + pub fn get_subscribed(&self) -> &HashSet { + &self.subscribed_channels + } + /// await for next message published on the subscribed channels pub async fn next_message(&mut self) -> crate::Result { match self.receive_message().await { diff --git a/src/server.rs b/src/server.rs index 8dbdc4b..4be37fe 100644 --- a/src/server.rs +++ b/src/server.rs @@ -182,7 +182,7 @@ pub async fn run(listener: TcpListener, shutdown: impl Future) -> crate::Result< } // Extract the `shutdown_complete` receiver and transmitter - // ` explicitly drop shutdown_transmitter`. This is important, as the + // explicitly drop `shutdown_transmitter`. This is important, as the // `.await` below would otherwise never complete. let Listener { mut shutdown_complete_rx, shutdown_complete_tx, .. } = server; diff --git a/tests/client.rs b/tests/client.rs new file mode 100644 index 0000000..648590a --- /dev/null +++ b/tests/client.rs @@ -0,0 +1,90 @@ +use std::net::SocketAddr; +use tokio::net::TcpListener; +use tokio::task::JoinHandle; +use mini_redis::{client, server}; + +/// A basic "hello world" style test. A server instance is started in a +/// background task. A client instance is then established and set and get +/// commands are sent to the server. The response is then evaluated +#[tokio::test] +async fn key_value_get_set() { + let (addr, _) = start_server().await; + + let mut client = client::connect(addr).await.unwrap(); + client.set("hello", "world".into()).await.unwrap(); + + let value = client.get("hello").await.unwrap().unwrap(); + assert_eq!(b"world", &value[..]) +} + +/// similar to the "hello world" style test, But this time +/// a single channel subscription will be tested instead +#[tokio::test] +async fn receive_message_subscribed_channel() { + let (addr, _) = start_server().await; + + let client = client::connect(addr.clone()).await.unwrap(); + let mut subscriber = client.subscribe(vec!["hello".into()]).await.unwrap(); + + tokio::spawn(async move { + let mut client = client::connect(addr).await.unwrap(); + client.publish("hello", "world".into()).await.unwrap() + }); + + let message = subscriber.next_message().await.unwrap(); + assert_eq!("hello", &message.channel); + assert_eq!(b"world", &message.content[..]) +} + +/// test that a client gets messages from multiple subscribed channels +#[tokio::test] +async fn receive_message_multiple_subscribed_channels() { + let (addr, _) = start_server().await; + + let client = client::connect(addr.clone()).await.unwrap(); + let mut subscriber = client.subscribe(vec!["hello".into(), "world".into()]).await.unwrap(); + + tokio::spawn(async move { + let mut client = client::connect(addr).await.unwrap(); + client.publish("hello", "world".into()).await.unwrap() + }); + + let message1 = subscriber.next_message().await.unwrap(); + assert_eq!("hello", &message1.channel); + assert_eq!(b"world", &message1.content[..]); + + tokio::spawn(async move { + let mut client = client::connect(addr).await.unwrap(); + client.publish("world", "howdy?".into()).await.unwrap() + }); + + + let message2 = subscriber.next_message().await.unwrap(); + assert_eq!("world", &message2.channel); + assert_eq!(b"howdy?", &message2.content[..]) +} + +/// test that a client accurately removes its own subscribed chanel list +/// when unbscribing to all subscribed channels by submitting an empty vec +#[tokio::test] +async fn unsubscribes_from_channels() { + let (addr, _) = start_server().await; + + let client = client::connect(addr.clone()).await.unwrap(); + let mut subscriber = client.subscribe(vec!["hello".into(), "world".into()]).await.unwrap(); + + subscriber.unsubscribe(vec![]).await.unwrap(); + assert_eq!(subscriber.get_subscribed().len(), 0); +} + +async fn start_server() -> (SocketAddr, JoinHandle>) { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + + let handle = tokio::spawn(async move { + server::run(listener, tokio::signal::ctrl_c()).await + }); + + (addr, handle) +} +