File size: 2,782 Bytes
17f328f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use std::sync::Arc;
use std::sync::Mutex;

use codex_exec_server::ExecServerError;
use codex_exec_server::HttpClient;
use codex_exec_server::HttpRedirectPolicy;
use codex_exec_server::HttpRequestParams;
use codex_exec_server::HttpRequestResponse;
use codex_exec_server::HttpResponseBodyStream;
use futures::FutureExt;
use futures::future::BoxFuture;
use pretty_assertions::assert_eq;

use super::OPENAI_DEVELOPER_DOCS_MCP_CODEX_URL;
use super::OPENAI_DEVELOPER_DOCS_MCP_URL;
use super::maybe_with_openai_docs_source_attribution;

#[derive(Default)]
struct RecordingHttpClient {
    urls: Mutex<Vec<String>>,
}

impl HttpClient for RecordingHttpClient {
    fn http_request(
        &self,
        params: HttpRequestParams,
    ) -> BoxFuture<'_, Result<HttpRequestResponse, ExecServerError>> {
        self.urls.lock().unwrap().push(params.url);
        async { Err(ExecServerError::HttpRequest("test response".to_string())) }.boxed()
    }

    fn http_request_stream(
        &self,
        params: HttpRequestParams,
    ) -> BoxFuture<'_, Result<(HttpRequestResponse, HttpResponseBodyStream), ExecServerError>> {
        self.urls.lock().unwrap().push(params.url);
        async { Err(ExecServerError::HttpRequest("test response".to_string())) }.boxed()
    }
}

fn request(url: &str) -> HttpRequestParams {
    HttpRequestParams {
        method: "POST".to_string(),
        url: url.to_string(),
        headers: Vec::new(),
        body: None,
        timeout_ms: None,
        redirect_policy: HttpRedirectPolicy::Follow,
        request_id: "test-request".to_string(),
        stream_response: true,
    }
}

#[tokio::test]
async fn attributes_only_docs_mcp_requests() {
    let recording_client = Arc::new(RecordingHttpClient::default());
    let http_client = maybe_with_openai_docs_source_attribution(
        OPENAI_DEVELOPER_DOCS_MCP_URL,
        recording_client.clone(),
    );

    let _ = http_client
        .http_request_stream(request(OPENAI_DEVELOPER_DOCS_MCP_URL))
        .await;
    let _ = http_client
        .http_request(request(
            "https://developers.openai.com/.well-known/oauth-protected-resource/mcp",
        ))
        .await;

    assert_eq!(
        recording_client.urls.lock().unwrap().as_slice(),
        [
            OPENAI_DEVELOPER_DOCS_MCP_CODEX_URL,
            "https://developers.openai.com/.well-known/oauth-protected-resource/mcp",
        ]
    );
}

#[test]
fn leaves_other_mcp_clients_unwrapped() {
    let recording_client = Arc::new(RecordingHttpClient::default());
    let http_client = maybe_with_openai_docs_source_attribution(
        "https://example.com/mcp",
        recording_client.clone(),
    );

    assert!(Arc::ptr_eq(
        &http_client,
        &(recording_client as Arc<dyn HttpClient>)
    ));
}