use super::*;
use bacnet_services::cov::SubscribeCOVPropertyRequest;
use bacnet_services::cov_multiple::{
COVReference, COVSubscriptionSpecification, SubscribeCOVPropertyMultipleRequest,
};
use bacnet_types::constructed::PropertyReference;
#[tokio::test]
async fn subscribe_initial_and_resub_ack_precede_notification_and_cancel_is_quiet() {
let fixture = DispatchFixture::new(life_safety_db(), []).await;
let encode_request = |confirmed: Option<bool>, lifetime: Option<u32>| {
let request = SubscribeCOVPropertyRequest {
subscriber_process_identifier: 12,
monitored_object_identifier: point_oid(),
issue_confirmed_notifications: confirmed,
lifetime,
monitored_property_identifier: PropertyIdentifier::SILENCED,
monitored_property_array_index: None,
cov_increment: None,
};
let mut encoded = BytesMut::new();
request.encode(&mut encoded).unwrap();
encoded.freeze()
};
for (invoke_id, confirmed, lifetime, expected_frames) in [
(1, Some(false), Some(300), 2),
(2, Some(false), Some(600), 2),
(3, None, None, 1),
] {
fixture
.dispatch(
invoke_id,
ConfirmedServiceChoice::SUBSCRIBE_COV_PROPERTY,
encode_request(confirmed, lifetime),
)
.await;
let apdus = fixture.take_apdus();
assert_eq!(apdus.len(), expected_frames);
assert!(matches!(apdus[0], Apdu::SimpleAck(_)));
if expected_frames == 2 {
assert_eq!(
single_properties(&apdus[1]),
vec![
PropertyIdentifier::SILENCED,
PropertyIdentifier::STATUS_FLAGS,
]
);
}
}
}
fn multiple_request(lifetime: Option<u32>, max_notification_delay: Option<u32>) -> Bytes {
let request = SubscribeCOVPropertyMultipleRequest {
subscriber_process_identifier: 13,
issue_confirmed_notifications: false,
lifetime,
max_notification_delay,
list_of_cov_subscription_specifications: vec![COVSubscriptionSpecification {
monitored_object_identifier: point_oid(),
list_of_cov_references: vec![COVReference {
monitored_property: PropertyReference {
property_identifier: PropertyIdentifier::SILENCED,
property_array_index: None,
},
cov_increment: None,
timestamped: false,
}],
}],
};
let mut encoded = BytesMut::new();
request.encode(&mut encoded).unwrap();
encoded.freeze()
}
#[tokio::test]
async fn multiple_initial_and_resub_ack_precede_payload_and_cancel_is_quiet() {
let fixture = DispatchFixture::new(life_safety_db(), []).await;
for (invoke_id, lifetime, delay, expected_frames) in [
(4, Some(300), Some(10), 2),
(5, Some(600), Some(10), 2),
(6, None, None, 1),
] {
fixture
.dispatch(
invoke_id,
ConfirmedServiceChoice::SUBSCRIBE_COV_PROPERTY_MULTIPLE,
multiple_request(lifetime, delay),
)
.await;
let apdus = fixture.take_apdus();
assert_eq!(apdus.len(), expected_frames);
assert!(matches!(apdus[0], Apdu::SimpleAck(_)));
if expected_frames == 2 {
let Apdu::UnconfirmedRequest(notification) = &apdus[1] else {
panic!("expected unconfirmed COVNotificationMultiple");
};
let notification =
COVNotificationMultipleRequest::decode(¬ification.service_request).unwrap();
let properties: Vec<_> = notification.list_of_cov_notifications[0]
.list_of_values
.iter()
.map(|value| value.property_identifier)
.collect();
assert_eq!(
properties,
vec![
PropertyIdentifier::SILENCED,
PropertyIdentifier::STATUS_FLAGS,
]
);
}
}
assert!(fixture.cov_table.read().await.is_empty());
}
#[path = "property_parameters.rs"]
mod property_parameters;
#[path = "ordinary_parameters.rs"]
mod ordinary_parameters;
#[tokio::test]
async fn initial_single_and_multiple_life_safety_payloads_include_one_status_flags() {
let single = subscription(
Some(PropertyIdentifier::OPERATION_EXPECTED),
CovNotificationKind::Single,
1,
);
let mut multiple = subscription(
Some(PropertyIdentifier::SILENCED),
CovNotificationKind::Multiple,
2,
);
multiple.subscriber_mac = single.subscriber_mac.clone();
let fixture = ExactFixture::new([single.clone(), multiple.clone()]).await;
let (single, multiple) = {
let table = fixture.cov_table.read().await;
(
table
.get_subscription(&single.key().unwrap())
.unwrap()
.clone(),
table
.get_subscription(&multiple.key().unwrap())
.unwrap()
.clone(),
)
};
BACnetServer::<TestTransport>::fire_initial_cov_notification(
&crate::server::cov_notify_context::CovNotifyContext {
db: &fixture.db,
network: &fixture.network,
cov_table: &fixture.cov_table,
cov_in_flight: &fixture.cov_in_flight,
notification_transactions: &fixture.transactions,
comm_state: &fixture.comm_state,
config: &Arc::default(),
},
&single,
)
.await;
BACnetServer::<TestTransport>::fire_initial_cov_notification_multiple(
&crate::server::cov_notify_context::CovNotifyContext {
db: &fixture.db,
network: &fixture.network,
cov_table: &fixture.cov_table,
cov_in_flight: &fixture.cov_in_flight,
notification_transactions: &fixture.transactions,
comm_state: &fixture.comm_state,
config: &Arc::default(),
},
&[multiple],
)
.await;
let apdus = fixture.take_apdus();
assert_eq!(apdus.len(), 2);
assert_eq!(
single_properties(&apdus[0]),
vec![
PropertyIdentifier::OPERATION_EXPECTED,
PropertyIdentifier::STATUS_FLAGS,
]
);
let Apdu::UnconfirmedRequest(request) = &apdus[1] else {
panic!("expected unconfirmed multiple notification");
};
let notification = COVNotificationMultipleRequest::decode(&request.service_request).unwrap();
let properties: Vec<_> = notification.list_of_cov_notifications[0]
.list_of_values
.iter()
.map(|value| value.property_identifier)
.collect();
assert_eq!(
properties,
vec![
PropertyIdentifier::SILENCED,
PropertyIdentifier::STATUS_FLAGS,
]
);
}