Add M2a plan: thirteen tasks, tests, fake server and recordings
The tasks build the inference path: emsha-backed SHA-256, inferproxy, config, a hand-written HTTP and SSE client, request building, delta assembly, the chat state machine, the thinking cap, the slot gate with retry, the startup self-test and on-device verification. Everything the tasks copy in was checked against a private reference implementation: the gate passes after each task in order, the timing tests pass repeatedly under CPU load, and the reference passes the self-test and all four device checks on straylight. Expected results for the recorded streams were derived by a separate script. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
//! Tests for the accept-rate limiter. Do not edit: these define the required behaviour.
|
||||
|
||||
use inferproxy::{Limits, TokenBucket};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[test]
|
||||
fn default_limits() {
|
||||
let want = Limits {
|
||||
max_connections: 8,
|
||||
burst: 10,
|
||||
per_second: 2,
|
||||
};
|
||||
assert_eq!(Limits::default(), want);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn starts_full_and_empties() {
|
||||
let t0 = Instant::now();
|
||||
let mut b = TokenBucket::new(3, 2, t0);
|
||||
assert!(b.take(t0));
|
||||
assert!(b.take(t0));
|
||||
assert!(b.take(t0));
|
||||
assert!(!b.take(t0), "a fourth take at the same instant must fail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refills_at_the_given_rate() {
|
||||
let t0 = Instant::now();
|
||||
let mut b = TokenBucket::new(1, 2, t0);
|
||||
assert!(b.take(t0));
|
||||
assert!(
|
||||
!b.take(t0 + Duration::from_millis(499)),
|
||||
"half a second at 2/s is one token"
|
||||
);
|
||||
assert!(b.take(t0 + Duration::from_millis(500)));
|
||||
assert!(!b.take(t0 + Duration::from_millis(500)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_refills_add_up() {
|
||||
// Ten checks 100 ms apart at 2/s must add up to two tokens, not zero.
|
||||
let t0 = Instant::now();
|
||||
let mut b = TokenBucket::new(1, 2, t0);
|
||||
assert!(b.take(t0));
|
||||
let granted = (1..=10)
|
||||
.filter(|i| b.take(t0 + Duration::from_millis(100 * i)))
|
||||
.count();
|
||||
assert_eq!(granted, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn never_holds_more_than_the_burst() {
|
||||
let t0 = Instant::now();
|
||||
let mut b = TokenBucket::new(2, 100, t0);
|
||||
let later = t0 + Duration::from_secs(3600);
|
||||
assert!(b.take(later));
|
||||
assert!(b.take(later));
|
||||
assert!(
|
||||
!b.take(later),
|
||||
"an hour of refill must still stop at the burst size"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_clock_that_does_not_advance_is_harmless() {
|
||||
let t0 = Instant::now();
|
||||
let mut b = TokenBucket::new(1, 2, t0 + Duration::from_secs(10));
|
||||
assert!(b.take(t0), "an earlier `now` must not panic or underflow");
|
||||
assert!(!b.take(t0));
|
||||
}
|
||||
Reference in New Issue
Block a user