use actix_web::{test, web, App, HttpRequest, HttpResponse, Error as ActixError}; use actix_web::http::StatusCode; use serde_json::json; use std::collections::HashMap; use discoursio_quoter::{ app_state::AppState, handlers::{ get_quota_handler, increase_quota_handler, set_quota_handler, upload_handler, proxy_handler, serve_file }, auth::get_id_by_token, }; /// Мок для Redis соединения #[derive(Clone)] struct MockRedisConnection; /// Мок для S3 клиента #[derive(Clone)] struct MockS3Client; /// Мок для AppState #[derive(Clone)] struct MockAppState { redis: MockRedisConnection, storj_client: MockS3Client, aws_client: MockS3Client, bucket: String, } impl MockAppState { fn new() -> Self { Self { redis: MockRedisConnection, storj_client: MockS3Client, aws_client: MockS3Client, bucket: "test-bucket".to_string(), } } async fn get_or_create_quota(&self, _user_id: &str) -> Result { Ok(1024 * 1024) // 1MB } async fn increase_user_quota(&self, _user_id: &str, _additional_bytes: u64) -> Result { Ok(2 * 1024 * 1024) // 2MB } async fn set_user_quota(&self, _user_id: &str, _bytes: u64) -> Result { Ok(3 * 1024 * 1024) // 3MB } async fn get_path(&self, _filename: &str) -> Result, actix_web::Error> { Ok(Some("test/path/file.jpg".to_string())) } async fn set_path(&self, _filename: &str, _filepath: &str) { // Mock implementation } async fn cache_filelist(&self) { // Mock implementation } } /// Тест для get_quota_handler #[actix_web::test] async fn test_get_quota_handler() { let app = test::init_service( App::new() .app_data(web::Data::new(MockAppState::new())) .route("/quota", web::get().to(get_quota_handler)) ).await; // Тест без авторизации let req = test::TestRequest::get() .uri("/quota?user_id=test-user") .to_request(); let resp = test::call_service(&app, req).await; assert_eq!(resp.status(), StatusCode::UNAUTHORIZED); // Тест с авторизацией (мокаем токен) let req = test::TestRequest::get() .uri("/quota?user_id=test-user") .header("Authorization", "Bearer valid-token") .to_request(); let resp = test::call_service(&app, req).await; // Должен вернуть ошибку, так как токен невалидный в тестовой среде assert!(resp.status().is_client_error() || resp.status().is_server_error()); } /// Тест для increase_quota_handler #[actix_web::test] async fn test_increase_quota_handler() { let app = test::init_service( App::new() .app_data(web::Data::new(MockAppState::new())) .route("/quota/increase", web::post().to(increase_quota_handler)) ).await; let quota_data = json!({ "user_id": "test-user", "additional_bytes": 1024 * 1024 }); let req = test::TestRequest::post() .uri("/quota/increase") .header("Authorization", "Bearer valid-token") .set_json(quota_data) .to_request(); let resp = test::call_service(&app, req).await; // Должен вернуть ошибку, так как токен невалидный в тестовой среде assert!(resp.status().is_client_error() || resp.status().is_server_error()); } /// Тест для set_quota_handler #[actix_web::test] async fn test_set_quota_handler() { let app = test::init_service( App::new() .app_data(web::Data::new(MockAppState::new())) .route("/quota/set", web::post().to(set_quota_handler)) ).await; let quota_data = json!({ "user_id": "test-user", "new_quota_bytes": 5 * 1024 * 1024 }); let req = test::TestRequest::post() .uri("/quota/set") .header("Authorization", "Bearer valid-token") .set_json(quota_data) .to_request(); let resp = test::call_service(&app, req).await; // Должен вернуть ошибку, так как токен невалидный в тестовой среде assert!(resp.status().is_client_error() || resp.status().is_server_error()); } /// Тест для upload_handler #[actix_web::test] async fn test_upload_handler() { let app = test::init_service( App::new() .app_data(web::Data::new(MockAppState::new())) .route("/", web::post().to(upload_handler)) ).await; // Тест с пустым multipart let req = test::TestRequest::post() .uri("/") .header("Authorization", "Bearer valid-token") .to_request(); let resp = test::call_service(&app, req).await; // Должен вернуть ошибку, так как нет multipart данных assert!(resp.status().is_client_error() || resp.status().is_server_error()); } /// Тест для proxy_handler #[actix_web::test] async fn test_proxy_handler() { let app = test::init_service( App::new() .app_data(web::Data::new(MockAppState::new())) .route("/{path:.*}", web::get().to(proxy_handler)) ).await; // Тест с несуществующим файлом let req = test::TestRequest::get() .uri("/nonexistent.jpg") .to_request(); let resp = test::call_service(&app, req).await; // Должен вернуть ошибку, так как файл не найден assert!(resp.status().is_client_error() || resp.status().is_server_error()); } /// Тест для serve_file #[actix_web::test] async fn test_serve_file() { let app_state = MockAppState::new(); // Тест с пустым путем let result = serve_file("", &app_state, "").await; assert!(result.is_err()); // Тест с несуществующим файлом let result = serve_file("nonexistent.jpg", &app_state, "").await; // Должен вернуть ошибку, так как файл не найден в S3 assert!(result.is_err()); } /// Тест для проверки обработки ошибок в handlers #[actix_web::test] async fn test_handler_error_handling() { let app = test::init_service( App::new() .app_data(web::Data::new(MockAppState::new())) .route("/test", web::get().to(|_req: HttpRequest| async { Err::( actix_web::error::ErrorInternalServerError("Test error") ) })) ).await; let req = test::TestRequest::get().uri("/test").to_request(); let resp = test::call_service(&app, req).await; assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); } /// Тест для проверки CORS headers #[actix_web::test] async fn test_cors_headers() { let app = test::init_service( App::new() .app_data(web::Data::new(MockAppState::new())) .route("/test", web::get().to(|_req: HttpRequest| async { Ok::( HttpResponse::Ok().body("test") ) })) .wrap(actix_cors::Cors::default().allow_any_origin()) ).await; let req = test::TestRequest::get().uri("/test").to_request(); let resp = test::call_service(&app, req).await; assert!(resp.status().is_success()); // Проверяем наличие CORS headers let headers = resp.headers(); assert!(headers.contains_key("access-control-allow-origin")); } /// Тест для проверки различных HTTP методов #[actix_web::test] async fn test_http_methods() { let app = test::init_service( App::new() .route("/test", web::get().to(|_req: HttpRequest| async { Ok::( HttpResponse::Ok().body("GET method") ) })) .route("/test", web::post().to(|_req: HttpRequest| async { Ok::( HttpResponse::Ok().body("POST method") ) })) ).await; // Тест GET метода let req = test::TestRequest::get().uri("/test").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, "GET method"); // Тест POST метода let req = test::TestRequest::post().uri("/test").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, "POST method"); } /// Тест для проверки query параметров #[actix_web::test] async fn test_query_parameters() { let app = test::init_service( App::new() .route("/test", web::get().to(|req: HttpRequest| async { let query_string = req.query_string(); Ok::( HttpResponse::Ok().body(query_string) ) })) ).await; let req = test::TestRequest::get() .uri("/test?param1=value1¶m2=value2") .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, "param1=value1¶m2=value2"); } /// Тест для проверки headers #[actix_web::test] async fn test_headers() { let app = test::init_service( App::new() .route("/test", web::get().to(|req: HttpRequest| async { let user_agent = req.headers() .get("user-agent") .and_then(|h| h.to_str().ok()) .unwrap_or("unknown"); Ok::( HttpResponse::Ok().body(user_agent) ) })) ).await; let req = test::TestRequest::get() .uri("/test") .header("user-agent", "test-agent") .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, "test-agent"); } /// Тест для проверки JSON responses #[actix_web::test] async fn test_json_responses() { let app = test::init_service( App::new() .route("/test", web::get().to(|_req: HttpRequest| async { let data = json!({ "status": "success", "message": "test message", "data": { "id": 123, "name": "test" } }); Ok::( HttpResponse::Ok().json(data) ) })) ).await; let req = test::TestRequest::get().uri("/test").to_request(); let resp = test::call_service(&app, req).await; assert!(resp.status().is_success()); let body = test::read_body(resp).await; let response_data: serde_json::Value = serde_json::from_slice(&body).unwrap(); assert_eq!(response_data["status"], "success"); assert_eq!(response_data["message"], "test message"); assert_eq!(response_data["data"]["id"], 123); assert_eq!(response_data["data"]["name"], "test"); } /// Тест для проверки различных content types #[actix_web::test] async fn test_content_types() { let app = test::init_service( App::new() .route("/text", web::get().to(|_req: HttpRequest| async { Ok::( HttpResponse::Ok() .content_type("text/plain") .body("plain text") ) })) .route("/html", web::get().to(|_req: HttpRequest| async { Ok::( HttpResponse::Ok() .content_type("text/html") .body("test") ) })) .route("/json", web::get().to(|_req: HttpRequest| async { Ok::( HttpResponse::Ok() .content_type("application/json") .json(json!({"test": "data"})) ) })) ).await; // Тест text/plain let req = test::TestRequest::get().uri("/text").to_request(); let resp = test::call_service(&app, req).await; assert_eq!(resp.headers().get("content-type").unwrap(), "text/plain"); // Тест text/html let req = test::TestRequest::get().uri("/html").to_request(); let resp = test::call_service(&app, req).await; assert_eq!(resp.headers().get("content-type").unwrap(), "text/html"); // Тест application/json let req = test::TestRequest::get().uri("/json").to_request(); let resp = test::call_service(&app, req).await; assert_eq!(resp.headers().get("content-type").unwrap(), "application/json"); }