use crate::carrier::adapters::mock::{
EnvelopeShape, MockAdapter, NativeShape, NativeShapedMock, WasmShape, WasmShapedMock,
};
use crate::carrier::{
AttemptGeneration, AuthenticatedPeerBinding, Carrier, CarrierConnectFailureCause,
CarrierConnectFailureDisposition, CarrierConnectFailureStage, CarrierCounterSnapshot,
CarrierEstablishedCause, CarrierEvent, CarrierLostCause, CarrierMachineInput, CarrierRefusal,
CarrierSendOutcome, CarrierState, ConnectionId, ConnectionKey, EpisodeId, Incarnation,
MAX_CARRIER_FRAME_BYTES, OpaqueBytes, encode_frame,
};
#[derive(Clone, Copy, Debug)]
enum Vector {
LengthZero,
LengthOne,
LengthMaxMinusOne,
LengthMax,
LengthMaxPlusOne,
LengthU32Max,
PrefixZero,
PrefixOne,
PrefixTwo,
PrefixThree,
ShortBody,
TrailingBody,
ConcatenatedEnvelopes,
Ordering,
Duplicate,
StaleGeneration,
LateAfterLoss,
InitialDialFailure,
OpaqueRandomPayload,
CompressedLookingIdentity,
}
const ALL_VECTORS: [Vector; 20] = [
Vector::LengthZero,
Vector::LengthOne,
Vector::LengthMaxMinusOne,
Vector::LengthMax,
Vector::LengthMaxPlusOne,
Vector::LengthU32Max,
Vector::PrefixZero,
Vector::PrefixOne,
Vector::PrefixTwo,
Vector::PrefixThree,
Vector::ShortBody,
Vector::TrailingBody,
Vector::ConcatenatedEnvelopes,
Vector::Ordering,
Vector::Duplicate,
Vector::StaleGeneration,
Vector::LateAfterLoss,
Vector::InitialDialFailure,
Vector::OpaqueRandomPayload,
Vector::CompressedLookingIdentity,
];
#[derive(Debug, Eq, PartialEq)]
struct Outcome {
events: Vec<CarrierEvent>,
refusal: Option<CarrierRefusal>,
state: CarrierState,
counters: CarrierCounterSnapshot,
}
fn key() -> ConnectionKey {
ConnectionKey {
connection_id: ConnectionId::new([0x5a; 16]),
incarnation: Incarnation::new(12),
}
}
fn establish<S: EnvelopeShape>(adapter: &mut MockAdapter<S>) -> ConnectionKey {
adapter.apply(CarrierMachineInput::ExplicitAction);
let generation = adapter
.current_attempt()
.unwrap_or(AttemptGeneration::new(0));
let established_key = key();
adapter.apply(CarrierMachineInput::AttemptEstablished {
generation,
key: established_key,
authenticated_peer_binding: AuthenticatedPeerBinding::new(vec![0xa5, 0x5a]),
cause: CarrierEstablishedCause::ExplicitAction,
});
adapter.clear_events();
established_key
}
fn valid_payload(vector: Vector) -> Option<Vec<u8>> {
match vector {
Vector::LengthZero => Some(Vec::new()),
Vector::LengthOne => Some(vec![7]),
Vector::LengthMaxMinusOne => Some(vec![0x33; MAX_CARRIER_FRAME_BYTES - 1]),
Vector::LengthMax => Some(vec![0x44; MAX_CARRIER_FRAME_BYTES]),
Vector::OpaqueRandomPayload => Some(
(0_u16..=255)
.map(|value| ((value * 73 + 19) % 256) as u8)
.collect(),
),
Vector::CompressedLookingIdentity => Some(vec![
0x1f, 0x8b, 0x08, 0x00, 0x78, 0x9c, 0x28, 0xb5, 0x2f, 0xfd, 0xff, 0x00,
]),
Vector::LengthMaxPlusOne
| Vector::LengthU32Max
| Vector::PrefixZero
| Vector::PrefixOne
| Vector::PrefixTwo
| Vector::PrefixThree
| Vector::ShortBody
| Vector::TrailingBody
| Vector::ConcatenatedEnvelopes
| Vector::Ordering
| Vector::Duplicate
| Vector::StaleGeneration
| Vector::LateAfterLoss
| Vector::InitialDialFailure => None,
}
}
fn malformed_envelope(vector: Vector) -> Option<Vec<u8>> {
match vector {
Vector::LengthMaxPlusOne => Some(
u32::try_from(MAX_CARRIER_FRAME_BYTES + 1)
.unwrap_or(u32::MAX)
.to_be_bytes()
.to_vec(),
),
Vector::LengthU32Max => Some(u32::MAX.to_be_bytes().to_vec()),
Vector::PrefixZero => Some(Vec::new()),
Vector::PrefixOne => Some(vec![0]),
Vector::PrefixTwo => Some(vec![0, 0]),
Vector::PrefixThree => Some(vec![0, 0, 0]),
Vector::ShortBody => Some(vec![0, 0, 0, 3, 1, 2]),
Vector::TrailingBody => Some(vec![0, 0, 0, 1, 7, 8]),
Vector::ConcatenatedEnvelopes => {
let first = encode_frame(&[1]).unwrap_or_default();
let second = encode_frame(&[2]).unwrap_or_default();
Some(first.into_iter().chain(second).collect())
}
Vector::LengthZero
| Vector::LengthOne
| Vector::LengthMaxMinusOne
| Vector::LengthMax
| Vector::Ordering
| Vector::Duplicate
| Vector::StaleGeneration
| Vector::LateAfterLoss
| Vector::InitialDialFailure
| Vector::OpaqueRandomPayload
| Vector::CompressedLookingIdentity => None,
}
}
fn run_vector<S: EnvelopeShape>(vector: Vector) -> Outcome {
let mut adapter = MockAdapter::<S>::new(EpisodeId::new(100));
let refusal = if let Some(payload) = valid_payload(vector) {
run_valid_frame(&mut adapter, &payload)
} else if let Some(envelope) = malformed_envelope(vector) {
run_malformed_frame(&mut adapter, &envelope)
} else {
run_lifecycle_vector(&mut adapter, vector);
None
};
Outcome {
events: adapter.events().to_vec(),
refusal,
state: adapter.state(),
counters: adapter.counters().snapshot(),
}
}
fn run_valid_frame<S: EnvelopeShape>(
adapter: &mut MockAdapter<S>,
payload: &[u8],
) -> Option<CarrierRefusal> {
let established_key = establish(adapter);
let encoded = encode_frame(payload).unwrap_or_default();
adapter.receive_envelope(established_key, &encoded).err()
}
fn run_malformed_frame<S: EnvelopeShape>(
adapter: &mut MockAdapter<S>,
envelope: &[u8],
) -> Option<CarrierRefusal> {
let established_key = establish(adapter);
let refusal = adapter.receive_envelope(established_key, envelope).err();
let event_count = adapter.events().len();
let valid = encode_frame(&[9]).unwrap_or_default();
assert_eq!(
adapter.receive_envelope(established_key, &valid).err(),
refusal
);
assert_eq!(adapter.events().len(), event_count);
refusal
}
fn run_lifecycle_vector<S: EnvelopeShape>(adapter: &mut MockAdapter<S>, vector: Vector) {
match vector {
Vector::Ordering => run_ordering(adapter),
Vector::Duplicate => {
let established_key = establish(adapter);
adapter.apply(CarrierMachineInput::EstablishedFate {
key: established_key,
cause: CarrierLostCause::CleanClose,
});
adapter.apply(CarrierMachineInput::EstablishedFate {
key: established_key,
cause: CarrierLostCause::TransportError,
});
}
Vector::StaleGeneration => {
adapter.apply(CarrierMachineInput::ExplicitAction);
let stale = adapter
.current_attempt()
.unwrap_or(AttemptGeneration::new(0));
adapter.apply(CarrierMachineInput::ExplicitAction);
adapter.clear_events();
adapter.apply(CarrierMachineInput::AttemptFailed {
generation: stale,
cause: CarrierConnectFailureCause::new(
CarrierConnectFailureStage::Dial,
CarrierConnectFailureDisposition::Park,
),
});
}
Vector::LateAfterLoss => {
let established_key = establish(adapter);
adapter.apply(CarrierMachineInput::EstablishedFate {
key: established_key,
cause: CarrierLostCause::TransportError,
});
let late = encode_frame(&[0xde, 0xad]).unwrap_or_default();
assert_eq!(adapter.receive_envelope(established_key, &late), Ok(()));
}
Vector::InitialDialFailure => {
adapter.apply(CarrierMachineInput::ExplicitAction);
let generation = adapter
.current_attempt()
.unwrap_or(AttemptGeneration::new(0));
adapter.apply(CarrierMachineInput::AttemptFailed {
generation,
cause: CarrierConnectFailureCause::new(
CarrierConnectFailureStage::Dial,
CarrierConnectFailureDisposition::Park,
),
});
}
Vector::LengthZero
| Vector::LengthOne
| Vector::LengthMaxMinusOne
| Vector::LengthMax
| Vector::LengthMaxPlusOne
| Vector::LengthU32Max
| Vector::PrefixZero
| Vector::PrefixOne
| Vector::PrefixTwo
| Vector::PrefixThree
| Vector::ShortBody
| Vector::TrailingBody
| Vector::ConcatenatedEnvelopes
| Vector::OpaqueRandomPayload
| Vector::CompressedLookingIdentity => {}
}
}
fn run_ordering<S: EnvelopeShape>(adapter: &mut MockAdapter<S>) {
let established_key = establish(adapter);
let first = encode_frame(&[1, 2]).unwrap_or_default();
let second = encode_frame(&[3, 4]).unwrap_or_default();
assert_eq!(adapter.receive_envelope(established_key, &first), Ok(()));
assert_eq!(adapter.receive_envelope(established_key, &second), Ok(()));
assert_eq!(
Carrier::send(adapter, established_key, OpaqueBytes::from(&[5, 6][..])),
CarrierSendOutcome::Accepted
);
assert_eq!(
Carrier::send(adapter, established_key, OpaqueBytes::from(&[7, 8][..])),
CarrierSendOutcome::Accepted
);
assert!(adapter.flush_one());
assert!(adapter.flush_one());
}
#[test]
fn native_and_wasm_shaped_mocks_run_identical_vectors() {
let _: Option<NativeShapedMock> = None;
let _: Option<WasmShapedMock> = None;
for vector in ALL_VECTORS {
let native = run_vector::<NativeShape>(vector);
let wasm = run_vector::<WasmShape>(vector);
assert_eq!(native, wasm, "parity vector {vector:?}");
}
}