- normalize_yaml_body 函数在解析 JSON 前添加 trim() 处理,解决 YAML `|` 和 `>` 语法产生的前导空格问题 - 修复 multiple_login.yaml 中 response body 格式错误(YAML 对象改为 JSON 字符串)
239 lines
7.6 KiB
Rust
239 lines
7.6 KiB
Rust
use std::path::Path;
|
||
use std::collections::HashMap;
|
||
use serde_json::json;
|
||
use mock_server::models::Payload;
|
||
use mock_server::loader::MockLoader;
|
||
use mock_server::router::MockRouter;
|
||
|
||
/// 加载 v1 目录的 mock 规则
|
||
fn load_v2_mocks() -> HashMap<String, Vec<mock_server::models::MockRule>> {
|
||
let v2_path = Path::new("../mocks/v1");
|
||
MockLoader::load_all_from_dir(v2_path)
|
||
}
|
||
|
||
// ========== 模块一:验证所有 YAML 文件正确加载 ==========
|
||
|
||
#[test]
|
||
fn test_v2_load_all_mocks() {
|
||
let index = load_v2_mocks();
|
||
|
||
// 验证索引键存在
|
||
assert!(index.contains_key("v1"), "应包含 'v2' 索引键");
|
||
|
||
// 验证规则总数
|
||
let total: usize = index.values().map(|v| v.len()).sum();
|
||
assert_eq!(total, 9, "v2 目录应有 9 个 mock 规则");
|
||
}
|
||
|
||
// ========== 模块二:JSON Payload 测试 ==========
|
||
|
||
#[test]
|
||
fn test_v2_json_login() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let mut headers = HashMap::new();
|
||
headers.insert("Content-Type".to_string(), "application/json".to_string());
|
||
|
||
let payload = Payload::Json(json!({
|
||
"username": "admin",
|
||
"password": "password123"
|
||
}));
|
||
|
||
let matched = router.match_rule("POST", "/v1/auth/login", &HashMap::new(), &headers, &payload);
|
||
|
||
assert!(matched.is_some(), "JSON 登录应匹配成功");
|
||
let rule = matched.unwrap();
|
||
assert_eq!(rule.name, "v2_user_login");
|
||
assert_eq!(rule.response.status, 200);
|
||
}
|
||
|
||
#[test]
|
||
fn test_v2_json_register() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let mut headers = HashMap::new();
|
||
headers.insert("Content-Type".to_string(), "application/json".to_string());
|
||
|
||
let payload = Payload::Json(json!({
|
||
"username": "newuser",
|
||
"password": "newpass123",
|
||
"email": "newuser@example.com"
|
||
}));
|
||
|
||
let matched = router.match_rule("POST", "/v1/auth/register", &HashMap::new(), &headers, &payload);
|
||
|
||
assert!(matched.is_some(), "JSON 注册应匹配成功");
|
||
let rule = matched.unwrap();
|
||
assert_eq!(rule.name, "v2_user_register");
|
||
assert_eq!(rule.response.status, 201);
|
||
}
|
||
|
||
// ========== 模块三:Form Payload 测试 ==========
|
||
|
||
#[test]
|
||
fn test_v2_form_login() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let mut headers = HashMap::new();
|
||
headers.insert("Content-Type".to_string(), "application/x-www-form-urlencoded".to_string());
|
||
|
||
let mut form_data = HashMap::new();
|
||
form_data.insert("username".to_string(), "formuser".to_string());
|
||
form_data.insert("password".to_string(), "formpass".to_string());
|
||
let payload = Payload::Form(form_data);
|
||
|
||
let matched = router.match_rule("POST", "/v1/user/login/form", &HashMap::new(), &headers, &payload);
|
||
|
||
assert!(matched.is_some(), "Form 登录应匹配成功");
|
||
assert_eq!(matched.unwrap().name, "v2_user_login_form");
|
||
}
|
||
|
||
// ========== 模块四:Text Payload 测试 ==========
|
||
|
||
#[test]
|
||
fn test_v2_text_echo() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let mut headers = HashMap::new();
|
||
headers.insert("Content-Type".to_string(), "text/plain".to_string());
|
||
|
||
let payload = Payload::Text("Hello V2 Mock Server".to_string());
|
||
|
||
let matched = router.match_rule("POST", "/v1/user/echo", &HashMap::new(), &headers, &payload);
|
||
|
||
assert!(matched.is_some(), "Text 回显应匹配成功");
|
||
let rule = matched.unwrap();
|
||
assert_eq!(rule.name, "v2_user_echo");
|
||
assert!(rule.response.body.contains("Echo from V2"));
|
||
}
|
||
|
||
// ========== 模块五:XML Payload 测试 ==========
|
||
|
||
#[test]
|
||
fn test_v2_xml_export() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let mut headers = HashMap::new();
|
||
headers.insert("Content-Type".to_string(), "application/xml".to_string());
|
||
|
||
let xml_body = r#"<request><userId>10001</userId><format>xml</format></request>"#;
|
||
let payload = Payload::Xml(xml_body.to_string());
|
||
|
||
let matched = router.match_rule("POST", "/v1/data/export", &HashMap::new(), &headers, &payload);
|
||
|
||
assert!(matched.is_some(), "XML 导出应匹配成功");
|
||
assert_eq!(matched.unwrap().name, "v2_data_export");
|
||
}
|
||
|
||
// ========== 模块六:Multipart Payload 测试 ==========
|
||
|
||
#[test]
|
||
fn test_v2_multipart_upload() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let mut headers = HashMap::new();
|
||
headers.insert("Content-Type".to_string(), "multipart/form-data".to_string());
|
||
|
||
let mut multipart_data = HashMap::new();
|
||
multipart_data.insert("avatar".to_string(), "file_content".to_string());
|
||
multipart_data.insert("description".to_string(), "user avatar".to_string());
|
||
let payload = Payload::Multipart(multipart_data);
|
||
|
||
let matched = router.match_rule("POST", "/v1/user/avatar", &HashMap::new(), &headers, &payload);
|
||
|
||
assert!(matched.is_some(), "Multipart 上传应匹配成功");
|
||
assert_eq!(matched.unwrap().name, "v2_user_upload_avatar");
|
||
}
|
||
|
||
// ========== 模块七:None Payload 测试 (GET 无 Body) ==========
|
||
|
||
#[test]
|
||
fn test_v2_health_check() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let payload = Payload::None;
|
||
|
||
let matched = router.match_rule("GET", "/v1/health", &HashMap::new(), &HashMap::new(), &payload);
|
||
|
||
assert!(matched.is_some(), "健康检查应匹配成功");
|
||
let rule = matched.unwrap();
|
||
assert_eq!(rule.name, "v2_health_check");
|
||
assert_eq!(rule.response.status, 200);
|
||
}
|
||
|
||
#[test]
|
||
fn test_v2_get_profile() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let mut headers = HashMap::new();
|
||
headers.insert("Authorization".to_string(), "Bearer v2_test_token".to_string());
|
||
|
||
let payload = Payload::None;
|
||
|
||
let matched = router.match_rule("GET", "/v1/user/profile", &HashMap::new(), &headers, &payload);
|
||
|
||
assert!(matched.is_some(), "获取用户信息应匹配成功");
|
||
assert_eq!(matched.unwrap().name, "v2_user_profile");
|
||
}
|
||
|
||
// ========== 模块八:Query Params 测试 ==========
|
||
|
||
#[test]
|
||
fn test_v2_query_params() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
let mut query = HashMap::new();
|
||
query.insert("format".to_string(), "json".to_string());
|
||
|
||
let payload = Payload::None;
|
||
|
||
let matched = router.match_rule("GET", "/v1/user/download", &query, &HashMap::new(), &payload);
|
||
|
||
assert!(matched.is_some(), "带 query params 的下载应匹配成功");
|
||
let rule = matched.unwrap();
|
||
assert_eq!(rule.name, "v2_user_download");
|
||
assert!(rule.response.body.starts_with("file://"));
|
||
}
|
||
|
||
// ========== 模块九:Header 匹配测试 ==========
|
||
|
||
#[test]
|
||
fn test_v2_header_required() {
|
||
let index = load_v2_mocks();
|
||
let router = MockRouter::new(index);
|
||
|
||
// 无 Authorization header 不应匹配
|
||
let payload = Payload::None;
|
||
let no_match = router.match_rule("GET", "/v1/user/profile", &HashMap::new(), &HashMap::new(), &payload);
|
||
assert!(no_match.is_none(), "无 Authorization 不应匹配");
|
||
|
||
// 有正确的 Authorization header 应匹配
|
||
let mut headers = HashMap::new();
|
||
headers.insert("Authorization".to_string(), "Bearer v2_test_token".to_string());
|
||
let matched = router.match_rule("GET", "/v1/user/profile", &HashMap::new(), &headers, &payload);
|
||
assert!(matched.is_some(), "有 Authorization 应匹配");
|
||
}
|
||
|
||
// ========== 模块十:name 字段验证 ==========
|
||
|
||
#[test]
|
||
fn test_v2_all_rules_have_name() {
|
||
let index = load_v2_mocks();
|
||
|
||
for (key, rules) in &index {
|
||
for rule in rules {
|
||
assert!(!rule.name.is_empty(), "规则 name 不能为空");
|
||
assert!(rule.name.starts_with("v2_"), "v2 规则 name 应以 'v2_' 开头");
|
||
}
|
||
}
|
||
}
|