mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-24 15:38:12 +02:00
Lot 27 : tests contre les mutations survivantes du banc d'essai
84 mutations du port Rust, 81 tuées ; trois équivalentes documentées dans la spécification (annulation déjà vue au premier tour du select, progression d'un job remplacé, PID nul du moteur). - bench/tests.rs : un mini moteur qui garde les corps des requêtes ; tranche pile à la fin du corpus, tour sans attendu, débits nuls recalculés, niveau rejoué une seule fois, préchauffage et ligne courte d'un run rapide, profondeur arrêtée (contexte plein, corpus épuisé, réponse reprise, note de reprise hybride ou gabarit) ; - tests/bench.rs : second lancement pendant la prise du bail, preset relu au départ du job, mesure enregistrée sous le preset actif ; - journal de parité : un prompt juste au-delà de la prose. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
6 files changed
+609
No files matched your search
@@ -536,6 +536,74 @@ async fn stop_du_chat_et_bail_perdu() {
|
||||
);
|
||||
}
|
||||
|
||||
/// Pendant la prise du bail, un second lancement est refusé ; le preset
|
||||
/// relu au départ du job l'emporte sur celui lu au lancement.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn relu_au_depart_du_job() {
|
||||
let bn = Arc::new(start().await);
|
||||
bn.base(16384, Duration::ZERO);
|
||||
*bn.go.lease_delay.lock().unwrap() = Some(Duration::from_millis(400));
|
||||
let first = {
|
||||
let bn = bn.clone();
|
||||
tokio::spawn(async move { bn.call("POST", "/api/bench", "{}").await })
|
||||
};
|
||||
tokio::time::sleep(Duration::from_millis(150)).await;
|
||||
let (code, out) = bn.call("POST", "/api/bench", "{}").await;
|
||||
assert_eq!(
|
||||
(code, out),
|
||||
(
|
||||
409,
|
||||
json!({"ok": false, "error": "un benchmark tourne déjà"})
|
||||
)
|
||||
);
|
||||
// Le preset devient une API externe pendant la prise du bail.
|
||||
bn.go.set("config", "EXTERNAL", "1");
|
||||
assert_eq!(first.await.unwrap().0, 202);
|
||||
bn.wait("externe").await;
|
||||
assert_eq!(
|
||||
bn.status().await["error"],
|
||||
json!("benchmark indisponible : le preset actif est une API externe")
|
||||
);
|
||||
// L'optimiseur démarre pendant la prise du bail.
|
||||
bn.go.set("config", "EXTERNAL", "");
|
||||
let first = {
|
||||
let bn = bn.clone();
|
||||
tokio::spawn(async move { bn.call("POST", "/api/bench", "{}").await })
|
||||
};
|
||||
tokio::time::sleep(Duration::from_millis(150)).await;
|
||||
*bn.go.tune_busy.lock().unwrap() = Some(TUNE_BUSY.to_string());
|
||||
assert_eq!(first.await.unwrap().0, 202);
|
||||
bn.wait("optimiseur").await;
|
||||
*bn.go.tune_busy.lock().unwrap() = None;
|
||||
assert_eq!(bn.status().await["error"], json!(TUNE_BUSY));
|
||||
assert!(
|
||||
bn.fake.lock().unwrap().chats == 0,
|
||||
"rien n'est parti au moteur"
|
||||
);
|
||||
}
|
||||
|
||||
/// La mesure s'enregistre sous le preset ACTIF, pas sous le premier de la
|
||||
/// liste.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
||||
async fn mesure_du_preset_actif() {
|
||||
let bn = start().await;
|
||||
bn.base(16384, Duration::ZERO);
|
||||
let dir = bn.home.join("presets");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let active = format!(
|
||||
"MODEL=/models/qwen.gguf\nPORT={}\nCTX=16384\nREASONING=off\nCACHE_ISOLATE=off\n",
|
||||
bn.port
|
||||
);
|
||||
std::fs::write(dir.join("qwen.env"), active).unwrap();
|
||||
std::fs::write(dir.join("autre.env"), "MODEL=/models/autre.gguf\n").unwrap();
|
||||
let (code, _) = bn.call("POST", "/api/bench", "{}").await;
|
||||
assert_eq!(code, 202);
|
||||
bn.wait("bench").await;
|
||||
let saved: Value = serde_json::from_str(&bn.go.get("state", "bench_presets").unwrap()).unwrap();
|
||||
let ids: Vec<&String> = saved.as_object().unwrap().keys().collect();
|
||||
assert_eq!(ids, ["qwen"]);
|
||||
}
|
||||
|
||||
/// Sans la façade pour le bench, ses routes partent au Go.
|
||||
#[tokio::test]
|
||||
async fn sans_la_facade() {
|
||||
|
||||
@@ -115,6 +115,8 @@ pub struct FakeGo {
|
||||
pub side_jobs: Mutex<Vec<String>>,
|
||||
/// /internal/v1/bench/perf reçus.
|
||||
pub bench_perfs: Mutex<Vec<serde_json::Value>>,
|
||||
/// Délai avant de répondre à une prise de bail.
|
||||
pub lease_delay: Mutex<Option<std::time::Duration>>,
|
||||
}
|
||||
|
||||
impl FakeGo {
|
||||
@@ -245,6 +247,10 @@ async fn handle(st: Arc<FakeGo>, req: Request<Incoming>) -> Response<Full<Bytes>
|
||||
}
|
||||
"/internal/v1/engine/lease" => {
|
||||
let body = req.into_body().collect().await.unwrap().to_bytes();
|
||||
let delay = *st.lease_delay.lock().unwrap();
|
||||
if let Some(d) = delay {
|
||||
tokio::time::sleep(d).await;
|
||||
}
|
||||
let v: serde_json::Value = serde_json::from_slice(&body).unwrap_or_default();
|
||||
if let Some(why) = v["why"].as_str() {
|
||||
st.lease_whys.lock().unwrap().push(why.to_string());
|
||||
|
||||
@@ -1988,6 +1988,173 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prompt juste au-delà de la prose",
|
||||
"engine": {
|
||||
"n_ctx": 16384
|
||||
},
|
||||
"method": "POST",
|
||||
"path": "/api/bench",
|
||||
"body": "{\"prompt\":900,\"n\":16}",
|
||||
"status": 202,
|
||||
"out": {
|
||||
"id": "{{ID}}",
|
||||
"ok": true
|
||||
},
|
||||
"wait": true,
|
||||
"job": {
|
||||
"elapsed_sec": "{{T}}",
|
||||
"id": "{{ID}}",
|
||||
"mode": "quick",
|
||||
"ok": true,
|
||||
"phase": "ligne courte (900 + 16 jetons)",
|
||||
"result": {
|
||||
"draft": {
|
||||
"accepted": 7,
|
||||
"n": 10
|
||||
},
|
||||
"elapsed_sec": "{{T}}",
|
||||
"engine": "b9999-test",
|
||||
"kv": "f16",
|
||||
"mode": "quick",
|
||||
"predicted_ms": 320,
|
||||
"predicted_n": 16,
|
||||
"predicted_per_second": 50,
|
||||
"prompt_ms": 470,
|
||||
"prompt_n": 940,
|
||||
"prompt_per_second": 2000,
|
||||
"protocol": 2
|
||||
},
|
||||
"running": false,
|
||||
"saved": true,
|
||||
"step": 2,
|
||||
"steps": 2
|
||||
},
|
||||
"calls": [
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/health"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/health"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/slots"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/props"
|
||||
},
|
||||
{
|
||||
"body": {
|
||||
"content": "<163664 octets b7452851885a>"
|
||||
},
|
||||
"method": "POST",
|
||||
"path": "/tokenize"
|
||||
},
|
||||
{
|
||||
"body": {
|
||||
"content": "<3561 octets f977dc7d4950>"
|
||||
},
|
||||
"method": "POST",
|
||||
"path": "/tokenize"
|
||||
},
|
||||
{
|
||||
"body": {
|
||||
"cache_prompt": false,
|
||||
"chat_template_kwargs": {
|
||||
"enable_thinking": false
|
||||
},
|
||||
"max_tokens": 32,
|
||||
"messages": [
|
||||
{
|
||||
"content": "<4110 octets c386aa380c09>",
|
||||
"role": "user"
|
||||
}
|
||||
],
|
||||
"min_p": 0.05,
|
||||
"model": "loki",
|
||||
"seed": 1234,
|
||||
"stream": false,
|
||||
"temperature": 0.7,
|
||||
"top_k": 40
|
||||
},
|
||||
"method": "POST",
|
||||
"path": "/v1/chat/completions"
|
||||
},
|
||||
{
|
||||
"body": {
|
||||
"cache_prompt": false,
|
||||
"chat_template_kwargs": {
|
||||
"enable_thinking": false
|
||||
},
|
||||
"max_tokens": 16,
|
||||
"messages": [
|
||||
{
|
||||
"content": "<3745 octets 5578a8f2779c>",
|
||||
"role": "user"
|
||||
}
|
||||
],
|
||||
"min_p": 0.05,
|
||||
"model": "loki",
|
||||
"seed": 1234,
|
||||
"stream": false,
|
||||
"temperature": 0.7,
|
||||
"top_k": 40
|
||||
},
|
||||
"method": "POST",
|
||||
"path": "/v1/chat/completions"
|
||||
}
|
||||
],
|
||||
"last": {
|
||||
"at": "{{T}}",
|
||||
"fingerprint": "{{FP}}",
|
||||
"model": "qwen.gguf",
|
||||
"result": {
|
||||
"draft": {
|
||||
"accepted": 7,
|
||||
"n": 10
|
||||
},
|
||||
"elapsed_sec": "{{T}}",
|
||||
"engine": "b9999-test",
|
||||
"kv": "f16",
|
||||
"mode": "quick",
|
||||
"predicted_ms": 320,
|
||||
"predicted_n": 16,
|
||||
"predicted_per_second": 50,
|
||||
"prompt_ms": 470,
|
||||
"prompt_n": 940,
|
||||
"prompt_per_second": 2000,
|
||||
"protocol": 2
|
||||
}
|
||||
},
|
||||
"presets": {
|
||||
"qwen": {
|
||||
"at": "{{T}}",
|
||||
"fingerprint": "{{FP}}",
|
||||
"model": "qwen.gguf",
|
||||
"result": {
|
||||
"draft": {
|
||||
"accepted": 7,
|
||||
"n": 10
|
||||
},
|
||||
"elapsed_sec": "{{T}}",
|
||||
"engine": "b9999-test",
|
||||
"kv": "f16",
|
||||
"mode": "quick",
|
||||
"predicted_ms": 320,
|
||||
"predicted_n": 16,
|
||||
"predicted_per_second": 50,
|
||||
"prompt_ms": 470,
|
||||
"prompt_n": 940,
|
||||
"prompt_per_second": 2000,
|
||||
"protocol": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "corps illisible : défauts",
|
||||
"engine": {
|
||||
|
||||
Reference in new issue
Block a user