1#[derive(Debug, Clone)]
9pub struct MockAuthMethod {
10 pub should_succeed: bool,
12 pub user_profiles: HashMap<String, ProviderProfile>,
14 pub delay: Option<Duration>,
16}
17
18impl MockAuthMethod {
19 pub fn new_success() -> Self {
27 MockAuthMethod {
28 should_succeed: true,
29 user_profiles: HashMap::new(),
30 delay: None,
31 }
32 }
33
34 pub fn with_user(mut self, user_id: impl Into<String>, profile: ProviderProfile) -> Self {
42 self.user_profiles.insert(user_id.into(), profile);
43 self
44 }
45
46 pub fn with_delay(mut self, delay: Duration) -> Self {
54 self.delay = Some(delay);
55 self
56 }
57}
58use crate::authentication::credentials::{Credential, CredentialMetadata};
59use crate::errors::{AuthError, Result};
60use crate::methods::{AuthMethod, MethodResult};
61use crate::providers::ProviderProfile;
62use crate::storage::AuthStorage;
63use crate::storage::core::SessionData;
64use crate::tokens::AuthToken;
65use dashmap::DashMap;
66use std::collections::HashMap;
67use std::sync::Arc;
68use std::time::Duration;
69use uuid::Uuid;
70#[cfg(test)]
72#[tokio::test]
74async fn test_mock_storage() {
75 use crate::testing::test_infrastructure::TestEnvironmentGuard;
76 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
77
78 let storage = MockStorage::new();
79 let token = helpers::create_test_token("testuser");
80 storage.store_token(&token).await.unwrap();
81 let retrieved = storage.get_token(&token.token_id).await.unwrap();
82 assert!(retrieved.is_some());
83 assert_eq!(retrieved.unwrap().token_id, token.token_id);
84}
85
86#[tokio::test]
87async fn test_failing_mock_storage() {
88 use crate::testing::test_infrastructure::TestEnvironmentGuard;
89 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
90
91 let storage = MockStorage::new_failing();
92 let token = helpers::create_test_token("testuser");
93 let result = storage.store_token(&token).await;
94 assert!(result.is_err());
95}
96
97#[test]
98fn test_secret_loading_from_env() {
99 use crate::auth::AuthFramework;
100 use crate::config::AuthConfig;
101 use crate::testing::test_infrastructure::TestEnvironmentGuard;
102
103 let _env = TestEnvironmentGuard::new().with_jwt_secret("env_secret_value");
104
105 let config = AuthConfig::default().secret("config_secret_value");
106 let framework = AuthFramework::new(config.clone());
107 let token = framework
108 .token_manager()
109 .create_jwt_token("user", vec!["read".to_string()], None);
110 assert!(token.is_ok());
111}
112
113#[test]
114fn test_secret_loading_from_config() {
115 use crate::auth::AuthFramework;
116 use crate::config::AuthConfig;
117 use crate::testing::test_infrastructure::TestEnvironmentGuard;
118
119 let _env = TestEnvironmentGuard::new();
121
122 let config = AuthConfig::default().secret("config_secret_value");
123 let framework = AuthFramework::new(config.clone());
124 let token = framework
125 .token_manager()
126 .create_jwt_token("user", vec!["read".to_string()], None);
127 assert!(token.is_ok());
128}
129
130#[test]
131fn test_secret_missing_returns_error() {
132 use crate::auth::AuthFramework;
133 use crate::config::AuthConfig;
134 use crate::testing::test_infrastructure::TestEnvironmentGuard;
135
136 let _env = TestEnvironmentGuard::new();
140
141 let config = AuthConfig::default().force_production_mode();
142 match AuthFramework::new_validated(config) {
143 Err(e) => {
144 assert!(
146 e.to_string().contains("JWT secret"),
147 "Expected JWT secret error, got: {e}"
148 );
149 }
150 Ok(_) => panic!("Expected error when JWT_SECRET is missing in production"),
151 }
152}
153
154impl AuthMethod for MockAuthMethod {
155 type MethodResult = MethodResult;
156 type AuthToken = AuthToken;
157
158 fn name(&self) -> &str {
159 "mock"
160 }
161
162 fn validate_config(&self) -> Result<()> {
163 Ok(())
164 }
165
166 async fn authenticate(
167 &self,
168 credential: Credential,
169 _metadata: CredentialMetadata,
170 ) -> Result<Self::MethodResult> {
171 if let Some(delay) = self.delay {
173 tokio::time::sleep(delay).await;
174 }
175
176 if !self.should_succeed {
177 return Ok(MethodResult::Failure {
178 reason: "Mock authentication failed".to_string(),
179 });
180 }
181
182 let user_id = match credential {
184 Credential::Password { username, .. } => username.clone(),
185 Credential::ApiKey { key } => format!("api_user_{}", &key[..8.min(key.len())]),
186 Credential::OAuth { .. } => "oauth_user".to_string(),
187 Credential::DeviceCode { .. } => "device_user".to_string(),
188 _ => "test_user".to_string(),
189 };
190
191 let token = AuthToken {
193 token_id: Uuid::new_v4().to_string(),
194 user_id: user_id.clone(),
195 access_token: format!("mock_token_{}", Uuid::new_v4()),
196 refresh_token: Some(format!("refresh_{}", Uuid::new_v4())),
197 token_type: Some("Bearer".to_string()),
198 expires_at: chrono::Utc::now() + chrono::Duration::seconds(3600),
199 scopes: vec!["read".to_string(), "write".to_string()].into(),
200 issued_at: chrono::Utc::now(),
201 auth_method: "mock".to_string(),
202 subject: Some(user_id.clone()),
203 issuer: Some("mock".to_string()),
204 user_profile: None,
205 client_id: Some("test_client".to_string()),
206 permissions: vec!["read:all".to_string(), "write:all".to_string()].into(),
207 roles: vec!["mock_user".to_string()].into(),
208 metadata: crate::tokens::TokenMetadata::default(),
209 };
210
211 Ok(MethodResult::Success(Box::new(token)))
212 }
213
214 async fn refresh_token(&self, _refresh_token: String) -> Result<Self::AuthToken> {
215 if !self.should_succeed {
216 return Err(AuthError::auth_method("mock", "Refresh failed"));
217 }
218
219 Ok(AuthToken {
220 token_id: Uuid::new_v4().to_string(),
221 user_id: "refreshed_user".to_string(),
222 access_token: "mock_refreshed_token".to_string(),
223 refresh_token: Some("mock_new_refresh_token".to_string()),
224 token_type: Some("Bearer".to_string()),
225 expires_at: chrono::Utc::now() + chrono::Duration::seconds(3600),
226 scopes: vec!["read".to_string(), "write".to_string()].into(),
227 issued_at: chrono::Utc::now(),
228 auth_method: "mock".to_string(),
229 client_id: Some("test_client".to_string()),
230 metadata: crate::tokens::TokenMetadata::default(),
231 subject: Some("refreshed_user".to_string()),
232 issuer: Some("mock".to_string()),
233 user_profile: None,
234 permissions: vec!["read:all".to_string(), "write:all".to_string()].into(),
235 roles: vec!["refreshed_user".to_string()].into(),
236 })
237 }
238}
239
240#[derive(Debug, Clone)]
248pub struct MockStorage {
249 tokens: Arc<DashMap<String, AuthToken>>,
250 sessions: Arc<DashMap<String, SessionData>>,
251 kv_store: Arc<DashMap<String, Vec<u8>>>,
252 should_fail: bool,
253}
254
255impl MockStorage {
256 pub fn new() -> Self {
263 Self {
264 tokens: Arc::new(DashMap::new()),
265 sessions: Arc::new(DashMap::new()),
266 kv_store: Arc::new(DashMap::new()),
267 should_fail: false,
268 }
269 }
270
271 pub fn new_failing() -> Self {
279 let mut storage = Self::new();
280 storage.should_fail = true;
281 storage
282 }
283
284 pub fn with_token(&self, token: AuthToken) -> Result<()> {
292 if self.should_fail {
293 return Err(AuthError::internal("Mock storage configured to fail"));
294 }
295
296 self.tokens.insert(token.access_token.clone(), token);
298 Ok(())
299 }
300
301 pub fn clear(&self) {
309 self.tokens.clear();
310 self.sessions.clear();
311 self.kv_store.clear();
312 }
313}
314
315impl Default for MockStorage {
316 fn default() -> Self {
317 Self::new()
318 }
319}
320
321#[async_trait::async_trait]
322impl AuthStorage for MockStorage {
323 async fn store_token(&self, token: &AuthToken) -> Result<()> {
324 if self.should_fail {
325 return Err(AuthError::internal("Mock storage configured to fail"));
326 }
327
328 self.tokens
330 .insert(token.access_token.clone(), token.clone());
331 Ok(())
332 }
333
334 async fn get_token(&self, token_id: &str) -> Result<Option<AuthToken>> {
335 if self.should_fail {
336 return Err(AuthError::internal("Mock storage configured to fail"));
337 }
338
339 for entry in self.tokens.iter() {
341 if entry.value().token_id == token_id {
342 return Ok(Some(entry.value().clone()));
343 }
344 }
345 Ok(None)
346 }
347
348 async fn get_token_by_access_token(&self, access_token: &str) -> Result<Option<AuthToken>> {
349 if self.should_fail {
350 return Err(AuthError::internal("Mock storage configured to fail"));
351 }
352
353 Ok(self
355 .tokens
356 .get(access_token)
357 .map(|entry| entry.value().clone()))
358 }
359
360 async fn update_token(&self, token: &AuthToken) -> Result<()> {
361 if self.should_fail {
362 return Err(AuthError::internal("Mock storage configured to fail"));
363 }
364
365 self.tokens
367 .insert(token.access_token.clone(), token.clone());
368 Ok(())
369 }
370
371 async fn delete_token(&self, token_id: &str) -> Result<()> {
372 if self.should_fail {
373 return Err(AuthError::internal("Mock storage configured to fail"));
374 }
375
376 self.tokens.retain(|_, token| token.token_id != token_id);
378 Ok(())
379 }
380
381 async fn list_user_tokens(&self, user_id: &str) -> Result<Vec<AuthToken>> {
382 if self.should_fail {
383 return Err(AuthError::internal("Mock storage configured to fail"));
384 }
385
386 let mut tokens = Vec::new();
388 for entry in self.tokens.iter() {
389 if entry.value().user_id == user_id {
390 tokens.push(entry.value().clone());
391 }
392 }
393 Ok(tokens)
394 }
395
396 async fn store_session(&self, session_id: &str, data: &SessionData) -> Result<()> {
397 if self.should_fail {
398 return Err(AuthError::internal("Mock storage configured to fail"));
399 }
400
401 self.sessions.insert(session_id.to_string(), data.clone());
403 Ok(())
404 }
405
406 async fn get_session(&self, session_id: &str) -> Result<Option<SessionData>> {
407 if self.should_fail {
408 return Err(AuthError::internal("Mock storage configured to fail"));
409 }
410
411 Ok(self
413 .sessions
414 .get(session_id)
415 .map(|entry| entry.value().clone()))
416 }
417
418 async fn delete_session(&self, session_id: &str) -> Result<()> {
419 if self.should_fail {
420 return Err(AuthError::internal("Mock storage configured to fail"));
421 }
422
423 self.sessions.remove(session_id);
425 Ok(())
426 }
427
428 async fn list_user_sessions(&self, user_id: &str) -> Result<Vec<SessionData>> {
429 if self.should_fail {
430 return Err(AuthError::internal("Mock storage configured to fail"));
431 }
432
433 let mut sessions = Vec::new();
435 for entry in self.sessions.iter() {
436 if entry.value().user_id == user_id && !entry.value().is_expired() {
437 sessions.push(entry.value().clone());
438 }
439 }
440 Ok(sessions)
441 }
442
443 async fn store_kv(&self, key: &str, value: &[u8], _ttl: Option<Duration>) -> Result<()> {
444 if self.should_fail {
445 return Err(AuthError::internal("Mock storage configured to fail"));
446 }
447
448 self.kv_store.insert(key.to_string(), value.to_vec());
450 Ok(())
451 }
452
453 async fn get_kv(&self, key: &str) -> Result<Option<Vec<u8>>> {
454 if self.should_fail {
455 return Err(AuthError::internal("Mock storage configured to fail"));
456 }
457
458 Ok(self.kv_store.get(key).map(|entry| entry.value().clone()))
460 }
461
462 async fn delete_kv(&self, key: &str) -> Result<()> {
463 if self.should_fail {
464 return Err(AuthError::internal("Mock storage configured to fail"));
465 }
466
467 self.kv_store.remove(key);
469 Ok(())
470 }
471
472 async fn cleanup_expired(&self) -> Result<()> {
473 if self.should_fail {
474 return Err(AuthError::internal("Mock storage configured to fail"));
475 }
476
477 let now = chrono::Utc::now();
478
479 self.tokens.retain(|_, token| token.expires_at > now);
481
482 Ok(())
483 }
484
485 async fn count_active_sessions(&self) -> Result<u64> {
486 if self.should_fail {
487 return Err(AuthError::internal("Mock storage configured to fail"));
488 }
489
490 let mut count = 0u64;
492 for entry in self.sessions.iter() {
493 if !entry.value().is_expired() {
494 count += 1;
495 }
496 }
497 Ok(count)
498 }
499}
500
501pub mod helpers {
503 use super::*;
504 pub fn create_test_user_profile(user_id: &str) -> ProviderProfile {
513 ProviderProfile::new()
514 .with_id(user_id)
515 .with_provider("test")
516 .with_name(Some(format!("Test User {}", user_id)))
517 .with_email(Some(format!("{}@test.com", user_id)))
518 .with_email_verified(true)
519 }
520
521 pub fn create_test_token(user_id: &str) -> AuthToken {
529 let now = chrono::Utc::now();
530 AuthToken {
531 token_id: Uuid::new_v4().to_string(),
532 user_id: user_id.to_string(),
533 access_token: format!("test_token_{}", Uuid::new_v4()),
534 refresh_token: Some(format!("refresh_token_{}", Uuid::new_v4())),
535 token_type: Some("Bearer".to_string()),
536 expires_at: now + chrono::Duration::seconds(3600),
537 scopes: vec!["read".to_string(), "write".to_string()].into(),
538 issued_at: now,
539 auth_method: "test".to_string(),
540 client_id: Some("test_client".to_string()),
541 metadata: crate::tokens::TokenMetadata::default(),
542 subject: Some(user_id.to_string()),
543 issuer: Some("test".to_string()),
544 user_profile: None,
545 permissions: vec!["read:all".to_string(), "write:all".to_string()].into(),
546 roles: vec!["test_user".to_string()].into(),
547 }
548 }
549
550 pub fn create_test_credentials() -> Vec<Credential> {
558 vec![
559 Credential::password("testuser", "testpass"),
560 Credential::api_key("test_api_key"),
561 Credential::oauth_code("test_auth_code"),
562 Credential::device_code("test_device_code", "test_client_id"),
563 Credential::jwt("test.jwt.token"),
564 ]
565 }
566}
567
568#[cfg(test)]
571mod edge_tests {
572 use super::*;
573 use crate::testing::test_infrastructure::TestEnvironmentGuard;
574
575 #[tokio::test]
578 async fn test_mock_auth_failure_mode() {
579 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
580 let mock = MockAuthMethod {
581 should_succeed: false,
582 user_profiles: HashMap::new(),
583 delay: None,
584 };
585 let cred = Credential::password("user", "pass");
586 let meta = CredentialMetadata::default();
587 let result = mock.authenticate(cred, meta).await.unwrap();
588 match result {
589 MethodResult::Failure { reason } => {
590 assert!(reason.contains("failed"), "Expected failure: {reason}");
591 }
592 _ => panic!("Expected Failure variant"),
593 }
594 }
595
596 #[tokio::test]
597 async fn test_mock_auth_api_key_empty() {
598 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
599 let mock = MockAuthMethod::new_success();
600 let cred = Credential::api_key("");
601 let meta = CredentialMetadata::default();
602 let result = mock.authenticate(cred, meta).await.unwrap();
604 match result {
605 MethodResult::Success(token) => {
606 assert!(token.user_id.starts_with("api_user_"));
607 }
608 _ => panic!("Expected success"),
609 }
610 }
611
612 #[tokio::test]
613 async fn test_mock_auth_api_key_short() {
614 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
615 let mock = MockAuthMethod::new_success();
616 let cred = Credential::api_key("abc");
617 let meta = CredentialMetadata::default();
618 let result = mock.authenticate(cred, meta).await.unwrap();
619 match result {
620 MethodResult::Success(token) => {
621 assert_eq!(token.user_id, "api_user_abc");
622 }
623 _ => panic!("Expected success"),
624 }
625 }
626
627 #[tokio::test]
628 async fn test_mock_auth_catch_all_credential() {
629 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
630 let mock = MockAuthMethod::new_success();
631 let cred = Credential::jwt("some.jwt.token");
632 let meta = CredentialMetadata::default();
633 let result = mock.authenticate(cred, meta).await.unwrap();
634 match result {
635 MethodResult::Success(token) => {
636 assert_eq!(token.user_id, "test_user");
637 }
638 _ => panic!("Expected success"),
639 }
640 }
641
642 #[tokio::test]
645 async fn test_mock_refresh_success() {
646 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
647 let mock = MockAuthMethod::new_success();
648 let token = mock
649 .refresh_token("old_refresh".to_string())
650 .await
651 .unwrap();
652 assert_eq!(token.user_id, "refreshed_user");
653 assert!(token.refresh_token.is_some());
654 }
655
656 #[tokio::test]
657 async fn test_mock_refresh_failure() {
658 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
659 let mock = MockAuthMethod {
660 should_succeed: false,
661 user_profiles: HashMap::new(),
662 delay: None,
663 };
664 let result = mock.refresh_token("old_refresh".to_string()).await;
665 assert!(result.is_err());
666 }
667
668 #[tokio::test]
671 async fn test_storage_get_token_by_access_token() {
672 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
673 let storage = MockStorage::new();
674 let token = helpers::create_test_token("user1");
675 let access = token.access_token.clone();
676 storage.store_token(&token).await.unwrap();
677 let found = storage
678 .get_token_by_access_token(&access)
679 .await
680 .unwrap();
681 assert!(found.is_some());
682 assert_eq!(found.unwrap().user_id, "user1");
683 }
684
685 #[tokio::test]
686 async fn test_storage_get_token_by_access_token_not_found() {
687 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
688 let storage = MockStorage::new();
689 let found = storage
690 .get_token_by_access_token("nonexistent")
691 .await
692 .unwrap();
693 assert!(found.is_none());
694 }
695
696 #[tokio::test]
697 async fn test_storage_update_token() {
698 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
699 let storage = MockStorage::new();
700 let mut token = helpers::create_test_token("user1");
701 storage.store_token(&token).await.unwrap();
702 token.user_id = "updated_user".to_string();
703 storage.update_token(&token).await.unwrap();
704 let found = storage
705 .get_token_by_access_token(&token.access_token)
706 .await
707 .unwrap()
708 .unwrap();
709 assert_eq!(found.user_id, "updated_user");
710 }
711
712 #[tokio::test]
713 async fn test_storage_delete_token() {
714 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
715 let storage = MockStorage::new();
716 let token = helpers::create_test_token("user1");
717 let tid = token.token_id.clone();
718 storage.store_token(&token).await.unwrap();
719 storage.delete_token(&tid).await.unwrap();
720 let found = storage.get_token(&tid).await.unwrap();
721 assert!(found.is_none());
722 }
723
724 #[tokio::test]
725 async fn test_storage_list_user_tokens_filters_by_user() {
726 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
727 let storage = MockStorage::new();
728 let t1 = helpers::create_test_token("alice");
729 let t2 = helpers::create_test_token("alice");
730 let t3 = helpers::create_test_token("bob");
731 storage.store_token(&t1).await.unwrap();
732 storage.store_token(&t2).await.unwrap();
733 storage.store_token(&t3).await.unwrap();
734 let alice_tokens = storage.list_user_tokens("alice").await.unwrap();
735 assert_eq!(alice_tokens.len(), 2);
736 let bob_tokens = storage.list_user_tokens("bob").await.unwrap();
737 assert_eq!(bob_tokens.len(), 1);
738 }
739
740 #[tokio::test]
743 async fn test_storage_session_crud() {
744 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
745 let storage = MockStorage::new();
746 let session = SessionData {
747 session_id: "sess1".to_string(),
748 user_id: "user1".to_string(),
749 created_at: chrono::Utc::now(),
750 expires_at: chrono::Utc::now() + chrono::Duration::seconds(3600),
751 last_activity: chrono::Utc::now(),
752 ip_address: Some("127.0.0.1".to_string()),
753 user_agent: None,
754 data: Default::default(),
755 };
756 storage.store_session("sess1", &session).await.unwrap();
757 let found = storage.get_session("sess1").await.unwrap();
758 assert!(found.is_some());
759 assert_eq!(found.unwrap().user_id, "user1");
760
761 storage.delete_session("sess1").await.unwrap();
762 let gone = storage.get_session("sess1").await.unwrap();
763 assert!(gone.is_none());
764 }
765
766 #[tokio::test]
767 async fn test_storage_list_user_sessions_filters_expired() {
768 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
769 let storage = MockStorage::new();
770 let active = SessionData {
771 session_id: "active".to_string(),
772 user_id: "user1".to_string(),
773 created_at: chrono::Utc::now(),
774 expires_at: chrono::Utc::now() + chrono::Duration::seconds(3600),
775 last_activity: chrono::Utc::now(),
776 ip_address: None,
777 user_agent: None,
778 data: Default::default(),
779 };
780 let expired = SessionData {
781 session_id: "expired".to_string(),
782 user_id: "user1".to_string(),
783 created_at: chrono::Utc::now() - chrono::Duration::seconds(7200),
784 expires_at: chrono::Utc::now() - chrono::Duration::seconds(3600),
785 last_activity: chrono::Utc::now() - chrono::Duration::seconds(7200),
786 ip_address: None,
787 user_agent: None,
788 data: Default::default(),
789 };
790 storage.store_session("active", &active).await.unwrap();
791 storage.store_session("expired", &expired).await.unwrap();
792 let sessions = storage.list_user_sessions("user1").await.unwrap();
793 assert_eq!(sessions.len(), 1);
794 assert_eq!(sessions[0].session_id, "active");
795 }
796
797 #[tokio::test]
800 async fn test_storage_kv_crud() {
801 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
802 let storage = MockStorage::new();
803 storage
804 .store_kv("key1", b"value1", None)
805 .await
806 .unwrap();
807 let val = storage.get_kv("key1").await.unwrap();
808 assert_eq!(val.unwrap(), b"value1");
809
810 storage.delete_kv("key1").await.unwrap();
811 let gone = storage.get_kv("key1").await.unwrap();
812 assert!(gone.is_none());
813 }
814
815 #[tokio::test]
816 async fn test_storage_kv_not_found() {
817 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
818 let storage = MockStorage::new();
819 let val = storage.get_kv("nonexistent").await.unwrap();
820 assert!(val.is_none());
821 }
822
823 #[tokio::test]
826 async fn test_storage_cleanup_expired_tokens() {
827 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
828 let storage = MockStorage::new();
829 let mut expired_token = helpers::create_test_token("user1");
830 expired_token.expires_at = chrono::Utc::now() - chrono::Duration::seconds(10);
831 let valid_token = helpers::create_test_token("user2");
832 storage.store_token(&expired_token).await.unwrap();
833 storage.store_token(&valid_token).await.unwrap();
834 storage.cleanup_expired().await.unwrap();
835 let found_expired = storage
837 .get_token_by_access_token(&expired_token.access_token)
838 .await
839 .unwrap();
840 assert!(found_expired.is_none());
841 let found_valid = storage
843 .get_token_by_access_token(&valid_token.access_token)
844 .await
845 .unwrap();
846 assert!(found_valid.is_some());
847 }
848
849 #[test]
852 fn test_create_test_credentials_all_variants() {
853 let creds = helpers::create_test_credentials();
854 assert_eq!(creds.len(), 5);
855 assert!(matches!(&creds[0], Credential::Password { .. }));
856 assert!(matches!(&creds[1], Credential::ApiKey { .. }));
857 assert!(matches!(&creds[2], Credential::OAuth { .. }));
858 assert!(matches!(&creds[3], Credential::DeviceCode { .. }));
859 assert!(matches!(&creds[4], Credential::Jwt { .. }));
860 }
861
862 #[tokio::test]
865 async fn test_storage_count_active_sessions() {
866 let _env = TestEnvironmentGuard::new().with_jwt_secret("test-secret");
867 let storage = MockStorage::new();
868 let active = SessionData {
869 session_id: "active1".to_string(),
870 user_id: "user1".to_string(),
871 created_at: chrono::Utc::now(),
872 expires_at: chrono::Utc::now() + chrono::Duration::seconds(3600),
873 last_activity: chrono::Utc::now(),
874 ip_address: None,
875 user_agent: None,
876 data: Default::default(),
877 };
878 let expired = SessionData {
879 session_id: "expired1".to_string(),
880 user_id: "user2".to_string(),
881 created_at: chrono::Utc::now() - chrono::Duration::seconds(7200),
882 expires_at: chrono::Utc::now() - chrono::Duration::seconds(3600),
883 last_activity: chrono::Utc::now() - chrono::Duration::seconds(7200),
884 ip_address: None,
885 user_agent: None,
886 data: Default::default(),
887 };
888 storage.store_session("active1", &active).await.unwrap();
889 storage.store_session("expired1", &expired).await.unwrap();
890 let count = storage.count_active_sessions().await.unwrap();
891 assert_eq!(count, 1);
892 }
893}