ソースを参照

Added a better way to tests any implementation of an storage

Cesar Rodas 9 ヶ月 前
コミット
aa4c3b4b2c
4 ファイル変更80 行追加87 行削除
  1. 1 1
      Cargo.toml
  2. 3 0
      crates/storage/Cargo.toml
  3. 66 2
      crates/storage/src/lib.rs
  4. 10 84
      crates/storage/src/rocksdb/mod.rs

+ 1 - 1
Cargo.toml

@@ -9,7 +9,7 @@ members = ["crates/types", "crates/client", "crates/relayer", "crates/storage"]
 [dependencies]
 nostr-rs-types = { path = "crates/types" }
 nostr-rs-client = { path = "crates/client" }
-nostr-rs-storage = { path = "crates/storage" }
+nostr-rs-storage = { path = "crates/storage", features = ["rocksdb"] }
 nostr-rs-relayer = { path = "crates/relayer" }
 tokio = { version = "1.26.0", features = ["full"] }
 env_logger = "0.10.0"

+ 3 - 0
crates/storage/Cargo.toml

@@ -16,3 +16,6 @@ rand = "0.8.5"
 chrono = "0.4.26"
 tokio = { version = "1.32.0", features = ["sync"] }
 parking_lot = "0.12.1"
+
+[features]
+rocksdb = []

+ 66 - 2
crates/storage/src/lib.rs

@@ -10,11 +10,75 @@
 mod error;
 mod event_filter;
 mod notification;
+#[cfg(feature = "rocksdb")]
 mod rocksdb;
 mod secondary_index;
 mod storage;
 
-pub use crate::{error::Error, notification::Subscription, rocksdb::RocksDb, storage::Storage};
+pub use crate::{error::Error, notification::Subscription, storage::Storage};
+
+#[cfg(feature = "rocksdb")]
+pub use crate::rocksdb::RocksDb;
+
+#[macro_export]
+/// This macro creates the
+macro_rules! storage_test {
+    ($type: tt, $init:tt, $destroy:tt) => {
+        #[cfg(test)]
+        mod test {
+            use super::*;
+            use std::sync::atomic::{AtomicUsize, Ordering};
+
+            static LAST_VERSION: AtomicUsize = AtomicUsize::new(0);
+
+            struct DisposableStorage {
+                path: String,
+                storage: $type,
+            }
+
+            impl DisposableStorage {
+                pub fn new() -> Self {
+                    let id = LAST_VERSION.fetch_add(1, Ordering::Relaxed);
+                    let path = format!("/tmp/nostr/test-{}", id);
+                    Self {
+                        storage: $init(&path),
+                        path,
+                    }
+                }
+            }
+
+            impl std::ops::Drop for DisposableStorage {
+                fn drop(&mut self) {
+                    $destroy(&self.path)
+                }
+            }
+
+            $crate::storage_test_name! { store_and_get }
+            $crate::storage_test_name! { records_are_sorted_by_date_desc }
+            $crate::storage_test_name! { filter_by_references }
+            $crate::storage_test_name! { filter_by_references_zero_match }
+            $crate::storage_test_name! { filter_by_references_and_kind }
+            $crate::storage_test_name! { filter_by_authors }
+            $crate::storage_test_name! { filter_by_author }
+            $crate::storage_test_name! { filter_by_author_and_kinds }
+            $crate::storage_test_name! { filter_by_kind }
+            $crate::storage_test_name! { get_event_and_related_events }
+            $crate::storage_test_name! { get_local_events }
+        }
+    };
+}
+
+#[macro_export]
+/// Creates a
+macro_rules! storage_test_name {
+    ($name:tt) => {
+        #[test]
+        fn $name() {
+            let x = DisposableStorage::new();
+            $crate::test::$name(&x.storage);
+        }
+    };
+}
 
 #[cfg(test)]
 mod test {
@@ -262,7 +326,7 @@ mod test {
         assert_eq!(records.len(), 2);
     }
 
-    pub fn filter_kind<T>(db: &T)
+    pub fn filter_by_kind<T>(db: &T)
     where
         T: Storage,
     {

+ 10 - 84
crates/storage/src/rocksdb/mod.rs

@@ -60,7 +60,8 @@ impl RocksDb {
         Ok(Self { db })
     }
 
-    /// Creates a new instance, passing just the path, the default options are passed
+    /// Creates a new instance, passing just the path, the default options are
+    /// passed
     pub fn new<T: AsRef<Path>>(path: T) -> Result<Self, Error> {
         let mut options = Options::default();
         options.create_if_missing(true);
@@ -273,88 +274,13 @@ impl Storage for RocksDb {
 }
 
 #[cfg(test)]
-mod test {
-    use super::*;
-    use crate::test;
-    use rand::Rng;
-
-    // Get current nanoseconds and use the last 3 digits as a random number (because
-    // sometimes it comes as 0)
-    pub fn unique_nanoseconds() -> u128 {
-        let mut rng = rand::thread_rng();
-        let random_number = rng.gen_range(0..999);
-
-        let ts = std::time::SystemTime::now()
-            .duration_since(std::time::UNIX_EPOCH)
-            .expect("time")
-            .as_nanos();
-
-        ts.checked_add(random_number).unwrap_or(ts)
-    }
-
-    #[test]
-    fn store_and_get() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::store_and_get(&db)
-    }
-
-    #[test]
-    fn records_are_sorted_by_date_desc() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::records_are_sorted_by_date_desc(&db)
-    }
-
-    #[test]
-    fn filter_by_references_zero_match() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::filter_by_references_zero_match(&db)
-    }
-
-    #[test]
-    fn filter_by_references_and_kind() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::filter_by_references_and_kind(&db)
-    }
-
-    #[test]
-    fn get_event_and_related_events() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::get_event_and_related_events(&db)
-    }
-
-    #[test]
-    fn filter_by_author() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::filter_by_author(&db)
-    }
-
-    #[test]
-    fn filter_by_authors() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::filter_by_authors(&db)
-    }
-
-    #[test]
-    fn filter_kind() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::filter_kind(&db)
-    }
-
-    #[test]
-    fn filter_by_references() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::filter_by_references(&db)
-    }
-
-    #[test]
-    fn filter_by_author_and_kinds() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::filter_by_author_and_kinds(&db)
-    }
+fn new_instance(path: &str) -> RocksDb {
+    RocksDb::new(&path).expect("valid db")
+}
 
-    #[test]
-    fn get_local_events() {
-        let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
-        test::get_local_events(&db)
-    }
+#[cfg(test)]
+fn destroy_instance(path: &str) {
+    std::fs::remove_dir_all(path).expect("deleted file");
 }
+
+crate::storage_test!(RocksDb, new_instance, destroy_instance);