Files
mock-server/tests/integration_test.rs
2026-03-26 19:20:22 +08:00

160 lines
5.4 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::fs::{self, File};
use std::io::Write;
use tempfile::tempdir;
// 确保 Cargo.toml 中有 serde_json
use serde_json::json;
use mock_server::model::{MockRule, MockSource};
use mock_server::loader::MockLoader;
use mock_server::router::MockRouter;
use std::collections::HashMap;
/// 模块一:验证 Config 反序列化逻辑
#[test]
fn test_config_parsing_scenarios() {
// 场景 A: 验证单接口配置 (增加 body 结构化校验)
let yaml_single = r#"
id: "auth_v1"
request:
method: "POST"
path: "/api/v1/login"
body: { "user": "admin" }
response: { status: 200, body: "welcome" }
"#;
let source_s: MockSource = serde_yaml::from_str(yaml_single).expect("解析单接口失败");
let rules = source_s.flatten();
assert_eq!(rules.len(), 1);
// 验证 body 是否被成功解析为 Value::Object
assert!(rules[0].request.body.is_some());
assert_eq!(rules[0].request.body.as_ref().unwrap()["user"], "admin");
// 场景 B: 验证多接口配置 (原有逻辑不变)
let yaml_multi = r#"
- id: "api_1"
request: { method: "GET", path: "/health" }
response: { status: 200, body: "ok" }
- id: "api_2"
request: { method: "GET", path: "/version" }
response: { status: 200, body: "1.0" }
"#;
let source_m: MockSource = serde_yaml::from_str(yaml_multi).expect("解析多接口失败");
assert_eq!(source_m.flatten().len(), 2);
// 场景 C: 验证 Smart Body 的 file:// 协议字符串解析 (原有逻辑不变)
let yaml_file = r#"
id: "export_api"
request: { method: "GET", path: "/download" }
response: { status: 200, body: "file://./storage/data.zip" }
"#;
let source_f: MockSource = serde_yaml::from_str(yaml_file).unwrap();
let rule = &source_f.flatten()[0];
assert!(rule.response.body.starts_with("file://"));
}
/// 模块二:验证 Loader 递归扫描与索引构建 (不涉及 Matcher 逻辑,基本保持不变)
#[test]
fn test_loader_recursive_indexing() {
let temp_root = tempdir().expect("无法创建临时目录");
let root_path = temp_root.path();
let auth_path = root_path.join("v1/auth");
fs::create_dir_all(&auth_path).unwrap();
let mut f1 = File::create(auth_path.join("login.yaml")).unwrap();
writeln!(f1, "id: 'l1'\nrequest: {{ method: 'POST', path: '/api/v1/login' }}\nresponse: {{ status: 200, body: 'ok' }}").unwrap();
let mut f2 = File::create(root_path.join("sys.yaml")).unwrap();
writeln!(f2, "- id: 's1'\n request: {{ method: 'GET', path: '/health' }}\n response: {{ status: 200, body: 'up' }}").unwrap();
let index = MockLoader::load_all_from_dir(root_path);
assert!(index.contains_key("api"));
assert!(index.contains_key("health"));
let total: usize = index.values().map(|v| v.len()).sum();
assert_eq!(total, 2);
}
#[test]
fn test_router_matching_logic() {
let mut index = HashMap::new();
// 1. 准备带有 Body 的规则
let rule_auth = serde_yaml::from_str::<MockSource>(
r#"
id: "auth_v1"
request:
method: "POST"
path: "/api/v1/login"
headers: { "Content-Type": "application/json" }
body: { "code": 123 }
response: { status: 200, body: "token_123" }
"#,
)
.unwrap()
.flatten();
index.insert("api".to_string(), vec![rule_auth[0].clone()]);
let router = MockRouter::new(index);
// 2. 测试场景 A完全匹配 (包括 Body)
let mut headers = HashMap::new();
headers.insert("Content-Type".to_string(), "application/json".to_string());
// 构造请求 Body
let incoming_body = Some(json!({ "code": 123 }));
let matched = router.match_rule(
"POST",
"/api/v1/login",
&HashMap::new(),
&headers,
&incoming_body // 传入新参数
);
assert!(matched.is_some());
assert_eq!(matched.unwrap().id, "auth_v1");
// 3. 测试场景 BBody 不匹配
let wrong_body = Some(json!({ "code": 456 }));
let matched_fail = router.match_rule(
"POST",
"/api/v1/login",
&HashMap::new(),
&headers,
&wrong_body
);
assert!(matched_fail.is_none(), "Body 不一致时不应匹配成功");
// 4. 测试场景 C智能字符串转换验证 (YAML 是字符串,请求是对象)
let rule_str_body = serde_yaml::from_str::<MockSource>(
r#"
id: "str_match"
request:
method: "POST"
path: "/api/str"
body: '{"type": "json_in_string"}' # 这里 YAML 解析为 Value::String
response: { status: 200, body: "ok" }
"#).unwrap().flatten();
let mut index2 = HashMap::new();
index2.insert("api".to_string(), vec![rule_str_body[0].clone()]);
let router2 = MockRouter::new(index2);
let incoming_obj = Some(json!({ "type": "json_in_string" })); // 请求是 JSON 对象
let matched_str = router2.match_rule(
"POST",
"/api/str",
&HashMap::new(),
&HashMap::new(),
&incoming_obj
);
assert!(matched_str.is_some(), "应该支持将 YAML 字符串 body 转换为对象进行匹配");
// 5. 测试场景 D末尾斜杠兼容性测试
let matched_slash = router.match_rule(
"POST",
"/api/v1/login/",
&HashMap::new(),
&headers,
&incoming_body
);
assert!(matched_slash.is_some());
}