use super::edition;
use super::hello::PROTOCOL;
use super::material::{CHAIN, KEY, Material, read_dir};
use super::{Channel, server_name};
use crate::test_support::engine::Engine;
use crate::test_support::{Scratch, mint};
use serde_json::{Value, json};
fn wired(protocol: u32, script: Vec<Vec<Value>>) -> (Scratch, Engine, Material) {
let scratch = Scratch::new();
mint::material(scratch.path());
let engine = Engine::start(scratch.path(), protocol, script);
let held = read_dir(scratch.path(), crate::channel::material::Whose::Own)
.expect("readable")
.expect("provisioned");
(scratch, engine, held)
}
fn answered() -> Value {
json!({"ok": true, "kind": "workspaces", "rows": []})
}
#[test]
fn opening_a_channel_dials_nothing_and_names_the_address() {
let scratch = Scratch::new();
let held = mint::provisioned(scratch.path(), "engine.example:9000");
let channel = Channel::open(&held).expect("opened");
assert_eq!(channel.address(), "engine.example:9000");
}
#[test]
fn one_ask_states_a_version_carries_the_request_and_answers_the_reply() {
let (_scratch, engine, held) = wired(PROTOCOL, vec![vec![answered()]]);
let channel = Channel::open(&held).expect("opened");
let request = json!({"op": "workspaces"});
assert_eq!(channel.ask(&request), Ok(vec![answered()]));
assert_eq!(
engine.heard(),
vec![
json!({ "protocol": PROTOCOL, "edition": edition::EDITION }),
request
],
"the preface rides beside the gesture, never inside it"
);
}
#[test]
fn a_channel_spells_this_majors_required_fields_before_and_after_a_dial() {
let (_scratch, _engine, held) = wired(PROTOCOL, vec![vec![answered()]]);
let channel = Channel::open(&held).expect("opened");
assert!(channel.spells("reply/workspaces", "/rows/[]/name"));
assert_eq!(
channel.ask(&json!({"op": "workspaces"})),
Ok(vec![answered()])
);
assert!(channel.spells("reply/workspaces", "/rows/[]/name"));
}
#[test]
fn an_answer_of_many_frames_reads_back_through_the_same_ask() {
let rows = vec![json!({"n": 1}), json!({"n": 2}), json!({"n": 3})];
let (_scratch, _engine, held) = wired(PROTOCOL, vec![rows.clone()]);
let channel = Channel::open(&held).expect("opened");
assert_eq!(channel.ask(&json!({"op": "conversations"})), Ok(rows));
}
#[test]
fn a_follower_takes_frames_one_at_a_time_and_can_stop_early() {
let rows = vec![json!({"n": 1}), json!({"n": 2}), json!({"n": 3})];
let (_scratch, _engine, held) = wired(PROTOCOL, vec![rows]);
let channel = Channel::open(&held).expect("opened");
let mut taken = Vec::new();
channel
.follow(&json!({"op": "conversations"}), &mut |frame| {
taken.push(frame);
taken.len() < 2
})
.expect("followed");
assert_eq!(taken, vec![json!({"n": 1}), json!({"n": 2})]);
}
#[test]
fn each_ask_is_its_own_connection() {
let (_scratch, engine, held) = wired(PROTOCOL, vec![vec![answered()], vec![answered()]]);
let channel = Channel::open(&held).expect("opened");
for op in ["workspaces", "board"] {
assert!(channel.ask(&json!({ "op": op })).is_ok());
}
let ops: Vec<String> = engine
.heard()
.iter()
.filter_map(|v| v.get("op")?.as_str().map(str::to_owned))
.collect();
assert_eq!(ops, ["workspaces", "board"]);
}
#[test]
fn an_engine_that_answers_nothing_ends_the_stream() {
let (_scratch, _engine, held) = wired(PROTOCOL, vec![vec![]]);
let channel = Channel::open(&held).expect("opened");
assert_eq!(channel.ask(&json!({"op": "workspaces"})), Ok(Vec::new()));
}
#[test]
fn an_engine_of_another_protocol_refuses_and_names_both_versions() {
let (_scratch, _engine, held) = wired(PROTOCOL + 1, vec![vec![answered()]]);
let channel = Channel::open(&held).expect("opened");
let reach = channel
.ask(&json!({"op": "workspaces"}))
.expect_err("refused");
assert!(!reach.crossed(), "a stated mismatch adjudicates nothing");
let refusal = reach.said();
assert!(
refusal.contains(&format!("seat speaks version {PROTOCOL}")),
"{refusal}"
);
assert!(
refusal.contains(&format!("engine speaks {}", PROTOCOL + 1)),
"{refusal}"
);
}
#[test]
fn an_engine_that_is_not_there_names_the_address_it_dialled() {
let scratch = Scratch::new();
let held = mint::provisioned(scratch.path(), "127.0.0.1:1");
let channel = Channel::open(&held).expect("opened");
let reach = channel
.ask(&json!({"op": "workspaces"}))
.expect_err("refused");
assert!(
!reach.crossed(),
"a socket that never opened carried nothing"
);
let refusal = reach.said();
assert!(refusal.contains("connect 127.0.0.1:1"), "{refusal}");
}
#[test]
fn an_engine_the_anchors_do_not_cover_never_reaches_the_boundary() {
let (_scratch, engine, mut held) = wired(PROTOCOL, vec![vec![answered()]]);
let elsewhere = Scratch::new();
mint::material(elsewhere.path());
held.anchors = elsewhere.join(super::material::ANCHORS);
let channel = Channel::open(&held).expect("opened");
let reach = channel
.ask(&json!({"op": "workspaces"}))
.expect_err("the anchors do not cover it");
assert!(!reach.crossed(), "a handshake that failed carried nothing");
let why = reach.said();
assert!(why.contains("did not verify"), "{why}");
assert!(
why.contains("did not verify (") && !why.contains("()"),
"rustls' own fault is named inside it: {why}"
);
assert!(
why.contains(&held.anchors.display().to_string()),
"it names the file to look at: {why}"
);
assert!(
why.contains(&held.chain.display().to_string()),
"and the other half of the pair: {why}"
);
assert!(
why.contains("the seat mints nothing"),
"and the act, which is not a mint: {why}"
);
assert_eq!(engine.heard(), Vec::<Value>::new(), "nothing was said");
}
#[test]
fn a_leaf_the_engine_will_not_accept_never_reaches_the_boundary() {
let (scratch, engine, mut held) = wired(PROTOCOL, vec![vec![answered()]]);
let elsewhere = Scratch::new();
mint::material(elsewhere.path());
held.chain = elsewhere.join(CHAIN);
held.key = elsewhere.join(KEY);
let channel = Channel::open(&held).expect("opened");
assert!(channel.ask(&json!({"op": "workspaces"})).is_err());
assert_eq!(engine.heard(), Vec::<Value>::new(), "nothing was said");
assert!(scratch.path().is_dir());
}
#[test]
fn the_engine_s_name_is_read_off_the_address() {
for address in [
"127.0.0.1:9000",
"[::1]:9000",
"engine.example:9000",
"engine.example",
] {
assert!(server_name(address).is_ok(), "{address}");
}
let refusal = server_name("not a name:9000").expect_err("refused");
assert!(refusal.contains("not a server name"), "{refusal}");
}
#[test]
fn a_write_that_is_not_a_handshake_is_said_in_the_transport_s_own_words() {
let scratch = Scratch::new();
let held = mint::provisioned(scratch.path(), "engine.example:9000");
let channel = Channel::open(&held).expect("opened");
let said = channel.wrote(&std::io::Error::other("the pipe went away"));
assert_eq!(said, "send: the pipe went away");
}