use axum::{
body::Body,
http::{Request, StatusCode},
};
use tower::util::ServiceExt;
use crate::api::test_helpers::create_test_app_shared;
use crate::api::{
build_trace_data, format_chat_messages, ChatChoice, ChatChunkChoice, ChatCompletionChunk,
ChatCompletionRequest, ChatCompletionResponse, ChatDelta, ChatMessage, ErrorResponse,
OpenAIModel, OpenAIModelsResponse, TraceData, TraceOperation, TraceProvenance, Usage,
};
#[test]
fn test_error_response_json_structure() {
let err = ErrorResponse {
error: "Test error message".to_string(),
};
let json = serde_json::to_string(&err).expect("serialize");
assert!(json.contains("error"));
assert!(json.contains("Test error message"));
let parsed: ErrorResponse = serde_json::from_str(&json).expect("deserialize");
assert_eq!(parsed.error, "Test error message");
}
#[test]
fn test_error_response_with_special_chars() {
let err = ErrorResponse {
error: "Error: \"quoted\" and 'apostrophe' <tag>".to_string(),
};
let json = serde_json::to_string(&err).expect("serialize");
assert!(json.contains("Error:"));
let parsed: ErrorResponse = serde_json::from_str(&json).expect("deserialize");
assert!(parsed.error.contains("quoted"));
}
#[test]
fn test_error_response_unicode() {
let err = ErrorResponse {
error: "エラー: 无法处理请求 🚫".to_string(),
};
let json = serde_json::to_string(&err).expect("serialize");
let parsed: ErrorResponse = serde_json::from_str(&json).expect("deserialize");
assert!(parsed.error.contains("エラー"));
}
#[tokio::test]
async fn test_openai_models_handler_demo_mode() {
let app = create_test_app_shared();
let response = app
.oneshot(
Request::builder()
.uri("/v1/models")
.body(Body::empty())
.expect("test"),
)
.await
.expect("test");
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");
let models: OpenAIModelsResponse = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(_) => return, };
assert_eq!(models.object, "list");
assert!(!models.data.is_empty());
assert_eq!(models.data[0].object, "model");
assert_eq!(models.data[0].owned_by, "realizar");
}
#[tokio::test]
async fn test_openai_models_response_format() {
let response = OpenAIModelsResponse {
object: "list".to_string(),
data: vec![OpenAIModel {
id: "test-model".to_string(),
object: "model".to_string(),
created: 1234567890,
owned_by: "test-owner".to_string(),
}],
};
let json = serde_json::to_string(&response).expect("serialize");
assert!(json.contains("test-model"));
assert!(json.contains("1234567890"));
assert!(json.contains("test-owner"));
}
#[test]
fn test_chat_completion_request_minimal() {
let request = ChatCompletionRequest {
model: "test".to_string(),
messages: vec![ChatMessage {
role: "user".to_string(),
content: "Hello".to_string(),
name: None,
..Default::default()
}],
max_tokens: None,
temperature: None,
top_p: None,
top_k: None,
repeat_penalty: None,
repeat_last_n: None,
seed: None,
n: crate::api::ChoiceCount::ONE,
stream: false,
stop: None,
user: None,
..Default::default()
};
let json = serde_json::to_string(&request).expect("serialize");
assert!(json.contains("test"));
assert!(json.contains("user"));
assert!(json.contains("Hello"));
}
#[test]
fn test_chat_completion_request_full() {
let request = ChatCompletionRequest {
model: "qwen2.5-coder".to_string(),
messages: vec![
ChatMessage {
role: "system".to_string(),
content: "You are a helpful assistant.".to_string(),
name: None,
..Default::default()
},
ChatMessage {
role: "user".to_string(),
content: "What is 2+2?".to_string(),
name: Some("Alice".to_string()),
..Default::default()
},
],
max_tokens: Some(256),
temperature: Some(0.7),
top_p: Some(0.9),
top_k: None,
repeat_penalty: None,
repeat_last_n: None,
seed: None,
n: crate::api::ChoiceCount::ONE,
stream: true,
stop: Some(vec!["stop".to_string()]),
user: Some("test-user".to_string()),
..Default::default()
};
let json = serde_json::to_string(&request).expect("serialize");
assert!(json.contains("qwen2.5-coder"));
assert!(json.contains("system"));
assert!(json.contains("256"));
assert!(json.contains("0.7"));
}
#[test]
fn test_chat_completion_request_deserialization() {
let json = r#"{
"model": "test",
"messages": [{"role": "user", "content": "Hi"}]
}"#;
let request: ChatCompletionRequest = serde_json::from_str(json).expect("deserialize");
assert_eq!(request.model, "test");
assert_eq!(request.messages.len(), 1);
assert_eq!(request.max_tokens, None);
assert!(!request.stream);
}
#[test]
fn test_chat_message_roles() {
for role in &["user", "assistant", "system", "function"] {
let msg = ChatMessage {
role: (*role).to_string(),
content: "test".to_string(),
name: None,
..Default::default()
};
let json = serde_json::to_string(&msg).expect("serialize");
assert!(json.contains(role));
}
}
#[test]
fn test_chat_message_with_name() {
let msg = ChatMessage {
role: "function".to_string(),
content: "result".to_string(),
name: Some("get_weather".to_string()),
..Default::default()
};
let json = serde_json::to_string(&msg).expect("serialize");
assert!(json.contains("get_weather"));
}
#[test]
fn test_chat_message_empty_content() {
let msg = ChatMessage {
role: "user".to_string(),
content: String::new(),
name: None,
..Default::default()
};
let json = serde_json::to_string(&msg).expect("serialize");
let parsed: ChatMessage = serde_json::from_str(&json).expect("deserialize");
assert!(parsed.content.is_empty());
}
#[test]
fn test_chat_completion_response_structure() {
let response = ChatCompletionResponse {
id: "chatcmpl-123".to_string(),
object: "chat.completion".to_string(),
created: 1234567890,
model: "test-model".to_string(),
choices: vec![ChatChoice {
index: 0,
message: ChatMessage {
role: "assistant".to_string(),
content: "Hello!".to_string(),
name: None,
..Default::default()
},
finish_reason: "stop".to_string(),
}],
usage: Usage {
prompt_tokens: 10,
completion_tokens: 5,
total_tokens: 15,
},
brick_trace: None,
step_trace: None,
layer_trace: None,
};
let json = serde_json::to_string(&response).expect("serialize");
assert!(json.contains("chatcmpl-123"));
assert!(json.contains("chat.completion"));
assert!(json.contains("Hello!"));
assert!(json.contains("15")); }
#[test]
fn test_chat_completion_response_with_traces() {
let trace = TraceData {
level: "brick".to_string(),
operations: 5,
total_time_us: 1000,
breakdown: vec![TraceOperation {
name: "embedding".to_string(),
time_us: 100,
details: Some("5 tokens".to_string()),
}],
provenance: TraceProvenance::Estimated,
};
let response = ChatCompletionResponse {
id: "test".to_string(),
object: "chat.completion".to_string(),
created: 0,
model: "test".to_string(),
choices: vec![],
usage: Usage {
prompt_tokens: 0,
completion_tokens: 0,
total_tokens: 0,
},
brick_trace: Some(trace.clone()),
step_trace: Some(trace.clone()),
layer_trace: Some(trace),
};
let json = serde_json::to_string(&response).expect("serialize");
assert!(json.contains("brick"));
assert!(json.contains("embedding"));
assert!(json.contains("1000"));
}
#[test]
fn test_chat_completion_chunk_initial() {
let chunk = ChatCompletionChunk::initial("chatcmpl-123", "test-model");
assert_eq!(chunk.id, "chatcmpl-123");
assert_eq!(chunk.object, "chat.completion.chunk");
assert_eq!(chunk.model, "test-model");
assert_eq!(chunk.choices.len(), 1);
assert_eq!(chunk.choices[0].delta.role, Some("assistant".to_string()));
assert_eq!(chunk.choices[0].delta.content, None);
}
#[test]
fn test_chat_completion_chunk_content() {
let chunk = ChatCompletionChunk::content("chatcmpl-123", "test-model", "Hello");
assert_eq!(chunk.choices.len(), 1);
assert_eq!(chunk.choices[0].delta.role, None);
assert_eq!(chunk.choices[0].delta.content, Some("Hello".to_string()));
assert_eq!(chunk.choices[0].finish_reason, None);
}
#[test]
fn test_chat_completion_chunk_done() {
let chunk = ChatCompletionChunk::done("chatcmpl-123", "test-model", crate::api::FinishReason::Stop);
assert_eq!(chunk.choices.len(), 1);
assert_eq!(chunk.choices[0].delta.role, None);
assert_eq!(chunk.choices[0].delta.content, None);
assert_eq!(chunk.choices[0].finish_reason, Some("stop".to_string()));
}
#[test]
fn test_chat_completion_chunk_serialization() {
let chunk = ChatCompletionChunk::content("id", "model", "test");
let json = serde_json::to_string(&chunk).expect("serialize");
assert!(json.contains("chat.completion.chunk"));
assert!(json.contains("delta"));
assert!(json.contains("test"));
}
#[test]
fn test_usage_structure() {
let usage = Usage {
prompt_tokens: 100,
completion_tokens: 50,
total_tokens: 150,
};
let json = serde_json::to_string(&usage).expect("serialize");
assert!(json.contains("100"));
assert!(json.contains("50"));
assert!(json.contains("150"));
}
#[test]
fn test_usage_zero_tokens() {
let usage = Usage {
prompt_tokens: 0,
completion_tokens: 0,
total_tokens: 0,
};
let json = serde_json::to_string(&usage).expect("serialize");
let parsed: Usage = serde_json::from_str(&json).expect("deserialize");
assert_eq!(parsed.total_tokens, 0);
}
#[test]
fn test_chat_choice_structure() {
let choice = ChatChoice {
index: 0,
message: ChatMessage {
role: "assistant".to_string(),
content: "Test response".to_string(),
name: None,
..Default::default()
},
finish_reason: "stop".to_string(),
};
let json = serde_json::to_string(&choice).expect("serialize");
assert!(json.contains("index"));
assert!(json.contains("message"));
assert!(json.contains("finish_reason"));
}
#[test]
fn test_chat_choice_length_finish_reason() {
let choice = ChatChoice {
index: 0,
message: ChatMessage {
role: "assistant".to_string(),
content: "...".to_string(),
name: None,
..Default::default()
},
finish_reason: "length".to_string(),
};
let json = serde_json::to_string(&choice).expect("serialize");
assert!(json.contains("length"));
}
include!("format_chat.rs");