use super::super::device_bindings::DeviceBindingTable;
use super::*;
const GROUPS: [[u8; 6]; 2] = [[224, 0, 0, 1, 0xBA, 0xC0], [127, 255, 255, 255, 0xBA, 0xC1]];
const PEER: [u8; 6] = [127, 0, 0, 1, 0xBA, 0xC1];
const THIS_NETWORK: u16 = 7;
const GROUP_PEER: u32 = 60;
const GROUP_ROUTER: u32 = 61;
const GROUP_FINAL: u32 = 62;
const ROUTER: [u8; 6] = [127, 0, 0, 3, 0xBA, 0xC0];
fn group_transport() -> (TestTransport, SendLog) {
let mut builder = TestTransport::builder()
.local_mac(&BIP_LOCAL_MAC)
.broadcast_mac(LITERAL_BROADCAST_MAC);
for group in GROUPS {
builder = builder.group_mac(&group);
}
let transport = builder.build();
let sent = transport.sent();
(transport, sent)
}
fn device(instance: u32) -> BACnetRecipient {
BACnetRecipient::Device(ObjectIdentifier::new(ObjectType::DEVICE, instance).unwrap())
}
fn group_bindings() -> Arc<RwLock<DeviceBindingTable>> {
let id = |instance| ObjectIdentifier::new(ObjectType::DEVICE, instance).unwrap();
let mut table = DeviceBindingTable::new();
for binding in [
DeviceBinding::local(id(GROUP_PEER), GROUPS[0]),
DeviceBinding::routed(id(GROUP_ROUTER), 700, [0x33], GROUPS[1]),
DeviceBinding::routed(id(GROUP_FINAL), THIS_NETWORK, GROUPS[0], ROUTER),
] {
table
.insert_configured(binding.unwrap(), |_| false)
.unwrap();
}
Arc::new(RwLock::new(table))
}
async fn distribute_one(
destination: BACnetDestination,
) -> (Vec<Bytes>, Vec<UnicastFrame>, EventNotificationCounters) {
let mut db = clocked_test_database();
let mut nc = NotificationClass::new(0, "NC-0").unwrap();
nc.add_destination(destination).unwrap();
db.add(Box::new(nc)).unwrap();
let (transport, sent) = group_transport();
let network = Arc::new(NetworkLayer::new(transport));
let state = bacnet_types::network_number::NetworkNumber::configured(THIS_NETWORK).unwrap();
network.local_network_number().publish(state);
distribute_counted_through(&network, &sent, db, group_bindings(), DccState::Enable).await
}
#[tokio::test(start_paused = true)]
async fn a_confirmed_recipient_at_a_group_address_gets_nothing_and_is_counted() {
let counted = EventNotificationCounters {
confirmed_broadcast_recipient: 1,
..Default::default()
};
for group in GROUPS {
for network in [0, THIS_NETWORK] {
let (broadcasts, unicasts, counters) =
distribute_one(destination_for(address_recipient(network, &group), true)).await;
assert!(
broadcasts.is_empty() && unicasts.is_empty(),
"{group:?} on {network}: nothing is sent"
);
assert_eq!(counters, counted, "{group:?} on {network}");
}
}
}
#[tokio::test(start_paused = true)]
async fn an_unconfirmed_recipient_at_a_group_address_is_sent_as_a_local_broadcast() {
for group in GROUPS {
for network in [0, THIS_NETWORK] {
let (broadcasts, unicasts, counters) =
distribute_one(destination_for(address_recipient(network, &group), false)).await;
assert_eq!(broadcasts.len(), 1, "{group:?} on {network}");
assert!(unicasts.is_empty(), "{group:?} on {network}");
assert_eq!(counters, EventNotificationCounters::default());
}
}
}
#[tokio::test(start_paused = true)]
async fn a_confirmed_recipient_at_a_station_is_still_sent_to() {
let (_, unicasts, counters) =
distribute_one(destination_for(address_recipient(0, &PEER), true)).await;
assert_eq!(unicasts.len(), 1);
assert_eq!(unicasts[0].0, PEER);
assert_eq!(counters, EventNotificationCounters::default());
}
#[tokio::test(start_paused = true)]
async fn a_device_bound_to_a_group_address_is_unroutable() {
let unroutable = EventNotificationCounters {
recipient_unroutable: 1,
..Default::default()
};
for instance in [GROUP_PEER, GROUP_ROUTER, GROUP_FINAL] {
for confirmed in [false, true] {
let (broadcasts, unicasts, counters) =
distribute_one(destination_for(device(instance), confirmed)).await;
assert!(
broadcasts.is_empty() && unicasts.is_empty(),
"Device {instance}, confirmed {confirmed}"
);
assert_eq!(
counters, unroutable,
"Device {instance}, confirmed {confirmed}"
);
}
}
}