use super::*;
use crate::testing;
fn run_logged(steps: &[Step]) -> Summary {
testing::init_tracing();
run(steps)
}
#[test]
fn test_scripted_round_trip() {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Send(1),
Step::Reply(1),
Step::Recv,
Step::Send(2),
Step::Send(3),
Step::Reply(2),
Step::Reply(3),
Step::Recv,
Step::Recv,
]);
assert_eq!(
summary,
Summary {
established: true,
handshakes: 1,
messages: 3,
resets: 0,
failures: 0,
reads: 4,
}
);
}
#[test]
fn test_scripted_send_failure_ends_receiving() {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Reply(1),
Step::Break,
Step::Send(2),
Step::Recv,
Step::Heal,
Step::Send(3),
Step::Handshake,
Step::Hello,
Step::Send(4),
Step::Reply(4),
Step::Recv,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.messages, 1);
assert_eq!(summary.failures, 1);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Break,
Step::Send(1),
Step::Recv,
]);
assert!(!summary.established);
assert_eq!(summary.failures, 1);
}
#[test]
fn test_scripted_send_refusal_and_receive_failure() {
let summary = run_logged(&[
Step::SendOversized,
Step::Handshake,
Step::Hello,
Step::SendOversized,
Step::Send(1),
Step::Reply(1),
Step::Recv,
Step::ReplyTampered,
Step::Recv,
Step::Send(2),
Step::Handshake,
Step::Hello,
Step::Send(3),
Step::Reply(3),
Step::Recv,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.messages, 2);
assert_eq!(summary.failures, 1);
}
#[test]
fn test_scripted_retained_sender() {
let summary = run_logged(&[
Step::Retain,
Step::SendRetained(0),
Step::Handshake,
Step::Hello,
Step::Retain,
Step::SendRetained(1),
Step::Handshake,
Step::Hello,
Step::SendRetained(2),
Step::Send(3),
Step::Reply(3),
Step::Recv,
Step::Retain,
Step::SendRetained(4),
Step::Reply(4),
Step::Recv,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.messages, 2);
assert_eq!(summary.failures, 0);
}
#[test]
fn test_scripted_retained_sender_failures() {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Retain,
Step::Handshake,
Step::HelloTampered,
Step::SendRetained(1),
Step::Handshake,
Step::Hello,
Step::SendRetained(2),
Step::Send(3),
Step::Retain,
Step::Break,
Step::SendRetained(4),
Step::Heal,
Step::SendRetained(5),
Step::Handshake,
Step::Hello,
Step::SendRetained(6),
Step::Send(7),
Step::Reply(7),
Step::Recv,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 3);
assert_eq!(summary.messages, 1);
assert_eq!(summary.failures, 1);
}
#[test]
fn test_scripted_flawed_hellos() {
for flaw in [
Step::HelloTampered,
Step::HelloBadAuth,
Step::HelloBadSigner,
Step::HelloBadPayload,
Step::HelloBadKey,
Step::HelloBadEncap,
Step::HelloBadAttest,
] {
let summary = run_logged(&[Step::Handshake, flaw.clone(), Step::Send(1)]);
assert!(!summary.established, "{flaw:?}");
assert_eq!(summary.failures, 1, "{flaw:?}");
let summary = run_logged(&[flaw.clone(), Step::Recv]);
assert!(!summary.established, "{flaw:?}");
assert_eq!(summary.failures, 1, "{flaw:?}");
}
}
#[test]
fn test_scripted_stale_skipping() {
let summary = run_logged(&[
Step::Dropped,
Step::Junk(vec![1, 2, 3]),
Step::Handshake,
Step::HelloStale,
Step::Dropped,
Step::Junk(vec![]),
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.failures, 0);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Send(1),
Step::Reply(1),
Step::Handshake,
Step::Hello,
Step::Send(2),
Step::Reply(2),
Step::Recv,
]);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.messages, 1);
assert_eq!(summary.failures, 0);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Hello,
Step::Handshake,
Step::Hello,
]);
assert_eq!(summary.handshakes, 2);
assert!(summary.established);
for stale in [40, MAX_STEPS - 2] {
let mut steps = vec![Step::Handshake];
steps.extend(std::iter::repeat_n(Step::Dropped, stale));
steps.push(Step::Hello);
let summary = run_logged(&steps);
assert!(summary.established);
assert_eq!(summary.failures, 0);
}
let summary = run_logged(&[Step::Handshake, Step::Undecodable, Step::Hello]);
assert!(summary.established);
assert_eq!(summary.failures, 0);
}
#[test]
fn test_scripted_handshake_interrupted() {
let summary = run_logged(&[Step::Handshake, Step::Yield, Step::Send(1)]);
assert!(!summary.established);
assert_eq!(summary.failures, 1);
let summary = run_logged(&[Step::Handshake]);
assert!(!summary.established);
assert_eq!(summary.failures, 1);
}
#[test]
fn test_scripted_garbage_keeps_session() {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Garbage,
Step::Recv,
Step::Reply(2),
Step::Recv,
]);
assert!(summary.established);
assert_eq!(summary.messages, 2);
assert_eq!(summary.failures, 0);
}
#[test]
fn test_scripted_undecryptable_drops_session() {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Reply(1),
Step::ReplyReplay,
Step::Recv,
Step::Recv,
Step::Send(1),
]);
assert!(!summary.established);
assert_eq!(summary.messages, 1);
assert_eq!(summary.failures, 1);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Reply(1),
Step::Recv,
Step::Handshake,
Step::Hello,
Step::ReplyReplay,
Step::Recv,
]);
assert!(!summary.established);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.messages, 1);
assert_eq!(summary.failures, 1);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::ReplyTampered,
Step::Recv,
]);
assert!(!summary.established);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Junk(vec![7]),
Step::Recv,
]);
assert!(!summary.established);
let summary = run_logged(&[Step::Handshake, Step::Hello, Step::Hello, Step::Recv]);
assert!(!summary.established);
let summary = run_logged(&[Step::Handshake, Step::Hello, Step::Undecodable, Step::Recv]);
assert!(!summary.established);
}
#[test]
fn test_scripted_dropped_signal() {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Dropped,
Step::Recv,
Step::Send(1),
Step::Handshake,
Step::Hello,
Step::Send(2),
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.resets, 1);
assert_eq!(summary.failures, 0);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Dropped,
Step::Send(1),
Step::Recv,
Step::Send(2),
]);
assert!(!summary.established);
assert_eq!(summary.resets, 1);
assert_eq!(summary.failures, 0);
let summary = run_logged(&[Step::Dropped, Step::Recv]);
assert_eq!(summary.resets, 0);
assert_eq!(summary.failures, 1);
assert_eq!(summary.reads, 0);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Dropped,
Step::Dropped,
Step::Recv,
Step::Recv,
]);
assert!(!summary.established);
assert_eq!(summary.resets, 1);
assert_eq!(summary.failures, 1);
}
#[test]
fn test_scripted_recv_without_session() {
let summary = run_logged(&[Step::Junk(vec![1]), Step::Recv]);
assert_eq!(summary.failures, 1);
assert_eq!(summary.reads, 0);
let summary = run_logged(&[Step::Undecodable, Step::Recv]);
assert_eq!(summary.failures, 1);
assert_eq!(summary.reads, 0);
let summary = run_logged(&[Step::Recv]);
assert_eq!(summary.failures, 1);
assert_eq!(summary.reads, 0);
let summary = run_logged(&[Step::Send(1)]);
assert_eq!(summary.failures, 0);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Undecodable,
Step::Recv,
Step::Junk(vec![1]),
Step::Recv,
Step::Handshake,
Step::Hello,
Step::Reply(1),
Step::Recv,
]);
assert!(summary.established);
assert_eq!(summary.failures, 2);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.messages, 1);
}
#[test]
fn test_scripted_read_failure_drops_session() {
let summary = run_logged(&[Step::Handshake, Step::Hello, Step::Recv, Step::Send(1)]);
assert!(!summary.established);
assert_eq!(summary.failures, 1);
let summary = run_logged(&[Step::Handshake, Step::Hello, Step::Recv]);
assert!(!summary.established);
assert_eq!(summary.failures, 1);
}
#[test]
fn test_scripted_broken_transport() {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Break,
Step::Send(1),
Step::Send(2),
Step::Handshake,
Step::Heal,
Step::Handshake,
Step::Hello,
Step::Send(3),
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.failures, 1);
let summary = run_logged(&[
Step::Handshake,
Step::Break,
Step::Hello,
Step::Heal,
Step::Handshake,
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 1);
assert_eq!(summary.failures, 1);
}
#[test]
fn test_scripted_cut_sends() {
for point in [
CutPoint::Start,
CutPoint::Middle(5),
CutPoint::Delimiter,
CutPoint::Flush,
] {
let cut = Step::Cut {
point,
then_broken: false,
};
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
cut.clone(),
Step::Send(1),
Step::Handshake,
Step::Hello,
Step::Send(2),
]);
assert!(summary.established, "{point:?}");
assert_eq!(summary.handshakes, 2, "{point:?}");
assert_eq!(summary.failures, 0, "{point:?}");
let summary = run_logged(&[cut.clone(), Step::Handshake, Step::Handshake, Step::Hello]);
assert!(summary.established, "{point:?}");
assert_eq!(summary.handshakes, 1, "{point:?}");
assert_eq!(summary.failures, 1, "{point:?}");
let summary = run_logged(&[
Step::Handshake,
cut,
Step::Hello,
Step::Handshake,
Step::Hello,
]);
assert!(summary.established, "{point:?}");
assert_eq!(summary.handshakes, 1, "{point:?}");
assert_eq!(summary.failures, 1, "{point:?}");
}
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Cut {
point: CutPoint::Middle(5),
then_broken: true,
},
Step::Send(1),
Step::Handshake,
Step::Heal,
Step::Handshake,
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.failures, 1);
}
#[test]
fn test_scripted_consecutive_handshake_failures() {
for timeout in [false, true] {
for point in [
CutPoint::Middle(5),
CutPoint::Start,
CutPoint::Middle(0),
CutPoint::Middle(u16::MAX),
CutPoint::Delimiter,
CutPoint::Flush,
] {
let fault = |point| {
if timeout {
Step::Timeout(point)
} else {
Step::Cut {
point,
then_broken: false,
}
}
};
let summary = run_logged(&[
fault(CutPoint::Middle(5)),
Step::Handshake,
fault(point),
Step::Handshake,
Step::Handshake,
Step::Hello,
Step::Send(1),
Step::Reply(1),
Step::Recv,
]);
assert!(summary.established, "{point:?}, timeout: {timeout}");
assert_eq!(summary.handshakes, 1, "{point:?}, timeout: {timeout}");
assert_eq!(summary.messages, 1, "{point:?}, timeout: {timeout}");
assert_eq!(summary.failures, 2, "{point:?}, timeout: {timeout}");
}
}
}
#[test]
fn test_scripted_chunked_reads() {
for chunk in [1u8, 7, 254, 255] {
let summary = run_logged(&[
Step::Chunk(chunk),
Step::Handshake,
Step::Hello,
Step::Send(1),
Step::Reply(1),
Step::Recv,
Step::Junk(vec![1; 300]),
Step::Recv,
Step::Handshake,
Step::Hello,
]);
assert!(summary.established, "chunk {chunk}");
assert_eq!(summary.messages, 1, "chunk {chunk}");
assert_eq!(summary.handshakes, 2, "chunk {chunk}");
}
}
#[test]
fn test_scripted_batched_reads() {
let summary = run_logged(&[
Step::Handshake,
Step::Batch(3),
Step::Dropped,
Step::Junk(vec![1]),
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.reads, 1);
let summary = run_logged(&[
Step::Handshake,
Step::Batch(2),
Step::Undecodable,
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.reads, 1);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Send(1),
Step::Send(2),
Step::Batch(2),
Step::Reply(1),
Step::Reply(2),
Step::Recv,
Step::Recv,
]);
assert!(summary.established);
assert_eq!(summary.messages, 2);
assert_eq!(summary.reads, 3);
for chunk in [1u8, 7] {
let summary = run_logged(&[
Step::Chunk(chunk),
Step::Handshake,
Step::Batch(3),
Step::Dropped,
Step::Junk(vec![1]),
Step::Hello,
Step::Send(1),
]);
assert!(summary.established, "chunk {chunk}");
}
}
#[test]
fn test_scripted_interrupted_frames() {
for cut in [0u8, 1, 7, 255] {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Handshake,
Step::Truncated(cut),
Step::Hello,
]);
assert!(summary.established, "cut {cut}");
assert_eq!(summary.handshakes, 2, "cut {cut}");
assert_eq!(summary.failures, 0, "cut {cut}");
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Send(1),
Step::Reply(1),
Step::Recv,
Step::Truncated(cut),
Step::Recv,
Step::Send(2),
]);
assert!(!summary.established, "cut {cut}");
assert_eq!(summary.messages, 1, "cut {cut}");
assert_eq!(summary.failures, 1, "cut {cut}");
}
let summary = run_logged(&[Step::Handshake, Step::Partial, Step::Dropped]);
assert!(summary.established);
assert_eq!(summary.reads, 2);
let summary = run_logged(&[
Step::Handshake,
Step::Partial,
Step::Junk(vec![1]),
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.failures, 0);
let summary = run_logged(&[
Step::Handshake,
Step::Partial,
Step::Partial,
Step::Dropped,
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.failures, 0);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Send(1),
Step::Partial,
Step::Reply(1),
Step::Recv,
Step::Send(2),
]);
assert!(!summary.established);
assert_eq!(summary.failures, 1);
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Partial,
Step::Dropped,
Step::Recv,
]);
assert!(!summary.established);
assert_eq!(summary.failures, 1);
for chunk in [1u8, 7] {
let summary = run_logged(&[
Step::Chunk(chunk),
Step::Handshake,
Step::Partial,
Step::Dropped,
]);
assert!(summary.established, "chunk {chunk}");
}
}
#[test]
fn test_scripted_interrupted_reads() {
let summary = run_logged(&[
Step::Handshake,
Step::Interrupt,
Step::Hello,
Step::Send(1),
Step::Recv,
Step::Interrupt,
Step::Reply(1),
]);
assert!(summary.established);
assert_eq!(summary.messages, 1);
assert_eq!(summary.failures, 0);
}
#[test]
fn test_scripted_read_timeouts() {
let summary = run_logged(&[
Step::Handshake,
Step::ReadTimeout,
Step::Hello,
Step::Retain,
Step::SendRetained(1),
Step::Recv,
Step::ReadTimeout,
Step::ReadTimeout,
Step::Reply(1),
Step::SendRetained(2),
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 1);
assert_eq!(summary.messages, 1);
assert_eq!(summary.failures, 0);
}
#[test]
fn test_scripted_handshake_timeouts() {
for point in [
CutPoint::Start,
CutPoint::Middle(7),
CutPoint::Delimiter,
CutPoint::Flush,
] {
let summary = run_logged(&[
Step::Timeout(point),
Step::Handshake,
Step::Handshake,
Step::Hello,
Step::Send(1),
Step::Recv,
Step::Reply(1),
]);
assert!(summary.established, "{point:?}");
assert_eq!(summary.handshakes, 1, "{point:?}");
assert_eq!(summary.messages, 1, "{point:?}");
assert_eq!(summary.failures, 1, "{point:?}");
}
}
#[test]
fn test_scripted_send_timeouts() {
for point in [
CutPoint::Start,
CutPoint::Middle(7),
CutPoint::Delimiter,
CutPoint::Flush,
] {
let summary = run_logged(&[
Step::Handshake,
Step::Hello,
Step::Retain,
Step::Timeout(point),
Step::Send(1),
Step::SendRetained(2),
Step::Handshake,
Step::Hello,
Step::SendRetained(3),
Step::Send(4),
Step::Recv,
Step::Reply(4),
]);
assert!(summary.established, "{point:?}");
assert_eq!(summary.handshakes, 2, "{point:?}");
assert_eq!(summary.messages, 1, "{point:?}");
assert_eq!(summary.failures, 0, "{point:?}");
}
}
#[test]
fn test_scripted_oversized_frames() {
let summary = run_logged(&[
Step::Handshake,
Step::Oversized,
Step::Hello,
Step::Retain,
Step::Send(1),
Step::Oversized,
Step::Reply(1),
Step::Recv,
Step::SendRetained(2),
Step::Recv,
Step::Handshake,
Step::Hello,
Step::SendRetained(3),
Step::Send(4),
Step::Reply(4),
Step::Recv,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 2);
assert_eq!(summary.messages, 1);
assert_eq!(summary.failures, 2);
}
#[test]
fn test_scripted_oversized_fragments() {
for chunk in [0, 255] {
let summary = run_logged(&[
Step::Chunk(chunk),
Step::Handshake,
Step::Batch(3),
Step::Partial,
Step::Oversized,
Step::Hello,
Step::Retain,
Step::Partial,
Step::Oversized,
Step::Recv,
Step::SendRetained(1),
Step::Recv,
Step::Dropped,
Step::Handshake,
Step::Hello,
Step::SendRetained(2),
Step::Send(3),
Step::Reply(3),
Step::Recv,
]);
assert!(summary.established, "chunk {chunk}");
assert_eq!(summary.handshakes, 2, "chunk {chunk}");
assert_eq!(summary.failures, 2, "chunk {chunk}");
assert_eq!(summary.resets, 0, "chunk {chunk}");
assert_eq!(summary.messages, 1, "chunk {chunk}");
}
}
#[test]
fn test_scripted_bytewise_oversized_frame() {
let summary = run_logged(&[
Step::Chunk(1),
Step::Handshake,
Step::Batch(3),
Step::Partial,
Step::Oversized,
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 1);
assert_eq!(summary.failures, 0);
assert!(summary.reads > MAX_FRAME_SIZE);
}
#[test]
fn test_scripted_oversized_stale_frames() {
for stale in [40, MAX_STEPS - 4] {
let mut steps = vec![Step::Handshake, Step::Batch(255), Step::Oversized];
steps.extend(std::iter::repeat_n(Step::Dropped, stale));
steps.push(Step::Hello);
let summary = run_logged(&steps);
assert!(summary.established, "stale {stale}");
assert_eq!(summary.handshakes, 1, "stale {stale}");
assert_eq!(summary.failures, 0, "stale {stale}");
}
}
#[test]
fn test_scripted_noops() {
let summary = run_logged(&[
Step::Yield,
Step::Interrupt,
Step::ReplyReplay,
Step::Truncated(3),
Step::Reply(1),
Step::Hello,
Step::Handshake,
Step::Hello,
]);
assert!(summary.established);
assert_eq!(summary.handshakes, 1);
}
#[test]
fn test_scripted_cut_survives_broken_handshake() {
let summary = run_logged(&[
Step::Cut {
point: CutPoint::Middle(100),
then_broken: true,
},
Step::Handshake,
Step::Heal,
Step::Handshake,
]);
assert_eq!(summary.handshakes, 0);
assert_eq!(summary.failures, 2);
}