use super::announce::handle_announce;
use super::*;
use crate::destination::link::{LinkEvent, LinkEventData, LinkPayload};
use crate::destination::{DestinationName, SingleInputDestination};
use crate::identity::PrivateIdentity;
use crate::packet::{Header, HeaderType};
use rand_core::OsRng;
use tokio::time::{timeout, Duration};
#[tokio::test]
async fn link_payload_is_forwarded_to_received_data() {
let identity = PrivateIdentity::new_from_rand(OsRng);
let config = TransportConfig::new("test", &identity, true);
let transport = Transport::new(config);
let mut rx = transport.received_data_events();
let address_hash = AddressHash::new_from_rand(OsRng);
let payload = LinkPayload::new_from_slice(b"hello");
let _ = transport.link_in_event_tx.send(LinkEventData {
id: AddressHash::new_from_rand(OsRng),
address_hash,
event: LinkEvent::Data(Box::new(payload)),
});
let received = timeout(Duration::from_millis(200), rx.recv())
.await
.expect("expected forwarded payload")
.expect("broadcast receive");
assert_eq!(received.destination, address_hash);
assert_eq!(received.data.as_slice(), b"hello");
}
#[tokio::test]
async fn drop_duplicates() {
let mut config: TransportConfig = Default::default();
config.set_retransmit(true);
let transport = Transport::new(config);
let handler = transport.get_handler();
let _source1 = AddressHash::new_from_slice(&[1u8; 32]);
let _source2 = AddressHash::new_from_slice(&[2u8; 32]);
let next_hop_iface = AddressHash::new_from_slice(&[3u8; 32]);
let destination = AddressHash::new_from_slice(&[4u8; 32]);
let mut announce: Packet = Default::default();
announce.header.header_type = HeaderType::Type2;
announce.header.packet_type = PacketType::Announce;
announce.header.hops = 3;
announce.transport = Some(destination);
assert!(
handler
.lock()
.await
.filter_duplicate_packets(&announce)
.await
);
handle_announce(&announce, handler.lock().await, next_hop_iface).await;
let data_packet: Packet = Packet {
data: PacketDataBuffer::new_from_slice(b"foo"),
destination,
..Default::default()
};
let duplicate: Packet = data_packet;
let mut different_packet = data_packet;
different_packet.data = PacketDataBuffer::new_from_slice(b"bar");
assert!(
handler
.lock()
.await
.filter_duplicate_packets(&data_packet)
.await
);
assert!(
!handler
.lock()
.await
.filter_duplicate_packets(&duplicate)
.await
);
assert!(
handler
.lock()
.await
.filter_duplicate_packets(&different_packet)
.await
);
tokio::time::sleep(Duration::from_secs(2)).await;
handler
.lock()
.await
.packet_cache
.lock()
.await
.release(Duration::from_secs(1));
assert!(
handler
.lock()
.await
.filter_duplicate_packets(&duplicate)
.await
);
}
#[tokio::test]
async fn announce_retransmit_key_uses_destination_hash() {
let local_identity = PrivateIdentity::new_from_rand(OsRng);
let mut config = TransportConfig::new("test", &local_identity, true);
config.set_retransmit(true);
let transport = Transport::new(config);
let handler = transport.get_handler();
let remote_identity = PrivateIdentity::new_from_rand(OsRng);
let mut remote_destination =
SingleInputDestination::new(remote_identity, DestinationName::new("lxmf", "delivery"));
let announce = remote_destination
.announce(OsRng, None)
.expect("valid announce packet");
let announced_destination = announce.destination;
let announced_identity = *remote_destination.identity.address_hash();
assert_ne!(
announced_destination, announced_identity,
"destination hash must differ from identity hash for named destinations"
);
let iface = AddressHash::new_from_rand(OsRng);
handle_announce(&announce, handler.lock().await, iface).await;
let mut guard = handler.lock().await;
let transport_id = *guard.config.identity.address_hash();
let keyed_by_destination = guard
.announce_table
.new_packet(&announced_destination, &transport_id);
assert!(
keyed_by_destination.is_some(),
"announce retransmit should be keyed by destination hash"
);
let keyed_by_identity = guard
.announce_table
.new_packet(&announced_identity, &transport_id);
assert!(
keyed_by_identity.is_none(),
"identity hash must not be used as announce retransmit key"
);
}
#[tokio::test]
async fn send_packet_with_outcome_reports_missing_identity() {
let identity = PrivateIdentity::new_from_rand(OsRng);
let config = TransportConfig::new("test", &identity, true);
let transport = Transport::new(config);
let packet = Packet {
destination: AddressHash::new_from_rand(OsRng),
..Default::default()
};
let outcome = transport.send_packet_with_outcome(packet).await;
assert_eq!(
outcome,
SendPacketOutcome::DroppedMissingDestinationIdentity
);
}
#[tokio::test]
async fn send_packet_with_outcome_reports_no_route() {
let identity = PrivateIdentity::new_from_rand(OsRng);
let config = TransportConfig::new("test", &identity, false);
let transport = Transport::new(config);
let packet = Packet {
header: Header {
packet_type: PacketType::Data,
..Default::default()
},
context: PacketContext::KeepAlive,
data: PacketDataBuffer::new_from_slice(&[KEEP_ALIVE_REQUEST]),
destination: AddressHash::new_from_rand(OsRng),
..Default::default()
};
let outcome = transport.send_packet_with_outcome(packet).await;
assert_eq!(outcome, SendPacketOutcome::DroppedNoRoute);
}
#[tokio::test]
async fn send_packet_with_outcome_broadcasts_announce_without_route() {
let identity = PrivateIdentity::new_from_rand(OsRng);
let config = TransportConfig::new("test", &identity, false);
let transport = Transport::new(config);
let packet = Packet {
header: Header {
packet_type: PacketType::Announce,
..Default::default()
},
destination: AddressHash::new_from_rand(OsRng),
..Default::default()
};
let outcome = transport.send_packet_with_outcome(packet).await;
assert_eq!(outcome, SendPacketOutcome::SentBroadcast);
}