1use cdk_sql_common::mint::SQLMintAuthDatabase;
4use cdk_sql_common::SQLMintDatabase;
5
6use crate::common::SqliteConnectionManager;
7
8pub mod memory;
9
10pub type MintSqliteDatabase = SQLMintDatabase<SqliteConnectionManager>;
12
13pub type MintSqliteAuthDatabase = SQLMintAuthDatabase<SqliteConnectionManager>;
15
16#[cfg(test)]
17mod test {
18 use std::fs::remove_file;
19 use std::str::FromStr;
20 use std::sync::Arc;
21 use std::time::Duration;
22
23 use cdk_common::database::{self, MintAuthDatabase};
24 use cdk_common::secret::Secret;
25 use cdk_common::{mint_db_test, AuthProof, Id, SecretKey, State};
26 use cdk_sql_common::pool::Pool;
27 use cdk_sql_common::stmt::query;
28
29 use super::*;
30 use crate::common::Config;
31
32 async fn provide_db(_test_name: String) -> MintSqliteDatabase {
33 memory::empty().await.unwrap()
34 }
35
36 mint_db_test!(provide_db);
37
38 #[tokio::test]
39 async fn kvstore_compare_and_swap() {
40 cdk_common::database::mint::test::kvstore_compare_and_swap(
41 provide_db("test_kvstore_compare_and_swap".to_owned()).await,
42 )
43 .await;
44 }
45
46 #[tokio::test]
47 async fn bug_opening_relative_path() {
48 let config: Config = "test.db".into();
49
50 let pool = Pool::<SqliteConnectionManager>::new(config);
51 let db = pool.get().await;
52 assert!(db.is_ok());
53 let _ = remove_file("test.db");
54 }
55
56 #[tokio::test]
57 async fn exhausted_in_memory_pool_times_out() {
58 let config: Config = ":memory:".into();
59 let pool = Pool::<SqliteConnectionManager>::new(config);
60
61 let _conn = pool.get().await.expect("valid connection");
62 let result = pool.get_timeout(Duration::from_millis(10)).await;
63
64 assert!(matches!(result, Err(cdk_sql_common::pool::Error::Timeout)));
65 }
66
67 async fn spend_auth_proof(
68 db: Arc<MintSqliteAuthDatabase>,
69 proof: AuthProof,
70 ) -> Result<(), database::Error> {
71 let mut tx = db.as_ref().begin_transaction().await?;
72 tx.add_proof(proof).await?;
73 tx.commit().await
74 }
75
76 #[tokio::test]
77 async fn concurrent_blind_auth_proof_spend_allows_one_request() {
78 let path = std::env::temp_dir().join(format!(
79 "cdk-blind-auth-replay-{}.sqlite",
80 uuid::Uuid::new_v4()
81 ));
82
83 #[cfg(not(feature = "sqlcipher"))]
84 let db = Arc::new(
85 MintSqliteAuthDatabase::new(&path)
86 .await
87 .expect("auth database"),
88 );
89 #[cfg(feature = "sqlcipher")]
90 let db = Arc::new(
91 MintSqliteAuthDatabase::new((path.clone(), "test".to_owned()))
92 .await
93 .expect("auth database"),
94 );
95
96 let proof = AuthProof {
97 keyset_id: Id::from_str("00916bbf7ef91a36").expect("valid keyset id"),
98 secret: Secret::generate(),
99 c: SecretKey::generate().public_key(),
100 dleq: None,
101 };
102 let y = proof.y().expect("proof y");
103
104 let (first, second) = tokio::join!(
105 spend_auth_proof(db.clone(), proof.clone()),
106 spend_auth_proof(db.clone(), proof)
107 );
108
109 assert!(matches!(
110 (&first, &second),
111 (Ok(()), Err(database::Error::Duplicate)) | (Err(database::Error::Duplicate), Ok(()))
112 ));
113 assert_eq!(
114 db.get_proofs_states(&[y]).await.expect("proof state"),
115 vec![Some(State::Spent)]
116 );
117
118 drop(db);
119 remove_file(path).expect("remove auth database");
120 }
121
122 #[tokio::test]
123 async fn open_legacy_and_migrate() {
124 let file = format!(
125 "{}/db.sqlite",
126 std::env::temp_dir().to_str().unwrap_or_default()
127 );
128
129 {
130 let _ = remove_file(&file);
131 #[cfg(not(feature = "sqlcipher"))]
132 let config: Config = file.as_str().into();
133 #[cfg(feature = "sqlcipher")]
134 let config: Config = (file.as_str(), "test").into();
135
136 let pool = Pool::<SqliteConnectionManager>::new(config);
137
138 let conn = pool.get().await.expect("valid connection");
139
140 query(include_str!("../../tests/legacy-sqlx.sql"))
141 .expect("query")
142 .execute(&*conn)
143 .await
144 .expect("create former db failed");
145 }
146
147 #[cfg(not(feature = "sqlcipher"))]
148 let conn = MintSqliteDatabase::new(file.as_str()).await;
149
150 #[cfg(feature = "sqlcipher")]
151 let conn = MintSqliteDatabase::new((file.as_str(), "test")).await;
152
153 assert!(conn.is_ok(), "Failed with {:?}", conn.unwrap_err());
154
155 let _ = remove_file(&file);
156 }
157}