From 3b3603efdd7f92a27dbc2525f3975302c848371a Mon Sep 17 00:00:00 2001 From: armour-bees Date: Thu, 19 Jun 2025 22:29:49 +0200 Subject: [PATCH 1/2] * remove mutable client * add test --- Cargo.toml | 4 +++ examples/chat_completion.rs | 4 --- examples/completion.rs | 2 +- examples/openrouter.rs | 1 - src/v1/api.rs | 12 +++---- tests/client_integration.rs | 63 +++++++++++++++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 tests/client_integration.rs diff --git a/Cargo.toml b/Cargo.toml index 322a356c..6c292ffa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,3 +43,7 @@ features = ["sink", "std"] [dependencies.url] version = "2.5.4" + +[dev-dependencies] +tokio = { version = "1", features = ["full"] } +wiremock = "0.6.0" \ No newline at end of file diff --git a/examples/chat_completion.rs b/examples/chat_completion.rs index 635add58..f82173b3 100644 --- a/examples/chat_completion.rs +++ b/examples/chat_completion.rs @@ -22,10 +22,6 @@ async fn main() -> Result<(), Box> { let result = client.chat_completion(req).await?; println!("Content: {:?}", result.choices[0].message.content); - // print response headers - for (key, value) in client.response_headers.unwrap().iter() { - println!("{}: {:?}", key, value); - } Ok(()) } diff --git a/examples/completion.rs b/examples/completion.rs index 95cbc231..138c1fe7 100644 --- a/examples/completion.rs +++ b/examples/completion.rs @@ -5,7 +5,7 @@ use std::env; #[tokio::main] async fn main() -> Result<(), Box> { let api_key = env::var("OPENAI_API_KEY").unwrap().to_string(); - let mut client = OpenAIClient::builder().with_api_key(api_key).build()?; + let client = OpenAIClient::builder().with_api_key(api_key).build()?; let req = CompletionRequest::new( completion::GPT3_TEXT_DAVINCI_003.to_string(), diff --git a/examples/openrouter.rs b/examples/openrouter.rs index 5295bf41..8bd5cdbc 100644 --- a/examples/openrouter.rs +++ b/examples/openrouter.rs @@ -24,7 +24,6 @@ async fn main() -> Result<(), Box> { let result = client.chat_completion(req).await?; println!("Content: {:?}", result.choices[0].message.content); - println!("Response Headers: {:?}", client.response_headers); Ok(()) } diff --git a/src/v1/api.rs b/src/v1/api.rs index 1c50695e..7470f49b 100644 --- a/src/v1/api.rs +++ b/src/v1/api.rs @@ -72,7 +72,6 @@ pub struct OpenAIClient { proxy: Option, timeout: Option, headers: Option, - pub response_headers: Option, } impl OpenAIClientBuilder { @@ -126,7 +125,6 @@ impl OpenAIClientBuilder { proxy: self.proxy, timeout: self.timeout, headers: self.headers, - response_headers: None, }) } } @@ -184,7 +182,7 @@ impl OpenAIClient { } async fn post( - &mut self, + & self, path: &str, body: &impl serde::ser::Serialize, ) -> Result { @@ -213,7 +211,7 @@ impl OpenAIClient { } async fn post_form( - &mut self, + &self, path: &str, form: Form, ) -> Result { @@ -231,16 +229,14 @@ impl OpenAIClient { } async fn handle_response( - &mut self, + &self, response: Response, ) -> Result { let status = response.status(); - let headers = response.headers().clone(); if status.is_success() { let text = response.text().await.unwrap_or_else(|_| "".to_string()); match serde_json::from_str::(&text) { Ok(parsed) => { - self.response_headers = Some(headers); Ok(parsed) } Err(e) => Err(APIError::CustomError { @@ -259,7 +255,7 @@ impl OpenAIClient { } pub async fn completion( - &mut self, + &self, req: CompletionRequest, ) -> Result { self.post("completions", &req).await diff --git a/tests/client_integration.rs b/tests/client_integration.rs new file mode 100644 index 00000000..f3dfb4ff --- /dev/null +++ b/tests/client_integration.rs @@ -0,0 +1,63 @@ +use serde_json::json; +use openai_api_rs::v1::api::OpenAIClient; +use wiremock::{ + matchers::{method, path}, + Mock, MockServer, ResponseTemplate, +}; + +#[tokio::test] +async fn test_completion_returns_expected_text() { + // Start a mock server + let mock_server = MockServer::start().await; + + Mock::given(method("POST")) + .and(path("/completions")) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "id": "cmpl-12345", + "object": "text_completion", + "created": 1633072800, + "model": "text-davinci-003", + "choices": [ + { + "text": "Bitcoin is a decentralized digital currency.", + "index": 0, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 10, + "completion_tokens": 20, + "total_tokens": 30 + } + }))) + .expect(1) + .mount(&mock_server) + .await; + + let client = OpenAIClient::builder() + .with_endpoint(mock_server.uri()) + .with_api_key("test_api_key") + .build() + .unwrap(); + + let response = client + .completion( + openai_api_rs::v1::completion::CompletionRequest::new( + openai_api_rs::v1::completion::GPT3_TEXT_DAVINCI_003.to_string(), + "What is Bitcoin?".to_string(), + ) + .max_tokens(100), + ) + .await; + + assert!(response.is_ok()); + + let result = response.unwrap(); + assert_eq!(result.id, "cmpl-12345"); + assert_eq!(result.model, "text-davinci-003"); + assert_eq!( + result.choices[0].text.trim(), + "Bitcoin is a decentralized digital currency." + ); +} From 87cf66e56b23518ead79fe2380d0c21f5f45a531 Mon Sep 17 00:00:00 2001 From: armour-bees Date: Thu, 19 Jun 2025 22:33:04 +0200 Subject: [PATCH 2/2] remove tests --- Cargo.toml | 4 --- tests/client_integration.rs | 63 ------------------------------------- 2 files changed, 67 deletions(-) delete mode 100644 tests/client_integration.rs diff --git a/Cargo.toml b/Cargo.toml index 6c292ffa..322a356c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,3 @@ features = ["sink", "std"] [dependencies.url] version = "2.5.4" - -[dev-dependencies] -tokio = { version = "1", features = ["full"] } -wiremock = "0.6.0" \ No newline at end of file diff --git a/tests/client_integration.rs b/tests/client_integration.rs deleted file mode 100644 index f3dfb4ff..00000000 --- a/tests/client_integration.rs +++ /dev/null @@ -1,63 +0,0 @@ -use serde_json::json; -use openai_api_rs::v1::api::OpenAIClient; -use wiremock::{ - matchers::{method, path}, - Mock, MockServer, ResponseTemplate, -}; - -#[tokio::test] -async fn test_completion_returns_expected_text() { - // Start a mock server - let mock_server = MockServer::start().await; - - Mock::given(method("POST")) - .and(path("/completions")) - .respond_with(ResponseTemplate::new(200).set_body_json(json!({ - "id": "cmpl-12345", - "object": "text_completion", - "created": 1633072800, - "model": "text-davinci-003", - "choices": [ - { - "text": "Bitcoin is a decentralized digital currency.", - "index": 0, - "logprobs": null, - "finish_reason": "stop" - } - ], - "usage": { - "prompt_tokens": 10, - "completion_tokens": 20, - "total_tokens": 30 - } - }))) - .expect(1) - .mount(&mock_server) - .await; - - let client = OpenAIClient::builder() - .with_endpoint(mock_server.uri()) - .with_api_key("test_api_key") - .build() - .unwrap(); - - let response = client - .completion( - openai_api_rs::v1::completion::CompletionRequest::new( - openai_api_rs::v1::completion::GPT3_TEXT_DAVINCI_003.to_string(), - "What is Bitcoin?".to_string(), - ) - .max_tokens(100), - ) - .await; - - assert!(response.is_ok()); - - let result = response.unwrap(); - assert_eq!(result.id, "cmpl-12345"); - assert_eq!(result.model, "text-davinci-003"); - assert_eq!( - result.choices[0].text.trim(), - "Bitcoin is a decentralized digital currency." - ); -}