Add tests for Ollama client
This commit adds several unit tests for the `generate_oneliner` function, which interacts with the Ollama API. These tests cover: - Successful parsing of a chat response. - Normalization of the response content to remove extra whitespace and quotes. - Handling of HTTP 500 errors from the server. - Verification of sent request parameters like `keep_alive` and `model`. - Parsing errors when the `content` field is missing in the response.
This commit is contained in:
@@ -3,9 +3,11 @@ use std::time::Duration;
|
||||
|
||||
use doctate_server::transcribe;
|
||||
use doctate_server::transcribe::ffmpeg::remux_faststart;
|
||||
use doctate_server::transcribe::ollama::{generate_oneliner, OllamaError};
|
||||
use doctate_server::transcribe::recovery::scan_and_enqueue;
|
||||
use doctate_server::transcribe::whisper::{transcribe, WhisperError};
|
||||
use wiremock::matchers::{method, path, query_param};
|
||||
use serde_json::json;
|
||||
use wiremock::matchers::{body_partial_json, method, path, query_param};
|
||||
use wiremock::{Mock, MockServer, ResponseTemplate};
|
||||
|
||||
fn fixture(name: &str) -> PathBuf {
|
||||
@@ -155,3 +157,110 @@ async fn recovery_enqueues_only_pending_recordings() {
|
||||
assert!(received[0].ends_with("2026-04-10T10-00-00Z.m4a"));
|
||||
assert!(received[1].ends_with("2026-04-12T10-00-00Z.m4a"));
|
||||
}
|
||||
|
||||
// -------------------- Ollama client --------------------
|
||||
|
||||
const MODEL: &str = "gemma3:4b";
|
||||
|
||||
fn ok_chat_body(content: &str) -> serde_json::Value {
|
||||
json!({
|
||||
"model": MODEL,
|
||||
"message": {"role": "assistant", "content": content},
|
||||
"done": true
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn ollama_oneliner_parses_chat_response() {
|
||||
let server = MockServer::start().await;
|
||||
|
||||
Mock::given(method("POST"))
|
||||
.and(path("/api/chat"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(ok_chat_body("HOCM mit Septum-Hypertrophie")))
|
||||
.expect(1)
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let out = generate_oneliner(&client, &server.uri(), MODEL, 0, "irrelevant", Duration::from_secs(5))
|
||||
.await
|
||||
.expect("call failed");
|
||||
|
||||
assert_eq!(out, "HOCM mit Septum-Hypertrophie");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn ollama_oneliner_normalizes_response() {
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("POST"))
|
||||
.and(path("/api/chat"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(ok_chat_body("\"Kniegelenk re., V.a. Meniskus.\"\nSonstiges")))
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let out = generate_oneliner(&client, &server.uri(), MODEL, 0, "x", Duration::from_secs(5))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(out, "Kniegelenk re., V.a. Meniskus");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn ollama_oneliner_returns_status_on_500() {
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("POST"))
|
||||
.and(path("/api/chat"))
|
||||
.respond_with(ResponseTemplate::new(500).set_body_string("boom"))
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let err = generate_oneliner(&client, &server.uri(), MODEL, 0, "x", Duration::from_secs(5))
|
||||
.await
|
||||
.expect_err("expected error");
|
||||
match err {
|
||||
OllamaError::Status { status, body } => {
|
||||
assert_eq!(status, 500);
|
||||
assert_eq!(body, "boom");
|
||||
}
|
||||
other => panic!("unexpected: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn ollama_oneliner_sends_keep_alive_and_model() {
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("POST"))
|
||||
.and(path("/api/chat"))
|
||||
.and(body_partial_json(json!({
|
||||
"model": MODEL,
|
||||
"stream": false,
|
||||
"keep_alive": 0
|
||||
})))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(ok_chat_body("OK")))
|
||||
.expect(1)
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let _ = generate_oneliner(&client, &server.uri(), MODEL, 0, "irrelevant", Duration::from_secs(5))
|
||||
.await
|
||||
.expect("call failed");
|
||||
// Mock::expect(1) + server drop verifies the matcher hit exactly once.
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn ollama_oneliner_parse_error_on_missing_content() {
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("POST"))
|
||||
.and(path("/api/chat"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(json!({"done": true})))
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let err = generate_oneliner(&client, &server.uri(), MODEL, 0, "x", Duration::from_secs(5))
|
||||
.await
|
||||
.expect_err("expected parse error");
|
||||
assert!(matches!(err, OllamaError::Parse(_)), "got {err:?}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user