mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-19 21:18:20 +02:00
bash_bg et bash_tail des tours de la façade ne passent plus par /tool/exec du Go : src/tools/jobs.rs porte code_jobs.go. Refus avant lancement (commande vide ou dangereuse, optimisation en cours), journal .loki/jobs/<id>.log dans le dossier de la discussion, processus qui survit au tour, shell sans le jeton interne ; relecture bornée (40 lignes par défaut, 200 au plus), état et durée, arrêt relu aussitôt comme le Go. paths::go_mkdir_all reproduit os.MkdirAll, erreur comprise. Les jobs d'une discussion supprimée s'arrêtent avec elle. L'optimiseur du Go compte ceux de la façade (POST /internal/facade/v1/bgjobs) avant de mesurer ; façade injoignable : les siens seulement. Parité : journal de 24 étapes tiré du Go (parity_jobs_test.go → tests/parity_jobs/jobs.json), rejoué par tests/jobs.rs ; un tour de la façade qui lance un job (tests/lot6.rs) ; TestFacadeJobsArrierePlan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
55 lines
2.3 KiB
Rust
55 lines
2.3 KiB
Rust
//! Lot 43 : jobs d'arrière-plan du mode Code (`bash_bg`, `bash_tail`) tenus
|
|
//! par la façade, rejoués sur le journal du Go
|
|
//! (`internal/loki/parity_jobs_test.go` → `tests/parity_jobs/jobs.json`).
|
|
#![cfg(target_os = "linux")]
|
|
|
|
use std::time::Duration;
|
|
|
|
use loki_rs::tools::jobs::BgJobs;
|
|
use regex::Regex;
|
|
use serde_json::{Map, Value};
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn jobs_comme_le_go() {
|
|
let fx: Value = serde_json::from_str(include_str!("parity_jobs/jobs.json")).expect("journal");
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let ws = tmp.path().join("ws");
|
|
std::fs::create_dir_all(&ws).unwrap();
|
|
let jobs = BgJobs::default();
|
|
let pid = Regex::new(r"\(pid [0-9]+\)").unwrap();
|
|
let since = Regex::new(r"depuis [0-9hms.]+").unwrap();
|
|
let state = Regex::new(r"— (en cours|terminé \(exit -1\)) —").unwrap();
|
|
for st in fx["steps"].as_array().unwrap() {
|
|
let name = st["name"].as_str().unwrap();
|
|
if let Some(id) = st["wait"].as_str() {
|
|
// Le job attendu est le seul qui tourne encore.
|
|
for _ in 0..1000 {
|
|
if jobs.running() == 0 {
|
|
break;
|
|
}
|
|
tokio::time::sleep(Duration::from_millis(10)).await;
|
|
}
|
|
assert_eq!(jobs.running(), 0, "{name} : {id} pas fini");
|
|
}
|
|
let args: Map<String, Value> = serde_json::from_value(st["args"].clone()).unwrap();
|
|
let got = match st["tool"].as_str().unwrap() {
|
|
"bash_bg" => jobs.bash_bg(&ws, "c1", &args, None).await,
|
|
_ => jobs.bash_tail(&args).await,
|
|
};
|
|
let got = pid.replace_all(&got, "(pid {{PID}})");
|
|
let mut got = since.replace_all(&got, "depuis {{D}}").into_owned();
|
|
if st["after"] == "kill" {
|
|
got = state.replace_all(&got, "— {{ETAT}} —").into_owned();
|
|
}
|
|
assert_eq!(got, st["result"].as_str().unwrap(), "{name}");
|
|
let mut logs: Vec<String> = std::fs::read_dir(ws.join(".loki/jobs"))
|
|
.into_iter()
|
|
.flatten()
|
|
.flatten()
|
|
.map(|e| e.file_name().to_string_lossy().into_owned())
|
|
.collect();
|
|
logs.sort();
|
|
assert_eq!(serde_json::json!(logs), st["logs"], "{name} : journaux");
|
|
}
|
|
}
|