actix_jwt/store/
factory.rs1use crate::core::TokenStore;
8use crate::errors::JwtError;
9
10use super::memory::InMemoryRefreshTokenStore;
11
12#[derive(Debug, Clone, PartialEq)]
23pub enum StoreType {
24 Memory,
26 Redis,
28}
29
30pub struct StoreConfig {
41 pub store_type: StoreType,
43 #[cfg(feature = "redis-store")]
46 pub redis: Option<super::redis::RedisConfig>,
47}
48
49impl Default for StoreConfig {
50 fn default() -> Self {
51 Self {
52 store_type: StoreType::Memory,
53 #[cfg(feature = "redis-store")]
54 redis: None,
55 }
56 }
57}
58
59pub struct Factory;
74
75impl Factory {
76 pub fn new() -> Self {
78 Factory
79 }
80
81 pub async fn create_store(
89 &self,
90 config: &StoreConfig,
91 ) -> Result<Box<dyn TokenStore>, JwtError> {
92 match config.store_type {
93 StoreType::Memory => Ok(Box::new(InMemoryRefreshTokenStore::new())),
94 StoreType::Redis => {
95 #[cfg(feature = "redis-store")]
96 {
97 let redis_config = config.redis.clone().unwrap_or_default();
98 let store = super::redis::RedisRefreshTokenStore::new(&redis_config).await?;
99 Ok(Box::new(store))
100 }
101 #[cfg(not(feature = "redis-store"))]
102 {
103 Err(JwtError::Internal(
104 "Redis store feature not enabled. Enable the 'redis-store' feature in Cargo.toml".into(),
105 ))
106 }
107 }
108 }
109 }
110}
111
112impl Default for Factory {
113 fn default() -> Self {
114 Self::new()
115 }
116}
117
118pub fn new_memory_store() -> Box<dyn TokenStore> {
132 Box::new(InMemoryRefreshTokenStore::new())
133}
134
135pub fn must_new_memory_store() -> Box<dyn TokenStore> {
150 new_memory_store()
151}
152
153pub async fn new_store(config: &StoreConfig) -> Result<Box<dyn TokenStore>, JwtError> {
168 Factory::new().create_store(config).await
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174
175 #[tokio::test]
176 async fn test_factory_create_store_memory() {
177 let factory = Factory::new();
178 let config = StoreConfig {
179 store_type: StoreType::Memory,
180 #[cfg(feature = "redis-store")]
181 redis: None,
182 };
183
184 let store = factory.create_store(&config).await;
185 assert!(
186 store.is_ok(),
187 "Factory should create memory store successfully"
188 );
189
190 let store = store.unwrap();
192 let count = store.count().await.unwrap();
193 assert_eq!(count, 0, "New memory store should be empty");
194 }
195
196 #[tokio::test]
197 async fn test_factory_default_config() {
198 let factory = Factory::new();
199 let config = StoreConfig::default();
200
201 assert_eq!(
202 config.store_type,
203 StoreType::Memory,
204 "Default config should use Memory type"
205 );
206
207 let store = factory.create_store(&config).await;
208 assert!(
209 store.is_ok(),
210 "Factory should create store from default config"
211 );
212 }
213
214 #[tokio::test]
215 async fn test_new_store_memory() {
216 let config = StoreConfig {
217 store_type: StoreType::Memory,
218 #[cfg(feature = "redis-store")]
219 redis: None,
220 };
221
222 let store = new_store(&config).await;
223 assert!(
224 store.is_ok(),
225 "new_store() should create memory store successfully"
226 );
227
228 let store = store.unwrap();
229 let count = store.count().await.unwrap();
230 assert_eq!(count, 0);
231 }
232
233 #[tokio::test]
234 async fn test_new_memory_store() {
235 let store = new_memory_store();
236 let count = store.count().await.unwrap();
237 assert_eq!(count, 0, "new_memory_store() should return an empty store");
238 }
239
240 #[tokio::test]
241 async fn test_default_store() {
242 let store = crate::store::default_store();
243 let count = store.count().await.unwrap();
244 assert_eq!(count, 0, "default_store() should return an empty store");
245 }
246
247 #[tokio::test]
248 async fn test_must_new_memory_store() {
249 let store = must_new_memory_store();
250 let count = store.count().await.unwrap();
251 assert_eq!(
252 count, 0,
253 "must_new_memory_store() should return an empty store"
254 );
255 }
256
257 #[cfg(not(feature = "redis-store"))]
258 #[tokio::test]
259 async fn test_factory_create_store_redis_without_feature() {
260 let factory = Factory::new();
261 let config = StoreConfig {
262 store_type: StoreType::Redis,
263 };
264
265 let result = factory.create_store(&config).await;
266 assert!(
267 result.is_err(),
268 "Creating Redis store without feature should fail"
269 );
270
271 let err_msg = match result {
272 Err(e) => e.to_string(),
273 Ok(_) => panic!("Expected error but got Ok"),
274 };
275 assert!(
276 err_msg.contains("Redis store feature not enabled"),
277 "Error should mention feature not enabled, got: {}",
278 err_msg
279 );
280 }
281}