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:
2026-04-13 17:28:33 +02:00
parent 47829b953c
commit 890f55ab8e
+110 -1
View File
@@ -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:?}");
}