about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2021-05-05 16:31:52 +0300
committerVika <vika@fireburn.ru>2021-05-05 16:31:52 +0300
commit4a1085b7e9a6231f3e21334af1ea43b71ee8d918 (patch)
treee817ef9b39563b610e3fb963f122b157d77ff4d3 /src
parentdc546640d066dfb7c72d204f3758b103bd415d2c (diff)
Moved the Redis spawner to the Redis module where it belongs, refactored tests to use the Redis database instead of a fake one
Diffstat (limited to 'src')
-rw-r--r--src/database/mod.rs52
-rw-r--r--src/database/redis/mod.rs39
-rw-r--r--src/lib.rs97
3 files changed, 110 insertions, 78 deletions
diff --git a/src/database/mod.rs b/src/database/mod.rs
index cdd5c43..1a6aa84 100644
--- a/src/database/mod.rs
+++ b/src/database/mod.rs
@@ -1,17 +1,17 @@
 #![warn(missing_docs)]
 use async_trait::async_trait;
 use serde::{Serialize,Deserialize};
+use crate::indieauth::User;
 
+mod redis;
+pub use crate::database::redis::RedisStorage;
+#[cfg(test)]
+pub use redis::tests::get_redis_instance;
 #[cfg(test)]
 mod memory;
 #[cfg(test)]
 pub(crate) use crate::database::memory::MemoryStorage;
 
-use crate::indieauth::User;
-
-mod redis;
-pub use crate::database::redis::RedisStorage;
-
 #[derive(Serialize, Deserialize, PartialEq, Debug)]
 pub struct MicropubChannel {
     pub uid: String,
@@ -169,9 +169,8 @@ pub trait Storage: Clone + Send + Sync {
 #[cfg(test)]
 mod tests {
     use super::{Storage, MicropubChannel};
-    use std::{process};
-    use std::time::Duration;
     use serde_json::json;
+    use super::redis::tests::get_redis_instance;
 
     async fn test_backend_basic_operations<Backend: Storage>(backend: Backend) {
         let post: serde_json::Value = json!({
@@ -236,49 +235,18 @@ mod tests {
         test_backend_get_channel_list(backend).await
     }
 
-    async fn get_redis_backend() -> (tempdir::TempDir, process::Child, super::RedisStorage) {
-        let tempdir = tempdir::TempDir::new("redis").expect("failed to create tempdir");
-        let socket = tempdir.path().join("redis.sock");
-        let redis_child = process::Command::new("redis-server")
-            .current_dir(&tempdir)
-            .arg("--port").arg("0")
-            .arg("--unixsocket").arg(&socket)
-            .stdout(process::Stdio::null())
-            .stderr(process::Stdio::null())
-            .spawn().expect("Failed to spawn Redis");
-        println!("redis+unix:///{}", socket.to_str().unwrap());
-        let uri = format!("redis+unix:///{}", socket.to_str().unwrap());
-        // There should be a slight delay, we need to wait for Redis to spin up
-        let client = redis::Client::open(uri.clone()).unwrap();
-        let millisecond = Duration::from_millis(1);
-        let mut retries: usize = 0;
-        const MAX_RETRIES: usize = 60 * 1000/*ms*/;
-        while let Err(err) = client.get_connection() {
-            if err.is_connection_refusal() {
-                async_std::task::sleep(millisecond).await;
-                retries += 1;
-                if retries > MAX_RETRIES {
-                    panic!("Timeout waiting for Redis, last error: {}", err);
-                }
-            } else {
-                panic!("Could not connect: {}", err);
-            }
-        }
-        let backend = super::RedisStorage::new(uri).await.unwrap();
-
-        return (tempdir, redis_child, backend)
-    }
-
     #[async_std::test]
     async fn test_redis_storage_basic_operations() {
-        let (tempdir, mut redis, backend) = get_redis_backend().await;
+        let (tempdir, mut redis, uri) = get_redis_instance().await;
+        let backend = super::RedisStorage::new(uri).await.unwrap();
         test_backend_basic_operations(backend).await;
         redis.kill().expect("Redis wasn't running");
         drop(tempdir);
     }
     #[async_std::test]
     async fn test_redis_storage_channel_support() {
-        let (tempdir, mut redis, backend) = get_redis_backend().await;
+        let (tempdir, mut redis, uri) = get_redis_instance().await;
+        let backend = super::RedisStorage::new(uri).await.unwrap();
         test_backend_get_channel_list(backend).await;
         redis.kill().expect("Redis wasn't running");
         drop(tempdir);
diff --git a/src/database/redis/mod.rs b/src/database/redis/mod.rs
index eded583..ccbf831 100644
--- a/src/database/redis/mod.rs
+++ b/src/database/redis/mod.rs
@@ -245,4 +245,43 @@ impl RedisStorage {
             Err(e) => Err(e.into())
         }
     }
+}
+
+#[cfg(test)]
+pub mod tests {
+    use std::{process};
+    use std::time::Duration;
+    use mobc_redis::redis;
+
+    pub async fn get_redis_instance() -> (tempdir::TempDir, process::Child, String) {
+        let tempdir = tempdir::TempDir::new("redis").expect("failed to create tempdir");
+        let socket = tempdir.path().join("redis.sock");
+        let redis_child = process::Command::new("redis-server")
+            .current_dir(&tempdir)
+            .arg("--port").arg("0")
+            .arg("--unixsocket").arg(&socket)
+            .stdout(process::Stdio::null())
+            .stderr(process::Stdio::null())
+            .spawn().expect("Failed to spawn Redis");
+        println!("redis+unix:///{}", socket.to_str().unwrap());
+        let uri = format!("redis+unix:///{}", socket.to_str().unwrap());
+        // There should be a slight delay, we need to wait for Redis to spin up
+        let client = redis::Client::open(uri.clone()).unwrap();
+        let millisecond = Duration::from_millis(1);
+        let mut retries: usize = 0;
+        const MAX_RETRIES: usize = 60 * 1000/*ms*/;
+        while let Err(err) = client.get_connection() {
+            if err.is_connection_refusal() {
+                async_std::task::sleep(millisecond).await;
+                retries += 1;
+                if retries > MAX_RETRIES {
+                    panic!("Timeout waiting for Redis, last error: {}", err);
+                }
+            } else {
+                panic!("Could not connect: {}", err);
+            }
+        }
+
+        return (tempdir, redis_child, uri)
+    }
 }
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 99d74b9..6a0a1cc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -92,6 +92,17 @@ pub async fn get_app_with_memory_for_testing(token_endpoint: surf::Url) -> (data
 
     return (database, equip_app(app))
 }
+#[cfg(test)]
+pub async fn get_app_with_test_redis(token_endpoint: surf::Url) -> (tempdir::TempDir, std::process::Child, database::RedisStorage, App<database::RedisStorage>) {
+    let (tempdir, child, uri) = crate::database::get_redis_instance().await;
+    let backend = database::RedisStorage::new(uri).await.unwrap();
+    let app = tide::with_state(ApplicationState {
+        token_endpoint, media_endpoint: None,
+        storage: backend.clone(),
+        http_client: surf::Client::new(),
+    });
+    return (tempdir, child, backend, equip_app(app))
+}
 
 #[cfg(test)]
 #[allow(unused_variables,unused_imports)]
@@ -103,11 +114,13 @@ mod tests {
     use mockito::mock;
 
     // Helpers
-    async fn create_app() -> (database::MemoryStorage, App<database::MemoryStorage>) {
-        get_app_with_memory_for_testing(surf::Url::parse(&*mockito::server_url()).unwrap()).await
+    async fn create_app() -> (database::RedisStorage, App<database::RedisStorage>, tempdir::TempDir, std::process::Child) {
+        //get_app_with_memory_for_testing(surf::Url::parse(&*mockito::server_url()).unwrap()).await
+        let (t, c, b, a) = get_app_with_test_redis(surf::Url::parse(&*mockito::server_url()).unwrap()).await;
+        (b, a, t, c)
     }
 
-    async fn post_json(app: &App<database::MemoryStorage>, json: serde_json::Value) -> surf::Response {
+    async fn post_json(app: &App<database::RedisStorage>, json: serde_json::Value) -> surf::Response {
         let request = app.post("/micropub")
             .header("Authorization", "Bearer test")
             .header("Content-Type", "application/json")
@@ -123,34 +136,36 @@ mod tests {
             .with_body(r#"{"me": "https://fireburn.ru", "client_id": "https://quill.p3k.io/", "scope": "create update media"}"#)
             .create();
 
-            let (db, app) = create_app().await;
+        let (db, app, tempdir, mut child) = create_app().await;
 
-            let response = post_json(&app, json!({
-                "type": ["h-entry"],
-                "properties": {
-                    "content": ["Fake news about Aaron Parecki!"],
-                    "uid": ["https://aaronparecki.com/posts/fake-news"]
-                }
-            })).await;
-            assert_eq!(response.status(), 403);
-
-            let response = post_json(&app, json!({
-                "type": ["h-entry"],
-                "properties": {
-                    "content": ["More fake news about Aaron Parecki!"],
-                    "url": ["https://aaronparecki.com/posts/more-fake-news"]
-                }
-            })).await;
-            assert_eq!(response.status(), 403);
-
-            let response = post_json(&app, json!({
-                "type": ["h-entry"],
-                "properties": {
-                    "content": ["Sneaky advertisement designed to creep into someone else's feed! Buy whatever I'm promoting!"],
-                    "channel": ["https://aaronparecki.com/feeds/main"]
-                }
-            })).await;
-            assert_eq!(response.status(), 403);
+        let response = post_json(&app, json!({
+            "type": ["h-entry"],
+            "properties": {
+                "content": ["Fake news about Aaron Parecki!"],
+                "uid": ["https://aaronparecki.com/posts/fake-news"]
+            }
+        })).await;
+        assert_eq!(response.status(), 403);
+
+        let response = post_json(&app, json!({
+            "type": ["h-entry"],
+            "properties": {
+                "content": ["More fake news about Aaron Parecki!"],
+                "url": ["https://aaronparecki.com/posts/more-fake-news"]
+            }
+        })).await;
+        assert_eq!(response.status(), 403);
+
+        let response = post_json(&app, json!({
+            "type": ["h-entry"],
+            "properties": {
+                "content": ["Sneaky advertisement designed to creep into someone else's feed! Buy whatever I'm promoting!"],
+                "channel": ["https://aaronparecki.com/feeds/main"]
+            }
+        })).await;
+        assert_eq!(response.status(), 403);
+
+        child.kill().expect("Couldn't kill Redis");
     }
 
     #[async_std::test]
@@ -161,12 +176,14 @@ mod tests {
             .with_body(r#"{"me": "https://fireburn.ru", "client_id": "https://quill.p3k.io/", "scope": "create update media"}"#)
             .create();
 
-        let (db, app) = create_app().await;
+        let (db, app, tempdir, mut child) = create_app().await;
 
         let response: serde_json::Value = app.get("/micropub?q=config")
             .header("Authorization", "test")
             .recv_json().await.unwrap();
         assert!(!response["q"].as_array().unwrap().is_empty());
+
+        child.kill().expect("Couldn't kill Redis");
     }
 
     #[async_std::test]
@@ -177,21 +194,25 @@ mod tests {
             .with_body(r#"{"error":"unauthorized","error_description":"A valid access token is required."}"#)
             .create();
 
-        let (db, app) = create_app().await;
+        let (db, app, tempdir, mut child) = create_app().await;
 
         let response: surf::Response = app.get("/micropub?q=config")
             .header("Authorization", "test")
             .send().await.unwrap();
         assert_eq!(response.status(), 401);
+
+        child.kill().expect("Couldn't kill Redis");
     }
 
     #[async_std::test]
     async fn test_no_auth_header() {
-        let (db, app) = create_app().await;
+        let (db, app, tempdir, mut child) = create_app().await;
 
         let request: surf::RequestBuilder = app.get("/micropub?q=config");
         let response: surf::Response = request.send().await.unwrap();
         assert_eq!(response.status(), 401);
+
+        child.kill().expect("Couldn't kill Redis");
     }
 
     #[async_std::test]
@@ -202,7 +223,7 @@ mod tests {
             .with_body(r#"{"me": "https://fireburn.ru", "client_id": "https://quill.p3k.io/", "scope": "create update media"}"#)
             .create();
 
-        let (storage, app) = create_app().await;
+        let (storage, app, tempdir, mut child) = create_app().await;
 
         let request: surf::RequestBuilder = app.post("/micropub")
             .header("Authorization", "Bearer test")
@@ -215,6 +236,8 @@ mod tests {
         // Assume the post is in the database at this point.
         let post = storage.get_post(&uid).await.unwrap().unwrap();
         assert_eq!(post["properties"]["content"][0]["html"].as_str().unwrap().trim(), "<p>something interesting</p>");
+
+        child.kill().expect("Couldn't kill Redis");
     }
 
     #[async_std::test]
@@ -225,7 +248,7 @@ mod tests {
             .with_body(r#"{"me": "https://fireburn.ru", "client_id": "https://quill.p3k.io/", "scope": "create update media"}"#)
             .create();
 
-        let (storage, app) = create_app().await;
+        let (storage, app, tempdir, mut child) = create_app().await;
 
         let mut response = post_json(&app, json!({
             "type": ["h-entry"],
@@ -254,11 +277,13 @@ mod tests {
         assert!(response.status() == 201 || response.status() == 202);
         let uid = response.header("Location").unwrap().last().to_string();
         // Assume the post is in the database at this point.
-        println!("Keys in database: {:?}", storage.mapping.read().await.keys());
+        //println!("Keys in database: {:?}", storage.mapping.read().await.keys());
         let new_feed = storage.get_post("https://fireburn.ru/feeds/main").await.unwrap().unwrap();
         println!("{}", new_feed["children"]);
         assert_eq!(new_feed["children"].as_array().unwrap().len(), 2);
         assert_eq!(new_feed["children"][0].as_str().unwrap(), uid);
         assert_eq!(new_feed["children"][1].as_str().unwrap(), first_uid);
+
+        child.kill().expect("Couldn't kill Redis");
     }
 }