use std::error::Error;
use liminal_protocol::wire::{
CommonStaleAuthorityEnvelope, ConnectionIncarnation, ServerValue, StaleAuthority,
};
use super::ProductionParticipantHandler;
use super::tests::{dispatch, open_disk_store_for_tests, test_participant_config};
use super::tests_receipts::{GEN_ONE, attach, attach_request, detach, enroll, generation};
#[test]
fn no_route_rebinds_to_a_lower_or_equal_generation() -> Result<(), Box<dyn Error>> {
let home = tempfile::tempdir()?;
let store = open_disk_store_for_tests(&home.path().join("durability"))?;
let handler = ProductionParticipantHandler::new(store, test_participant_config())?;
let conversation_id = 9051;
let earlier_connection = ConnectionIncarnation::new(905, 1);
let later_connection = ConnectionIncarnation::new(905, 2);
let receipt = enroll(&handler, later_connection, conversation_id, [21; 16])?;
let participant_id = receipt.participant_id();
detach(
&handler,
later_connection,
conversation_id,
participant_id,
GEN_ONE,
[22; 16],
)?;
let first = attach(
&handler,
later_connection,
attach_request(
conversation_id,
participant_id,
GEN_ONE,
receipt.attach_secret(),
[23; 16],
),
)?;
detach(
&handler,
later_connection,
conversation_id,
participant_id,
generation(2)?,
[24; 16],
)?;
let second = attach(
&handler,
earlier_connection,
attach_request(
conversation_id,
participant_id,
generation(2)?,
first.attach_secret(),
[25; 16],
),
)?;
let (first_epoch, second_epoch) = (first.origin_binding_epoch(), second.origin_binding_epoch());
assert_eq!(
(
first_epoch.capability_generation,
second_epoch.capability_generation
),
(generation(2)?, generation(3)?),
"each rebind is at exactly the next generation"
);
assert!(
second_epoch.connection_incarnation < first_epoch.connection_incarnation,
"the second rebind is on a connection opened before the first's: {second_epoch:?} against \
{first_epoch:?}"
);
detach(
&handler,
earlier_connection,
conversation_id,
participant_id,
generation(3)?,
[26; 16],
)?;
let current = generation(3)?;
for (presented, token) in [(GEN_ONE, [27; 16]), (generation(2)?, [28; 16])] {
let refused = dispatch(
&handler,
later_connection,
attach_request(
conversation_id,
participant_id,
presented,
first.attach_secret(),
token,
),
)?;
assert!(
matches!(
refused,
ServerValue::StaleAuthority(StaleAuthority::Live {
request: CommonStaleAuthorityEnvelope::CredentialAttach(_),
current_generation,
}) if current_generation == current
),
"R3b review row 11: an attach presenting generation {presented:?} below the current \
3 was not refused as stale: {refused:?}"
);
}
Ok(())
}