db_integration.rs (5832B)
1 use anyhow::Result; 2 use kych_oauth2_gateway_lib::db::{authorization_codes, clients, sessions, tokens}; 3 use serde_json::json; 4 use sqlx::{PgPool, postgres::PgPoolOptions}; 5 use uuid::Uuid; 6 7 async fn get_pool() -> Option<PgPool> { 8 let url = match std::env::var("DATABASE_URL") { 9 Ok(url) if !url.trim().is_empty() => url, 10 _ => { 11 eprintln!("DATABASE_URL not set; skipping DB integration tests."); 12 return None; 13 } 14 }; 15 16 match PgPoolOptions::new().max_connections(5).connect(&url).await { 17 Ok(pool) => Some(pool), 18 Err(err) => { 19 eprintln!("Failed to connect to DATABASE_URL; skipping tests: {}", err); 20 None 21 } 22 } 23 } 24 25 struct TestClient { 26 client: clients::Client, 27 secret: String, 28 } 29 30 async fn create_test_client(pool: &PgPool) -> Result<TestClient> { 31 let suffix = Uuid::new_v4().to_string(); 32 let client_id = format!("test-client-{}", suffix); 33 let secret = format!("secret-{}", suffix); 34 let verifier_url = "https://verifier.example"; 35 let redirect_uri = "https://example.com/callback"; 36 let accepted_issuer_dids = Some("did:example:issuer1,did:example:issuer2"); 37 38 let client = clients::register_client( 39 pool, 40 &client_id, 41 &secret, 42 verifier_url, 43 None, 44 redirect_uri, 45 accepted_issuer_dids, 46 ) 47 .await?; 48 49 Ok(TestClient { client, secret }) 50 } 51 52 #[tokio::test] 53 async fn test_clients_crud() -> Result<()> { 54 let Some(pool) = get_pool().await else { return Ok(()); }; 55 56 let test_client = create_test_client(&pool).await?; 57 let client = &test_client.client; 58 59 let fetched = clients::get_client_by_id(&pool, &client.client_id).await?; 60 assert!(fetched.is_some()); 61 assert_eq!(fetched.as_ref().unwrap().id, client.id); 62 63 let auth_ok = clients::authenticate_client(&pool, &client.client_id, "wrong-secret").await?; 64 assert!(auth_ok.is_none()); 65 66 let auth_ok = clients::authenticate_client(&pool, &client.client_id, &test_client.secret) 67 .await?; 68 assert!(auth_ok.is_some()); 69 70 let updated = clients::update_client( 71 &pool, 72 client.id, 73 Some("https://verifier.example/v2"), 74 Some("/management/api/verifications"), 75 Some("https://example.com/redirect2"), 76 None, 77 ) 78 .await?; 79 assert_eq!(updated.redirect_uri, "https://example.com/redirect2"); 80 81 let all = clients::list_clients(&pool).await?; 82 assert!(all.iter().any(|c| c.id == client.id)); 83 84 let deleted = clients::delete_client(&pool, client.id).await?; 85 assert!(deleted); 86 87 Ok(()) 88 } 89 90 #[tokio::test] 91 async fn test_sessions_codes_tokens_flow() -> Result<()> { 92 let Some(pool) = get_pool().await else { return Ok(()); }; 93 94 let test_client = create_test_client(&pool).await?; 95 let client = &test_client.client; 96 97 let nonce = format!("nonce-{}", Uuid::new_v4()); 98 let session = sessions::create_session(&pool, &client.client_id, &nonce, 5) 99 .await? 100 .expect("client should exist"); 101 assert_eq!(session.nonce, nonce); 102 103 let scope = "first_name last_name"; 104 let redirect_uri = "https://example.com/callback"; 105 let state = "state-123"; 106 let authorize = sessions::get_session_for_authorize( 107 &pool, 108 &nonce, 109 &client.client_id, 110 scope, 111 redirect_uri, 112 state, 113 ) 114 .await? 115 .expect("session should exist"); 116 assert_eq!(authorize.scope, scope); 117 assert_eq!(authorize.redirect_uri.as_deref(), Some(redirect_uri)); 118 assert_eq!(authorize.state.as_deref(), Some(state)); 119 120 let verification_url = "https://verifier.example/verify/1"; 121 let request_id = Uuid::new_v4().to_string(); 122 let authorized = sessions::update_session_authorized( 123 &pool, 124 authorize.session_id, 125 verification_url, 126 None, 127 &request_id, 128 None, 129 ) 130 .await?; 131 assert_eq!(authorized.request_id, request_id); 132 133 let authorization_code = format!("code-{}", Uuid::new_v4()); 134 let issued_code = sessions::verify_session_and_issue_code( 135 &pool, 136 authorize.session_id, 137 sessions::SessionStatus::Verified, 138 &authorization_code, 139 10, 140 client.id, 141 "", 142 Some(&json!({"vc": "data"})), 143 ) 144 .await?; 145 assert_eq!(issued_code, authorization_code); 146 147 let code_row = authorization_codes::get_code_by_session(&pool, authorize.session_id) 148 .await? 149 .expect("code should exist"); 150 assert!(!code_row.used); 151 152 let exchange = authorization_codes::get_code_for_token_exchange(&pool, &authorization_code) 153 .await? 154 .expect("code should be exchangeable"); 155 assert!(!exchange.was_already_used); 156 assert_eq!(exchange.session_status, sessions::SessionStatus::Verified); 157 assert!(exchange.existing_token.is_none()); 158 159 let exchange_again = authorization_codes::get_code_for_token_exchange(&pool, &authorization_code) 160 .await? 161 .expect("code still exists"); 162 assert!(exchange_again.was_already_used); 163 164 let token_value = format!("token-{}", Uuid::new_v4()); 165 let token = tokens::create_token_and_complete_session( 166 &pool, 167 authorize.session_id, 168 &token_value, 169 60, 170 ) 171 .await?; 172 assert_eq!(token.token, token_value); 173 174 let token_data = tokens::get_token_with_session(&pool, &token_value) 175 .await? 176 .expect("token should exist"); 177 assert!(!token_data.revoked); 178 assert_eq!(token_data.session_status, sessions::SessionStatus::Completed); 179 180 let status_data = sessions::get_session_for_status(&pool, &request_id) 181 .await? 182 .expect("status should exist"); 183 assert_eq!(status_data.status, sessions::SessionStatus::Completed); 184 185 let _ = clients::delete_client(&pool, client.id).await?; 186 Ok(()) 187 }