//! 分页功能的HTTP API集成测试 use reqwest; use serde_json::{json, Value}; use tokio; const BASE_URL: &str = "http://127.0.0.1:3000"; /// 测试辅助函数:创建 HTTP 客户端 fn create_client() -> reqwest::Client { reqwest::Client::new() } /// 测试辅助函数:解析 JSON 响应 async fn parse_json_response(response: reqwest::Response) -> Result> { let text = response.text().await?; let json: Value = serde_json::from_str(&text)?; Ok(json) } /// 测试辅助函数:创建测试用户 async fn create_test_user(client: &reqwest::Client, username: &str, email: &str) -> Result> { let user_data = json!({ "username": username, "email": email, "password": "password123" }); let response = client .post(&format!("{}/api/users", BASE_URL)) .json(&user_data) .send() .await?; if response.status().is_success() { parse_json_response(response).await } else { Err(format!("Failed to create user: {}", response.status()).into()) } } /// 测试辅助函数:创建多个测试用户 async fn create_multiple_test_users(client: &reqwest::Client, count: usize) -> Result, Box> { let mut users = Vec::new(); for i in 0..count { let username = format!("pagination_test_user_{:02}", i + 1); let email = format!("pagination_test_{}@example.com", i + 1); match create_test_user(client, &username, &email).await { Ok(user) => users.push(user), Err(e) => { // 如果用户已存在,跳过 if e.to_string().contains("409") { continue; } else { return Err(e); } } } // 添加小延迟确保创建时间不同 tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; } Ok(users) } #[tokio::test] async fn test_users_list_pagination_basic() { let client = create_client(); // 创建测试用户 let _users = create_multiple_test_users(&client, 15).await .expect("Failed to create test users"); // 测试第一页(默认参数) let response = client .get(&format!("{}/api/users", BASE_URL)) .send() .await .expect("Failed to get users"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); // 验证分页响应结构 assert!(json["data"].is_array(), "Response should have data array"); assert!(json["pagination"].is_object(), "Response should have pagination object"); let pagination = &json["pagination"]; assert!(pagination["current_page"].is_number(), "Should have current_page"); assert!(pagination["per_page"].is_number(), "Should have per_page"); assert!(pagination["total_pages"].is_number(), "Should have total_pages"); assert!(pagination["total_items"].is_number(), "Should have total_items"); assert!(pagination["has_next"].is_boolean(), "Should have has_next"); assert!(pagination["has_prev"].is_boolean(), "Should have has_prev"); // 验证默认值 assert_eq!(pagination["current_page"], 1); assert_eq!(pagination["per_page"], 10); assert!(!pagination["has_prev"].as_bool().unwrap(), "First page should not have previous"); } #[tokio::test] async fn test_users_list_pagination_with_params() { let client = create_client(); // 确保有足够的测试数据 let _users = create_multiple_test_users(&client, 12).await .expect("Failed to create test users"); // 测试第一页,每页5个 let response = client .get(&format!("{}/api/users?page=1&limit=5", BASE_URL)) .send() .await .expect("Failed to get users page 1"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); let data = json["data"].as_array().unwrap(); let pagination = &json["pagination"]; assert_eq!(data.len(), 5, "First page should have 5 users"); assert_eq!(pagination["current_page"], 1); assert_eq!(pagination["per_page"], 5); assert!(!pagination["has_prev"].as_bool().unwrap()); // 测试第二页 let response = client .get(&format!("{}/api/users?page=2&limit=5", BASE_URL)) .send() .await .expect("Failed to get users page 2"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); let data = json["data"].as_array().unwrap(); let pagination = &json["pagination"]; assert_eq!(data.len(), 5, "Second page should have 5 users"); assert_eq!(pagination["current_page"], 2); assert_eq!(pagination["per_page"], 5); assert!(pagination["has_prev"].as_bool().unwrap(), "Second page should have previous"); } #[tokio::test] async fn test_users_list_pagination_edge_cases() { let client = create_client(); // 测试页码为0(应该被修正为1) let response = client .get(&format!("{}/api/users?page=0&limit=5", BASE_URL)) .send() .await .expect("Failed to get users with page=0"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); let pagination = &json["pagination"]; assert_eq!(pagination["current_page"], 1, "Page 0 should be corrected to 1"); // 测试超大限制(应该被限制为100) let response = client .get(&format!("{}/api/users?page=1&limit=200", BASE_URL)) .send() .await .expect("Failed to get users with large limit"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); let pagination = &json["pagination"]; assert_eq!(pagination["per_page"], 100, "Limit should be capped at 100"); // 测试限制为0(应该被修正为1) let response = client .get(&format!("{}/api/users?page=1&limit=0", BASE_URL)) .send() .await .expect("Failed to get users with limit=0"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); let pagination = &json["pagination"]; assert_eq!(pagination["per_page"], 1, "Limit 0 should be corrected to 1"); } #[tokio::test] async fn test_users_list_pagination_beyond_range() { let client = create_client(); // 确保有一些测试数据 let _users = create_multiple_test_users(&client, 5).await .expect("Failed to create test users"); // 测试超出范围的页码 let response = client .get(&format!("{}/api/users?page=100&limit=5", BASE_URL)) .send() .await .expect("Failed to get users beyond range"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); let data = json["data"].as_array().unwrap(); let pagination = &json["pagination"]; assert_eq!(data.len(), 0, "Beyond range page should return empty array"); assert_eq!(pagination["current_page"], 100); assert!(!pagination["has_next"].as_bool().unwrap(), "Beyond range should not have next"); } #[tokio::test] async fn test_users_search_pagination() { let client = create_client(); // 创建一些包含特定关键词的用户 let admin_users = vec![ ("admin_user_1", "admin1@example.com"), ("admin_user_2", "admin2@example.com"), ("admin_user_3", "admin3@example.com"), ("admin_user_4", "admin4@example.com"), ("admin_user_5", "admin5@example.com"), ]; for (username, email) in admin_users { let _ = create_test_user(&client, username, email).await; } // 创建一些普通用户 let _ = create_multiple_test_users(&client, 3).await; // 搜索admin用户,第一页 let response = client .get(&format!("{}/api/users/search?q=admin&page=1&limit=3", BASE_URL)) .send() .await .expect("Failed to search users"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); // 验证搜索响应结构 assert!(json["data"].is_array(), "Search response should have data array"); assert!(json["pagination"].is_object(), "Search response should have pagination"); assert!(json["search_params"].is_object(), "Search response should have search_params"); assert!(json["total_filtered"].is_number(), "Search response should have total_filtered"); let data = json["data"].as_array().unwrap(); let pagination = &json["pagination"]; // 验证搜索结果 assert!(data.len() <= 3, "Should return at most 3 results per page"); assert_eq!(pagination["current_page"], 1); assert_eq!(pagination["per_page"], 3); // 验证搜索结果包含关键词 for user in data { let username = user["username"].as_str().unwrap(); let email = user["email"].as_str().unwrap(); assert!( username.contains("admin") || email.contains("admin"), "Search result should contain 'admin' keyword" ); } // 测试搜索第二页 let response = client .get(&format!("{}/api/users/search?q=admin&page=2&limit=3", BASE_URL)) .send() .await .expect("Failed to search users page 2"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); let pagination = &json["pagination"]; assert_eq!(pagination["current_page"], 2); assert!(pagination["has_prev"].as_bool().unwrap(), "Second page should have previous"); } #[tokio::test] async fn test_users_search_with_filters_and_pagination() { let client = create_client(); // 创建一些测试用户 let test_users = vec![ ("filter_test_1", "filter1@test.com"), ("filter_test_2", "filter2@test.com"), ("filter_test_3", "filter3@test.com"), ("other_user_1", "other1@example.com"), ("other_user_2", "other2@example.com"), ]; for (username, email) in test_users { let _ = create_test_user(&client, username, email).await; } // 按邮箱域名搜索,带分页 let response = client .get(&format!("{}/api/users/search?email=test.com&page=1&limit=2&sort_by=username&sort_order=asc", BASE_URL)) .send() .await .expect("Failed to search users with email filter"); assert_eq!(response.status(), 200); let json = parse_json_response(response).await.expect("Failed to parse JSON"); let data = json["data"].as_array().unwrap(); let pagination = &json["pagination"]; let search_params = &json["search_params"]; // 验证过滤结果 assert!(data.len() <= 2, "Should return at most 2 results per page"); assert_eq!(pagination["per_page"], 2); // 验证搜索参数被正确返回 assert_eq!(search_params["email"], "test.com"); assert_eq!(search_params["sort_by"], "username"); assert_eq!(search_params["sort_order"], "asc"); // 验证结果包含正确的邮箱域名 for user in data { let email = user["email"].as_str().unwrap(); assert!(email.contains("test.com"), "Filtered result should contain test.com domain"); } // 验证排序(用户名升序) if data.len() > 1 { let first_username = data[0]["username"].as_str().unwrap(); let second_username = data[1]["username"].as_str().unwrap(); assert!(first_username <= second_username, "Results should be sorted by username ascending"); } } #[tokio::test] async fn test_pagination_consistency_across_requests() { let client = create_client(); // 创建固定数量的用户 let _users = create_multiple_test_users(&client, 10).await .expect("Failed to create test users"); // 获取第一页 let response1 = client .get(&format!("{}/api/users?page=1&limit=3", BASE_URL)) .send() .await .expect("Failed to get first page"); let json1 = parse_json_response(response1).await.expect("Failed to parse JSON"); let data1 = json1["data"].as_array().unwrap(); let total_items1 = json1["pagination"]["total_items"].as_u64().unwrap(); // 获取第二页 let response2 = client .get(&format!("{}/api/users?page=2&limit=3", BASE_URL)) .send() .await .expect("Failed to get second page"); let json2 = parse_json_response(response2).await.expect("Failed to parse JSON"); let data2 = json2["data"].as_array().unwrap(); let total_items2 = json2["pagination"]["total_items"].as_u64().unwrap(); // 验证总数一致性 assert_eq!(total_items1, total_items2, "Total items should be consistent across pages"); // 验证没有重复用户 let mut user_ids1: Vec = data1.iter() .map(|u| u["id"].as_str().unwrap().to_string()) .collect(); let user_ids2: Vec = data2.iter() .map(|u| u["id"].as_str().unwrap().to_string()) .collect(); user_ids1.extend(user_ids2); user_ids1.sort(); user_ids1.dedup(); // 去重后的长度应该等于原始长度(没有重复) let expected_length = data1.len() + data2.len(); assert_eq!(user_ids1.len(), expected_length, "No duplicate users should appear across pages"); }