about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2021-09-26 02:04:27 +0300
committerVika <vika@fireburn.ru>2021-09-26 02:06:56 +0300
commit9203dd3ef7b62489116e7b7fe0b9d288c3389c78 (patch)
treec958b9bd42241b4452262ddfe197b1e91d211cbb
parent572435f7c8e1d613983309eca268c3f87ec5f00f (diff)
downloadkittybox-9203dd3ef7b62489116e7b7fe0b9d288c3389c78.tar.zst
Moved integration tests and allowed the binary to use file backend
Now the Redis dependencies are optional and only required if you want
to test the backend or actually use it in production. The app displays
a hint if you try to launch with an unsupported backend.
-rw-r--r--Cargo.toml8
-rw-r--r--src/database/mod.rs6
-rw-r--r--src/lib.rs50
-rw-r--r--src/main.rs50
4 files changed, 93 insertions, 21 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 3974d9c..3f93407 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2018"
 [features]
 default = ["util"]
 util = ["anyhow"]
+redis = ["mobc", "mobc-redis"]
 
 [[bin]]
 name = "kittybox-bulk-import"
@@ -16,7 +17,7 @@ required-features = ["util"]
 [[bin]]
 name = "pyindieblog-export"
 path = "src/bin/pyindieblog_to_kittybox.rs"
-required-features = ["util"]
+required-features = ["util", "redis"]
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dev-dependencies]
@@ -39,7 +40,6 @@ lazy_static = "^1.4.0"       # A macro for declaring lazily evaluated statics in
 log = "^0.4.14"              # A lightweight logging facade for Rust
 markdown = "^0.3.0"          # Native Rust library for parsing Markdown and (outputting HTML)
 markup = "^0.12.0"           # HTML templating engine... ok also very funny about markdown and markup... i just realized the pun...
-mobc = "^0.7.2"              # A generic connection pool with async/await support
 newbase60 = "^0.1.3"         # A library that implements Tantek Çelik's New Base 60
 retainer = "^0.2.2"          # Minimal async cache in Rust with support for key expirations
 serde_json = "^1.0.64"       # A JSON serialization file format
@@ -54,8 +54,12 @@ features = ["attributes", "unstable"]
 [dependencies.chrono]        # Date and time library for Rust
 version = "^0.4.19"
 features = ["serde"]
+[dependencies.mobc]          # A generic connection pool with async/await support
+version = "^0.7.2"
+optional = true
 [dependencies.mobc-redis]    # Redis support for the mobc connection pool
 version = "^0.7.0"
+optional = true
 features = ["async-std-comp"]
 default-features = false
 [dependencies.prometheus]    # Prometheus instrumentation library for Rust applications
diff --git a/src/database/mod.rs b/src/database/mod.rs
index e6873b0..a1f5861 100644
--- a/src/database/mod.rs
+++ b/src/database/mod.rs
@@ -3,10 +3,14 @@ use crate::indieauth::User;
 use async_trait::async_trait;
 use serde::{Deserialize, Serialize};
 
+#[cfg(redis)]
 mod redis;
+#[cfg(redis)]
 pub use crate::database::redis::RedisStorage;
+#[cfg(redis)]
 #[cfg(test)]
 pub use redis::tests::{get_redis_instance, RedisInstance};
+
 mod file;
 pub use crate::database::file::FileStorage;
 
@@ -184,6 +188,7 @@ pub trait Storage: Clone + Send + Sync {
 
 #[cfg(test)]
 mod tests {
+    #[cfg(redis)]
     use super::redis::tests::get_redis_instance;
     use super::{MicropubChannel, Storage};
     use serde_json::json;
@@ -352,6 +357,7 @@ mod tests {
     macro_rules! redis_test {
         ($func_name:expr) => {
             paste! {
+                #[cfg(redis)]
                 #[async_std::test]
                 async fn [<redis_ $func_name>] () {
                     test_logger::ensure_env_logger_initialized();
diff --git a/src/lib.rs b/src/lib.rs
index 77a6c11..1c6394a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -67,6 +67,7 @@ where
     app
 }
 
+#[cfg(redis)]
 pub async fn get_app_with_redis(
     token_endpoint: surf::Url,
     authorization_endpoint: surf::Url,
@@ -86,7 +87,46 @@ pub async fn get_app_with_redis(
     equip_app(app)
 }
 
+pub async fn get_app_with_file(
+    token_endpoint: surf::Url,
+    authorization_endpoint: surf::Url,
+    backend_uri: String,
+    media_endpoint: Option<String>,
+    internal_token: Option<String>,
+) -> App<database::FileStorage> {
+    let app = tide::with_state(ApplicationState {
+        token_endpoint,
+        media_endpoint,
+        authorization_endpoint,
+        internal_token,
+        storage: database::FileStorage::new(todo!()).await.unwrap(),
+        http_client: surf::Client::new(),
+    });
+
+    equip_app(app)
+}
+
 #[cfg(test)]
+pub async fn get_app_with_test_file(token_endpoint: surf::Url) -> (
+    tempdir::TempDir,
+    database::FileStorage,
+    App<database::FileStorage>
+) {
+    use surf::Url;
+    let tempdir = tempdir::TempDir::new("file").expect("Failed to create tempdir");
+    let backend = database::FileStorage::new(tempdir.path().to_path_buf()).await.unwrap();
+    let app = tide::with_state(ApplicationState {
+        token_endpoint,
+        media_endpoint: None,
+        authorization_endpoint: Url::parse("https://indieauth.com/auth").unwrap(),
+        storage: backend.clone(),
+        internal_token: None,
+        http_client: surf::Client::new()
+    });
+    (tempdir, backend, equip_app(app))
+}
+
+#[cfg(all(redis, test))]
 pub async fn get_app_with_test_redis(
     token_endpoint: surf::Url,
 ) -> (
@@ -122,18 +162,18 @@ mod tests {
 
     // Helpers
     async fn create_app() -> (
-        database::RedisStorage,
-        App<database::RedisStorage>,
-        database::RedisInstance,
+        database::FileStorage,
+        App<database::FileStorage>,
+        tempdir::TempDir,
     ) {
         //get_app_with_memory_for_testing(surf::Url::parse(&*mockito::server_url()).unwrap()).await
         let (r, b, a) =
-            get_app_with_test_redis(surf::Url::parse(&*mockito::server_url()).unwrap()).await;
+            get_app_with_test_file(surf::Url::parse(&*mockito::server_url()).unwrap()).await;
         (b, a, r)
     }
 
     async fn post_json(
-        app: &App<database::RedisStorage>,
+        app: &App<database::FileStorage>,
         json: serde_json::Value,
     ) -> surf::Response {
         let request = app
diff --git a/src/main.rs b/src/main.rs
index 0e57ed5..e91476b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,14 +10,14 @@ async fn main() -> Result<(), std::io::Error> {
 
     info!("Starting the kittybox server...");
 
-    let redis_uri: String;
-    match env::var("REDIS_URI") {
+    let backend_uri: String;
+    match env::var("BACKEND_URI") {
         Ok(val) => {
-            debug!("Redis connection: {}", val);
-            redis_uri = val
+            debug!("Backend URI: {}", val);
+            backend_uri = val
         }
         Err(_) => {
-            error!("REDIS_URI is not set, cannot find a database");
+            error!("BACKEND_URI is not set, cannot find a database");
             std::process::exit(1);
         }
     };
@@ -63,13 +63,35 @@ async fn main() -> Result<(), std::io::Error> {
     let host = env::var("SERVE_AT")
         .ok()
         .unwrap_or_else(|| "0.0.0.0:8080".to_string());
-    let app = kittybox::get_app_with_redis(
-        token_endpoint,
-        authorization_endpoint,
-        redis_uri,
-        media_endpoint,
-        internal_token,
-    )
-    .await;
-    app.listen(host).await
+
+    if backend_uri.starts_with("redis") {
+        #[cfg(redis)]
+        {
+            let app = kittybox::get_app_with_redis(
+                token_endpoint,
+                authorization_endpoint,
+                backend_uri,
+                media_endpoint,
+                internal_token,
+            ).await;
+            app.listen(host).await
+        }
+        #[cfg(not(redis))]
+        {
+            println!("The Redis backend was disabled at build-time. Please recompile the package with --features=redis.");
+            std::process::exit(1);
+        }
+    } else if backend_uri.starts_with("file") {
+        let app = kittybox::get_app_with_file(
+            token_endpoint,
+            authorization_endpoint,
+            backend_uri,
+            media_endpoint,
+            internal_token
+        ).await;
+        app.listen(host).await
+    } else {
+        println!("Unknown backend, not starting.");
+        std::process::exit(1);
+    }
 }