diff --git a/crates/huginn-daemon/tests/desk_door.rs b/crates/huginn-daemon/tests/desk_door.rs index d60a699..15951d3 100644 --- a/crates/huginn-daemon/tests/desk_door.rs +++ b/crates/huginn-daemon/tests/desk_door.rs @@ -783,3 +783,46 @@ fn the_newest_fork_too_large_is_named_and_its_cursor_resumes_to_the_older_forks( let rest = page_ids(ask(&desk, "m-p", &forks_page("x", Some("c2")))); assert_eq!(rest, (vec!["eureka-state:question:Q2".to_string(), FORK.to_string()], None)); } + +/// Grows `fork` over the socket until a READ of it no longer fits the reply cap; returns the raw reply. +fn grown_until_read_overflows(desk: &Path, hash: &str, fork: &str) -> CultNetMessage { + let note = "a long reason, ".repeat(60); + for sent in 1..400_u32 { + let reply = exchange(desk, &desk_bytes("m-read", &fork_read("x", fork))).expect("the door replied"); + if !matches!(decode_desk_response(&reply).unwrap().1, Ok(DeskResponse::Fork { .. })) { + return reply; + } + let mut grow = answer("x", hash, &format!("00000000-0000-4000-8000-{sent:012}")); + if let DeskRequest::Answer { request, .. } = &mut grow { + request.fork_id = fork.into(); + request.answer = Some(ForkAnswer { choice: None, note: Some(note.clone()) }); + } + assert!(matches!(ask(desk, "m-w", &grow), DeskResponse::Answered { .. })); + } + panic!("the record does not grow") +} + +/// A READ of a fork whose entry is past the reply cap is `fork_too_large` naming the fork, with no +/// order and no cursor; a fitting fork still reads; the list's refusal is unchanged; the generic +/// response-too-large stays for every other reply. +#[test] +fn a_read_of_an_oversize_fork_is_fork_too_large_naming_only_the_fork() { + let _serial = serial(); + let (_root, _run, hash, desk, _daemon) = three_forks(); + let big = "eureka-state:question:Q2"; + let reply = grown_until_read_overflows(&desk, &hash, big); + let (id, response) = decode_desk_response(&reply).unwrap(); + assert_eq!(id, "m-read"); + let (code, text) = refusal_of(&response.unwrap()).expect("a not-stored refusal"); + assert_eq!(code, "fork_too_large"); + assert!(text.contains(big) && !text.contains("order") && !text.contains("cursor") && !text.contains(" c1"), "{text}"); + // Fitting forks read, the others untouched. + for fork in [FORK, "eureka-state:question:Q3"] { + assert!(matches!(ask(&desk, "m-ok", &fork_read("x", fork)), DeskResponse::Fork { .. })); + } + // The list still names the fork and its order, and the cursor goes on. + let listed = ask(&desk, "m-l", &forks_page("x", Some("c2"))); + let (code, text) = refusal_of(&listed).unwrap(); + assert_eq!(code, "fork_too_large"); + assert!(text.contains(big) && text.contains("order 1") && text.contains("c1"), "{text}"); +}