use axum::{
body::Body,
http::{Request, StatusCode},
};
use tower::util::ServiceExt;
use crate::api::{create_router, AppState};
use super::native_routes_2376::{body_string, get, post};
#[cfg(feature = "gpu")]
use super::native_routes_2376::quantized_state;
#[cfg(feature = "gpu")]
fn varied_quantized_state() -> AppState {
use crate::api::test_helpers::create_test_quantized_model;
use crate::gguf::{ArchConstraints, GGUFConfig};
let config = GGUFConfig {
architecture: "llama".to_string(),
constraints: ArchConstraints::from_architecture("llama"),
hidden_dim: 64,
intermediate_dim: 128,
num_layers: 2,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 256,
context_length: 128,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
let mut model = create_test_quantized_model(&config);
for token in 0..config.vocab_size {
for i in 0..config.hidden_dim {
model.token_embedding[token * config.hidden_dim + i] =
0.1 + (token as f32) * 0.01 + (i as f32) * 0.001;
}
}
AppState::with_quantized_model(model).expect("build varied quantized AppState")
}
fn embeddings_from(body: &str) -> Vec<Vec<f32>> {
let parsed: serde_json::Value = serde_json::from_str(body).expect("json embedding body");
parsed["data"]
.as_array()
.expect("data array")
.iter()
.map(|d| {
d["embedding"]
.as_array()
.expect("embedding array")
.iter()
.map(|v| v.as_f64().expect("float") as f32)
.collect()
})
.collect()
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_realize_embed_answers_on_quantized_server() {
let (status, body) = post(
quantized_state(),
"/realize/embed",
r#"{"input":["token5 token6"]}"#,
)
.await;
assert_eq!(
status,
StatusCode::OK,
"a quantized model can produce hidden states; body: {body}"
);
assert!(
!body.contains("No model available"),
"the quantized backend IS a model, body: {body}"
);
let vectors = embeddings_from(&body);
assert_eq!(vectors.len(), 1, "one input, one embedding");
assert_eq!(
vectors[0].len(),
64,
"embedding width must be the model hidden_dim"
);
let norm: f32 = vectors[0].iter().map(|x| x * x).sum::<f32>().sqrt();
assert!(
(norm - 1.0).abs() < 1e-3,
"embeddings are L2-normalized, got norm {norm}"
);
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_quantized_embeddings_vary_with_input_and_repeat_exactly() {
let (_, a1) = post(
varied_quantized_state(),
"/realize/embed",
r#"{"input":["token5"]}"#,
)
.await;
let (_, a2) = post(
varied_quantized_state(),
"/realize/embed",
r#"{"input":["token5"]}"#,
)
.await;
let (_, b) = post(
varied_quantized_state(),
"/realize/embed",
r#"{"input":["token9 token9 token9"]}"#,
)
.await;
let v_a1 = embeddings_from(&a1).remove(0);
let v_a2 = embeddings_from(&a2).remove(0);
let v_b = embeddings_from(&b).remove(0);
assert_eq!(v_a1, v_a2, "the same text must embed identically");
assert_ne!(
v_a1, v_b,
"different text must embed differently — a constant vector is not an embedding"
);
assert!(
v_a1.iter().any(|x| x.abs() > 1e-6),
"an all-zero vector is not a model-backed embedding"
);
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_quantized_embed_batch_is_per_input_and_ordered() {
let (status, body) = post(
varied_quantized_state(),
"/realize/embed",
r#"{"input":["token5","token9 token9 token9"]}"#,
)
.await;
assert_eq!(status, StatusCode::OK, "body: {body}");
let vectors = embeddings_from(&body);
assert_eq!(vectors.len(), 2, "two inputs, two embeddings");
assert_ne!(vectors[0], vectors[1], "each input gets its own vector");
let (_, single) = post(
varied_quantized_state(),
"/realize/embed",
r#"{"input":["token5"]}"#,
)
.await;
assert_eq!(
vectors[0],
embeddings_from(&single).remove(0),
"batching must not change an input's embedding"
);
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_v1_embeddings_matches_realize_embed_on_quantized_server() {
let (native_status, native) = post(
quantized_state(),
"/realize/embed",
r#"{"input":["token5"]}"#,
)
.await;
let (openai_status, openai) =
post(quantized_state(), "/v1/embeddings", r#"{"input":["token5"]}"#).await;
assert_eq!(native_status, StatusCode::OK, "body: {native}");
assert_eq!(openai_status, StatusCode::OK, "body: {openai}");
assert_eq!(
embeddings_from(&native),
embeddings_from(&openai),
"two routes over one model must not disagree about the same text"
);
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_api_embeddings_is_mounted_and_ollama_shaped() {
let (status, body) = post(
quantized_state(),
"/api/embeddings",
r#"{"model":"default","prompt":"token5"}"#,
)
.await;
assert_eq!(status, StatusCode::OK, "body: {body}");
assert!(
!body.contains("not_found"),
"the route must exist; got the 404 fallback: {body}"
);
let parsed: serde_json::Value = serde_json::from_str(&body).expect("json body");
let vector: Vec<f32> = parsed["embedding"]
.as_array()
.expect("flat `embedding` array — Ollama's shape")
.iter()
.map(|v| v.as_f64().expect("float") as f32)
.collect();
assert_eq!(vector.len(), 64, "width must be the model hidden_dim");
let (_, native) = post(quantized_state(), "/realize/embed", r#"{"input":["token5"]}"#).await;
assert_eq!(
vector,
embeddings_from(&native).remove(0),
"all three embedding routes must agree"
);
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_embed_rejects_empty_input_with_400() {
let (status, body) = post(quantized_state(), "/realize/embed", r#"{"input":[""]}"#).await;
assert_eq!(status, StatusCode::BAD_REQUEST, "body: {body}");
}
#[tokio::test]
async fn test_embed_without_any_model_is_503() {
let (status, body) = post(
AppState::demo_mock().expect("mock state"),
"/realize/embed",
r#"{"input":["hello"]}"#,
)
.await;
assert_eq!(
status,
StatusCode::SERVICE_UNAVAILABLE,
"no model at all is a server condition, body: {body}"
);
}
async fn probe(
state: AppState,
method: &str,
uri: &str,
content_type: Option<&str>,
body: &str,
) -> (StatusCode, String, String) {
let mut builder = Request::builder().method(method).uri(uri);
if let Some(ct) = content_type {
builder = builder.header("content-type", ct);
}
let response = create_router(state)
.oneshot(builder.body(Body::from(body.to_string())).expect("request"))
.await
.expect("dispatch");
let status = response.status();
let ct = response
.headers()
.get("content-type")
.map(|v| v.to_str().unwrap_or_default().to_string())
.unwrap_or_default();
(status, ct, body_string(response).await)
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_malformed_json_is_a_sanitized_json_envelope() {
let (status, content_type, body) = probe(
quantized_state(),
"POST",
"/generate",
Some("application/json"),
"{not json",
)
.await;
assert_eq!(status, StatusCode::BAD_REQUEST, "body: {body}");
assert!(
content_type.starts_with("application/json"),
"every error must be machine-parseable, got content-type {content_type:?}"
);
let parsed: serde_json::Value = serde_json::from_str(&body).expect("json error body");
assert!(
parsed["error"].is_string(),
"the envelope is {{\"error\": \"...\"}}, got: {body}"
);
assert!(
!body.contains("line 1 column") && !body.contains("Failed to parse the request body"),
"the parser's internals must not reach a client: {body}"
);
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_missing_content_type_is_a_json_envelope() {
let (status, content_type, body) = probe(
quantized_state(),
"POST",
"/generate",
None,
r#"{"prompt":"token5","max_tokens":2}"#,
)
.await;
assert_eq!(status, StatusCode::UNSUPPORTED_MEDIA_TYPE, "body: {body}");
assert!(
content_type.starts_with("application/json"),
"got content-type {content_type:?}, body: {body}"
);
let parsed: serde_json::Value = serde_json::from_str(&body).expect("json error body");
assert!(parsed["error"].is_string(), "body: {body}");
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_schema_mismatch_stays_sanitized_422() {
let (status, content_type, body) = probe(
quantized_state(),
"POST",
"/generate",
Some("application/json"),
r#"{"prompt":123}"#,
)
.await;
assert_eq!(status, StatusCode::UNPROCESSABLE_ENTITY, "body: {body}");
assert!(
content_type.starts_with("application/json"),
"content-type {content_type:?}"
);
assert!(body.contains("Invalid request body"), "body: {body}");
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_405_keeps_its_allow_header_and_gains_a_json_body() {
let response = create_router(quantized_state())
.oneshot(
Request::builder()
.method("GET")
.uri("/generate")
.body(Body::empty())
.expect("request"),
)
.await
.expect("dispatch");
assert_eq!(response.status(), StatusCode::METHOD_NOT_ALLOWED);
let allow = response
.headers()
.get("allow")
.map(|v| v.to_str().unwrap_or_default().to_string())
.unwrap_or_default();
assert!(
allow.contains("POST"),
"the allow header must survive the envelope, got {allow:?}"
);
let body = body_string(response).await;
let parsed: serde_json::Value = serde_json::from_str(&body).expect("json error body");
assert!(parsed["error"].is_string(), "body: {body}");
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_handler_json_errors_pass_through_unchanged() {
let (status, content_type, body) = probe(
quantized_state(),
"POST",
"/generate",
Some("application/json"),
r#"{"prompt":""}"#,
)
.await;
assert_eq!(status, StatusCode::BAD_REQUEST, "body: {body}");
assert!(
content_type.starts_with("application/json"),
"content-type {content_type:?}"
);
assert!(
body.contains("Prompt cannot be empty"),
"the handler's own message must survive: {body}"
);
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_success_bodies_are_not_rewritten() {
let (status, body) = post(quantized_state(), "/generate", r#"{"prompt":"token5"}"#).await;
assert_eq!(status, StatusCode::OK, "body: {body}");
assert!(body.contains("token_ids"), "body: {body}");
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_v1_predict_error_names_no_internal_rust_api() {
let (status, body) = post(quantized_state(), "/v1/predict", r#"{"features":[1.0,2.0]}"#).await;
assert_eq!(status, StatusCode::SERVICE_UNAVAILABLE, "body: {body}");
assert!(
!body.contains("AppState::demo"),
"an HTTP client cannot call a Rust constructor: {body}"
);
assert!(
body.contains("/v1/predict") && body.contains(".apr"),
"the message must say what the OPERATOR needs to do instead: {body}"
);
}
#[tokio::test]
#[cfg(feature = "gpu")]
async fn test_root_and_ready_are_mounted() {
let (status, body) = get(quantized_state(), "/").await;
assert_eq!(status, StatusCode::OK, "body: {body}");
let parsed: serde_json::Value = serde_json::from_str(&body).expect("json index");
let routes = parsed["routes"].as_array().expect("routes array");
assert!(
routes.iter().any(|r| r == "POST /generate"),
"the index must list what is mounted: {body}"
);
assert!(
routes.iter().any(|r| r == "POST /api/embeddings"),
"the index must list the newly mounted Ollama embedding route: {body}"
);
let (ready_status, ready_body) = get(quantized_state(), "/ready").await;
assert_ne!(
ready_status,
StatusCode::NOT_FOUND,
"/ready is the conventional readiness path, body: {ready_body}"
);
}
#[tokio::test]
async fn test_registry_unknown_model_id_is_404_not_a_silent_substitution() {
use crate::layers::{Model, ModelConfig};
use crate::registry::ModelRegistry;
use crate::tokenizer::BPETokenizer;
let config = ModelConfig {
vocab_size: 100,
hidden_dim: 32,
num_heads: 1,
num_layers: 1,
intermediate_dim: 64,
eps: 1e-5,
};
let vocab: Vec<String> = (0..100)
.map(|i| {
if i == 0 {
"<unk>".to_string()
} else {
format!("t{i}")
}
})
.collect();
let registry = ModelRegistry::new(10);
registry
.register(
"known",
Model::new(config).expect("model"),
BPETokenizer::new(vocab, vec![], "<unk>").expect("tokenizer"),
)
.expect("register");
let state = AppState::with_registry(registry, "known").expect("registry state");
let (known_status, known_body) = post(
state.clone(),
"/realize/embed",
r#"{"input":["t1 t2"],"model":"known"}"#,
)
.await;
assert_eq!(known_status, StatusCode::OK, "body: {known_body}");
let (unknown_status, unknown_body) = post(
state,
"/realize/embed",
r#"{"input":["t1 t2"],"model":"nope"}"#,
)
.await;
assert_eq!(
unknown_status,
StatusCode::NOT_FOUND,
"an unknown model id must not be answered by another model, body: {unknown_body}"
);
}