Files
quoter/tests/basic_test.rs
Untone ea92a376ed
Some checks failed
CI / test (push) Failing after 4m0s
CI / lint (push) Failing after 4s
CI / deploy (push) Has been skipped
docs
2025-08-02 00:18:09 +03:00

323 lines
11 KiB
Rust

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, actix_web::Error>(
HttpResponse::Ok().content_type("text/plain").body("ok"),
),
_ => {
Ok::<HttpResponse, actix_web::Error>(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::<u32>() {
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::Value, _> = serde_json::from_str(invalid_json);
assert!(result.is_err());
// Тестируем парсинг неполного JSON
let incomplete_json = r#"{"user_id": "test"#;
let result: Result<serde_json::Value, _> = 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
);
}