From 8a2d00591b45472bf782091c809242da81d749ea Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 4 Apr 2026 21:25:51 -0400 Subject: [PATCH] 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. --- lib/crates/fabro-hooks/src/executor.rs | 19 +++++++-- lib/crates/fabro-llm/src/cli.rs | 20 ++++++---- .../fabro-llm/src/providers/anthropic.rs | 1 - .../fabro-llm/src/providers/fabro_server.rs | 16 +++++--- .../fabro-llm/src/providers/http_api.rs | 28 +++++++++---- lib/crates/fabro-llm/src/providers/openai.rs | 1 - lib/crates/fabro-oauth/src/lib.rs | 40 ++++++++++--------- .../fabro-server/src/github_webhooks.rs | 6 ++- .../src/fixtures/github-app-test-key.pem | 28 +++++++++++++ lib/crates/fabro-tracker/src/github.rs | 33 +++++---------- lib/crates/fabro-tracker/src/linear.rs | 37 +++++++++-------- 11 files changed, 141 insertions(+), 88 deletions(-) create mode 100644 lib/crates/fabro-tracker/src/fixtures/github-app-test-key.pem diff --git a/lib/crates/fabro-hooks/src/executor.rs b/lib/crates/fabro-hooks/src/executor.rs index de73cf7a9..3034faf55 100644 --- a/lib/crates/fabro-hooks/src/executor.rs +++ b/lib/crates/fabro-hooks/src/executor.rs @@ -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. diff --git a/lib/crates/fabro-llm/src/cli.rs b/lib/crates/fabro-llm/src/cli.rs index c141a8968..44a5449f6 100644 --- a/lib/crates/fabro-llm/src/cli.rs +++ b/lib/crates/fabro-llm/src/cli.rs @@ -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(""), }; diff --git a/lib/crates/fabro-llm/src/providers/anthropic.rs b/lib/crates/fabro-llm/src/providers/anthropic.rs index e541a9b5a..6b553e501 100644 --- a/lib/crates/fabro-llm/src/providers/anthropic.rs +++ b/lib/crates/fabro-llm/src/providers/anthropic.rs @@ -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); diff --git a/lib/crates/fabro-llm/src/providers/fabro_server.rs b/lib/crates/fabro-llm/src/providers/fabro_server.rs index da26c8a2e..e16008a40 100644 --- a/lib/crates/fabro-llm/src/providers/fabro_server.rs +++ b/lib/crates/fabro-llm/src/providers/fabro_server.rs @@ -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"); } } diff --git a/lib/crates/fabro-llm/src/providers/http_api.rs b/lib/crates/fabro-llm/src/providers/http_api.rs index 5f55d2407..d63bde0a5 100644 --- a/lib/crates/fabro-llm/src/providers/http_api.rs +++ b/lib/crates/fabro-llm/src/providers/http_api.rs @@ -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, base_url: impl Into) -> 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 diff --git a/lib/crates/fabro-llm/src/providers/openai.rs b/lib/crates/fabro-llm/src/providers/openai.rs index 13473cad8..60509b076 100644 --- a/lib/crates/fabro-llm/src/providers/openai.rs +++ b/lib/crates/fabro-llm/src/providers/openai.rs @@ -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 { diff --git a/lib/crates/fabro-oauth/src/lib.rs b/lib/crates/fabro-oauth/src/lib.rs index 705bc8a8a..255858ee8 100644 --- a/lib/crates/fabro-oauth/src/lib.rs +++ b/lib/crates/fabro-oauth/src/lib.rs @@ -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>), 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 diff --git a/lib/crates/fabro-server/src/github_webhooks.rs b/lib/crates/fabro-server/src/github_webhooks.rs index 667b649bd..8ead7a605 100644 --- a/lib/crates/fabro-server/src/github_webhooks.rs +++ b/lib/crates/fabro-server/src/github_webhooks.rs @@ -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) diff --git a/lib/crates/fabro-tracker/src/fixtures/github-app-test-key.pem b/lib/crates/fabro-tracker/src/fixtures/github-app-test-key.pem new file mode 100644 index 000000000..67e9b98c3 --- /dev/null +++ b/lib/crates/fabro-tracker/src/fixtures/github-app-test-key.pem @@ -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----- diff --git a/lib/crates/fabro-tracker/src/github.rs b/lib/crates/fabro-tracker/src/github.rs index 76e9a78e6..1ccaa9df1 100644 --- a/lib/crates/fabro-tracker/src/github.rs +++ b/lib/crates/fabro-tracker/src/github.rs @@ -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") diff --git a/lib/crates/fabro-tracker/src/linear.rs b/lib/crates/fabro-tracker/src/linear.rs index 12f22a877..77115dcaa 100644 --- a/lib/crates/fabro-tracker/src/linear.rs +++ b/lib/crates/fabro-tracker/src/linear.rs @@ -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()); }