Add loopd configuration with every M2a limit
Implemented-By: Laguna S 2.1 (OpenCode)
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
//! Tests for `loopd`'s configuration. Do not edit: these define the required behaviour.
|
||||
|
||||
use loopd::config::{Config, ConfigError, Limits, Sampling};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn fixture(name: &str) -> PathBuf {
|
||||
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("tests/fixtures/config")
|
||||
.join(name)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimal_file_gets_the_documented_defaults() {
|
||||
let c = Config::load(&fixture("minimal.toml")).unwrap();
|
||||
assert_eq!(
|
||||
c.infer.socket,
|
||||
PathBuf::from("/run/boxmaker/infer/infer.sock")
|
||||
);
|
||||
assert_eq!(c.infer.model, "ornith-1.5-35b-a3b");
|
||||
assert_eq!((c.slots.main, c.slots.background), (0, 1));
|
||||
assert_eq!(c.expect.n_ctx, 131_072);
|
||||
assert_eq!(c.expect.slots, 2);
|
||||
assert_eq!(
|
||||
c.expect.template_sha256.to_hex(),
|
||||
"f55f52930aa8bf44ab5cb85f99370fcc3c56e9a85640b812086d5330bce5d86b"
|
||||
);
|
||||
assert_eq!(
|
||||
c.sampling,
|
||||
Sampling {
|
||||
temperature: 0.6,
|
||||
top_p: 0.95,
|
||||
top_k: 20
|
||||
}
|
||||
);
|
||||
let want = Limits {
|
||||
poll_ms: 5_000,
|
||||
busy_wait_ms: 600_000,
|
||||
load_wait_ms: 180_000,
|
||||
idle_grace_ms: 30_000,
|
||||
liveness_ms: 30_000,
|
||||
thinking_cap: 4_096,
|
||||
thinking_overrun: 256,
|
||||
max_tokens: 8_192,
|
||||
queue_len: 8,
|
||||
retry_attempts: 4,
|
||||
retry_backoff_ms: vec![2_000, 8_000, 30_000],
|
||||
retry_window_ms: 300_000,
|
||||
};
|
||||
assert_eq!(c.limits, want);
|
||||
assert_eq!(Limits::default(), want);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_file_overrides_every_default() {
|
||||
let c = Config::load(&fixture("full.toml")).unwrap();
|
||||
assert_eq!(
|
||||
c.sampling,
|
||||
Sampling {
|
||||
temperature: 0.2,
|
||||
top_p: 0.9,
|
||||
top_k: 40
|
||||
}
|
||||
);
|
||||
let want = Limits {
|
||||
poll_ms: 50,
|
||||
busy_wait_ms: 200,
|
||||
load_wait_ms: 300,
|
||||
idle_grace_ms: 150,
|
||||
liveness_ms: 100,
|
||||
thinking_cap: 20,
|
||||
thinking_overrun: 10,
|
||||
max_tokens: 512,
|
||||
queue_len: 1,
|
||||
retry_attempts: 2,
|
||||
retry_backoff_ms: vec![10],
|
||||
retry_window_ms: 1_000,
|
||||
};
|
||||
assert_eq!(c.limits, want);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_partial_limits_table_keeps_the_other_defaults() {
|
||||
let text = std::fs::read_to_string(fixture("minimal.toml")).unwrap();
|
||||
let c = Config::parse(&format!("{text}\n[limits]\nliveness_ms = 1234\n")).unwrap();
|
||||
assert_eq!(c.limits.liveness_ms, 1234);
|
||||
assert_eq!(c.limits.poll_ms, 5_000);
|
||||
}
|
||||
|
||||
/// Every table in the file must reject a key it does not know: a misspelt limit that silently
|
||||
/// fell back to its default would be a limit the owner believes is set and is not.
|
||||
#[test]
|
||||
fn unknown_keys_are_errors_in_every_table() {
|
||||
let text = std::fs::read_to_string(fixture("full.toml")).unwrap();
|
||||
assert!(Config::parse(&text).is_ok());
|
||||
for table in ["infer", "slots", "expect", "sampling", "limits"] {
|
||||
let header = format!("[{table}]\n");
|
||||
assert!(text.contains(&header), "fixture has no [{table}] table");
|
||||
let bad = text.replacen(&header, &format!("{header}zz_unknown = 1\n"), 1);
|
||||
assert!(
|
||||
Config::parse(&bad).is_err(),
|
||||
"[{table}] accepted an unknown key"
|
||||
);
|
||||
}
|
||||
assert!(
|
||||
Config::parse(&format!("zz_unknown = 1\n{text}")).is_err(),
|
||||
"top level"
|
||||
);
|
||||
assert!(
|
||||
Config::parse(&format!("{text}\n[zz_unknown]\nx = 1\n")).is_err(),
|
||||
"unknown table"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn required_tables_and_values_are_checked() {
|
||||
let text = std::fs::read_to_string(fixture("minimal.toml")).unwrap();
|
||||
for table in ["infer", "slots", "expect"] {
|
||||
let without: String = text
|
||||
.split("\n\n")
|
||||
.filter(|block| !block.trim_start().starts_with(&format!("[{table}]")))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n");
|
||||
assert!(Config::parse(&without).is_err(), "[{table}] is required");
|
||||
}
|
||||
let bad_hash = text.replace("f55f5293", "F55F5293");
|
||||
assert!(
|
||||
Config::parse(&bad_hash).is_err(),
|
||||
"the hash must be lowercase hex"
|
||||
);
|
||||
let negative = text.replace("main = 0", "main = -1");
|
||||
assert!(Config::parse(&negative).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_reports_which_file_failed() {
|
||||
let missing = fixture("does-not-exist.toml");
|
||||
match Config::load(&missing) {
|
||||
Err(ConfigError::Read(path, _)) => assert_eq!(path, missing),
|
||||
other => panic!("expected a read error, got {other:?}"),
|
||||
}
|
||||
let e: Box<dyn std::error::Error> = Box::new(Config::load(&missing).unwrap_err());
|
||||
assert!(e.to_string().contains("does-not-exist.toml"));
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
[infer]
|
||||
socket = "/tmp/infer.sock"
|
||||
model = "some-model"
|
||||
|
||||
[slots]
|
||||
main = 2
|
||||
background = 3
|
||||
|
||||
[expect]
|
||||
template_sha256 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
|
||||
n_ctx = 4096
|
||||
slots = 4
|
||||
|
||||
[sampling]
|
||||
temperature = 0.2
|
||||
top_p = 0.9
|
||||
top_k = 40
|
||||
|
||||
[limits]
|
||||
poll_ms = 50
|
||||
busy_wait_ms = 200
|
||||
load_wait_ms = 300
|
||||
idle_grace_ms = 150
|
||||
liveness_ms = 100
|
||||
thinking_cap = 20
|
||||
thinking_overrun = 10
|
||||
max_tokens = 512
|
||||
queue_len = 1
|
||||
retry_attempts = 2
|
||||
retry_backoff_ms = [10]
|
||||
retry_window_ms = 1000
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
[infer]
|
||||
socket = "/run/boxmaker/infer/infer.sock"
|
||||
model = "ornith-1.5-35b-a3b"
|
||||
|
||||
[slots]
|
||||
main = 0
|
||||
background = 1
|
||||
|
||||
[expect]
|
||||
template_sha256 = "f55f52930aa8bf44ab5cb85f99370fcc3c56e9a85640b812086d5330bce5d86b"
|
||||
n_ctx = 131072
|
||||
slots = 2
|
||||
Reference in New Issue
Block a user