1#![allow(clippy::unwrap_used)]
2
3use std::path::Path;
4
5use crate::{DbConnection, EncryptedMessageStore, StorageOption};
6mod impls;
7mod mls_memory_storage;
8
9pub use mls_memory_storage::*;
10
11pub type TestDb = EncryptedMessageStore<crate::DefaultDatabase>;
12
13#[allow(async_fn_in_trait)]
14pub trait XmtpTestDb {
15 async fn create_ephemeral_store() -> EncryptedMessageStore<crate::DefaultDatabase>;
17
18 async fn create_ephemeral_store_from_snapshot(
19 snapshot: &[u8],
20 path: Option<impl AsRef<Path>>,
21 ) -> EncryptedMessageStore<crate::DefaultDatabase>;
22
23 async fn create_persistent_store(
25 path: Option<String>,
26 ) -> EncryptedMessageStore<crate::DefaultDatabase>;
27 async fn create_database(path: Option<String>) -> crate::DefaultDatabase;
30}
31
32impl<Db> EncryptedMessageStore<Db> {
33 pub fn generate_enc_key() -> [u8; 32] {
34 let key = xmtp_common::rand_array::<32>();
35 tracing::debug!("generated key is [{}]", hex::encode(key));
36 key
37 }
38
39 #[cfg(not(target_arch = "wasm32"))]
40 pub fn remove_db_files<P: AsRef<str>>(path: P) {
41 use crate::database::native::EncryptedConnection;
42
43 let path = path.as_ref();
44 std::fs::remove_file(path).unwrap();
45 std::fs::remove_file(EncryptedConnection::salt_file(path).unwrap()).unwrap();
46 }
47
48 #[cfg(target_arch = "wasm32")]
50 pub fn remove_db_files<P: AsRef<str>>(_path: P) {}
51}
52
53impl Clone for crate::MockXmtpDb {
54 fn clone(&self) -> Self {
55 panic!("clone is not allowed")
56 }
57}
58
59#[cfg(all(target_family = "wasm", target_os = "unknown"))]
60pub use wasm::*;
61#[cfg(all(target_family = "wasm", target_os = "unknown"))]
62mod wasm {
63 use super::*;
64 use crate::{PersistentOrMem, WasmDbConnection};
65 use futures::FutureExt;
66 use std::sync::Arc;
67
68 impl XmtpTestDb for super::TestDb {
69 async fn create_ephemeral_store() -> EncryptedMessageStore<crate::DefaultDatabase> {
70 let db = crate::database::WasmDb::new(&StorageOption::Ephemeral)
71 .await
72 .unwrap();
73 EncryptedMessageStore::new(db).unwrap()
74 }
75
76 async fn create_ephemeral_store_from_snapshot(
77 snapshot: &[u8],
78 _path: Option<impl AsRef<Path>>,
79 ) -> EncryptedMessageStore<crate::DefaultDatabase> {
80 let db = crate::database::WasmDb::new(&StorageOption::Ephemeral)
81 .await
82 .unwrap();
83 let store = EncryptedMessageStore::new_uninit(db).unwrap();
84 store
85 .db()
86 .raw_query_write(|conn| conn.deserialize_database_from_buffer(snapshot))
87 .unwrap();
88
89 store
90 }
91
92 async fn create_persistent_store(
93 path: Option<String>,
94 ) -> EncryptedMessageStore<crate::DefaultDatabase> {
95 let tmp = path.unwrap_or(xmtp_common::tmp_path());
96 let db = crate::database::WasmDb::new(&StorageOption::Persistent(tmp))
97 .await
98 .unwrap();
99 EncryptedMessageStore::new(db).unwrap()
100 }
101
102 async fn create_database(path: Option<String>) -> crate::DefaultDatabase {
103 let tmp = path.unwrap_or(xmtp_common::tmp_path());
104 crate::database::WasmDb::new(&StorageOption::Persistent(tmp))
105 .await
106 .unwrap()
107 }
108 }
109
110 pub fn with_connection<F, R>(fun: F) -> R
112 where
113 F: FnOnce(
114 &crate::DbConnection<Arc<PersistentOrMem<WasmDbConnection, WasmDbConnection>>>,
115 ) -> R,
116 {
117 let db = crate::database::WasmDb::new(&StorageOption::Ephemeral)
119 .now_or_never()
120 .unwrap()
121 .unwrap();
122 let store = EncryptedMessageStore::new(db).unwrap();
123 let conn = store.conn();
124 fun(&DbConnection::new(conn))
125 }
126
127 pub async fn with_connection_async<F, T, R>(fun: F) -> R
129 where
130 F: FnOnce(
131 crate::DbConnection<Arc<PersistentOrMem<WasmDbConnection, WasmDbConnection>>>,
132 ) -> T,
133 T: Future<Output = R>,
134 {
135 let db = crate::database::WasmDb::new(&StorageOption::Ephemeral)
136 .await
137 .unwrap();
138 let store = EncryptedMessageStore::new(db).unwrap();
139 let conn = store.conn();
140 fun(DbConnection::new(conn)).await
141 }
142
143 impl EncryptedMessageStore<crate::database::WasmDb> {
144 pub async fn new_test() -> Self {
145 let db = crate::database::WasmDb::new(&StorageOption::Ephemeral)
146 .await
147 .unwrap();
148 EncryptedMessageStore::new(db).expect("constructing message store failed.")
149 }
150
151 pub async fn new_test_with_path(path: &str) -> Self {
152 let db = crate::database::WasmDb::new(&StorageOption::Persistent(path.into()))
153 .await
154 .unwrap();
155 EncryptedMessageStore::new(db).expect("constructing message store failed.")
156 }
157 }
158}
159
160#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
161pub use native::*;
162#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
163mod native {
164 use super::*;
165 use crate::{
166 ConnectionExt, EphemeralDbConnection, MIGRATIONS, NativeDbConnection, PersistentOrMem,
167 };
168 use diesel::{Connection, SqliteConnection, connection::SimpleConnection};
169 use diesel_migrations::MigrationHarness;
170 use std::sync::Arc;
171
172 impl XmtpTestDb for super::TestDb {
173 async fn create_ephemeral_store() -> crate::DefaultStore {
174 let opts = StorageOption::Ephemeral;
175 let db = crate::database::NativeDb::new_unencrypted(&opts).unwrap();
176 EncryptedMessageStore::new(db).unwrap()
177 }
178 async fn create_ephemeral_store_from_snapshot(
179 mut snapshot: &[u8],
180 path: Option<impl AsRef<Path>>,
181 ) -> crate::DefaultStore {
182 let path = path.as_ref();
183 let mut buffer;
184
185 let mut i = 0;
186 let store = loop {
187 let opts = StorageOption::Ephemeral;
188 let db = crate::database::NativeDb::new_unencrypted(&opts).unwrap();
189 let store = EncryptedMessageStore::new_uninit(db).unwrap();
190 let result = store.db().raw_query_write(|conn| {
191 conn.deserialize_database_from_buffer(snapshot)?;
192 conn.batch_execute("PRAGMA journal_mode = DELETE")?;
193 Ok(())
194 });
195
196 if result.is_ok() {
197 break store;
198 } else if i >= 1 || path.is_none() {
199 #[allow(clippy::panicking_unwrap)]
200 result.unwrap();
201 }
202
203 if let Some(path) = path {
204 let path = path.as_ref();
205 {
207 let mut conn =
208 SqliteConnection::establish(path.to_string_lossy().as_ref()).unwrap();
209 conn.batch_execute("PRAGMA journal_mode = DELETE").unwrap();
210 }
211
212 buffer = std::fs::read(path).unwrap();
213 snapshot = &buffer;
214 };
215
216 i += 1;
217 };
218
219 store
220 .conn()
221 .raw_query_write(|c| {
222 c.run_pending_migrations(MIGRATIONS).unwrap();
223 Ok(())
224 })
225 .unwrap();
226
227 store
228 }
229 async fn create_persistent_store(path: Option<String>) -> crate::DefaultStore {
230 let path = path.unwrap_or(xmtp_common::tmp_path());
231 let opts = StorageOption::Persistent(path.to_string());
232 let db = crate::database::NativeDb::new(&opts, [0u8; 32]).unwrap();
233 EncryptedMessageStore::new(db).expect("constructing message store failed.")
234 }
235
236 async fn create_database(path: Option<String>) -> crate::DefaultDatabase {
237 let path = path.unwrap_or(xmtp_common::tmp_path());
238 let opts = StorageOption::Persistent(path.to_string());
239 crate::database::NativeDb::new(&opts, xmtp_common::rand_array::<32>()).unwrap()
240 }
241 }
242
243 pub fn with_connection<F, R>(fun: F) -> R
245 where
246 F: FnOnce(
247 &crate::DbConnection<Arc<PersistentOrMem<NativeDbConnection, EphemeralDbConnection>>>,
248 ) -> R,
249 {
250 let opts = StorageOption::Ephemeral;
251 let db = crate::database::NativeDb::new_unencrypted(&opts).unwrap();
252 let store = EncryptedMessageStore::new(db).unwrap();
253 let conn = store.conn();
254 fun(&DbConnection::new(conn))
255 }
256
257 pub async fn with_connection_async<F, T, R>(fun: F) -> R
259 where
260 F: FnOnce(
261 crate::DbConnection<Arc<PersistentOrMem<NativeDbConnection, EphemeralDbConnection>>>,
262 ) -> T,
263 T: Future<Output = R>,
264 {
265 let opts = StorageOption::Ephemeral;
266 let db = crate::database::NativeDb::new_unencrypted(&opts).unwrap();
267 let store = EncryptedMessageStore::new(db).unwrap();
268 let conn = store.conn();
269 fun(DbConnection::new(conn)).await
270 }
271
272 impl EncryptedMessageStore<crate::database::NativeDb> {
273 pub async fn new_test() -> Self {
274 let tmp_path = xmtp_common::tmp_path();
275 let opts = StorageOption::Persistent(tmp_path);
276 let db =
277 crate::database::NativeDb::new(&opts, xmtp_common::rand_array::<32>()).unwrap();
278 EncryptedMessageStore::new(db).expect("constructing message store failed.")
279 }
280
281 pub async fn new_test_with_path(path: &str) -> Self {
282 let opts = StorageOption::Persistent(path.to_string());
283 let db =
284 crate::database::NativeDb::new(&opts, xmtp_common::rand_array::<32>()).unwrap();
285 EncryptedMessageStore::new(db).expect("constructing message store failed.")
286 }
287 }
288}