use super::*;
use crate::protocol::schema::{
self, ArkToHost, DeviceInfoRequest, HostToArk, ark_to_host, host_to_ark,
};
#[test]
fn test_input_format() {
for input in [&[][..], &[0], &[1]] {
assert!(!run(input));
}
let bytes = ArkToHost {
id: 2,
err: None,
content: Some(ark_to_host::Content::RelayFail(Default::default())),
}
.encode_to_vec();
for direction in [0, 1, 254, 255] {
let mut input = vec![direction];
input.extend_from_slice(&bytes);
assert_eq!(run(&input), direction & 1 != 0);
input.push(0x80);
assert!(!run(&input));
}
}
#[test]
fn test_envelope_shapes() {
struct TestCase {
client: bool,
bytes: Vec<u8>,
accepted: bool,
}
let error = schema::Error {
code: 7,
msg: "refused".into(),
};
let tests = [
TestCase {
client: false,
bytes: HostToArk {
id: 3,
err: None,
content: Some(host_to_ark::Content::DeviceInfo(DeviceInfoRequest {})),
}
.encode_to_vec(),
accepted: true,
},
TestCase {
client: false,
bytes: HostToArk {
id: 0,
err: None,
content: Some(host_to_ark::Content::Develop(vec![1, 2, 3])),
}
.encode_to_vec(),
accepted: true,
},
TestCase {
client: true,
bytes: ArkToHost {
id: u64::MAX,
err: None,
content: Some(ark_to_host::Content::Onboard(
crate::protocol::schema::OnboardingResponse {},
)),
}
.encode_to_vec(),
accepted: true,
},
TestCase {
client: true,
bytes: ArkToHost {
id: u64::MAX - 1,
err: Some(error.clone()),
content: None,
}
.encode_to_vec(),
accepted: true,
},
TestCase {
client: false,
bytes: HostToArk {
id: 1,
err: Some(error),
content: Some(host_to_ark::Content::Develop(vec![4])),
}
.encode_to_vec(),
accepted: false,
},
TestCase {
client: false,
bytes: HostToArk {
id: 2,
err: None,
content: None,
}
.encode_to_vec(),
accepted: false,
},
TestCase {
client: true,
bytes: vec![0x80],
accepted: false,
},
TestCase {
client: true,
bytes: Vec::new(),
accepted: false,
},
];
for (i, tt) in tests.iter().enumerate() {
let mut input = vec![u8::from(tt.client)];
input.extend_from_slice(&tt.bytes);
assert_eq!(run(&input), tt.accepted, "test {i}");
}
}
#[test]
fn test_envelope_normalization() {
for client in [false, true] {
let (side, peer, content) = if client {
(
Side::Client,
Side::Server,
ArkToHost {
id: 0,
err: None,
content: Some(ark_to_host::Content::Develop(vec![1, 2])),
}
.encode_to_vec(),
)
} else {
(
Side::Server,
Side::Client,
HostToArk {
id: 0,
err: None,
content: Some(host_to_ark::Content::Develop(vec![1, 2])),
}
.encode_to_vec(),
)
};
for prefix in [
&[0x08, 0x81, 0x00][..], &[0x08, 0x02, 0x08, 0x01], &[0x08, 0x01, 0x78, 0x2a], ] {
let mut bytes = prefix.to_vec();
bytes.extend_from_slice(&content);
let (id, body) = side.decode(&bytes).unwrap();
assert_eq!(id, 1);
assert_eq!(body, Ok(crate::protocol::Message::Develop(vec![1, 2])));
assert!(peer.encode(id, body).unwrap().len() < bytes.len());
let mut input = vec![u8::from(client)];
input.extend_from_slice(&bytes);
assert!(run(&input));
}
}
}
#[test]
fn test_encoded_size_boundaries() {
fn envelope(client: bool, id: u64, len: usize, error: bool) -> Vec<u8> {
let err = error.then(|| schema::Error {
code: u64::MAX,
msg: "x".repeat(len),
});
let content = (!error).then(|| vec![0x42; len]);
match client {
true => ArkToHost {
id,
err,
content: content.map(ark_to_host::Content::Develop),
}
.encode_to_vec(),
false => HostToArk {
id,
err,
content: content.map(host_to_ark::Content::Develop),
}
.encode_to_vec(),
}
}
for client in [false, true] {
for id in [0, 127, 128, u64::MAX] {
for error in [false, true] {
let len = MAX_MESSAGE_SIZE - 64;
let overhead = envelope(client, id, len, error).len() - len;
for size in [MAX_MESSAGE_SIZE - 1, MAX_MESSAGE_SIZE, MAX_MESSAGE_SIZE + 1] {
let bytes = envelope(client, id, size - overhead, error);
assert_eq!(bytes.len(), size);
assert!(check(client, &bytes));
}
}
}
}
}
#[test]
fn test_opaque_header_defers_nested_validation() {
for client in [false, true] {
let side = if client { Side::Client } else { Side::Server };
for error in [false, true] {
let bytes = malformed_body(client, u64::MAX, error);
let header = side.decode_header(bytes.clone().into()).unwrap();
assert_eq!(header.id, u64::MAX);
assert_eq!(header.failed, error);
let mut input = vec![u8::from(client)];
input.extend(bytes);
assert!(!run(&input));
}
}
}