From 72708a05f31a725d1964e6e2047c1f4a67f71c20 Mon Sep 17 00:00:00 2001 From: perf3ct Date: Fri, 27 Jun 2025 05:03:27 +0000 Subject: [PATCH] feat(oidc): fix oidc, tests, and everything in between --- .../Auth/__tests__/Login.oidc.test.tsx | 24 ++- .../Auth/__tests__/OidcCallback.test.tsx | 30 ++- frontend/src/test/setup.ts | 17 +- src/db/mod.rs | 26 ++- src/routes/auth.rs | 41 +++- src/tests/config_oidc_tests.rs | 22 ++ src/tests/oidc_tests.rs | 189 +++++++++++++++--- tests/auto_resume_tests.rs | 6 + tests/document_upload_hash_duplicate_tests.rs | 6 + tests/ignored_files_integration_tests.rs | 6 + tests/source_scheduler_simple_tests.rs | 6 + tests/source_scheduler_tests.rs | 6 + tests/source_sync_hash_duplicate_tests.rs | 6 + tests/webdav_comprehensive_tests.rs | 5 + tests/webdav_integration_tests.rs | 6 + 15 files changed, 348 insertions(+), 48 deletions(-) diff --git a/frontend/src/components/Auth/__tests__/Login.oidc.test.tsx b/frontend/src/components/Auth/__tests__/Login.oidc.test.tsx index f51eb15..9232e0b 100644 --- a/frontend/src/components/Auth/__tests__/Login.oidc.test.tsx +++ b/frontend/src/components/Auth/__tests__/Login.oidc.test.tsx @@ -44,6 +44,7 @@ Object.defineProperty(window, 'location', { writable: true }); + // Mock AuthContext const mockAuthContextValue = { user: null, @@ -54,16 +55,35 @@ const mockAuthContextValue = { }; const MockAuthProvider = ({ children }: { children: React.ReactNode }) => ( -
{children}
+ + {children} + ); const MockThemeProvider = ({ children }: { children: React.ReactNode }) => ( -
{children}
+ + {children} + ); describe('Login - OIDC Features', () => { beforeEach(() => { vi.clearAllMocks(); + + // Mock window.matchMedia + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), + removeListener: vi.fn(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); }); const renderLogin = () => { diff --git a/frontend/src/components/Auth/__tests__/OidcCallback.test.tsx b/frontend/src/components/Auth/__tests__/OidcCallback.test.tsx index c4a5f6b..37c2601 100644 --- a/frontend/src/components/Auth/__tests__/OidcCallback.test.tsx +++ b/frontend/src/components/Auth/__tests__/OidcCallback.test.tsx @@ -17,14 +17,16 @@ vi.mock('../../../services/api', () => ({ } })); -// Mock useNavigate +// Mock useNavigate and useSearchParams const mockNavigate = vi.fn(); +const mockUseSearchParams = vi.fn(() => [new URLSearchParams('code=test-code&state=test-state')]); + vi.mock('react-router-dom', async () => { const actual = await vi.importActual('react-router-dom'); return { ...actual, useNavigate: () => mockNavigate, - useSearchParams: () => [new URLSearchParams('code=test-code&state=test-state')] + useSearchParams: mockUseSearchParams }; }); @@ -45,6 +47,7 @@ Object.defineProperty(window, 'location', { writable: true }); + // Mock AuthContext const mockAuthContextValue = { user: null, @@ -55,12 +58,29 @@ const mockAuthContextValue = { }; const MockAuthProvider = ({ children }: { children: React.ReactNode }) => ( -
{children}
+ + {children} + ); describe('OidcCallback', () => { beforeEach(() => { vi.clearAllMocks(); + + // Mock window.matchMedia + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), + removeListener: vi.fn(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); }); const renderOidcCallback = () => { @@ -106,7 +126,7 @@ describe('OidcCallback', () => { it('handles authentication error from URL params', () => { // Mock useSearchParams to return error - vi.mocked(require('react-router-dom').useSearchParams).mockReturnValue([ + mockUseSearchParams.mockReturnValueOnce([ new URLSearchParams('error=access_denied&error_description=User+denied+access') ]); @@ -118,7 +138,7 @@ describe('OidcCallback', () => { it('handles missing authorization code', () => { // Mock useSearchParams to return no code - vi.mocked(require('react-router-dom').useSearchParams).mockReturnValue([ + mockUseSearchParams.mockReturnValueOnce([ new URLSearchParams('') ]); diff --git a/frontend/src/test/setup.ts b/frontend/src/test/setup.ts index ea93d68..2286153 100644 --- a/frontend/src/test/setup.ts +++ b/frontend/src/test/setup.ts @@ -19,4 +19,19 @@ vi.mock('axios', () => ({ defaults: { headers: { common: {} } }, })), }, -})) \ No newline at end of file +})) + +// Mock window.matchMedia +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: vi.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: vi.fn(), // deprecated + removeListener: vi.fn(), // deprecated + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), +}) \ No newline at end of file diff --git a/src/db/mod.rs b/src/db/mod.rs index 288f28c..e1d28bf 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -88,23 +88,41 @@ impl Database { .execute(&self.pool) .await?; - // Create users table + // Create users table with OIDC support sqlx::query( r#" CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), username VARCHAR(255) UNIQUE NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, - password_hash VARCHAR(255) NOT NULL, - role VARCHAR(10) DEFAULT 'user', + password_hash VARCHAR(255), + role VARCHAR(20) DEFAULT 'user', created_at TIMESTAMPTZ DEFAULT NOW(), - updated_at TIMESTAMPTZ DEFAULT NOW() + updated_at TIMESTAMPTZ DEFAULT NOW(), + oidc_subject VARCHAR(255), + oidc_issuer VARCHAR(255), + oidc_email VARCHAR(255), + auth_provider VARCHAR(50) DEFAULT 'local', + CONSTRAINT check_auth_method CHECK ( + (auth_provider = 'local' AND password_hash IS NOT NULL) OR + (auth_provider = 'oidc' AND oidc_subject IS NOT NULL AND oidc_issuer IS NOT NULL) + ), + CONSTRAINT check_user_role CHECK (role IN ('admin', 'user')) ) "#, ) .execute(&self.pool) .await?; + // Create indexes for OIDC + sqlx::query(r#"CREATE INDEX IF NOT EXISTS idx_users_oidc_subject_issuer ON users(oidc_subject, oidc_issuer)"#) + .execute(&self.pool) + .await?; + + sqlx::query(r#"CREATE INDEX IF NOT EXISTS idx_users_auth_provider ON users(auth_provider)"#) + .execute(&self.pool) + .await?; + // Create documents table sqlx::query( diff --git a/src/routes/auth.rs b/src/routes/auth.rs index 7c20f8f..5091c3f 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -23,6 +23,7 @@ pub fn router() -> Router> { .route("/oidc/callback", get(oidc_callback)) } + #[utoipa::path( post, path = "/api/auth/register", @@ -170,6 +171,9 @@ async fn oidc_callback( State(state): State>, Query(params): Query, ) -> Result, StatusCode> { + tracing::info!("OIDC callback called with params: code={:?}, state={:?}, error={:?}", + params.code, params.state, params.error); + if let Some(error) = params.error { tracing::error!("OIDC callback error: {}", error); return Err(StatusCode::UNAUTHORIZED); @@ -201,9 +205,15 @@ async fn oidc_callback( })?; // Find or create user in database - let user = match state.db.get_user_by_oidc_subject(&user_info.sub, &state.config.oidc_issuer_url.as_ref().unwrap()).await { - Ok(Some(existing_user)) => existing_user, + let issuer_url = state.config.oidc_issuer_url.as_ref().unwrap(); + tracing::debug!("Looking up user by OIDC subject: {} and issuer: {}", user_info.sub, issuer_url); + let user = match state.db.get_user_by_oidc_subject(&user_info.sub, issuer_url).await { + Ok(Some(existing_user)) => { + tracing::debug!("Found existing OIDC user: {}", existing_user.username); + existing_user + }, Ok(None) => { + tracing::debug!("Creating new OIDC user"); // Create new user let username = user_info.preferred_username .or_else(|| user_info.email.clone()) @@ -211,6 +221,8 @@ async fn oidc_callback( let email = user_info.email.unwrap_or_else(|| format!("{}@oidc.local", username)); + tracing::debug!("New user details - username: {}, email: {}", username, email); + let create_user = CreateUser { username, email: email.clone(), @@ -218,15 +230,23 @@ async fn oidc_callback( role: Some(UserRole::User), }; - state.db.create_oidc_user( + let result = state.db.create_oidc_user( create_user, &user_info.sub, - &state.config.oidc_issuer_url.as_ref().unwrap(), + issuer_url, &email, - ).await.map_err(|e| { - tracing::error!("Failed to create OIDC user: {}", e); - StatusCode::INTERNAL_SERVER_ERROR - })? + ).await; + + match result { + Ok(user) => { + tracing::info!("Successfully created OIDC user: {}", user.username); + user + }, + Err(e) => { + tracing::error!("Failed to create OIDC user: {} (full error: {:#})", e, e); + return Err(StatusCode::INTERNAL_SERVER_ERROR); + } + } } Err(e) => { tracing::error!("Database error during OIDC lookup: {}", e); @@ -236,7 +256,10 @@ async fn oidc_callback( // Create JWT token let token = create_jwt(&user, &state.config.jwt_secret) - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + .map_err(|e| { + tracing::error!("Failed to create JWT token: {}", e); + StatusCode::INTERNAL_SERVER_ERROR + })?; Ok(Json(LoginResponse { token, diff --git a/src/tests/config_oidc_tests.rs b/src/tests/config_oidc_tests.rs index 321b03c..d6eaff2 100644 --- a/src/tests/config_oidc_tests.rs +++ b/src/tests/config_oidc_tests.rs @@ -40,11 +40,22 @@ mod tests { #[test] fn test_oidc_enabled_from_env() { + // Clean up environment first to ensure test isolation + env::remove_var("OIDC_ENABLED"); + env::remove_var("OIDC_CLIENT_ID"); + env::remove_var("OIDC_CLIENT_SECRET"); + env::remove_var("OIDC_ISSUER_URL"); + env::remove_var("OIDC_REDIRECT_URI"); + env::remove_var("DATABASE_URL"); + env::remove_var("JWT_SECRET"); + env::set_var("OIDC_ENABLED", "true"); env::set_var("OIDC_CLIENT_ID", "test-client-id"); env::set_var("OIDC_CLIENT_SECRET", "test-client-secret"); env::set_var("OIDC_ISSUER_URL", "https://provider.example.com"); env::set_var("OIDC_REDIRECT_URI", "http://localhost:8000/auth/oidc/callback"); + env::set_var("DATABASE_URL", "postgresql://test:test@localhost/test"); + env::set_var("JWT_SECRET", "test-secret"); let config = Config::from_env().unwrap(); @@ -60,6 +71,8 @@ mod tests { env::remove_var("OIDC_CLIENT_SECRET"); env::remove_var("OIDC_ISSUER_URL"); env::remove_var("OIDC_REDIRECT_URI"); + env::remove_var("DATABASE_URL"); + env::remove_var("JWT_SECRET"); } #[test] @@ -83,6 +96,15 @@ mod tests { ]; for (value, expected) in test_cases { + // Clean up environment first for each iteration + env::remove_var("OIDC_ENABLED"); + env::remove_var("OIDC_CLIENT_ID"); + env::remove_var("OIDC_CLIENT_SECRET"); + env::remove_var("OIDC_ISSUER_URL"); + env::remove_var("OIDC_REDIRECT_URI"); + env::remove_var("DATABASE_URL"); + env::remove_var("JWT_SECRET"); + env::set_var("OIDC_ENABLED", value); env::set_var("DATABASE_URL", "postgresql://test:test@localhost/test"); env::set_var("JWT_SECRET", "test-secret"); diff --git a/src/tests/oidc_tests.rs b/src/tests/oidc_tests.rs index a20f29f..e088bfd 100644 --- a/src/tests/oidc_tests.rs +++ b/src/tests/oidc_tests.rs @@ -1,16 +1,76 @@ #[cfg(test)] mod tests { use crate::models::{AuthProvider, CreateUser, UserRole}; - use super::super::helpers::{create_test_app}; use axum::http::StatusCode; use serde_json::json; use tower::util::ServiceExt; - use wiremock::{matchers::{method, path, query_param}, Mock, MockServer, ResponseTemplate}; + use wiremock::{matchers::{method, path, query_param, header}, Mock, MockServer, ResponseTemplate}; use std::sync::Arc; use crate::{AppState, oidc::OidcClient}; - async fn create_test_app_with_oidc() -> (axum::Router, testcontainers::ContainerAsync, MockServer) { - let (mut app, container) = create_test_app().await; + async fn create_test_app_simple() -> (axum::Router, ()) { + // Use TEST_DATABASE_URL directly, no containers + let database_url = std::env::var("TEST_DATABASE_URL") + .or_else(|_| std::env::var("DATABASE_URL")) + .unwrap_or_else(|_| "postgresql://readur:readur@localhost:5432/readur".to_string()); + + let config = crate::config::Config { + database_url: database_url.clone(), + server_address: "127.0.0.1:0".to_string(), + jwt_secret: "test-secret".to_string(), + upload_path: "./test-uploads".to_string(), + watch_folder: "./test-watch".to_string(), + allowed_file_types: vec!["pdf".to_string()], + watch_interval_seconds: Some(30), + file_stability_check_ms: Some(500), + max_file_age_hours: None, + ocr_language: "eng".to_string(), + concurrent_ocr_jobs: 2, + ocr_timeout_seconds: 60, + max_file_size_mb: 10, + memory_limit_mb: 256, + cpu_priority: "normal".to_string(), + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, + }; + + let db = crate::db::Database::new(&config.database_url).await.unwrap(); + + // Retry migration up to 3 times to handle concurrent test execution + for attempt in 1..=3 { + match db.migrate().await { + Ok(_) => break, + Err(e) if attempt < 3 && e.to_string().contains("tuple concurrently updated") => { + // Wait a bit and retry + tokio::time::sleep(tokio::time::Duration::from_millis(100 * attempt)).await; + continue; + } + Err(e) => panic!("Migration failed after {} attempts: {}", attempt, e), + } + } + + let app = axum::Router::new() + .nest("/api/auth", crate::routes::auth::router()) + .with_state(Arc::new(AppState { + db: db.clone(), + config, + webdav_scheduler: None, + source_scheduler: None, + queue_service: Arc::new(crate::ocr_queue::OcrQueueService::new( + db.clone(), + db.pool.clone(), + 2 + )), + oidc_client: None, + })); + + (app, ()) + } + + async fn create_test_app_with_oidc() -> (axum::Router, MockServer) { let mock_server = MockServer::start().await; // Mock OIDC discovery endpoint @@ -27,9 +87,14 @@ mod tests { .mount(&mock_server) .await; + // Use TEST_DATABASE_URL directly, no containers + let database_url = std::env::var("TEST_DATABASE_URL") + .or_else(|_| std::env::var("DATABASE_URL")) + .unwrap_or_else(|_| "postgresql://readur:readur@localhost:5432/readur".to_string()); + // Update the app state to include OIDC client let config = crate::config::Config { - database_url: "postgresql://test:test@localhost/test".to_string(), + database_url: database_url.clone(), server_address: "127.0.0.1:0".to_string(), jwt_secret: "test-secret".to_string(), upload_path: "./test-uploads".to_string(), @@ -51,34 +116,51 @@ mod tests { oidc_redirect_uri: Some("http://localhost:8000/auth/oidc/callback".to_string()), }; - let oidc_client = OidcClient::new(&config).await.ok().map(Arc::new); + let oidc_client = match OidcClient::new(&config).await { + Ok(client) => Some(Arc::new(client)), + Err(e) => { + panic!("OIDC client creation failed: {}", e); + } + }; - // We need to extract the state from the existing app and recreate it - // This is a bit hacky, but necessary for testing - app = axum::Router::new() + // Connect to the database and run migrations with retry logic for concurrency + let db = crate::db::Database::new(&config.database_url).await.unwrap(); + + // Retry migration up to 3 times to handle concurrent test execution + for attempt in 1..=3 { + match db.migrate().await { + Ok(_) => break, + Err(e) if attempt < 3 && e.to_string().contains("tuple concurrently updated") => { + // Wait a bit and retry + tokio::time::sleep(tokio::time::Duration::from_millis(100 * attempt)).await; + continue; + } + Err(e) => panic!("Migration failed after {} attempts: {}", attempt, e), + } + } + + // Create app with OIDC configuration + let app = axum::Router::new() .nest("/api/auth", crate::routes::auth::router()) .with_state(Arc::new(AppState { - db: crate::db::Database::new(&format!("postgresql://test:test@localhost:{}/test", - container.get_host_port_ipv4(5432).await.unwrap())).await.unwrap(), + db: db.clone(), config, webdav_scheduler: None, source_scheduler: None, queue_service: Arc::new(crate::ocr_queue::OcrQueueService::new( - crate::db::Database::new(&format!("postgresql://test:test@localhost:{}/test", - container.get_host_port_ipv4(5432).await.unwrap())).await.unwrap(), - sqlx::PgPool::connect(&format!("postgresql://test:test@localhost:{}/test", - container.get_host_port_ipv4(5432).await.unwrap())).await.unwrap(), + db.clone(), + db.pool.clone(), 2 )), oidc_client, })); - (app, container, mock_server) + (app, mock_server) } #[tokio::test] async fn test_oidc_login_redirect() { - let (app, _container, _mock_server) = create_test_app_with_oidc().await; + let (app, _mock_server) = create_test_app_with_oidc().await; let response = app .oneshot( @@ -101,7 +183,7 @@ mod tests { #[tokio::test] async fn test_oidc_login_disabled() { - let (app, _container) = create_test_app().await; // Regular app without OIDC + let (app, _container) = create_test_app_simple().await; // Regular app without OIDC let response = app .oneshot( @@ -119,7 +201,7 @@ mod tests { #[tokio::test] async fn test_oidc_callback_missing_code() { - let (app, _container, _mock_server) = create_test_app_with_oidc().await; + let (app, _mock_server) = create_test_app_with_oidc().await; let response = app .oneshot( @@ -137,7 +219,7 @@ mod tests { #[tokio::test] async fn test_oidc_callback_with_error() { - let (app, _container, _mock_server) = create_test_app_with_oidc().await; + let (app, _mock_server) = create_test_app_with_oidc().await; let response = app .oneshot( @@ -155,7 +237,21 @@ mod tests { #[tokio::test] async fn test_oidc_callback_success_new_user() { - let (app, _container, mock_server) = create_test_app_with_oidc().await; + let (app, mock_server) = create_test_app_with_oidc().await; + + // Clean up any existing test user to ensure test isolation + let database_url = std::env::var("TEST_DATABASE_URL") + .or_else(|_| std::env::var("DATABASE_URL")) + .unwrap_or_else(|_| "postgresql://readur:readur@localhost:5432/readur".to_string()); + let db = crate::db::Database::new(&database_url).await.unwrap(); + + // Delete any existing user with the test username or OIDC subject + let _ = sqlx::query("DELETE FROM users WHERE username = $1 OR oidc_subject = $2") + .bind("oidcuser") + .bind("oidc-user-123") + .execute(&db.pool) + .await; + // Mock token exchange let token_response = json!({ @@ -166,7 +262,10 @@ mod tests { Mock::given(method("POST")) .and(path("/token")) - .respond_with(ResponseTemplate::new(200).set_body_json(token_response)) + .and(header("content-type", "application/x-www-form-urlencoded")) + .respond_with(ResponseTemplate::new(200) + .set_body_json(token_response) + .insert_header("content-type", "application/json")) .mount(&mock_server) .await; @@ -180,10 +279,15 @@ mod tests { Mock::given(method("GET")) .and(path("/userinfo")) - .respond_with(ResponseTemplate::new(200).set_body_json(user_info_response)) + .respond_with(ResponseTemplate::new(200) + .set_body_json(user_info_response) + .insert_header("content-type", "application/json")) .mount(&mock_server) .await; + // Add a small delay to make sure everything is set up + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + let response = app .oneshot( axum::http::Request::builder() @@ -195,11 +299,31 @@ mod tests { .await .unwrap(); - assert_eq!(response.status(), StatusCode::OK); - + let status = response.status(); let body = axum::body::to_bytes(response.into_body(), usize::MAX) .await .unwrap(); + + if status != StatusCode::OK { + let error_text = String::from_utf8_lossy(&body); + eprintln!("Response status: {}", status); + eprintln!("Response body: {}", error_text); + + // Also check if we made the expected API calls to the mock server + eprintln!("Mock server received calls:"); + let received_requests = mock_server.received_requests().await.unwrap(); + for req in received_requests { + eprintln!(" {} {} - {}", req.method, req.url.path(), String::from_utf8_lossy(&req.body)); + } + + // Try to parse as JSON to see if there's a more detailed error message + if let Ok(error_json) = serde_json::from_slice::(&body) { + eprintln!("Error JSON: {:#}", error_json); + } + } + + assert_eq!(status, StatusCode::OK); + let login_response: serde_json::Value = serde_json::from_slice(&body).unwrap(); assert!(login_response["token"].is_string()); @@ -209,7 +333,7 @@ mod tests { #[tokio::test] async fn test_oidc_callback_invalid_token() { - let (app, _container, mock_server) = create_test_app_with_oidc().await; + let (app, mock_server) = create_test_app_with_oidc().await; // Mock failed token exchange Mock::given(method("POST")) @@ -236,7 +360,18 @@ mod tests { #[tokio::test] async fn test_oidc_callback_invalid_user_info() { - let (app, _container, mock_server) = create_test_app_with_oidc().await; + let (app, mock_server) = create_test_app_with_oidc().await; + + // Clean up any existing test user to ensure test isolation + let database_url = std::env::var("TEST_DATABASE_URL") + .or_else(|_| std::env::var("DATABASE_URL")) + .unwrap_or_else(|_| "postgresql://readur:readur@localhost:5432/readur".to_string()); + let db = crate::db::Database::new(&database_url).await.unwrap(); + + // Delete any existing user that might conflict + let _ = sqlx::query("DELETE FROM users WHERE username LIKE 'oidc%' OR oidc_subject IS NOT NULL") + .execute(&db.pool) + .await; // Mock successful token exchange let token_response = json!({ diff --git a/tests/auto_resume_tests.rs b/tests/auto_resume_tests.rs index 21fe269..98feeb9 100644 --- a/tests/auto_resume_tests.rs +++ b/tests/auto_resume_tests.rs @@ -47,6 +47,11 @@ async fn create_test_app_state() -> Arc { max_file_size_mb: 50, memory_limit_mb: 512, cpu_priority: "normal".to_string(), + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, }; let db = Database::new(&config.database_url).await.unwrap(); @@ -62,6 +67,7 @@ async fn create_test_app_state() -> Arc { webdav_scheduler: None, source_scheduler: None, queue_service, + oidc_client: None, }) } diff --git a/tests/document_upload_hash_duplicate_tests.rs b/tests/document_upload_hash_duplicate_tests.rs index 6730dce..ecca3b8 100644 --- a/tests/document_upload_hash_duplicate_tests.rs +++ b/tests/document_upload_hash_duplicate_tests.rs @@ -76,6 +76,11 @@ async fn create_test_app_state() -> Result> { max_file_size_mb: 10, memory_limit_mb: 256, cpu_priority: "normal".to_string(), + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, } }); let db = Database::new(&config.database_url).await?; @@ -89,6 +94,7 @@ async fn create_test_app_state() -> Result> { webdav_scheduler: None, source_scheduler: None, queue_service, + oidc_client: None, })) } diff --git a/tests/ignored_files_integration_tests.rs b/tests/ignored_files_integration_tests.rs index a349316..48d0b27 100644 --- a/tests/ignored_files_integration_tests.rs +++ b/tests/ignored_files_integration_tests.rs @@ -31,6 +31,11 @@ async fn create_test_app_state() -> Result> { max_file_size_mb: 10, memory_limit_mb: 256, cpu_priority: "normal".to_string(), + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, } }); @@ -43,6 +48,7 @@ async fn create_test_app_state() -> Result> { webdav_scheduler: None, source_scheduler: None, queue_service, + oidc_client: None, })) } diff --git a/tests/source_scheduler_simple_tests.rs b/tests/source_scheduler_simple_tests.rs index 565bf6f..d8c8e1f 100644 --- a/tests/source_scheduler_simple_tests.rs +++ b/tests/source_scheduler_simple_tests.rs @@ -39,6 +39,11 @@ async fn create_test_app_state() -> Arc { max_file_size_mb: 100, memory_limit_mb: 512, cpu_priority: "normal".to_string(), + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, }; let db = Database::new(&config.database_url).await.unwrap(); @@ -50,6 +55,7 @@ async fn create_test_app_state() -> Arc { webdav_scheduler: None, source_scheduler: None, queue_service, + oidc_client: None, }) } diff --git a/tests/source_scheduler_tests.rs b/tests/source_scheduler_tests.rs index ca24315..91769d4 100644 --- a/tests/source_scheduler_tests.rs +++ b/tests/source_scheduler_tests.rs @@ -176,6 +176,11 @@ async fn create_test_app_state() -> Arc { max_file_size_mb: 10, memory_limit_mb: 256, cpu_priority: "normal".to_string(), + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, }; let db = Database::new(&config.database_url).await.unwrap(); @@ -187,6 +192,7 @@ async fn create_test_app_state() -> Arc { webdav_scheduler: None, source_scheduler: None, queue_service, + oidc_client: None, }) } diff --git a/tests/source_sync_hash_duplicate_tests.rs b/tests/source_sync_hash_duplicate_tests.rs index baaa25d..642453d 100644 --- a/tests/source_sync_hash_duplicate_tests.rs +++ b/tests/source_sync_hash_duplicate_tests.rs @@ -113,6 +113,11 @@ async fn create_test_app_state() -> Result> { max_file_size_mb: 10, memory_limit_mb: 256, cpu_priority: "normal".to_string(), + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, } }); let db = Database::new(&config.database_url).await?; @@ -126,6 +131,7 @@ async fn create_test_app_state() -> Result> { webdav_scheduler: None, source_scheduler: None, queue_service, + oidc_client: None, })) } diff --git a/tests/webdav_comprehensive_tests.rs b/tests/webdav_comprehensive_tests.rs index 1bdfd4a..bc3ae67 100644 --- a/tests/webdav_comprehensive_tests.rs +++ b/tests/webdav_comprehensive_tests.rs @@ -340,6 +340,11 @@ fn test_webdav_scheduler_creation() { max_file_size_mb: 50, ocr_language: "eng".to_string(), ocr_timeout_seconds: 300, + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, }; // Note: This is a minimal test since we can't easily mock the database diff --git a/tests/webdav_integration_tests.rs b/tests/webdav_integration_tests.rs index 63f4a3a..c2fb351 100644 --- a/tests/webdav_integration_tests.rs +++ b/tests/webdav_integration_tests.rs @@ -93,6 +93,11 @@ async fn setup_test_app() -> (Router, Arc) { max_file_size_mb: 50, ocr_language: "eng".to_string(), ocr_timeout_seconds: 300, + oidc_enabled: false, + oidc_client_id: None, + oidc_client_secret: None, + oidc_issuer_url: None, + oidc_redirect_uri: None, }; // Use the environment-based database URL @@ -106,6 +111,7 @@ async fn setup_test_app() -> (Router, Arc) { webdav_scheduler: None, source_scheduler: None, queue_service, + oidc_client: None, }); let app = Router::new()