mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
fix(test): remove hidden HTTP client startup overhead
Disable proxy discovery for the hot test HTTP clients so nextest no longer pays macOS system proxy lookup on repeated reqwest client creation. Also keep the approved OAuth loopback cleanup and replace GitHub test key generation with a checked-in PEM fixture.
This commit is contained in:
parent
aa5047c509
commit
8a2d00591b
11 changed files with 141 additions and 88 deletions
|
|
@ -394,10 +394,21 @@ impl HookExecutorImpl {
|
|||
/// Build a reqwest client for the given TLS mode.
|
||||
fn build_http_client(tls: TlsMode) -> reqwest::Client {
|
||||
let accept_invalid = matches!(tls, TlsMode::NoVerify | TlsMode::Off);
|
||||
reqwest::Client::builder()
|
||||
.danger_accept_invalid_certs(accept_invalid)
|
||||
.build()
|
||||
.unwrap_or_default()
|
||||
#[cfg(test)]
|
||||
{
|
||||
return reqwest::Client::builder()
|
||||
.danger_accept_invalid_certs(accept_invalid)
|
||||
.no_proxy()
|
||||
.build()
|
||||
.unwrap_or_default();
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
reqwest::Client::builder()
|
||||
.danger_accept_invalid_certs(accept_invalid)
|
||||
.build()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute an HTTP hook: POST context JSON and parse the response.
|
||||
|
|
|
|||
|
|
@ -1413,6 +1413,10 @@ async fn test_models(
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn test_http_client() -> reqwest::Client {
|
||||
reqwest::Client::builder().no_proxy().build().unwrap()
|
||||
}
|
||||
|
||||
// --- parse_option ---
|
||||
|
||||
#[test]
|
||||
|
|
@ -1618,7 +1622,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let resp = test_model_via_server(&client, &server.url(""), "test-model")
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -1646,7 +1650,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let resp = test_model_via_server(&client, &server.url(""), "test-model")
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -1669,7 +1673,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let result = test_model_via_server(&client, &server.url(""), "bad-model").await;
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
|
@ -1701,7 +1705,7 @@ mod tests {
|
|||
}).to_string());
|
||||
}).await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let models = fetch_models_from_server(&client, &server.url(""), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -1753,7 +1757,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let models = fetch_models_from_server(&client, &server.url(""), Some("anthropic"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -1772,7 +1776,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let result = fetch_models_from_server(&client, &server.url(""), None).await;
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
|
@ -1801,7 +1805,7 @@ mod tests {
|
|||
.await;
|
||||
|
||||
let server = ServerConnection {
|
||||
client: reqwest::Client::new(),
|
||||
client: test_http_client(),
|
||||
base_url: mock_server.url(""),
|
||||
};
|
||||
|
||||
|
|
@ -1841,7 +1845,7 @@ data: {\"type\":\"finish\",\"finish_reason\":\"stop\",\"usage\":{\"input_tokens\
|
|||
.await;
|
||||
|
||||
let server = ServerConnection {
|
||||
client: reqwest::Client::new(),
|
||||
client: test_http_client(),
|
||||
base_url: mock_server.url(""),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2201,7 +2201,6 @@ mod tests {
|
|||
"beta header should contain fast-mode header, got: {beta}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn beta_header_includes_both_cache_and_fast_mode() {
|
||||
let result = build_beta_header(None, true, true, false);
|
||||
|
|
|
|||
|
|
@ -229,6 +229,10 @@ mod tests {
|
|||
use futures::StreamExt;
|
||||
use httpmock::prelude::*;
|
||||
|
||||
fn test_http_client() -> reqwest::Client {
|
||||
reqwest::Client::builder().no_proxy().build().unwrap()
|
||||
}
|
||||
|
||||
fn make_request() -> Request {
|
||||
Request {
|
||||
model: "test-model".to_string(),
|
||||
|
|
@ -270,7 +274,7 @@ data: {\"type\":\"text_delta\",\"delta\":\" world\",\"text_id\":null}\n\
|
|||
.body(sse_body);
|
||||
});
|
||||
|
||||
let adapter = Adapter::new(reqwest::Client::new(), server.base_url(), "test-provider");
|
||||
let adapter = Adapter::new(test_http_client(), server.base_url(), "test-provider");
|
||||
|
||||
let mut stream = adapter.stream(&make_request()).await.unwrap();
|
||||
|
||||
|
|
@ -323,7 +327,7 @@ data: {\"type\":\"text_delta\",\"delta\":\" world\",\"text_id\":null}\n\
|
|||
.json_body(response_json);
|
||||
});
|
||||
|
||||
let adapter = Adapter::new(reqwest::Client::new(), server.base_url(), "test-provider");
|
||||
let adapter = Adapter::new(test_http_client(), server.base_url(), "test-provider");
|
||||
|
||||
let response = adapter.complete(&make_request()).await.unwrap();
|
||||
|
||||
|
|
@ -346,7 +350,7 @@ data: {\"type\":\"text_delta\",\"delta\":\" world\",\"text_id\":null}\n\
|
|||
then.status(502).body("Bad Gateway");
|
||||
});
|
||||
|
||||
let adapter = Adapter::new(reqwest::Client::new(), server.base_url(), "test-provider");
|
||||
let adapter = Adapter::new(test_http_client(), server.base_url(), "test-provider");
|
||||
|
||||
let err = adapter.complete(&make_request()).await.unwrap_err();
|
||||
match &err {
|
||||
|
|
@ -367,7 +371,7 @@ data: {\"type\":\"text_delta\",\"delta\":\" world\",\"text_id\":null}\n\
|
|||
then.status(502).body("Bad Gateway");
|
||||
});
|
||||
|
||||
let adapter = Adapter::new(reqwest::Client::new(), server.base_url(), "test-provider");
|
||||
let adapter = Adapter::new(test_http_client(), server.base_url(), "test-provider");
|
||||
|
||||
let result = adapter.stream(&make_request()).await;
|
||||
let Err(err) = result else {
|
||||
|
|
@ -401,7 +405,7 @@ data: {\"type\":\"stream_start\"}\n\
|
|||
.body(sse_body);
|
||||
});
|
||||
|
||||
let adapter = Adapter::new(reqwest::Client::new(), server.base_url(), "test-provider");
|
||||
let adapter = Adapter::new(test_http_client(), server.base_url(), "test-provider");
|
||||
|
||||
let mut stream = adapter.stream(&make_request()).await.unwrap();
|
||||
|
||||
|
|
@ -447,7 +451,7 @@ data: {\"type\":\"stream_start\"}\n\
|
|||
|
||||
#[test]
|
||||
fn adapter_name() {
|
||||
let adapter = Adapter::new(reqwest::Client::new(), "http://localhost", "anthropic");
|
||||
let adapter = Adapter::new(test_http_client(), "http://localhost", "anthropic");
|
||||
assert_eq!(adapter.name(), "anthropic");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,28 @@ pub struct HttpApi {
|
|||
}
|
||||
|
||||
impl HttpApi {
|
||||
fn build_client(timeout: AdapterTimeout) -> reqwest::Client {
|
||||
#[cfg(test)]
|
||||
{
|
||||
return reqwest::Client::builder()
|
||||
.connect_timeout(Duration::from_secs_f64(timeout.connect))
|
||||
.no_proxy()
|
||||
.build()
|
||||
.unwrap_or_default();
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
reqwest::Client::builder()
|
||||
.connect_timeout(Duration::from_secs_f64(timeout.connect))
|
||||
.build()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn new(api_key: impl Into<String>, base_url: impl Into<String>) -> Self {
|
||||
let timeout = AdapterTimeout::default();
|
||||
let client = reqwest::Client::builder()
|
||||
.connect_timeout(Duration::from_secs_f64(timeout.connect))
|
||||
.build()
|
||||
.unwrap_or_default();
|
||||
let client = Self::build_client(timeout);
|
||||
Self {
|
||||
api_key: api_key.into(),
|
||||
base_url: base_url.into(),
|
||||
|
|
@ -37,10 +52,7 @@ impl HttpApi {
|
|||
|
||||
#[must_use]
|
||||
pub fn with_timeout(mut self, timeout: AdapterTimeout) -> Self {
|
||||
self.client = reqwest::Client::builder()
|
||||
.connect_timeout(Duration::from_secs_f64(timeout.connect))
|
||||
.build()
|
||||
.unwrap_or_default();
|
||||
self.client = Self::build_client(timeout);
|
||||
self.request_timeout = timeout.request.map(Duration::from_secs_f64);
|
||||
self.stream_read_timeout = timeout.stream_read.map(Duration::from_secs_f64);
|
||||
self
|
||||
|
|
|
|||
|
|
@ -1223,7 +1223,6 @@ mod tests {
|
|||
assert!(adapter.project_id.is_none());
|
||||
assert!(adapter.http.default_headers.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn audio_content_produces_text_fallback() {
|
||||
let msg = Message {
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ fn validate_callback_path(path: &str) -> Result<(), String> {
|
|||
}
|
||||
|
||||
fn build_redirect_uri(port: u16, path: &str) -> String {
|
||||
format!("http://localhost:{port}{path}")
|
||||
format!("http://127.0.0.1:{port}{path}")
|
||||
}
|
||||
|
||||
pub async fn start_callback_server(
|
||||
|
|
@ -234,7 +234,7 @@ pub async fn start_callback_server(
|
|||
) -> Result<(u16, oneshot::Receiver<Result<String, String>>), String> {
|
||||
validate_callback_path(path)?;
|
||||
|
||||
let listener = TcpListener::bind(format!("localhost:{port}"))
|
||||
let listener = TcpListener::bind(("127.0.0.1", port))
|
||||
.await
|
||||
.map_err(|e| format!("Failed to bind callback server: {e}"))?;
|
||||
let actual_port = listener
|
||||
|
|
@ -414,6 +414,10 @@ pub async fn run_browser_flow(
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn test_http_client() -> reqwest::Client {
|
||||
reqwest::Client::builder().no_proxy().build().unwrap()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Phase 1: PKCE
|
||||
// -----------------------------------------------------------------------
|
||||
|
|
@ -554,13 +558,13 @@ mod tests {
|
|||
fn build_redirect_uri_constructs_expected_uri() {
|
||||
assert_eq!(
|
||||
build_redirect_uri(1455, "/auth/callback"),
|
||||
"http://localhost:1455/auth/callback"
|
||||
"http://127.0.0.1:1455/auth/callback"
|
||||
);
|
||||
assert_eq!(
|
||||
build_redirect_uri(8080, "/oauth/done"),
|
||||
"http://localhost:8080/oauth/done"
|
||||
"http://127.0.0.1:8080/oauth/done"
|
||||
);
|
||||
assert_eq!(build_redirect_uri(1, "/"), "http://localhost:1/");
|
||||
assert_eq!(build_redirect_uri(1, "/"), "http://127.0.0.1:1/");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
|
@ -595,7 +599,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let tokens = exchange_code_for_tokens(
|
||||
&client,
|
||||
&server.url(""),
|
||||
|
|
@ -633,7 +637,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let tokens = exchange_code_for_tokens(
|
||||
&client,
|
||||
&server.url(""),
|
||||
|
|
@ -662,7 +666,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let err = exchange_code_for_tokens(
|
||||
&client,
|
||||
&server.url(""),
|
||||
|
|
@ -706,7 +710,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let tokens =
|
||||
refresh_access_token(&client, &server.url(""), "test-client", "old-refresh-tok")
|
||||
.await
|
||||
|
|
@ -731,7 +735,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let err = refresh_access_token(&client, &server.url(""), "test-client", "expired-tok")
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
|
@ -752,10 +756,10 @@ mod tests {
|
|||
|
||||
assert_ne!(port, 0);
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
client
|
||||
.get(format!(
|
||||
"http://localhost:{port}{callback_path}?code=abc&state=test-state"
|
||||
"http://127.0.0.1:{port}{callback_path}?code=abc&state=test-state"
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
|
|
@ -772,10 +776,10 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let resp = client
|
||||
.get(format!(
|
||||
"http://localhost:{port}{callback_path}?code=abc&state=test-state"
|
||||
"http://127.0.0.1:{port}{callback_path}?code=abc&state=test-state"
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
|
|
@ -791,10 +795,10 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let resp = client
|
||||
.get(format!(
|
||||
"http://localhost:{port}{callback_path}?code=abc&state=wrong-state"
|
||||
"http://127.0.0.1:{port}{callback_path}?code=abc&state=wrong-state"
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
|
|
@ -810,10 +814,10 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let resp = client
|
||||
.get(format!(
|
||||
"http://localhost:{port}{callback_path}?code=abc&state=test-state"
|
||||
"http://127.0.0.1:{port}{callback_path}?code=abc&state=test-state"
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
|
|
|
|||
|
|
@ -286,6 +286,10 @@ mod tests {
|
|||
use axum::http::Request;
|
||||
use tower::ServiceExt;
|
||||
|
||||
fn test_http_client() -> reqwest::Client {
|
||||
reqwest::Client::builder().no_proxy().build().unwrap()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// verify_signature
|
||||
// -----------------------------------------------------------------------
|
||||
|
|
@ -407,7 +411,7 @@ mod tests {
|
|||
let body = b"{}";
|
||||
let sig = compute_signature(secret, body);
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let resp = client
|
||||
.post(format!("http://127.0.0.1:{port}/webhooks/github"))
|
||||
.header("x-hub-signature-256", sig)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDLrOym7SsuLj2K
|
||||
yFR9UC3jhPUDgCVC1yWa2XF7Hl2LoCGuUIyxFJwUyoWGFgkWpQKCKmNqp1AEyJI3
|
||||
LEOQTBT9wqLBImuZ2J7vtDCYhMWyzMH0vLatAqcDTvPfDcdu9B27VVU1TGfiNe7t
|
||||
EXP5jfjNvi7AZKdwEYnZUeE4rC4fmraQy4XY9jSm/l9hEq4/RgNg6Pnjr8EJMpxM
|
||||
L8CJGLnYcJA7k4wD6VwpCQoI2vOPjfEiffkAK7Ul264/ex+hWDLycqvpeL4dJ8ZM
|
||||
PGOpjuG2z9dElP50pTTycAO5wXkm+luTDVYXgtSQAs5qA4mdMMvsWUCfvV0hxer6
|
||||
aaa0EVBlAgMBAAECggEAKBjFBh/OzmqgBwBlUb5FKnN0YNoLe9srNg70vk4+EEzY
|
||||
FJ8a84mhKJ6uJrWT2HdnxQRfShHiOO7bii0WqAOyZjq5G9iQ4lq4/2uz3XLWENsq
|
||||
m+nC9NB+3LHgZNsrlfZNHCIygimmkewYO2eiM1D12FtGjO3D4NYzEyuBcUzET8gl
|
||||
k0ZbBCYee6D0cRhABlg8c35ZYQ7CGeP5eUnlPMXxh/GR3VTXs5ZXeuX2G0na6COT
|
||||
t3AM0xia9FJiCw73sCb3M5xVhu+61UHXQFU2gqbUZq51B/7wiEhVmIqxoU9IUIgd
|
||||
UIVGUAGfPkOmZcEhIF4Kv3tEzU+hgX9aReF7hNKXAQKBgQDq6Qy9s9HdThiu2hGV
|
||||
sUF7g4uglYSPQBwddNdO+x/EgvIoij91Qh44/XF5DbHy2hUVMLJivBaO9g0xjBEL
|
||||
ZAhFzYEZuKTvGEYzZw9T2K1WE0lSbk+z3kp6+nasOxrtrk63oAPTB71yiGi44S2r
|
||||
eqov19s6519Qpji1W8ApW063oQKBgQDd9gDFKKa6wpYVH+6KmBeaUrGUhnoujujz
|
||||
fIWX4DapGoqhpx2fTOJe8vlyPbXqfG/akzvEjd21voXHeeR9GfsOOqjtW9v89Aq3
|
||||
Pfqli6VdLcRFxT81kgL87/3m6WvmT6sq0mfIuIwiVul6bCdIBWoYOGffiGu5NCS6
|
||||
BSFi3yCSRQKBgQCLwWbRHcBHl4Tb0eUQV8qLfzF8sjeROiT/6VmHJaQ6t2T2dXlX
|
||||
e6SbZz0xNdKeltxgJP6b+ya4mu4yghBJ5JN/Y8ng0Zden+R0BGZ8DbbiNMs0fWhx
|
||||
rFhHXedohCl7Km6ulEZyMHKnRzx2cZFIKcxCdnt5SdnNE3c9fn6OnEHywQKBgQC0
|
||||
RBk4Bt3yjBqsKXTopsF0mniS8ezFZ1eWeKlfQb/i8yVoSHtsZ1rqVld1Ct12BX4q
|
||||
fK1r4vQPqR6pdTu2xqT5V3be3135QJJ7ZCDu1k2FMahYKew+K8m1d4w0P5tcP5P6
|
||||
gUu83vUg5olU3gXBHnSeGyFxkDA9CDZTxdrpm+GuKQKBgQCHPw1CBsijUwrSOEqu
|
||||
4U4DkvrchEHiix3BMv6rYrDBFYu+NbDJEEkLORjN0uIV5Iq++zwewCYq1QzIdX/a
|
||||
ZRBsajgkhzM5Cw8BtsRz0NgT0wsw2gk4NnViy/pLUzXWfwVpFsMTgNpJ/ya3/giU
|
||||
imhV/k13UHJZzwEx/cR3JiK1uQ==
|
||||
-----END PRIVATE KEY-----
|
||||
|
|
@ -498,21 +498,12 @@ mod tests {
|
|||
|
||||
use crate::Issue;
|
||||
use fabro_github::GitHubAppCredentials;
|
||||
fn test_http_client() -> reqwest::Client {
|
||||
reqwest::Client::builder().no_proxy().build().unwrap()
|
||||
}
|
||||
|
||||
fn test_rsa_key() -> String {
|
||||
use std::process::Command;
|
||||
let output = Command::new("openssl")
|
||||
.args([
|
||||
"genpkey",
|
||||
"-algorithm",
|
||||
"RSA",
|
||||
"-pkeyopt",
|
||||
"rsa_keygen_bits:2048",
|
||||
])
|
||||
.output()
|
||||
.expect("openssl should be available");
|
||||
assert!(output.status.success(), "openssl keygen failed");
|
||||
String::from_utf8(output.stdout).unwrap()
|
||||
include_str!("fixtures/github-app-test-key.pem").to_string()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
|
@ -535,7 +526,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let result = execute_github_graphql(
|
||||
&client,
|
||||
"test-token",
|
||||
|
|
@ -561,7 +552,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let err = execute_github_graphql(
|
||||
&client,
|
||||
"bad-token",
|
||||
|
|
@ -587,7 +578,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let err = execute_github_graphql(
|
||||
&client,
|
||||
"token",
|
||||
|
|
@ -616,7 +607,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
execute_github_graphql(
|
||||
&client,
|
||||
"my-token",
|
||||
|
|
@ -640,7 +631,7 @@ mod tests {
|
|||
app_id: "test-app".to_string(),
|
||||
private_key_pem: pem,
|
||||
},
|
||||
reqwest::Client::new(),
|
||||
test_http_client(),
|
||||
"owner".to_string(),
|
||||
"repo".to_string(),
|
||||
1,
|
||||
|
|
@ -768,7 +759,6 @@ mod tests {
|
|||
then.status(201).body(r#"{"token": "ghs_test"}"#);
|
||||
})
|
||||
.await;
|
||||
// Org query returns null → fall back to user
|
||||
server
|
||||
.mock_async(|when, then| {
|
||||
when.method("POST")
|
||||
|
|
@ -777,7 +767,6 @@ mod tests {
|
|||
then.status(200).body(r#"{"data": {"organization": null}}"#);
|
||||
})
|
||||
.await;
|
||||
// User query succeeds
|
||||
server
|
||||
.mock_async(|when, then| {
|
||||
when.method("POST")
|
||||
|
|
@ -787,7 +776,6 @@ mod tests {
|
|||
.body(r#"{"data": {"user": {"projectV2": {"id": "PVT_user1"}}}}"#);
|
||||
})
|
||||
.await;
|
||||
// Items page (empty)
|
||||
server
|
||||
.mock_async(|when, then| {
|
||||
when.method("POST")
|
||||
|
|
@ -894,7 +882,6 @@ mod tests {
|
|||
then.status(201).body(r#"{"token": "ghs_test"}"#);
|
||||
})
|
||||
.await;
|
||||
// Resolve project node ID (org path)
|
||||
server
|
||||
.mock_async(|when, then| {
|
||||
when.method("POST")
|
||||
|
|
@ -908,7 +895,6 @@ mod tests {
|
|||
when.method("POST").path("/graphql").body_includes("field(name:");
|
||||
then.status(200).body(r#"{"data": {"node": {"field": {"id": "FLD_1", "options": [{"id": "opt-done", "name": "Done"}, {"id": "opt-todo", "name": "Todo"}]}}}}"#);
|
||||
}).await;
|
||||
// Update mutation
|
||||
server.mock_async(|when, then| {
|
||||
when.method("POST").path("/graphql").body_includes("updateProjectV2ItemFieldValue");
|
||||
then.status(200).body(r#"{"data": {"updateProjectV2ItemFieldValue": {"projectV2Item": {"id": "PVTI_item1"}}}}"#);
|
||||
|
|
@ -937,7 +923,6 @@ mod tests {
|
|||
then.status(201).body(r#"{"token": "ghs_test"}"#);
|
||||
})
|
||||
.await;
|
||||
// Resolve project node ID
|
||||
server
|
||||
.mock_async(|when, then| {
|
||||
when.method("POST")
|
||||
|
|
|
|||
|
|
@ -355,6 +355,9 @@ impl Tracker for LinearTracker {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
fn test_http_client() -> reqwest::Client {
|
||||
reqwest::Client::builder().no_proxy().build().unwrap()
|
||||
}
|
||||
|
||||
fn mock_config(server_url: &str) -> LinearOptions {
|
||||
LinearOptions {
|
||||
|
|
@ -591,7 +594,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let result = execute_graphql(
|
||||
&client,
|
||||
&config,
|
||||
|
|
@ -617,7 +620,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let err = execute_graphql(
|
||||
&client,
|
||||
&config,
|
||||
|
|
@ -642,7 +645,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let err = execute_graphql(
|
||||
&client,
|
||||
&config,
|
||||
|
|
@ -668,7 +671,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
let err = execute_graphql(&client, &config, "query { bad }", serde_json::json!({}))
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
|
@ -691,7 +694,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let client = test_http_client();
|
||||
execute_graphql(
|
||||
&client,
|
||||
&config,
|
||||
|
|
@ -721,7 +724,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let id = tracker.fetch_viewer_id().await.unwrap();
|
||||
assert_eq!(id, "user-abc");
|
||||
}
|
||||
|
|
@ -738,7 +741,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let err = tracker.fetch_viewer_id().await.unwrap_err();
|
||||
assert!(err.contains("401"), "got: {err}");
|
||||
}
|
||||
|
|
@ -760,7 +763,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issue = make_test_issue();
|
||||
tracker.create_comment(&issue, "Hello world").await.unwrap();
|
||||
}
|
||||
|
|
@ -778,7 +781,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issue = make_test_issue();
|
||||
let err = tracker.create_comment(&issue, "Hello").await.unwrap_err();
|
||||
assert!(err.contains("success: false"), "got: {err}");
|
||||
|
|
@ -811,7 +814,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issue = make_test_issue();
|
||||
tracker.update_issue_state(&issue, "Done").await.unwrap();
|
||||
|
||||
|
|
@ -832,7 +835,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issue = make_test_issue();
|
||||
let err = tracker
|
||||
.update_issue_state(&issue, "Nonexistent")
|
||||
|
|
@ -868,7 +871,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "my-project".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "my-project".to_string());
|
||||
let issues = tracker
|
||||
.fetch_candidate_issues(&["In Progress"])
|
||||
.await
|
||||
|
|
@ -929,7 +932,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issues = tracker.fetch_candidate_issues(&["Todo"]).await.unwrap();
|
||||
|
||||
assert_eq!(issues.len(), 2);
|
||||
|
|
@ -958,7 +961,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issues = tracker.fetch_candidate_issues(&["Todo"]).await.unwrap();
|
||||
|
||||
assert!(issues.is_empty());
|
||||
|
|
@ -1000,7 +1003,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issues = tracker
|
||||
.fetch_issues_by_ids(&["id-a", "id-b"])
|
||||
.await
|
||||
|
|
@ -1060,7 +1063,7 @@ mod tests {
|
|||
})
|
||||
.await;
|
||||
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issues = tracker.fetch_issues_by_ids(&id_refs).await.unwrap();
|
||||
|
||||
assert_eq!(issues.len(), 51);
|
||||
|
|
@ -1071,7 +1074,7 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn fetch_issues_by_ids_empty() {
|
||||
let config = LinearOptions::new("unused".to_string());
|
||||
let tracker = LinearTracker::new(config, reqwest::Client::new(), "proj".to_string());
|
||||
let tracker = LinearTracker::new(config, test_http_client(), "proj".to_string());
|
||||
let issues = tracker.fetch_issues_by_ids(&[]).await.unwrap();
|
||||
assert!(issues.is_empty());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue