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使用文档 - 部署检查清单 - 运维操作手册 - 性能和安全指南 - 故障排除指南
300 lines
8.3 KiB
Rust
300 lines
8.3 KiB
Rust
//! 集成测试
|
|
|
|
use reqwest;
|
|
use serde_json::{json, Value};
|
|
use std::collections::HashMap;
|
|
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<Value, Box<dyn std::error::Error>> {
|
|
let text = response.text().await?;
|
|
let json: Value = serde_json::from_str(&text)?;
|
|
Ok(json)
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_health_check() {
|
|
let client = create_client();
|
|
|
|
let response = client
|
|
.get(&format!("{}/health", BASE_URL))
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
|
|
assert_eq!(response.status(), 200);
|
|
|
|
let json = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
assert_eq!(json["status"], "healthy");
|
|
assert!(json["timestamp"].is_string());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_root_endpoint() {
|
|
let client = create_client();
|
|
|
|
let response = client
|
|
.get(&format!("{}/", BASE_URL))
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
|
|
assert_eq!(response.status(), 200);
|
|
|
|
let json = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
assert_eq!(json["message"], "欢迎使用 Rust User API");
|
|
assert_eq!(json["version"], "0.1.0");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_user_lifecycle() {
|
|
let client = create_client();
|
|
|
|
// 1. 获取初始用户列表(应该为空)
|
|
let response = client
|
|
.get(&format!("{}/api/users", BASE_URL))
|
|
.send()
|
|
.await
|
|
.expect("Failed to get users");
|
|
|
|
assert_eq!(response.status(), 200);
|
|
let users_response = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
assert!(users_response["data"].is_array());
|
|
assert!(users_response["pagination"].is_object());
|
|
|
|
// 2. 创建新用户
|
|
let user_data = json!({
|
|
"username": "testuser_integration",
|
|
"email": "integration@example.com",
|
|
"password": "password123"
|
|
});
|
|
|
|
let response = client
|
|
.post(&format!("{}/api/users", BASE_URL))
|
|
.json(&user_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to create user");
|
|
|
|
assert_eq!(response.status(), 201);
|
|
let created_user = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
|
|
assert_eq!(created_user["username"], "testuser_integration");
|
|
assert_eq!(created_user["email"], "integration@example.com");
|
|
assert!(created_user["id"].is_string());
|
|
assert!(created_user["created_at"].is_string());
|
|
|
|
let user_id = created_user["id"].as_str().unwrap();
|
|
|
|
// 3. 获取创建的用户
|
|
let response = client
|
|
.get(&format!("{}/api/users/{}", BASE_URL, user_id))
|
|
.send()
|
|
.await
|
|
.expect("Failed to get user");
|
|
|
|
assert_eq!(response.status(), 200);
|
|
let fetched_user = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
assert_eq!(fetched_user["id"], user_id);
|
|
assert_eq!(fetched_user["username"], "testuser_integration");
|
|
|
|
// 4. 更新用户
|
|
let update_data = json!({
|
|
"username": "updated_testuser",
|
|
"email": "updated@example.com"
|
|
});
|
|
|
|
let response = client
|
|
.put(&format!("{}/api/users/{}", BASE_URL, user_id))
|
|
.json(&update_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to update user");
|
|
|
|
assert_eq!(response.status(), 200);
|
|
let updated_user = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
assert_eq!(updated_user["username"], "updated_testuser");
|
|
assert_eq!(updated_user["email"], "updated@example.com");
|
|
|
|
// 5. 删除用户
|
|
let response = client
|
|
.delete(&format!("{}/api/users/{}", BASE_URL, user_id))
|
|
.send()
|
|
.await
|
|
.expect("Failed to delete user");
|
|
|
|
assert_eq!(response.status(), 204);
|
|
|
|
// 6. 验证用户已被删除
|
|
let response = client
|
|
.get(&format!("{}/api/users/{}", BASE_URL, user_id))
|
|
.send()
|
|
.await
|
|
.expect("Failed to get deleted user");
|
|
|
|
assert_eq!(response.status(), 404);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_user_validation() {
|
|
let client = create_client();
|
|
|
|
// 测试无效的用户数据
|
|
let invalid_user_data = json!({
|
|
"username": "ab", // 太短
|
|
"email": "invalid-email", // 无效邮箱
|
|
"password": "123" // 太短
|
|
});
|
|
|
|
let response = client
|
|
.post(&format!("{}/api/users", BASE_URL))
|
|
.json(&invalid_user_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
|
|
assert_eq!(response.status(), 400);
|
|
let error_response = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
assert!(error_response["error"].is_string());
|
|
assert_eq!(error_response["status"], 400);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_duplicate_username() {
|
|
let client = create_client();
|
|
|
|
let user_data = json!({
|
|
"username": "duplicate_test",
|
|
"email": "duplicate1@example.com",
|
|
"password": "password123"
|
|
});
|
|
|
|
// 创建第一个用户
|
|
let response = client
|
|
.post(&format!("{}/api/users", BASE_URL))
|
|
.json(&user_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to create first user");
|
|
|
|
assert_eq!(response.status(), 201);
|
|
|
|
// 尝试创建相同用户名的用户
|
|
let duplicate_user_data = json!({
|
|
"username": "duplicate_test", // 相同用户名
|
|
"email": "duplicate2@example.com",
|
|
"password": "password123"
|
|
});
|
|
|
|
let response = client
|
|
.post(&format!("{}/api/users", BASE_URL))
|
|
.json(&duplicate_user_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send duplicate request");
|
|
|
|
assert_eq!(response.status(), 409);
|
|
let error_response = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
assert!(error_response["error"].as_str().unwrap().contains("用户名已存在"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_login_flow() {
|
|
let client = create_client();
|
|
|
|
// 1. 创建测试用户
|
|
let user_data = json!({
|
|
"username": "login_test",
|
|
"email": "login@example.com",
|
|
"password": "password123"
|
|
});
|
|
|
|
let response = client
|
|
.post(&format!("{}/api/users", BASE_URL))
|
|
.json(&user_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to create user");
|
|
|
|
assert_eq!(response.status(), 201);
|
|
|
|
// 2. 测试正确的登录凭据
|
|
let login_data = json!({
|
|
"username": "login_test",
|
|
"password": "password123"
|
|
});
|
|
|
|
let response = client
|
|
.post(&format!("{}/api/auth/login", BASE_URL))
|
|
.json(&login_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to login");
|
|
|
|
assert_eq!(response.status(), 200);
|
|
let login_response = parse_json_response(response).await.expect("Failed to parse JSON");
|
|
|
|
assert!(login_response["token"].is_string());
|
|
assert!(login_response["user"]["id"].is_string());
|
|
assert_eq!(login_response["user"]["username"], "login_test");
|
|
|
|
// 3. 测试错误的密码
|
|
let wrong_login_data = json!({
|
|
"username": "login_test",
|
|
"password": "wrongpassword"
|
|
});
|
|
|
|
let response = client
|
|
.post(&format!("{}/api/auth/login", BASE_URL))
|
|
.json(&wrong_login_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send wrong login");
|
|
|
|
assert_eq!(response.status(), 401);
|
|
|
|
// 4. 测试不存在的用户
|
|
let nonexistent_login_data = json!({
|
|
"username": "nonexistent_user",
|
|
"password": "password123"
|
|
});
|
|
|
|
let response = client
|
|
.post(&format!("{}/api/auth/login", BASE_URL))
|
|
.json(&nonexistent_login_data)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send nonexistent login");
|
|
|
|
assert_eq!(response.status(), 404);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_not_found_endpoints() {
|
|
let client = create_client();
|
|
|
|
// 测试不存在的用户 ID
|
|
let response = client
|
|
.get(&format!("{}/api/users/00000000-0000-0000-0000-000000000000", BASE_URL))
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
|
|
assert_eq!(response.status(), 404);
|
|
|
|
// 测试不存在的端点
|
|
let response = client
|
|
.get(&format!("{}/api/nonexistent", BASE_URL))
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
|
|
assert_eq!(response.status(), 404);
|
|
} |