aprender-serve 0.64.0

Pure Rust ML inference engine built from scratch - model serving for GGUF and safetensors

#[tokio::test]
async fn test_deep_apicov_generate_with_model_id() {
    let app = create_test_app_shared();
    let json = r#"{"prompt":"token1","max_tokens":2,"model_id":"custom"}"#;

    let response = app
        .oneshot(
            Request::builder()
                .method("POST")
                .uri("/generate")
                .header("content-type", "application/json")
                .body(Body::from(json))
                .expect("test"),
        )
        .await
        .expect("test");

    // Will fail because custom model doesn't exist, but exercises the path
    let status = response.status();
    // aprender#2376(5): the shared test state has NO model, so this condition is
    // deterministic — a server with no usable model answers 503 on every route.
    // The old assertion accepted a SET of statuses that included the defect, so it
    // could not fail and held the 404-here/500-there split in place.
    assert_eq!(
        status,
        StatusCode::SERVICE_UNAVAILABLE,
        "no model is resident: expected 503"
    );
}

#[tokio::test]
async fn test_deep_apicov_batch_tokenize_multiple_texts() {
    let app = create_test_app_shared();
    let json = r#"{"texts":["hello","world","test","input","more"]}"#;

    let response = app
        .oneshot(
            Request::builder()
                .method("POST")
                .uri("/batch/tokenize")
                .header("content-type", "application/json")
                .body(Body::from(json))
                .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
    );
    let body = axum::body::to_bytes(response.into_body(), usize::MAX)
        .await
        .expect("test");
    let result: BatchTokenizeResponse = match serde_json::from_slice(&body) {
        Ok(v) => v,
        Err(_) => return, // Mock state: error response, skip body assertions
    };
    assert_eq!(result.results.len(), 5);
}

#[test]
fn test_deep_apicov_dispatch_metrics_response_serialize() {
    let resp = DispatchMetricsResponse {
        cpu_dispatches: 100,
        gpu_dispatches: 50,
        total_dispatches: 150,
        gpu_ratio: 0.333,
        cpu_latency_p50_us: 50.0,
        cpu_latency_p95_us: 200.0,
        cpu_latency_p99_us: 500.0,
        gpu_latency_p50_us: 100.0,
        gpu_latency_p95_us: 400.0,
        gpu_latency_p99_us: 800.0,
        cpu_latency_mean_us: 75.5,
        gpu_latency_mean_us: 150.3,
        cpu_latency_min_us: 10,
        cpu_latency_max_us: 1000,
        gpu_latency_min_us: 20,
        gpu_latency_max_us: 2000,
        cpu_latency_variance_us: 1250.0,
        cpu_latency_stddev_us: 35.4,
        gpu_latency_variance_us: 2500.0,
        gpu_latency_stddev_us: 50.0,
        bucket_boundaries_us: vec!["0-100".to_string()],
        cpu_latency_bucket_counts: vec![10, 20, 30],
        gpu_latency_bucket_counts: vec![5, 15, 30],
        throughput_rps: 1000.0,
        elapsed_seconds: 60.0,
    };
    let json = serde_json::to_string(&resp).expect("serialize");
    assert!(json.contains("cpu_dispatches"));
    assert!(json.contains("throughput_rps"));
}

#[tokio::test]
async fn test_deep_apicov_dispatch_metrics_no_gpu_503() {
    let app = create_test_app_shared();

    let response = app
        .oneshot(
            Request::builder()
                .uri("/metrics/dispatch")
                .body(Body::empty())
                .expect("test"),
        )
        .await
        .expect("test");

    // Demo app has no dispatch metrics, should return 503
    assert!(
        response.status() == StatusCode::SERVICE_UNAVAILABLE
            || response.status() == StatusCode::NOT_FOUND
    );
}

#[tokio::test]
async fn test_deep_apicov_dispatch_reset_no_gpu() {
    let app = create_test_app_shared();

    let response = app
        .oneshot(
            Request::builder()
                .method("POST")
                .uri("/metrics/dispatch/reset")
                .body(Body::empty())
                .expect("test"),
        )
        .await
        .expect("test");

    // Should handle gracefully when no GPU model
    let status = response.status();
    assert!(
        status == StatusCode::OK || status == StatusCode::SERVICE_UNAVAILABLE,
        "Got status: {}",
        status
    );
}

#[test]
fn test_deep_apicov_app_state_with_cache() {
    let state = AppState::with_cache(10);
    assert!(state.model.is_some());
    assert!(state.tokenizer.is_some());
    assert!(state.cache.is_some());
}

#[test]
fn test_deep_apicov_app_state_with_registry_error() {
    let registry = ModelRegistry::new(10);
    // Default model doesn't exist in empty registry
    let result = AppState::with_registry(registry, "nonexistent");
    assert!(result.is_err());
}

#[test]
fn test_deep_apicov_format_chat_messages_vicuna() {
    let messages = vec![ChatMessage {
        role: "user".to_string(),
        content: "Test".to_string(),
        name: None,
    
        ..Default::default()
    }];
    let result = format_chat_messages(&messages, Some("vicuna-7b"));
    assert!(result.contains("USER:") || result.contains("Test"));
}

#[test]
fn test_deep_apicov_format_chat_messages_gemma() {
    let messages = vec![ChatMessage {
        role: "user".to_string(),
        content: "Hello".to_string(),
        name: None,
    
        ..Default::default()
    }];
    let result = format_chat_messages(&messages, Some("gemma-2b"));
    assert!(result.contains("Hello"));
}

#[test]
fn test_deep_apicov_format_chat_messages_multi_turn() {
    let messages = vec![
        ChatMessage {
            role: "system".to_string(),
            content: "You are helpful.".to_string(),
            name: None,
        
            ..Default::default()
        },
        ChatMessage {
            role: "user".to_string(),
            content: "Hi".to_string(),
            name: None,
        
            ..Default::default()
        },
        ChatMessage {
            role: "assistant".to_string(),
            content: "Hello!".to_string(),
            name: None,
        
            ..Default::default()
        },
        ChatMessage {
            role: "user".to_string(),
            content: "How are you?".to_string(),
            name: None,
        
            ..Default::default()
        },
    ];
    let result = format_chat_messages(&messages, Some("TinyLlama-1.1B"));
    assert!(result.contains("Hi"));
    assert!(result.contains("Hello!"));
    assert!(result.contains("How are you?"));
}

#[test]
fn test_deep_apicov_context_window_large_system_message() {
    // Available = 200 - 50 = 150 tokens
    // Token estimate = len/4 + 10 overhead
    // Need total > 150 to trigger truncation
    let config = ContextWindowConfig::new(200).with_reserved_output(50);
    let manager = ContextWindowManager::new(config);

    let messages = vec![
        ChatMessage {
            role: "system".to_string(),
            content: "x".repeat(800), // 800/4 + 10 = 210 tokens > 150 available
            name: None,
        
            ..Default::default()
        },
        ChatMessage {
            role: "user".to_string(),
            content: "Hi".to_string(), // 11 tokens
            name: None,
        
            ..Default::default()
        },
    ];

    let (result, truncated) = manager.truncate_messages(&messages);
    assert!(truncated);
    // User message should still be included (most recent messages prioritized)
    assert!(result.iter().any(|m| m.content == "Hi"));
}

#[test]
fn test_deep_apicov_health_response_structure() {
    let resp = HealthResponse {
        status: "ok".to_string(),
        version: "0.1.0".to_string(),
        compute_mode: "cpu".to_string(),
        model_loaded: true,
        uptime_sec: 3.14,
    };
    let json = serde_json::to_string(&resp).expect("serialize");
    assert!(json.contains("\"ok\""));
    assert!(json.contains("0.1.0"));
    assert!(json.contains("cpu"));
    assert!(json.contains("model_loaded"));
    assert!(json.contains("uptime_sec"));
}

#[test]
fn test_deep_apicov_tokenize_response_structure() {
    let resp = TokenizeResponse {
        token_ids: vec![1, 2, 3, 4, 5],
        num_tokens: 5,
    };
    let json = serde_json::to_string(&resp).expect("serialize");
    assert!(json.contains("token_ids"));
    assert!(json.contains("num_tokens"));
}

#[test]
fn test_deep_apicov_generate_response_structure() {
    let resp = GenerateResponse {
        token_ids: vec![1, 2, 3],
        text: "hello world".to_string(),
        num_generated: 3,
    };
    let json = serde_json::to_string(&resp).expect("serialize");
    assert!(json.contains("hello world"));
    assert!(json.contains("num_generated"));
}

#[test]
fn test_deep_apicov_error_response_structure() {
    let resp = ErrorResponse {
        error: "Something went wrong".to_string(),
    };
    let json = serde_json::to_string(&resp).expect("serialize");
    assert!(json.contains("Something went wrong"));
}

#[test]
fn test_deep_apicov_stream_token_event_structure() {
    let event = StreamTokenEvent {
        token_id: 42,
        text: "hello".to_string(),
    };
    let json = serde_json::to_string(&event).expect("serialize");
    assert!(json.contains("42"));
    assert!(json.contains("hello"));
}

#[test]
fn test_deep_apicov_stream_done_event_structure() {
    let event = StreamDoneEvent { num_generated: 10 };
    let json = serde_json::to_string(&event).expect("serialize");
    assert!(json.contains("num_generated"));
    assert!(json.contains("10"));
}