dwarves-gui/tests/live_lenses.rs
//! **The Lenses tab's own path against a live forge, read-only.** `#[ignore]`d:
//! it needs a running forge. Every lens is asked exactly as the tab asks it
//! (`RemoteLensSource::remote_spawn`, one worker per lens, re-asking a lens the
//! server has queued on jera) and printed as it lands: state, seconds, and the
//! reason for every lens that did not compute.
//!
//! ```text
//! LIVE_FORGE=http://192.168.1.102:7910 LIVE_WORKSPACE=nordisk LIVE_TOKEN_FILE=~/.dwarves/token \
//! cargo test -p dwarves-gui --test live_lenses -- --ignored --nocapture
//! ```
use std::time::{Duration, Instant};
use dwarves_gui::mimir_lens::{lens_state_word, LensSource, RemoteLensSource, THIN_LENSES};
#[test]
#[ignore = "asks a live forge: set LIVE_FORGE"]
fn every_lens_answers_or_says_why() {
let endpoint = std::env::var("LIVE_FORGE").expect("LIVE_FORGE");
let workspace = std::env::var("LIVE_WORKSPACE").unwrap_or_else(|_| "nordisk".into());
let token = std::env::var("LIVE_TOKEN_FILE")
.ok()
.and_then(|p| std::fs::read_to_string(p).ok())
.map(|t| t.trim().to_string())
.unwrap_or_default();
let mut src = RemoteLensSource::new(endpoint.clone(), token, workspace.clone());
src.limit = 10;
let rx = src.remote_spawn().expect("a remote source spawns");
let t0 = Instant::now();
let mut last: std::collections::BTreeMap<&str, serde_json::Value> = Default::default();
let bound = Duration::from_secs(
std::env::var("LIVE_BOUND_S")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(1500),
);
println!("live: {endpoint} / {workspace}");
while let Ok(u) = rx.recv_timeout(bound.saturating_sub(t0.elapsed())) {
let word = lens_state_word(&u.answer).to_string();
let note: String = u
.answer
.get("evidence_note")
.and_then(|n| n.as_str())
.unwrap_or("")
.chars()
.take(220)
.collect();
println!(
"{:>7.1}s {:<16} {:<16} {}{}",
t0.elapsed().as_secs_f64(),
u.lens,
word,
if u.last { "" } else { "(asks again) " },
if word == "complete" { String::new() } else { note.replace('\n', " ") }
);
last.insert(u.lens, u.answer);
}
println!("\nsummary after {:.0}s:", t0.elapsed().as_secs_f64());
let mut silent = Vec::new();
for (lens, _) in THIN_LENSES {
match last.get(lens) {
Some(v) => println!(
" {lens:<16} {:<16} worst={}",
lens_state_word(v),
v.get("worst").and_then(|w| w.as_array()).map_or(0, Vec::len)
),
None => {
println!(" {lens:<16} (no answer)");
silent.push(lens);
}
}
}
assert!(silent.is_empty(), "lenses that said nothing: {silent:?}");
for (lens, v) in &last {
let w = lens_state_word(v);
assert!(!w.is_empty(), "{lens} answered without a state: {v}");
}
}