Skip to content

Commit 881c797

Browse files
authored
Move responses mocking helpers to a shared lib (#3878)
These are generally useful
1 parent a7fda70 commit 881c797

File tree

6 files changed

+141
-131
lines changed

6 files changed

+141
-131
lines changed

codex-rs/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codex-rs/core/tests/common/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ codex-core = { path = "../.." }
1111
serde_json = "1"
1212
tempfile = "3"
1313
tokio = { version = "1", features = ["time"] }
14+
wiremock = "0.6"

codex-rs/core/tests/common/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use codex_core::config::Config;
77
use codex_core::config::ConfigOverrides;
88
use codex_core::config::ConfigToml;
99

10+
pub mod responses;
11+
1012
/// Returns a default `Config` whose on-disk state is confined to the provided
1113
/// temporary directory. Using a per-test directory keeps tests hermetic and
1214
/// avoids clobbering a developer’s real `~/.codex`.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use serde_json::Value;
2+
use wiremock::BodyPrintLimit;
3+
use wiremock::Mock;
4+
use wiremock::MockServer;
5+
use wiremock::ResponseTemplate;
6+
use wiremock::matchers::method;
7+
use wiremock::matchers::path;
8+
9+
/// Build an SSE stream body from a list of JSON events.
10+
pub fn sse(events: Vec<Value>) -> String {
11+
use std::fmt::Write as _;
12+
let mut out = String::new();
13+
for ev in events {
14+
let kind = ev.get("type").and_then(|v| v.as_str()).unwrap();
15+
writeln!(&mut out, "event: {kind}").unwrap();
16+
if !ev.as_object().map(|o| o.len() == 1).unwrap_or(false) {
17+
write!(&mut out, "data: {ev}\n\n").unwrap();
18+
} else {
19+
out.push('\n');
20+
}
21+
}
22+
out
23+
}
24+
25+
/// Convenience: SSE event for a completed response with a specific id.
26+
pub fn ev_completed(id: &str) -> Value {
27+
serde_json::json!({
28+
"type": "response.completed",
29+
"response": {
30+
"id": id,
31+
"usage": {"input_tokens":0,"input_tokens_details":null,"output_tokens":0,"output_tokens_details":null,"total_tokens":0}
32+
}
33+
})
34+
}
35+
36+
pub fn ev_completed_with_tokens(id: &str, total_tokens: u64) -> Value {
37+
serde_json::json!({
38+
"type": "response.completed",
39+
"response": {
40+
"id": id,
41+
"usage": {
42+
"input_tokens": total_tokens,
43+
"input_tokens_details": null,
44+
"output_tokens": 0,
45+
"output_tokens_details": null,
46+
"total_tokens": total_tokens
47+
}
48+
}
49+
})
50+
}
51+
52+
/// Convenience: SSE event for a single assistant message output item.
53+
pub fn ev_assistant_message(id: &str, text: &str) -> Value {
54+
serde_json::json!({
55+
"type": "response.output_item.done",
56+
"item": {
57+
"type": "message",
58+
"role": "assistant",
59+
"id": id,
60+
"content": [{"type": "output_text", "text": text}]
61+
}
62+
})
63+
}
64+
65+
pub fn ev_function_call(call_id: &str, name: &str, arguments: &str) -> Value {
66+
serde_json::json!({
67+
"type": "response.output_item.done",
68+
"item": {
69+
"type": "function_call",
70+
"call_id": call_id,
71+
"name": name,
72+
"arguments": arguments
73+
}
74+
})
75+
}
76+
77+
pub fn sse_response(body: String) -> ResponseTemplate {
78+
ResponseTemplate::new(200)
79+
.insert_header("content-type", "text/event-stream")
80+
.set_body_raw(body, "text/event-stream")
81+
}
82+
83+
pub async fn mount_sse_once<M>(server: &MockServer, matcher: M, body: String)
84+
where
85+
M: wiremock::Match + Send + Sync + 'static,
86+
{
87+
Mock::given(method("POST"))
88+
.and(path("/v1/responses"))
89+
.and(matcher)
90+
.respond_with(sse_response(body))
91+
.mount(server)
92+
.await;
93+
}
94+
95+
pub async fn start_mock_server() -> MockServer {
96+
MockServer::builder()
97+
.body_print_limit(BodyPrintLimit::Limited(80_000))
98+
.start()
99+
.await
100+
}

0 commit comments

Comments
 (0)