use crate::api::gpu_handlers::{BatchConfig, ContinuousBatchResponse};
use crate::api::realize_handlers::{
clean_chat_output, format_chat_messages, ContextWindowConfig, ContextWindowManager,
};
use crate::api::test_helpers::create_test_app_shared;
use crate::api::*;
use axum::body::Body;
use axum::http::{Request, StatusCode};
use tower::util::ServiceExt;
#[test]
fn test_batch_config_low_latency() {
let config = BatchConfig::low_latency();
assert!(config.max_batch > 0);
assert!(config.window_ms < 100);
assert!(config.min_batch > 0);
}
#[test]
fn test_batch_config_high_throughput() {
let config = BatchConfig::high_throughput();
assert!(config.max_batch >= 32);
assert!(config.window_ms >= 50);
assert!(config.optimal_batch >= 8);
}
#[test]
fn test_batch_config_should_process_empty() {
let config = BatchConfig::low_latency();
assert!(!config.should_process(0));
}
#[test]
fn test_batch_config_should_process_at_optimal() {
let config = BatchConfig::low_latency();
assert!(config.should_process(config.optimal_batch));
assert!(config.should_process(config.optimal_batch + 1));
}
#[test]
fn test_batch_config_should_process_below_optimal() {
let config = BatchConfig::high_throughput();
assert!(!config.should_process(config.optimal_batch - 1));
}
#[test]
fn test_batch_config_meets_minimum_edge() {
let config = BatchConfig::low_latency();
assert!(!config.meets_minimum(0));
assert!(!config.meets_minimum(config.min_batch - 1));
assert!(config.meets_minimum(config.min_batch));
assert!(config.meets_minimum(config.min_batch + 1));
}
#[test]
fn test_batch_config_debug() {
let config = BatchConfig::low_latency();
let debug = format!("{:?}", config);
assert!(debug.contains("BatchConfig"));
}
#[test]
fn test_batch_config_clone() {
let config = BatchConfig::high_throughput();
let cloned = config.clone();
assert_eq!(cloned.max_batch, config.max_batch);
assert_eq!(cloned.window_ms, config.window_ms);
assert_eq!(cloned.gpu_threshold, config.gpu_threshold);
}
#[test]
fn test_batch_config_default() {
let config = BatchConfig::default();
assert!(config.max_batch > 0);
assert!(config.queue_size > 0);
}
#[test]
fn test_batch_config_fields_low_latency() {
let config = BatchConfig::low_latency();
assert_eq!(config.window_ms, 5);
assert_eq!(config.min_batch, 2);
assert_eq!(config.max_batch, 16);
}
#[test]
fn test_batch_config_fields_high_throughput() {
let config = BatchConfig::high_throughput();
assert_eq!(config.window_ms, 100);
assert_eq!(config.min_batch, 8);
assert_eq!(config.max_batch, 128);
assert_eq!(config.gpu_threshold, 32);
}
#[test]
fn test_continuous_batch_response_single() {
let resp = ContinuousBatchResponse::single(vec![1, 2, 3], 2, 10.5);
assert_eq!(resp.generated_tokens(), &[3]); assert!((resp.latency_ms - 10.5).abs() < f64::EPSILON);
}
#[test]
fn test_continuous_batch_response_single_empty() {
let resp = ContinuousBatchResponse::single(vec![], 0, 1.0);
assert!(resp.generated_tokens().is_empty());
}
#[test]
fn test_continuous_batch_response_batched() {
let resp = ContinuousBatchResponse::batched(vec![1, 2, 3, 4, 5], 2, 2, 5.0);
assert!(!resp.generated_tokens().is_empty());
assert!(resp.batched);
}
#[test]
fn test_continuous_batch_response_batched_empty() {
let resp = ContinuousBatchResponse::batched(vec![], 0, 0, 1.0);
assert!(resp.generated_tokens().is_empty());
}
#[test]
fn test_continuous_batch_response_debug() {
let resp = ContinuousBatchResponse::single(vec![1], 0, 1.0);
let debug = format!("{:?}", resp);
assert!(debug.contains("ContinuousBatchResponse"));
}
#[test]
fn test_continuous_batch_response_clone() {
let resp = ContinuousBatchResponse::single(vec![1, 2, 3], 1, 10.0);
let cloned = resp.clone();
assert_eq!(cloned.token_ids, resp.token_ids);
assert_eq!(cloned.prompt_len, resp.prompt_len);
}
#[test]
fn test_context_window_config_new() {
let config = ContextWindowConfig::new(4096);
assert!(config.available_tokens() > 0);
}
#[test]
fn test_context_window_config_with_reserved_output() {
let config = ContextWindowConfig::new(2048).with_reserved_output(256);
assert!(config.available_tokens() <= 2048 - 256);
}
#[test]
fn test_context_window_config_available_tokens() {
let config = ContextWindowConfig::new(1024);
assert!(config.available_tokens() <= 1024);
assert!(config.available_tokens() > 0);
}
#[test]
fn test_context_window_config_small() {
let config = ContextWindowConfig::new(128).with_reserved_output(32);
assert!(config.available_tokens() <= 96);
}
fn make_msg(role: &str, content: &str) -> ChatMessage {
ChatMessage {
role: role.to_string(),
content: content.to_string(),
name: None,
..Default::default()
}
}
#[test]
fn test_context_window_manager_new() {
let config = ContextWindowConfig::new(2048);
let manager = ContextWindowManager::new(config);
assert!(!manager.needs_truncation(&[]));
}
#[test]
fn test_context_window_manager_default() {
let manager = ContextWindowManager::default_manager();
let (truncated, was_truncated) = manager.truncate_messages(&[]);
assert!(truncated.is_empty());
assert!(!was_truncated);
}
#[test]
fn test_context_window_manager_truncate_empty() {
let manager = ContextWindowManager::default_manager();
let (truncated, was_truncated) = manager.truncate_messages(&[]);
assert!(truncated.is_empty());
assert!(!was_truncated);
}
#[test]
fn test_context_window_manager_truncate_single_message() {
let manager = ContextWindowManager::default_manager();
let messages = vec![make_msg("user", "Hello, world!")];
let (truncated, was_truncated) = manager.truncate_messages(&messages);
assert_eq!(truncated.len(), 1);
assert!(!was_truncated);
}
#[test]
fn test_context_window_manager_truncate_multi_message() {
let manager = ContextWindowManager::default_manager();
let messages = vec![
make_msg("user", "First message"),
make_msg("assistant", "Response"),
make_msg("user", "Follow up"),
];
let (truncated, _was_truncated) = manager.truncate_messages(&messages);
assert!(!truncated.is_empty());
}
#[test]
fn test_context_window_manager_needs_truncation_empty() {
let manager = ContextWindowManager::default_manager();
assert!(!manager.needs_truncation(&[]));
}
#[test]
fn test_context_window_manager_needs_truncation_small() {
let manager = ContextWindowManager::default_manager();
let messages = vec![make_msg("user", "Short")];
assert!(!manager.needs_truncation(&messages));
}
#[test]
fn test_context_window_manager_estimate_tokens_empty() {
let manager = ContextWindowManager::default_manager();
let estimate = manager.estimate_total_tokens(&[]);
assert_eq!(estimate, 0);
}
#[test]
fn test_context_window_manager_estimate_tokens_single() {
let manager = ContextWindowManager::default_manager();
let messages = vec![make_msg("user", "Hello world")];
let estimate = manager.estimate_total_tokens(&messages);
assert!(estimate > 0);
}
#[test]
fn test_context_window_manager_estimate_tokens_multi() {
let manager = ContextWindowManager::default_manager();
let messages = vec![
make_msg("user", "First"),
make_msg("assistant", "Second with more content"),
];
let estimate = manager.estimate_total_tokens(&messages);
assert!(estimate >= 2);
}
#[test]
fn test_format_chat_messages_empty() {
let result = format_chat_messages(&[], None);
let _ = result; }
#[test]
fn test_format_chat_messages_single_user() {
let messages = vec![make_msg("user", "Hello")];
let result = format_chat_messages(&messages, None);
assert!(result.contains("Hello") || !result.is_empty());
}
#[test]
fn test_format_chat_messages_multi_turn() {
let messages = vec![
make_msg("user", "What is 2+2?"),
make_msg("assistant", "4"),
make_msg("user", "And 3+3?"),
];
let result = format_chat_messages(&messages, None);
assert!(!result.is_empty());
}
#[test]
fn test_format_chat_messages_system_role() {
let messages = vec![
make_msg("system", "You are helpful"),
make_msg("user", "Hi"),
];
let result = format_chat_messages(&messages, None);
assert!(!result.is_empty());
}
#[test]
fn test_format_chat_messages_with_model_name() {
let messages = vec![make_msg("user", "Test")];
let result = format_chat_messages(&messages, Some("llama"));
assert!(!result.is_empty());
}
#[test]
fn test_format_chat_messages_tinyllama() {
let messages = vec![make_msg("user", "Hello")];
let result = format_chat_messages(&messages, Some("tinyllama"));
assert!(!result.is_empty());
}
#[test]
fn test_format_chat_messages_phi() {
let messages = vec![make_msg("user", "Test prompt")];
let result = format_chat_messages(&messages, Some("phi"));
assert!(!result.is_empty());
}
#[test]
fn test_clean_chat_output_empty() {
let result = clean_chat_output("");
assert!(result.is_empty());
}
#[test]
fn test_clean_chat_output_plain() {
let result = clean_chat_output("Hello, world!");
assert_eq!(result, "Hello, world!");
}
#[test]
fn test_clean_chat_output_with_assistant_prefix() {
let result = clean_chat_output("<|assistant|>Hello");
assert!(result.contains("Hello") || !result.is_empty());
}
#[test]
fn test_clean_chat_output_with_im_end() {
let result = clean_chat_output("Response text<|im_end|>");
assert!(!result.contains("<|im_end|>") || result.contains("Response"));
}
#[test]
fn test_clean_chat_output_with_eos() {
let result = clean_chat_output("Some output<|endoftext|>");
assert!(!result.contains("<|endoftext|>") || result.contains("output"));
}
#[test]
fn test_clean_chat_output_multiple_markers() {
let result = clean_chat_output("<|assistant|>Hello<|im_end|><|endoftext|>");
assert!(result.contains("Hello") || !result.is_empty());
}
#[test]
fn test_clean_chat_output_partial_marker() {
let result = clean_chat_output("Text with partial <| marker");
assert!(!result.is_empty());
}
#[test]
fn test_clean_chat_output_nested() {
let result = clean_chat_output("<|im_start|>assistant\nHello<|im_end|>");
let _ = result;
}
#[test]
fn test_clean_chat_output_whitespace() {
let result = clean_chat_output(" \n Hello \n ");
assert!(result.contains("Hello"));
}
fn is_acceptable_status(status: StatusCode) -> bool {
status == StatusCode::OK
|| status == StatusCode::SERVICE_UNAVAILABLE
|| status == StatusCode::BAD_REQUEST
|| status == StatusCode::NOT_FOUND
|| status == StatusCode::INTERNAL_SERVER_ERROR
|| status == StatusCode::UNPROCESSABLE_ENTITY
|| status == StatusCode::METHOD_NOT_ALLOWED
}
#[tokio::test]
async fn test_realize_embed_endpoint() {
let app = create_test_app_shared();
let body = serde_json::json!({"text": "Hello world"});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/v1/embed")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_string(&body).expect("JSON serialization failed")))
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert!(is_acceptable_status(response.status()));
}
#[tokio::test]
async fn test_realize_model_endpoint() {
let app = create_test_app_shared();
let response = app
.oneshot(
Request::builder()
.uri("/v1/model")
.body(Body::empty())
.expect("test value should be present"),
)
.await
.expect("test value should be present");
assert!(is_acceptable_status(response.status()));
}
include!("realize_reload.rs");