Some checks failed
Deploy to Production / Run Tests (push) Failing after 16m35s
Deploy to Production / Security Scan (push) Has been skipped
Deploy to Production / Build Docker Image (push) Has been skipped
Deploy to Production / Deploy to Staging (push) Has been skipped
Deploy to Production / Deploy to Production (push) Has been skipped
Deploy to Production / Notify Results (push) Successful in 31s
✨ 新功能: - SQLite数据库集成和持久化存储 - 数据库迁移系统和版本管理 - API分页功能和高效查询 - 用户搜索和过滤机制 - 完整的RBAC角色权限系统 - 结构化日志记录和系统监控 - API限流和多层安全防护 - Docker容器化和生产部署配置 🔒 安全特性: - JWT认证和授权 - 限流和防暴力破解 - 安全头和CORS配置 - 输入验证和XSS防护 - 审计日志和安全监控 📊 监控和运维: - Prometheus指标收集 - 健康检查和系统监控 - 自动化备份和恢复 - 完整的运维文档和脚本 - CI/CD流水线配置 🚀 部署支持: - 多环境Docker配置 - 生产环境部署指南 - 性能优化和安全加固 - 故障排除和应急响应 - 自动化运维脚本 📚 文档完善: - API使用文档 - 部署检查清单 - 运维操作手册 - 性能和安全指南 - 故障排除指南
354 lines
11 KiB
Rust
354 lines
11 KiB
Rust
//! 分页功能专项测试
|
||
|
||
use rust_user_api::{
|
||
models::{
|
||
user::User,
|
||
pagination::{PaginationParams, PaginatedResponse},
|
||
search::UserSearchParams,
|
||
role::UserRole,
|
||
},
|
||
storage::{database::DatabaseUserStore, memory::MemoryUserStore, UserStore},
|
||
utils::errors::ApiError,
|
||
};
|
||
use uuid::Uuid;
|
||
use chrono::Utc;
|
||
use std::sync::Arc;
|
||
|
||
/// 创建测试用户
|
||
fn create_test_user(username: &str, email: &str) -> User {
|
||
User {
|
||
id: Uuid::new_v4(),
|
||
username: username.to_string(),
|
||
email: email.to_string(),
|
||
password_hash: "hashed_password".to_string(),
|
||
role: UserRole::User,
|
||
created_at: Utc::now(),
|
||
updated_at: Utc::now(),
|
||
}
|
||
}
|
||
|
||
/// 创建多个测试用户
|
||
async fn create_multiple_users(store: &dyn UserStore, count: usize) -> Vec<User> {
|
||
let mut users = Vec::new();
|
||
|
||
for i in 0..count {
|
||
let user = create_test_user(
|
||
&format!("user{:02}", i + 1),
|
||
&format!("user{}@example.com", i + 1),
|
||
);
|
||
|
||
let created_user = store.create_user(user).await.unwrap();
|
||
users.push(created_user);
|
||
|
||
// 添加小延迟确保创建时间不同
|
||
tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
|
||
}
|
||
|
||
users
|
||
}
|
||
|
||
/// 测试内存存储的分页功能
|
||
#[tokio::test]
|
||
async fn test_memory_store_pagination() {
|
||
let store = MemoryUserStore::new();
|
||
|
||
// 创建15个用户
|
||
let users = create_multiple_users(&store, 15).await;
|
||
|
||
// 测试第一页(每页5个)
|
||
let params = PaginationParams {
|
||
page: Some(1),
|
||
limit: Some(5),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 15, "总用户数应该是15");
|
||
assert_eq!(paginated_users.len(), 5, "第一页应该有5个用户");
|
||
|
||
// 测试第二页
|
||
let params = PaginationParams {
|
||
page: Some(2),
|
||
limit: Some(5),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 15, "总用户数应该是15");
|
||
assert_eq!(paginated_users.len(), 5, "第二页应该有5个用户");
|
||
|
||
// 测试第三页
|
||
let params = PaginationParams {
|
||
page: Some(3),
|
||
limit: Some(5),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 15, "总用户数应该是15");
|
||
assert_eq!(paginated_users.len(), 5, "第三页应该有5个用户");
|
||
|
||
// 测试第四页(超出范围)
|
||
let params = PaginationParams {
|
||
page: Some(4),
|
||
limit: Some(5),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 15, "总用户数应该是15");
|
||
assert_eq!(paginated_users.len(), 0, "第四页应该没有用户");
|
||
}
|
||
|
||
/// 测试数据库存储的分页功能
|
||
#[tokio::test]
|
||
async fn test_database_store_pagination() {
|
||
let database_url = "sqlite::memory:";
|
||
let store = DatabaseUserStore::from_url(database_url).await.unwrap();
|
||
|
||
// 创建12个用户
|
||
let users = create_multiple_users(&store, 12).await;
|
||
|
||
// 测试第一页(每页4个)
|
||
let params = PaginationParams {
|
||
page: Some(1),
|
||
limit: Some(4),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 12, "总用户数应该是12");
|
||
assert_eq!(paginated_users.len(), 4, "第一页应该有4个用户");
|
||
|
||
// 验证排序(应该按创建时间倒序)
|
||
for i in 0..paginated_users.len() - 1 {
|
||
assert!(
|
||
paginated_users[i].created_at >= paginated_users[i + 1].created_at,
|
||
"用户应该按创建时间倒序排列"
|
||
);
|
||
}
|
||
|
||
// 测试最后一页
|
||
let params = PaginationParams {
|
||
page: Some(3),
|
||
limit: Some(4),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 12, "总用户数应该是12");
|
||
assert_eq!(paginated_users.len(), 4, "第三页应该有4个用户");
|
||
}
|
||
|
||
/// 测试分页参数的默认值和边界情况
|
||
#[tokio::test]
|
||
async fn test_pagination_params_edge_cases() {
|
||
let store = MemoryUserStore::new();
|
||
|
||
// 创建8个用户
|
||
create_multiple_users(&store, 8).await;
|
||
|
||
// 测试默认参数
|
||
let params = PaginationParams {
|
||
page: None,
|
||
limit: None,
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 8, "总用户数应该是8");
|
||
assert_eq!(paginated_users.len(), 8, "默认应该返回所有用户(限制为10)");
|
||
|
||
// 测试页码为0(应该被修正为1)
|
||
let params = PaginationParams {
|
||
page: Some(0),
|
||
limit: Some(3),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 8, "总用户数应该是8");
|
||
assert_eq!(paginated_users.len(), 3, "页码0应该被修正为1,返回3个用户");
|
||
|
||
// 测试超大限制(应该被限制为100)
|
||
let params = PaginationParams {
|
||
page: Some(1),
|
||
limit: Some(200),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 8, "总用户数应该是8");
|
||
assert_eq!(paginated_users.len(), 8, "应该返回所有8个用户(限制为100)");
|
||
|
||
// 测试限制为0(应该被修正为1)
|
||
let params = PaginationParams {
|
||
page: Some(1),
|
||
limit: Some(0),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 8, "总用户数应该是8");
|
||
assert_eq!(paginated_users.len(), 1, "限制0应该被修正为1");
|
||
}
|
||
|
||
/// 测试空数据库的分页
|
||
#[tokio::test]
|
||
async fn test_pagination_empty_database() {
|
||
let store = MemoryUserStore::new();
|
||
|
||
let params = PaginationParams {
|
||
page: Some(1),
|
||
limit: Some(10),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
assert_eq!(total_count, 0, "空数据库总用户数应该是0");
|
||
assert_eq!(paginated_users.len(), 0, "空数据库应该返回空列表");
|
||
}
|
||
|
||
/// 测试搜索功能的分页
|
||
#[tokio::test]
|
||
async fn test_search_pagination() {
|
||
let store = MemoryUserStore::new();
|
||
|
||
// 创建用户,其中一些包含"admin"
|
||
let users = vec![
|
||
create_test_user("admin1", "admin1@example.com"),
|
||
create_test_user("user1", "user1@example.com"),
|
||
create_test_user("admin2", "admin2@example.com"),
|
||
create_test_user("user2", "user2@example.com"),
|
||
create_test_user("admin3", "admin3@example.com"),
|
||
create_test_user("user3", "user3@example.com"),
|
||
];
|
||
|
||
for user in users {
|
||
store.create_user(user).await.unwrap();
|
||
}
|
||
|
||
// 搜索包含"admin"的用户,第一页
|
||
let search_params = UserSearchParams {
|
||
q: Some("admin".to_string()),
|
||
..Default::default()
|
||
};
|
||
|
||
let pagination_params = PaginationParams {
|
||
page: Some(1),
|
||
limit: Some(2),
|
||
};
|
||
|
||
let (search_results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap();
|
||
|
||
assert_eq!(total_count, 3, "应该找到3个admin用户");
|
||
assert_eq!(search_results.len(), 2, "第一页应该返回2个用户");
|
||
|
||
// 验证搜索结果
|
||
for user in &search_results {
|
||
assert!(
|
||
user.username.contains("admin") || user.email.contains("admin"),
|
||
"搜索结果应该包含admin关键词"
|
||
);
|
||
}
|
||
|
||
// 搜索第二页
|
||
let pagination_params = PaginationParams {
|
||
page: Some(2),
|
||
limit: Some(2),
|
||
};
|
||
|
||
let (search_results, total_count) = store.search_users(&search_params, &pagination_params).await.unwrap();
|
||
|
||
assert_eq!(total_count, 3, "总数应该仍然是3");
|
||
assert_eq!(search_results.len(), 1, "第二页应该返回1个用户");
|
||
}
|
||
|
||
/// 测试PaginatedResponse结构
|
||
#[tokio::test]
|
||
async fn test_paginated_response_structure() {
|
||
let store = MemoryUserStore::new();
|
||
|
||
// 创建7个用户
|
||
create_multiple_users(&store, 7).await;
|
||
|
||
let params = PaginationParams {
|
||
page: Some(2),
|
||
limit: Some(3),
|
||
};
|
||
|
||
let (users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
let response = PaginatedResponse::new(
|
||
users.into_iter().map(|u| u.username).collect(),
|
||
¶ms,
|
||
total_count
|
||
);
|
||
|
||
// 验证分页信息
|
||
assert_eq!(response.pagination.current_page, 2);
|
||
assert_eq!(response.pagination.per_page, 3);
|
||
assert_eq!(response.pagination.total_pages, 3); // 7个用户,每页3个,共3页
|
||
assert_eq!(response.pagination.total_items, 7);
|
||
assert!(response.pagination.has_prev, "第二页应该有上一页");
|
||
assert!(response.pagination.has_next, "第二页应该有下一页");
|
||
|
||
// 测试第一页
|
||
let params = PaginationParams {
|
||
page: Some(1),
|
||
limit: Some(3),
|
||
};
|
||
|
||
let (users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
let response = PaginatedResponse::new(
|
||
users.into_iter().map(|u| u.username).collect(),
|
||
¶ms,
|
||
total_count
|
||
);
|
||
|
||
assert!(!response.pagination.has_prev, "第一页不应该有上一页");
|
||
assert!(response.pagination.has_next, "第一页应该有下一页");
|
||
|
||
// 测试最后一页
|
||
let params = PaginationParams {
|
||
page: Some(3),
|
||
limit: Some(3),
|
||
};
|
||
|
||
let (users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
let response = PaginatedResponse::new(
|
||
users.into_iter().map(|u| u.username).collect(),
|
||
¶ms,
|
||
total_count
|
||
);
|
||
|
||
assert!(response.pagination.has_prev, "最后一页应该有上一页");
|
||
assert!(!response.pagination.has_next, "最后一页不应该有下一页");
|
||
assert_eq!(response.data.len(), 1, "最后一页应该有1个用户");
|
||
}
|
||
|
||
/// 测试分页功能的性能(大数据量)
|
||
#[tokio::test]
|
||
async fn test_pagination_performance() {
|
||
let store = MemoryUserStore::new();
|
||
|
||
// 创建100个用户
|
||
create_multiple_users(&store, 100).await;
|
||
|
||
let start = std::time::Instant::now();
|
||
|
||
// 测试获取中间页面的性能
|
||
let params = PaginationParams {
|
||
page: Some(50),
|
||
limit: Some(2),
|
||
};
|
||
|
||
let (paginated_users, total_count) = store.list_users_paginated(¶ms).await.unwrap();
|
||
|
||
let duration = start.elapsed();
|
||
|
||
assert_eq!(total_count, 100, "总用户数应该是100");
|
||
assert_eq!(paginated_users.len(), 2, "应该返回2个用户");
|
||
|
||
// 性能检查:应该在合理时间内完成(这里设置为100ms,实际应该更快)
|
||
assert!(duration.as_millis() < 100, "分页查询应该在100ms内完成,实际用时: {:?}", duration);
|
||
} |