Skip to main content

rest_e2e_mcp/
types.rs

1use std::collections::HashMap;
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6// =============================================================================
7// Test suite definition (YAML input)
8// =============================================================================
9
10/// テストスイート定義。YAMLファイルの最上位構造。
11#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
12pub struct TestSuite {
13    /// ファイルレベルの変数定義。
14    #[serde(default)]
15    pub variables: HashMap<String, String>,
16
17    /// スイート全体のデフォルトタイムアウト (ms)。省略時は run の timeout_ms を使用。
18    #[serde(default)]
19    pub timeout_ms: Option<u64>,
20
21    /// リクエスト一覧。
22    pub requests: Vec<RequestDef>,
23}
24
25/// 1リクエストの定義。
26#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
27pub struct RequestDef {
28    /// テスト名。
29    pub name: String,
30
31    /// HTTPメソッド (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS)。
32    pub method: String,
33
34    /// リクエストURL。変数展開可 (`{{VAR}}`, `$VAR`, `${VAR}`)。
35    pub url: String,
36
37    /// リクエストヘッダー。
38    #[serde(default)]
39    pub headers: HashMap<String, String>,
40
41    /// リクエストボディ。JSONやフォームデータ等。
42    #[serde(default)]
43    pub body: Option<String>,
44
45    /// 期待値。省略時はステータスコードのみ確認しない。
46    #[serde(default)]
47    pub expect: Option<ExpectDef>,
48
49    /// Bearer自動注入を無効化。
50    #[serde(default)]
51    pub no_auth: bool,
52
53    /// このリクエストのタイムアウト (ms)。省略時はスイートレベルの値を使用。
54    #[serde(default)]
55    pub timeout_ms: Option<u64>,
56
57    /// このテストをスキップ。
58    #[serde(default)]
59    pub skip: bool,
60
61    /// タグ(フィルタで使用: `@tag:smoke`)。
62    #[serde(default)]
63    pub tags: Vec<String>,
64}
65
66/// 期待値定義。
67#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
68pub struct ExpectDef {
69    /// 期待HTTPステータスコード。単一 or 複数。
70    #[serde(default)]
71    pub status: Option<StatusExpect>,
72
73    /// ヘッダー検証。キーはcase-insensitive、値は部分一致。
74    #[serde(default)]
75    pub headers: HashMap<String, String>,
76
77    /// ボディに含まれるべき文字列。
78    #[serde(default)]
79    pub body_contains: Vec<String>,
80
81    /// ボディに含まれてはいけない文字列。
82    #[serde(default)]
83    pub body_not_contains: Vec<String>,
84
85    /// ボディがマッチすべき正規表現(Rust regex構文)。ボディ全体に対して検索 (is_match) する。
86    #[serde(default)]
87    pub body_matches: Vec<String>,
88
89    /// ボディがマッチしてはいけない正規表現(Rust regex構文)。ボディ全体に対して検索 (is_match) する。
90    #[serde(default)]
91    pub body_not_matches: Vec<String>,
92}
93
94/// 期待ステータスコード。単一値 or 複数値。
95#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
96#[serde(untagged)]
97pub enum StatusExpect {
98    Single(u16),
99    Multiple(Vec<u16>),
100}
101
102impl StatusExpect {
103    pub fn matches(&self, actual: u16) -> bool {
104        match self {
105            Self::Single(s) => *s == actual,
106            Self::Multiple(v) => v.contains(&actual),
107        }
108    }
109}
110
111impl std::fmt::Display for StatusExpect {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        match self {
114            Self::Single(s) => write!(f, "{s}"),
115            Self::Multiple(v) => {
116                let s: Vec<String> = v.iter().map(|n| n.to_string()).collect();
117                write!(f, "{}", s.join(" or "))
118            }
119        }
120    }
121}
122
123// =============================================================================
124// Variable resolution types
125// =============================================================================
126
127/// 変数の出所。
128#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
129pub enum VarSource {
130    /// run の variables パラメータ。
131    Runtime,
132    /// YAMLファイル内の variables。
133    SuiteFile,
134    /// .env ファイル。
135    DotEnv,
136    /// OS環境変数。
137    OsEnv,
138}
139
140impl std::fmt::Display for VarSource {
141    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142        match self {
143            Self::Runtime => write!(f, "runtime"),
144            Self::SuiteFile => write!(f, "suite"),
145            Self::DotEnv => write!(f, ".env"),
146            Self::OsEnv => write!(f, "OS"),
147        }
148    }
149}
150
151/// 変数解決の追跡情報。config ツールの出力に使う。
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct VarTrace {
154    pub name: String,
155    pub value: String,
156    pub source: VarSource,
157    /// この変数が見つかった全ソースと値。低い優先順位から高い順。
158    pub found_in: Vec<(VarSource, String)>,
159}
160
161/// 解決済み変数セット。
162#[derive(Debug, Clone, Default)]
163pub struct ResolvedVars {
164    pub vars: HashMap<String, String>,
165    pub traces: Vec<VarTrace>,
166}
167
168// =============================================================================
169// HTTP execution types
170// =============================================================================
171
172/// HTTPリクエスト実行結果。
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct HttpResponse {
175    pub status: u16,
176    pub http_version: String,
177    pub headers: HashMap<String, String>,
178    /// reqwest が実際に送信したリクエストヘッダー。
179    pub actual_request_headers: HashMap<String, String>,
180    pub body: String,
181    pub charset: Option<String>,
182    pub elapsed_ms: u64,
183    pub size_bytes: usize,
184}
185
186// =============================================================================
187// Assertion types
188// =============================================================================
189
190/// 1つの検証失敗。
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct Failure {
193    pub check: String,
194    pub expected: String,
195    pub actual: String,
196}
197
198/// 1リクエストの検証結果。
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct TestResult {
201    pub name: String,
202    pub status: u16,
203    pub passed: bool,
204    pub elapsed_ms: u64,
205    pub failures: Vec<Failure>,
206    pub response_preview: String,
207    pub request_method: String,
208    pub request_url: String,
209    pub request_headers: HashMap<String, String>,
210    pub request_body: Option<String>,
211    pub response_headers: HashMap<String, String>,
212    /// HTTPバージョン("HTTP/1.1", "HTTP/2" 等)。
213    #[serde(default)]
214    pub response_http_version: String,
215    /// レスポンスの文字コード(content-type から検出)。
216    #[serde(default, skip_serializing_if = "Option::is_none")]
217    pub response_charset: Option<String>,
218    /// レスポンスボディのバイト数。
219    #[serde(default)]
220    pub response_size_bytes: usize,
221    pub skipped: bool,
222    /// エラー種別("timeout", "connection", "dns", "tls", None=成功 or アサート失敗)。
223    #[serde(default, skip_serializing_if = "Option::is_none")]
224    pub error_type: Option<String>,
225}
226
227/// スイート全体の結果。
228#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct SuiteResult {
230    pub total: usize,
231    pub passed: usize,
232    pub failed: usize,
233    pub skipped: usize,
234    pub elapsed_ms: u64,
235    pub results: Vec<TestResult>,
236    /// 警告メッセージ(未解決変数、circuit breaker 等)。
237    #[serde(default, skip_serializing_if = "Vec::is_empty")]
238    pub warnings: Vec<String>,
239}