use readur::test_utils::{TestContext, AssertRequest}; use axum::http::StatusCode; use axum::body::Body; use axum::http::Request; use tower::ServiceExt; use serde_json::json; use uuid::Uuid; // Helper function for tests - no longer needs tessdata setup since we use system tesseract async fn setup_simple_test_context() -> TestContext { TestContext::new().await } #[tokio::test] async fn test_get_available_languages_success() { // No tessdata setup needed - using system tesseract installation // Use the existing admin credentials to test against the running server let client = reqwest::Client::new(); // Login with admin credentials let login_response = client .post("http://localhost:8000/api/auth/login") .json(&serde_json::json!({ "username": "admin", "password": "readur2024" })) .send() .await .expect("Failed to login"); let login_data: serde_json::Value = login_response.json().await.expect("Failed to parse login data"); let token = login_data["token"].as_str().expect("Missing token"); // Test against the running server let response = client .get("http://localhost:8000/api/ocr/languages") .header("Authorization", format!("Bearer {}", token)) .send() .await .expect("Failed to make request"); let status = response.status(); if status != 200 { println!("🔍 AssertRequest Debug Info for: get available languages"); println!("🔗 Request URL: http://localhost:8000/api/ocr/languages"); println!("📤 Request Payload: (empty - GET request)"); println!("📊 Response Status: {} (expected: 200)", status); println!("📝 Response Body:"); let error_text = response.text().await.unwrap_or_else(|_| "Unable to read response body".to_string()); println!("{}", error_text); panic!("Expected status 200, got {}. Response: {}", status, error_text); } let body: serde_json::Value = response.json().await.expect("Failed to parse JSON"); if body.get("available_languages").is_none() { println!("🔍 AssertRequest Debug Info for: available_languages field check"); println!("🔗 Request URL: http://localhost:8000/api/ocr/languages"); println!("📤 Request Payload: (empty - GET request)"); println!("📊 Response Status: 200"); println!("📝 Response Body:"); println!("{}", serde_json::to_string_pretty(&body).unwrap_or_else(|_| body.to_string())); panic!("Response missing 'available_languages' field"); } let languages = body["available_languages"].as_array().unwrap(); if languages.len() < 1 { println!("🔍 AssertRequest Debug Info for: minimum languages check"); println!("🔗 Request URL: http://localhost:8000/api/ocr/languages"); println!("📤 Request Payload: (empty - GET request)"); println!("📊 Response Status: 200"); println!("📝 Response Body:"); println!("{}", serde_json::to_string_pretty(&body).unwrap_or_else(|_| body.to_string())); panic!("Expected at least 1 language, got {}", languages.len()); } // Check that languages have the expected structure for (i, lang) in languages.iter().enumerate() { if lang.get("code").is_none() || lang.get("name").is_none() { println!("🔍 AssertRequest Debug Info for: language structure check"); println!("🔗 Request URL: http://localhost:8000/api/ocr/languages"); println!("📤 Request Payload: (empty - GET request)"); println!("📊 Response Status: 200"); println!("📝 Response Body:"); println!("{}", serde_json::to_string_pretty(&body).unwrap_or_else(|_| body.to_string())); println!("❌ Language at index {} missing required fields 'code' or 'name': {}", i, lang); panic!("Language structure validation failed"); } } // Check that English is included let has_english = languages.iter().any(|lang| { lang.get("code").unwrap().as_str().unwrap() == "eng" }); if !has_english { println!("🔍 AssertRequest Debug Info for: English language check"); println!("🔗 Request URL: http://localhost:8000/api/ocr/languages"); println!("📤 Request Payload: (empty - GET request)"); println!("📊 Response Status: 200"); println!("📝 Response Body:"); println!("{}", serde_json::to_string_pretty(&body).unwrap_or_else(|_| body.to_string())); let available_codes: Vec<&str> = languages.iter() .filter_map(|lang| lang.get("code")?.as_str()) .collect(); println!("Available language codes: {:?}", available_codes); panic!("English language 'eng' not found in available languages"); } } #[tokio::test] async fn test_get_available_languages_unauthorized() { let ctx = setup_simple_test_context().await; // Test against the running server since the test environment has issues let client = reqwest::Client::new(); let response = client .get("http://localhost:8000/api/ocr/languages") .send() .await .expect("Failed to make request"); let status = response.status(); if status != 401 { println!("🔍 AssertRequest Debug Info for: unauthorized access check"); println!("🔗 Request URL: http://localhost:8000/api/ocr/languages"); println!("📤 Request Payload: (empty - GET request without auth)"); println!("📊 Response Status: {} (expected: 401)", status); println!("📝 Response Body:"); let error_text = response.text().await.unwrap_or_else(|_| "Unable to read response body".to_string()); println!("{}", error_text); panic!("Expected status 401 (unauthorized), got {}. Response: {}", status, error_text); } } #[tokio::test] async fn test_retry_ocr_with_language_success() { let ctx = setup_simple_test_context().await; // Create test user and get token let auth_helper = readur::test_utils::TestAuthHelper::new(ctx.app().clone()); let mut test_user = auth_helper.create_test_user().await; let user_id = test_user.user_response.id; let token = test_user.login(&auth_helper).await.unwrap(); // Create a test document let document_id = Uuid::new_v4(); sqlx::query( "INSERT INTO documents (id, user_id, filename, original_filename, file_path, file_size, mime_type, ocr_status, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())" ) .bind(document_id) .bind(user_id) .bind("test.pdf") .bind("test.pdf") .bind("/tmp/test.pdf") .bind(1024i64) .bind("application/pdf") .bind("failed") .execute(&ctx.state().db.pool) .await .expect("Failed to create test document"); let retry_request = json!({ "language": "spa" }); let request = Request::builder() .method("POST") .uri(&format!("/api/documents/{}/ocr/retry", document_id)) .header("Authorization", format!("Bearer {}", token)) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_vec(&retry_request).unwrap())) .unwrap(); let response = ctx.app().clone().oneshot(request).await.unwrap(); let body = AssertRequest::assert_response( response, StatusCode::OK, "retry OCR with language success", &format!("/api/documents/{}/ocr/retry", document_id), Some(&retry_request), ).await.expect("Response assertion failed"); if body["success"].as_bool() != Some(true) { println!("🔍 AssertRequest Debug Info for: success field check"); println!("🔗 Request URL: /api/documents/{}/ocr/retry", document_id); println!("📤 Request Payload:"); println!("{}", serde_json::to_string_pretty(&retry_request).unwrap()); println!("📝 Response Body:"); println!("{}", serde_json::to_string_pretty(&body).unwrap_or_else(|_| body.to_string())); panic!("Expected success=true in response body"); } if body.get("message").is_none() { println!("🔍 AssertRequest Debug Info for: message field check"); println!("🔗 Request URL: /api/documents/{}/ocr/retry", document_id); println!("📤 Request Payload:"); println!("{}", serde_json::to_string_pretty(&retry_request).unwrap()); println!("📝 Response Body:"); println!("{}", serde_json::to_string_pretty(&body).unwrap_or_else(|_| body.to_string())); panic!("Expected 'message' field in response body"); } } #[tokio::test] async fn test_retry_ocr_with_invalid_language() { let ctx = setup_simple_test_context().await; // Create test user and get token let auth_helper = readur::test_utils::TestAuthHelper::new(ctx.app().clone()); let mut test_user = auth_helper.create_test_user().await; let user_id = test_user.user_response.id; let token = test_user.login(&auth_helper).await.unwrap(); // Create a test document let document_id = Uuid::new_v4(); sqlx::query( "INSERT INTO documents (id, user_id, filename, original_filename, file_path, file_size, mime_type, ocr_status, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())" ) .bind(document_id) .bind(user_id) .bind("test.pdf") .bind("test.pdf") .bind("/tmp/test.pdf") .bind(1024i64) .bind("application/pdf") .bind("failed") .execute(&ctx.state().db.pool) .await .expect("Failed to create test document"); let retry_request = json!({ "language": "invalid_lang" }); let request = Request::builder() .method("POST") .uri(&format!("/api/documents/{}/ocr/retry", document_id)) .header("Authorization", format!("Bearer {}", token)) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_vec(&retry_request).unwrap())) .unwrap(); let response = ctx.app().clone().oneshot(request).await.unwrap(); AssertRequest::assert_response( response, StatusCode::BAD_REQUEST, "retry OCR with invalid language", &format!("/api/documents/{}/ocr/retry", document_id), Some(&retry_request), ).await.expect("Response assertion failed"); } #[tokio::test] async fn test_retry_ocr_with_multiple_languages_success() { let ctx = setup_simple_test_context().await; // Create test user and get token let auth_helper = readur::test_utils::TestAuthHelper::new(ctx.app().clone()); let mut test_user = auth_helper.create_test_user().await; let user_id = test_user.user_response.id; let token = test_user.login(&auth_helper).await.unwrap(); // Create a test document let document_id = Uuid::new_v4(); sqlx::query( "INSERT INTO documents (id, user_id, filename, original_filename, file_path, file_size, mime_type, ocr_status, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())" ) .bind(document_id) .bind(user_id) .bind("test.pdf") .bind("test.pdf") .bind("/tmp/test.pdf") .bind(1024i64) .bind("application/pdf") .bind("failed") .execute(&ctx.state().db.pool) .await .expect("Failed to create test document"); let retry_request = json!({ "languages": ["eng", "spa", "fra"] }); let request = Request::builder() .method("POST") .uri(&format!("/api/documents/{}/ocr/retry", document_id)) .header("Authorization", format!("Bearer {}", token)) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_vec(&retry_request).unwrap())) .unwrap(); let response = ctx.app().clone().oneshot(request).await.unwrap(); let body = AssertRequest::assert_response( response, StatusCode::OK, "retry OCR with multiple languages success", &format!("/api/documents/{}/ocr/retry", document_id), Some(&retry_request), ).await.expect("Response assertion failed"); if body["success"].as_bool() != Some(true) { println!("🔍 AssertRequest Debug Info for: multiple languages success field check"); println!("🔗 Request URL: /api/documents/{}/ocr/retry", document_id); println!("📤 Request Payload:"); println!("{}", serde_json::to_string_pretty(&retry_request).unwrap()); println!("📝 Response Body:"); println!("{}", serde_json::to_string_pretty(&body).unwrap_or_else(|_| body.to_string())); panic!("Expected success=true in response body"); } if body.get("message").is_none() { println!("🔍 AssertRequest Debug Info for: multiple languages message field check"); println!("🔗 Request URL: /api/documents/{}/ocr/retry", document_id); println!("📤 Request Payload:"); println!("{}", serde_json::to_string_pretty(&retry_request).unwrap()); println!("📝 Response Body:"); println!("{}", serde_json::to_string_pretty(&body).unwrap_or_else(|_| body.to_string())); panic!("Expected 'message' field in response body"); } } #[tokio::test] async fn test_retry_ocr_with_too_many_languages() { let ctx = setup_simple_test_context().await; // Create test user and get token let auth_helper = readur::test_utils::TestAuthHelper::new(ctx.app().clone()); let mut test_user = auth_helper.create_test_user().await; let user_id = test_user.user_response.id; let token = test_user.login(&auth_helper).await.unwrap(); // Create a test document let document_id = Uuid::new_v4(); sqlx::query( "INSERT INTO documents (id, user_id, filename, original_filename, file_path, file_size, mime_type, ocr_status, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())" ) .bind(document_id) .bind(user_id) .bind("test.pdf") .bind("test.pdf") .bind("/tmp/test.pdf") .bind(1024i64) .bind("application/pdf") .bind("failed") .execute(&ctx.state().db.pool) .await .expect("Failed to create test document"); // Try to use more than 4 languages (should fail) let retry_request = json!({ "languages": ["eng", "spa", "fra", "deu", "ita"] }); let request = Request::builder() .method("POST") .uri(&format!("/api/documents/{}/ocr/retry", document_id)) .header("Authorization", format!("Bearer {}", token)) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_vec(&retry_request).unwrap())) .unwrap(); let response = ctx.app().clone().oneshot(request).await.unwrap(); AssertRequest::assert_response( response, StatusCode::BAD_REQUEST, "retry OCR with too many languages", &format!("/api/documents/{}/ocr/retry", document_id), Some(&retry_request), ).await.expect("Response assertion failed"); } #[tokio::test] async fn test_retry_ocr_with_invalid_language_in_array() { let ctx = setup_simple_test_context().await; // Create test user and get token let auth_helper = readur::test_utils::TestAuthHelper::new(ctx.app().clone()); let mut test_user = auth_helper.create_test_user().await; let user_id = test_user.user_response.id; let token = test_user.login(&auth_helper).await.unwrap(); // Create a test document let document_id = Uuid::new_v4(); sqlx::query( "INSERT INTO documents (id, user_id, filename, original_filename, file_path, file_size, mime_type, ocr_status, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())" ) .bind(document_id) .bind(user_id) .bind("test.pdf") .bind("test.pdf") .bind("/tmp/test.pdf") .bind(1024i64) .bind("application/pdf") .bind("failed") .execute(&ctx.state().db.pool) .await .expect("Failed to create test document"); // Include an invalid language in the array let retry_request = json!({ "languages": ["eng", "spa", "invalid_lang"] }); let request = Request::builder() .method("POST") .uri(&format!("/api/documents/{}/ocr/retry", document_id)) .header("Authorization", format!("Bearer {}", token)) .header("Content-Type", "application/json") .body(Body::from(serde_json::to_vec(&retry_request).unwrap())) .unwrap(); let response = ctx.app().clone().oneshot(request).await.unwrap(); AssertRequest::assert_response( response, StatusCode::BAD_REQUEST, "retry OCR with invalid language in array", &format!("/api/documents/{}/ocr/retry", document_id), Some(&retry_request), ).await.expect("Response assertion failed"); }