use actix_web::{test, web, App, HttpResponse}; /// Простой тест health check #[actix_web::test] async fn test_health_check() { let app = test::init_service(App::new().route( "/", web::get().to(|req: actix_web::HttpRequest| async move { match req.method().as_str() { "GET" => Ok::( HttpResponse::Ok().content_type("text/plain").body("ok"), ), _ => { Ok::(HttpResponse::MethodNotAllowed().finish()) } } }), )) .await; // Тестируем GET запрос let req = test::TestRequest::get().uri("/").to_request(); let resp = test::call_service(&app, req).await; assert!(resp.status().is_success()); let body = test::read_body(resp).await; assert_eq!(body, "ok"); // Тестируем POST запрос (должен вернуть 405) let req = test::TestRequest::post().uri("/").to_request(); let resp = test::call_service(&app, req).await; assert_eq!(resp.status(), actix_web::http::StatusCode::NOT_FOUND); } /// Тест для проверки JSON сериализации/десериализации #[test] async fn test_json_serialization() { #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)] struct TestStruct { user_id: String, current_quota: u64, max_quota: u64, } let test_data = TestStruct { user_id: "test-user-123".to_string(), current_quota: 1024, max_quota: 5368709120, // 5 GB }; // Сериализация let json_string = serde_json::to_string(&test_data).unwrap(); assert!(json_string.contains("test-user-123")); assert!(json_string.contains("1024")); assert!(json_string.contains("5368709120")); // Десериализация let deserialized: TestStruct = serde_json::from_str(&json_string).unwrap(); assert_eq!(deserialized, test_data); } /// Тест для проверки multipart form data #[test] async fn test_multipart_form_data() { let boundary = "test-boundary"; let filename = "test.png"; let content = b"fake image data"; let mut form_data = Vec::new(); // Начало multipart form_data.extend_from_slice(format!("--{}\r\n", boundary).as_bytes()); form_data.extend_from_slice( format!( "Content-Disposition: form-data; name=\"file\"; filename=\"{}\"\r\n", filename ) .as_bytes(), ); form_data.extend_from_slice(b"Content-Type: image/png\r\n\r\n"); // Содержимое файла form_data.extend_from_slice(content); form_data.extend_from_slice(b"\r\n"); // Конец multipart form_data.extend_from_slice(format!("--{}--\r\n", boundary).as_bytes()); // Проверяем, что form_data содержит ожидаемые части let form_data_str = String::from_utf8_lossy(&form_data); assert!(form_data_str.contains(filename)); assert!(form_data_str.contains("image/png")); assert!(form_data_str.contains("fake image data")); assert!(form_data_str.contains(&format!("--{}", boundary))); } /// Тест для проверки UUID генерации #[test] async fn test_uuid_generation() { use uuid::Uuid; let uuid1 = Uuid::new_v4(); let uuid2 = Uuid::new_v4(); // UUID должны быть разными assert_ne!(uuid1, uuid2); // UUID должны быть в правильном формате let uuid_str = uuid1.to_string(); assert_eq!(uuid_str.len(), 36); // 32 символа + 4 дефиса assert!(uuid_str.contains('-')); // Проверяем, что UUID можно парсить обратно let parsed_uuid = Uuid::parse_str(&uuid_str).unwrap(); assert_eq!(parsed_uuid, uuid1); } /// Тест для проверки MIME типов #[test] async fn test_mime_type_detection() { // Тестируем определение MIME типа по расширению let get_mime_type = |ext: &str| -> Option<&'static str> { match ext.to_lowercase().as_str() { "jpg" | "jpeg" => Some("image/jpeg"), "png" => Some("image/png"), "gif" => Some("image/gif"), "webp" => Some("image/webp"), "mp3" => Some("audio/mpeg"), "wav" => Some("audio/wav"), "mp4" => Some("video/mp4"), _ => None, } }; assert_eq!(get_mime_type("jpg"), Some("image/jpeg")); assert_eq!(get_mime_type("jpeg"), Some("image/jpeg")); assert_eq!(get_mime_type("png"), Some("image/png")); assert_eq!(get_mime_type("gif"), Some("image/gif")); assert_eq!(get_mime_type("webp"), Some("image/webp")); assert_eq!(get_mime_type("mp3"), Some("audio/mpeg")); assert_eq!(get_mime_type("wav"), Some("audio/wav")); assert_eq!(get_mime_type("mp4"), Some("video/mp4")); assert_eq!(get_mime_type("pdf"), None); assert_eq!(get_mime_type(""), None); } /// Тест для проверки парсинга путей файлов #[test] async fn test_file_path_parsing() { fn parse_file_path(path: &str) -> (String, u32, String) { let parts: Vec<&str> = path.split('.').collect(); if parts.len() != 2 { return (path.to_string(), 0, "".to_string()); } let base_with_width = parts[0]; let ext = parts[1]; // Ищем ширину в формате _NUMBER let base_parts: Vec<&str> = base_with_width.split('_').collect(); if base_parts.len() >= 2 { if let Ok(width) = base_parts.last().unwrap().parse::() { let base = base_parts[..base_parts.len() - 1].join("_"); return (base, width, ext.to_string()); } } (base_with_width.to_string(), 0, ext.to_string()) } let (base, width, ext) = parse_file_path("image_300.jpg"); assert_eq!(base, "image"); assert_eq!(width, 300); assert_eq!(ext, "jpg"); let (base, width, ext) = parse_file_path("document.pdf"); assert_eq!(base, "document"); assert_eq!(width, 0); assert_eq!(ext, "pdf"); let (base, width, ext) = parse_file_path("file_with_underscore_but_no_width.jpg"); assert_eq!(base, "file_with_underscore_but_no_width"); assert_eq!(width, 0); assert_eq!(ext, "jpg"); } /// Тест для проверки расчетов квот #[test] async fn test_quota_calculations() { const MAX_QUOTA_BYTES: u64 = 5 * 1024 * 1024 * 1024; // 5 ГБ const MB: u64 = 1024 * 1024; const GB: u64 = 1024 * 1024 * 1024; // Тестируем различные сценарии let test_cases = vec![ (0, 1 * MB, true), // Пустая квота + 1MB = OK (1 * GB, 1 * MB, true), // 1GB + 1MB = OK (4 * GB, 1 * GB, true), // 4GB + 1GB = OK (4 * GB, 2 * GB, false), // 4GB + 2GB = превышение (5 * GB, 1 * MB, false), // 5GB + 1MB = превышение ]; for (current_quota, file_size, should_allow) in test_cases { let would_exceed = current_quota + file_size > MAX_QUOTA_BYTES; assert_eq!( would_exceed, !should_allow, "Квота: {} + файл: {} = {}, должно быть разрешено: {}", current_quota, file_size, current_quota + file_size, should_allow ); } } /// Тест для проверки форматирования размеров файлов #[test] async fn test_file_size_formatting() { fn format_file_size(bytes: u64) -> String { const KB: u64 = 1024; const MB: u64 = 1024 * 1024; const GB: u64 = 1024 * 1024 * 1024; match bytes { 0..KB => format!("{} B", bytes), KB..MB => format!("{:.1} KB", bytes as f64 / KB as f64), MB..GB => format!("{:.1} MB", bytes as f64 / MB as f64), _ => format!("{:.1} GB", bytes as f64 / GB as f64), } } assert_eq!(format_file_size(512), "512 B"); assert_eq!(format_file_size(1024), "1.0 KB"); assert_eq!(format_file_size(1536), "1.5 KB"); assert_eq!(format_file_size(1024 * 1024), "1.0 MB"); assert_eq!(format_file_size(1024 * 1024 * 1024), "1.0 GB"); assert_eq!(format_file_size(5 * 1024 * 1024 * 1024), "5.0 GB"); } /// Тест для проверки обработки ошибок #[test] async fn test_error_handling() { // Тестируем парсинг неверного JSON let invalid_json = "{ invalid json }"; let result: Result = serde_json::from_str(invalid_json); assert!(result.is_err()); // Тестируем парсинг неполного JSON let incomplete_json = r#"{"user_id": "test"#; let result: Result = serde_json::from_str(incomplete_json); assert!(result.is_err()); // Тестируем неверный UUID use uuid::Uuid; let invalid_uuid = "not-a-uuid"; let result = Uuid::parse_str(invalid_uuid); assert!(result.is_err()); // Тестируем пустой UUID let empty_uuid = ""; let result = Uuid::parse_str(empty_uuid); assert!(result.is_err()); } /// Тест для проверки производительности #[test] async fn test_performance() { use std::time::Instant; // Тест UUID генерации let start = Instant::now(); let iterations = 10000; for _ in 0..iterations { let _uuid = uuid::Uuid::new_v4(); } let duration = start.elapsed(); let avg_time = duration.as_nanos() as f64 / iterations as f64; println!( "UUID generation: {} UUIDs in {:?}, avg: {:.2} ns per UUID", iterations, duration, avg_time ); // Проверяем, что среднее время меньше 1μs assert!( avg_time < 1000.0, "UUID generation too slow: {:.2} ns", avg_time ); // Тест JSON сериализации let start = Instant::now(); for _ in 0..iterations { let data = serde_json::json!({ "user_id": "test-user-123", "current_quota": 1024, "max_quota": 5368709120u64 }); let _json_string = serde_json::to_string(&data).unwrap(); } let duration = start.elapsed(); let avg_time = duration.as_micros() as f64 / iterations as f64; println!( "JSON serialization: {} operations in {:?}, avg: {:.2} μs per operation", iterations, duration, avg_time ); // Проверяем, что среднее время меньше 100μs assert!( avg_time < 100.0, "JSON serialization too slow: {:.2} μs", avg_time ); }