122 lines
3.7 KiB
Rust
122 lines
3.7 KiB
Rust
//! The speaker `deliver` is given goes on the turn it sends to `loopd`, and nowhere else: not into
|
|
//! the turn's text (M5c spec, section 11). Do not edit.
|
|
|
|
#[path = "support/fake_loop.rs"]
|
|
mod fake_loop;
|
|
#[path = "support/tmp.rs"]
|
|
mod tmp;
|
|
|
|
use std::sync::Mutex;
|
|
use std::time::Duration;
|
|
|
|
use bxcore::{ErrorCode, SessionId, Turn};
|
|
use fake_loop::{done, error, serve_loop};
|
|
use gatewayd::deliver::{Notice, Poster, deliver};
|
|
use gatewayd::mm::MmError;
|
|
use gatewayd::sessions::{Batch, Thread};
|
|
use tmp::TempDir;
|
|
|
|
const DM: &str = "d0000000000000000000000000";
|
|
const ROOT: &str = "r0000000000000000000000000";
|
|
const KYLE: &str = "k0000000000000000000000000";
|
|
const WAIT: Duration = Duration::from_secs(5);
|
|
|
|
#[derive(Default)]
|
|
struct Record(Mutex<Vec<String>>);
|
|
|
|
impl Poster for Record {
|
|
fn post(&self, _: &str, _: &str, text: &str) -> Result<(), MmError> {
|
|
self.0.lock().unwrap().push(text.to_string());
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
/// One `deliver` of "one\n\ntwo" with `speaker`, against a fake `loopd` whose n-th turn gets
|
|
/// `script(n)`; the turns it received and what was posted.
|
|
fn deliver_with(
|
|
tag: &str,
|
|
speaker: Option<&str>,
|
|
script: fn(usize) -> Vec<fake_loop::Reply>,
|
|
) -> (Vec<Turn>, Vec<String>) {
|
|
let dir = TempDir::new(tag);
|
|
let socket = dir.path().join("loop.sock");
|
|
let turns = serve_loop(&socket, move |n, _| script(n));
|
|
let batch = Batch {
|
|
session: SessionId::new(&format!("mm-{ROOT}")).unwrap(),
|
|
thread: Thread {
|
|
channel: DM.to_string(),
|
|
root: ROOT.to_string(),
|
|
},
|
|
resume: true,
|
|
text: "one\n\ntwo".to_string(),
|
|
senders: vec![KYLE.to_string(), KYLE.to_string()],
|
|
};
|
|
let never = |_: u64| false;
|
|
let notice = Notice {
|
|
posted: &never,
|
|
wait: Duration::ZERO,
|
|
};
|
|
let poster = Record::default();
|
|
let log = Mutex::new(Vec::new());
|
|
deliver(
|
|
&poster,
|
|
&socket,
|
|
&batch,
|
|
speaker,
|
|
&|line| log.lock().unwrap().push(line.to_string()),
|
|
¬ice,
|
|
);
|
|
assert!(log.lock().unwrap().is_empty(), "{:?}", log.lock().unwrap());
|
|
// The fake reports each turn before it answers, so every turn is in by now.
|
|
let mut got = vec![turns.recv_timeout(WAIT).unwrap()];
|
|
while let Ok(turn) = turns.try_recv() {
|
|
got.push(turn);
|
|
}
|
|
(got, poster.0.into_inner().unwrap())
|
|
}
|
|
|
|
fn answer(_: usize) -> Vec<fake_loop::Reply> {
|
|
vec![done("fine")]
|
|
}
|
|
|
|
#[test]
|
|
fn the_speaker_goes_on_the_turn_and_not_into_its_text() {
|
|
let (turns, posts) = deliver_with("speaker-some", Some("first.last"), answer);
|
|
assert_eq!(turns.len(), 1);
|
|
let turn = &turns[0];
|
|
assert_eq!(turn.speaker.as_deref(), Some("first.last"));
|
|
assert_eq!(
|
|
(turn.content.as_str(), turn.resume),
|
|
("one\n\ntwo", true),
|
|
"the text is the batch's, unchanged"
|
|
);
|
|
assert_eq!(posts, ["fine"]);
|
|
}
|
|
|
|
#[test]
|
|
fn without_a_speaker_the_turn_has_none() {
|
|
let (turns, posts) = deliver_with("speaker-none", None, answer);
|
|
assert_eq!(turns.len(), 1);
|
|
assert_eq!(turns[0].speaker, None, "never the user id");
|
|
assert_eq!(turns[0].content, "one\n\ntwo");
|
|
assert_eq!(posts, ["fine"]);
|
|
}
|
|
|
|
#[test]
|
|
fn the_turn_sent_again_for_an_unknown_session_keeps_the_speaker() {
|
|
let unknown_first = |n: usize| {
|
|
if n == 0 {
|
|
vec![error(ErrorCode::NoSuchSession, "no such session")]
|
|
} else {
|
|
vec![done("hello")]
|
|
}
|
|
};
|
|
let (turns, posts) = deliver_with("speaker-again", Some("kyle"), unknown_first);
|
|
let seen: Vec<(bool, Option<&str>)> = turns
|
|
.iter()
|
|
.map(|t| (t.resume, t.speaker.as_deref()))
|
|
.collect();
|
|
assert_eq!(seen, [(true, Some("kyle")), (false, Some("kyle"))]);
|
|
assert_eq!(posts, ["hello"]);
|
|
}
|