use crate::wire::{
AttachAttemptToken, AttachSecret, ClientDiscriminant, ClientRequest, CredentialAttachRequest,
DetachAttemptToken, DetachRequest, EnrollmentRequest, EnrollmentSettlementBackpressure,
EnrollmentToken, Generation, MarkerSettlementBackpressure, RecordAdmission,
RecordAdmissionAttemptToken, ServerValue,
};
type TestResult<T = ()> = Result<T, &'static str>;
const CONVERSATION: u64 = 10;
const PARTICIPANT: u64 = 20;
fn generation() -> TestResult<Generation> {
Generation::new(7).ok_or("generation must be nonzero")
}
fn attach_request() -> TestResult<ClientRequest> {
Ok(ClientRequest::CredentialAttach(CredentialAttachRequest {
conversation_id: CONVERSATION,
participant_id: PARTICIPANT,
capability_generation: generation()?,
attach_secret: AttachSecret::new([5; 32]),
attach_attempt_token: AttachAttemptToken::new([2; 16]),
accept_marker_delivery_seq: None,
}))
}
fn detach_request() -> TestResult<ClientRequest> {
Ok(ClientRequest::Detach(DetachRequest {
conversation_id: CONVERSATION,
participant_id: PARTICIPANT,
capability_generation: generation()?,
detach_attempt_token: DetachAttemptToken::new([3; 16]),
}))
}
fn enrollment_request() -> ClientRequest {
ClientRequest::Enrollment(EnrollmentRequest {
conversation_id: CONVERSATION,
enrollment_token: EnrollmentToken::new([1; 16]),
})
}
fn record_request(token: RecordAdmissionAttemptToken) -> TestResult<ClientRequest> {
Ok(ClientRequest::RecordAdmission(RecordAdmission {
conversation_id: CONVERSATION,
participant_id: PARTICIPANT,
capability_generation: generation()?,
record_admission_attempt_token: token,
payload: alloc::vec![1, 2, 3],
}))
}
#[test]
fn record_admission_body_conflict_correlates_to_its_own_request() -> TestResult {
let token = RecordAdmissionAttemptToken::new([0xA7; 16]);
let value = ServerValue::AttemptTokenBodyConflict(
crate::wire::AttemptTokenBodyConflict::RecordAdmission {
token,
conversation_id: CONVERSATION,
presented_participant_id: PARTICIPANT,
presented_generation: generation()?,
},
);
assert!(super::correlation::matches_request(
&value,
&record_request(token)?
));
assert!(super::correlation::same_identity(
&value,
&record_request(token)?
));
assert!(!super::correlation::matches_request(
&value,
&record_request(RecordAdmissionAttemptToken::new([0xB8; 16]))?
));
Ok(())
}
#[test]
fn settlement_refusals_correlate_to_their_own_pending_request() -> TestResult {
let cases: [(ServerValue, ClientRequest, ClientDiscriminant); 3] = [
(
ServerValue::MarkerSettlementBackpressure(
MarkerSettlementBackpressure::CredentialAttach {
conversation_id: CONVERSATION,
refused_epoch: 111,
},
),
attach_request()?,
ClientDiscriminant::CredentialAttachRequest,
),
(
ServerValue::MarkerSettlementBackpressure(MarkerSettlementBackpressure::Detach {
conversation_id: CONVERSATION,
refused_epoch: 111,
}),
detach_request()?,
ClientDiscriminant::DetachRequest,
),
(
ServerValue::EnrollmentSettlementBackpressure(EnrollmentSettlementBackpressure {
conversation_id: CONVERSATION,
}),
enrollment_request(),
ClientDiscriminant::EnrollmentRequest,
),
];
for (value, request, family) in cases {
assert_eq!(value.originating_request(), Some(family));
assert_eq!(request.discriminant(), family);
assert!(
super::correlation::matches_request(&value, &request),
"a settlement refusal must correlate to its own pending {family:?}"
);
assert!(!super::correlation::same_identity(&value, &request));
}
Ok(())
}
#[test]
fn a_settlement_refusal_correlates_to_no_other_conversation_or_family() -> TestResult {
const OTHER_CONVERSATION: u64 = CONVERSATION + 1;
let attach_row =
ServerValue::MarkerSettlementBackpressure(MarkerSettlementBackpressure::CredentialAttach {
conversation_id: OTHER_CONVERSATION,
refused_epoch: 111,
});
assert!(!super::correlation::matches_request(
&attach_row,
&attach_request()?
));
let detach_row =
ServerValue::MarkerSettlementBackpressure(MarkerSettlementBackpressure::Detach {
conversation_id: CONVERSATION,
refused_epoch: 111,
});
assert!(!super::correlation::matches_request(
&detach_row,
&attach_request()?
));
let same_conversation_attach_row =
ServerValue::MarkerSettlementBackpressure(MarkerSettlementBackpressure::CredentialAttach {
conversation_id: CONVERSATION,
refused_epoch: 111,
});
assert!(!super::correlation::matches_request(
&same_conversation_attach_row,
&detach_request()?
));
let enrollment_row =
ServerValue::EnrollmentSettlementBackpressure(EnrollmentSettlementBackpressure {
conversation_id: CONVERSATION,
});
assert!(!super::correlation::matches_request(
&enrollment_row,
&attach_request()?
));
assert!(!super::correlation::matches_request(
&enrollment_row,
&record_request(RecordAdmissionAttemptToken::new([0xC9; 16]))?
));
assert!(super::correlation::matches_request(
&enrollment_row,
&enrollment_request()
));
Ok(())
}
#[test]
fn the_settlement_retry_discipline_does_not_extend_the_195_orphan_window() -> TestResult {
let row =
ServerValue::MarkerSettlementBackpressure(MarkerSettlementBackpressure::CredentialAttach {
conversation_id: CONVERSATION,
refused_epoch: 111,
});
assert!(super::correlation::matches_request(
&row,
&attach_request()?
));
assert!(!super::correlation::same_identity(&row, &attach_request()?));
assert_eq!(
row.originating_request(),
Some(ClientDiscriminant::CredentialAttachRequest)
);
Ok(())
}