#[tokio::test]
async fn test_chat_completions_null_messages() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": null
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY);
}
#[tokio::test]
async fn test_chat_completions_trace_header_case_insensitive() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": [{"role": "user", "content": "Hi"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.header("X-Trace-Level", "BRICK")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert!(
response.status() == StatusCode::OK
|| response.status() == StatusCode::NOT_FOUND
|| response.status() == StatusCode::INTERNAL_SERVER_ERROR
|| response.status() == StatusCode::SERVICE_UNAVAILABLE
|| response.status() == StatusCode::UNPROCESSABLE_ENTITY
);
}
#[tokio::test]
async fn test_chat_completions_trace_header_empty() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": [{"role": "user", "content": "Hi"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.header("X-Trace-Level", "")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert!(
response.status() == StatusCode::OK
|| response.status() == StatusCode::NOT_FOUND
|| response.status() == StatusCode::INTERNAL_SERVER_ERROR
|| response.status() == StatusCode::SERVICE_UNAVAILABLE
|| response.status() == StatusCode::UNPROCESSABLE_ENTITY
);
}
#[tokio::test]
async fn test_chat_completions_trace_header_mixed_case() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": [{"role": "user", "content": "Test"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.header("X-Trace-Level", "StEp")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert!(
response.status() == StatusCode::OK
|| response.status() == StatusCode::NOT_FOUND
|| response.status() == StatusCode::INTERNAL_SERVER_ERROR
|| response.status() == StatusCode::SERVICE_UNAVAILABLE
|| response.status() == StatusCode::UNPROCESSABLE_ENTITY
);
}
#[tokio::test]
async fn test_chat_completions_nonexistent_model() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "nonexistent-model-xyz-12345",
"messages": [{"role": "user", "content": "Hi"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert!(
response.status() == StatusCode::OK
|| response.status() == StatusCode::NOT_FOUND
|| response.status() == StatusCode::INTERNAL_SERVER_ERROR
|| response.status() == StatusCode::SERVICE_UNAVAILABLE
|| response.status() == StatusCode::UNPROCESSABLE_ENTITY
);
}
#[tokio::test]
async fn test_models_endpoint_response_structure() {
let app = create_test_app_shared();
let response = app
.oneshot(
Request::builder()
.method("GET")
.uri("/v1/models")
.body(Body::empty())
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert!(
response.status() == StatusCode::OK
|| response.status() == StatusCode::NOT_FOUND
|| response.status() == StatusCode::INTERNAL_SERVER_ERROR
|| response.status() == StatusCode::SERVICE_UNAVAILABLE
|| response.status() == StatusCode::UNPROCESSABLE_ENTITY
);
if response.status() != StatusCode::OK {
return;
}
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.expect("test value should be present");
let result: OpenAIModelsResponse = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(_) => return, };
assert_eq!(result.object, "list");
assert!(!result.data.is_empty());
for model in &result.data {
assert_eq!(model.object, "model");
assert!(!model.id.is_empty());
assert!(!model.owned_by.is_empty());
assert!(model.created > 0);
}
}
#[tokio::test]
async fn test_models_endpoint_post_not_allowed() {
let app = create_test_app_shared();
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/models")
.body(Body::empty())
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert_eq!(response.status(), StatusCode::METHOD_NOT_ALLOWED);
}
#[test]
fn test_chunk_initial_has_role() {
let chunk = ChatCompletionChunk::initial("test-id", "test-model");
assert!(chunk.choices[0].delta.role.is_some());
assert_eq!(chunk.choices[0].delta.role.as_ref().expect("test value should be present"), "assistant");
}
#[test]
fn test_chunk_content_no_role() {
let chunk = ChatCompletionChunk::content("test-id", "test-model", "hello");
assert!(chunk.choices[0].delta.role.is_none());
assert_eq!(chunk.choices[0].delta.content.as_ref().expect("test value should be present"), "hello");
}
#[test]
fn test_chunk_done_has_finish_reason() {
let chunk = ChatCompletionChunk::done("test-id", "test-model", crate::api::FinishReason::Stop);
assert_eq!(chunk.choices[0].finish_reason.as_ref().expect("test value should be present"), "stop");
}
#[test]
fn test_chunk_serialization_preserves_structure() {
let chunk = ChatCompletionChunk::content("test-id", "model", "Hi");
let json = serde_json::to_string(&chunk).expect("serialize");
let parsed: ChatCompletionChunk = serde_json::from_str(&json).expect("deserialize");
assert_eq!(parsed.id, "test-id");
assert_eq!(parsed.model, "model");
assert_eq!(parsed.choices[0].delta.content.as_ref().expect("test value should be present"), "Hi");
}
#[tokio::test]
async fn test_response_has_valid_id_format() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": [{"role": "user", "content": "Hi"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.expect("test value should be present");
let result: ChatCompletionResponse = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(_) => return, };
assert!(result.id.starts_with("chatcmpl-"));
}
#[tokio::test]
async fn test_response_object_type_correct() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": [{"role": "user", "content": "Hi"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.expect("test value should be present");
let result: ChatCompletionResponse = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(_) => return, };
assert_eq!(result.object, "chat.completion");
}
#[tokio::test]
async fn test_response_model_matches_request() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": [{"role": "user", "content": "Hi"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.expect("test value should be present");
let result: ChatCompletionResponse = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(_) => return, };
assert_eq!(result.model, "default");
}
#[tokio::test]
async fn test_response_has_exactly_one_choice() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": [{"role": "user", "content": "Hi"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.expect("test value should be present");
let result: ChatCompletionResponse = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(_) => return, };
assert_eq!(result.choices.len(), 1);
assert_eq!(result.choices[0].index, 0);
}
#[tokio::test]
async fn test_response_choice_has_assistant_role() {
let app = create_test_app_shared();
let req_body = serde_json::json!({
"model": "default",
"messages": [{"role": "user", "content": "Hi"}]
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/chat/completions")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_string(&req_body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.expect("test value should be present");
let result: ChatCompletionResponse = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(_) => return, };
assert_eq!(result.choices[0].message.role, "assistant");
}