#![cfg(feature = "der")]
use std::{sync::Arc, time::Duration};
use sep2_client::{
client::Client,
device::SEDevice,
event::{EIStatus, EventCallback, EventInstance, Schedule, Scheduler},
time::current_time,
};
use sep2_common::{
packages::{
der::{DERControl, DERProgram},
identification::ResponseStatus,
objects::EventStatusType,
primitives::{HexBinary128, Int64, Uint32},
types::{DeviceCategoryType, PrimacyType},
},
traits::SEIdentifiedObject,
};
use tokio::sync::RwLock;
fn test_setup() -> (Schedule<DERControl>, DERControlHandler) {
let client = Client::new_https(
"https://127.0.0.1:1337",
"../certs/client_cert.pem",
"../certs/client_private_key.pem",
"../certs/rootCA.pem",
None,
None,
)
.unwrap();
let device =
SEDevice::new_from_cert("../certs/client_cert.pem", DeviceCategoryType::all()).unwrap();
let handler = DERControlHandler {
logs: Arc::new(RwLock::new(vec![])),
};
(
Schedule::new(
client,
Arc::new(RwLock::new(device)),
handler.clone(),
Duration::from_secs(0),
),
handler,
)
}
#[derive(Clone)]
struct DERControlHandler {
logs: Arc<RwLock<Vec<String>>>,
}
impl EventCallback<DERControl> for DERControlHandler {
async fn event_update(&self, event: &EventInstance<DERControl>) -> ResponseStatus {
let log = match event.status() {
EIStatus::Scheduled => {
format!("Received DERControl: {}", event.event().mrid().0)
}
EIStatus::Active => {
format!("DERControl Started: {}", event.event().mrid().0)
}
EIStatus::Cancelled => {
format!("DERControl Cancelled: {}", event.event().mrid().0)
}
EIStatus::Complete => {
format!("DERControl Complete: {}", event.event().mrid().0)
}
EIStatus::CancelledRandom => {
format!("DERControl Cancelled: {}", event.event().mrid().0)
}
EIStatus::Superseded => {
format!("DERControl Superseded: {}", event.event().mrid().0)
}
};
log::debug!("{log}");
self.logs.write().await.push(log);
event.status().into()
}
}
fn create_event(status: EventStatusType, count: i64, start: i64, duration: u32) -> DERControl {
let mut out = DERControl::default();
out.mrid = HexBinary128(count.try_into().unwrap());
out.creation_time = Int64(count);
out.event_status.current_status = status;
out.interval.start = Int64(start);
out.interval.duration = Uint32(duration);
out
}
#[tokio::test]
async fn basic_der_scheduler() {
let program = DERProgram::default();
let (mut schedule, logs) = test_setup();
let first = create_event(
EventStatusType::Scheduled,
1,
i64::from(current_time()) + 1,
2,
);
let second = create_event(
EventStatusType::Scheduled,
2,
i64::from(current_time()) + 4,
2,
);
let third = create_event(
EventStatusType::Scheduled,
3,
i64::from(current_time()) + 7,
2,
);
schedule.add_event(second, &program, 0).await;
schedule.add_event(third, &program, 0).await;
schedule.add_event(first, &program, 0).await;
tokio::time::sleep(Duration::from_secs(10)).await;
assert_eq!(
logs.logs.read().await.as_ref(),
vec![
"DERControl Started: 1",
"DERControl Complete: 1",
"DERControl Started: 2",
"DERControl Complete: 2",
"DERControl Started: 3",
"DERControl Complete: 3"
]
);
}
#[tokio::test]
async fn superseded_der_scheduler() {
let program = DERProgram::default();
let (mut schedule, logs) = test_setup();
let superseded = create_event(
EventStatusType::Scheduled,
0,
i64::from(current_time()) + 2,
1,
);
let first = create_event(
EventStatusType::Scheduled,
1,
i64::from(current_time()) + 1,
4,
);
let second = create_event(
EventStatusType::Scheduled,
2,
i64::from(current_time()) + 4,
2,
);
let third = create_event(
EventStatusType::Scheduled,
3,
i64::from(current_time()) + 7,
2,
);
schedule.add_event(first, &program, 0).await;
schedule.add_event(superseded, &program, 0).await;
tokio::time::sleep(Duration::from_secs(3)).await;
schedule.add_event(second, &program, 0).await;
schedule.add_event(third, &program, 0).await;
tokio::time::sleep(Duration::from_secs(7)).await;
assert_eq!(
logs.logs.read().await.as_ref(),
vec![
"DERControl Started: 1",
"DERControl Superseded: 1",
"DERControl Started: 2",
"DERControl Complete: 2",
"DERControl Started: 3",
"DERControl Complete: 3"
]
);
}
#[tokio::test]
async fn cancelling_der_scheduler() {
let program = DERProgram::default();
let (mut schedule, logs) = test_setup();
let mut first = create_event(
EventStatusType::Scheduled,
1,
i64::from(current_time()) + 1,
2,
);
let mut second = create_event(
EventStatusType::Scheduled,
2,
i64::from(current_time()) + 4,
2,
);
let mut third = create_event(
EventStatusType::Scheduled,
3,
i64::from(current_time()) + 7,
2,
);
schedule.add_event(second.clone(), &program, 0).await;
schedule.add_event(third.clone(), &program, 0).await;
schedule.add_event(first.clone(), &program, 0).await;
tokio::time::sleep(Duration::from_secs(3)).await;
first.event_status.current_status = EventStatusType::Cancelled;
schedule.add_event(first, &program, 0).await;
tokio::time::sleep(Duration::from_secs(3)).await;
second.event_status.current_status = EventStatusType::Cancelled;
schedule.add_event(second, &program, 0).await;
third.event_status.current_status = EventStatusType::Cancelled;
schedule.add_event(third, &program, 0).await;
tokio::time::sleep(Duration::from_secs(4)).await;
assert_eq!(
logs.logs.read().await.as_ref(),
vec![
"DERControl Started: 1",
"DERControl Cancelled: 1",
"DERControl Started: 2",
"DERControl Cancelled: 2",
]
);
}
#[tokio::test]
async fn unsupersede_der_scheduler() {
let program = DERProgram::default();
let (mut schedule, logs) = test_setup();
let second = create_event(
EventStatusType::Scheduled,
0,
i64::from(current_time()) + 4,
2,
);
let mut first = create_event(
EventStatusType::Scheduled,
1,
i64::from(current_time()) + 1,
4,
);
let third = create_event(
EventStatusType::Scheduled,
3,
i64::from(current_time()) + 7,
2,
);
schedule.add_event(first.clone(), &program, 0).await;
schedule.add_event(second, &program, 0).await;
schedule.add_event(third, &program, 0).await;
tokio::time::sleep(Duration::from_secs(3)).await;
first.event_status.current_status = EventStatusType::Cancelled;
schedule.add_event(first.clone(), &program, 0).await;
tokio::time::sleep(Duration::from_secs(7)).await;
assert_eq!(
logs.logs.read().await.as_ref(),
vec![
"DERControl Started: 1",
"DERControl Cancelled: 1",
"DERControl Started: 0",
"DERControl Complete: 0",
"DERControl Started: 3",
"DERControl Complete: 3"
]
);
}
#[tokio::test]
async fn schedule_der_differing_primacy() {
let (program1, mut program2, mut program3) = (
DERProgram::default(),
DERProgram::default(),
DERProgram::default(),
);
program2.primacy = PrimacyType::ContractedPremisesServiceProvider;
program3.primacy = PrimacyType::NonContractualServiceProvider;
let (mut schedule, logs) = test_setup();
let first = create_event(
EventStatusType::Scheduled,
1,
i64::from(current_time()) + 1,
3,
);
let second = create_event(
EventStatusType::Scheduled,
2,
i64::from(current_time()) + 2,
2,
);
let third = create_event(
EventStatusType::Scheduled,
3,
i64::from(current_time()) + 3,
2,
);
schedule.add_event(first, &program3, 0).await;
schedule.add_event(second, &program1, 0).await;
schedule.add_event(third, &program2, 0).await;
tokio::time::sleep(Duration::from_secs(5)).await;
assert_eq!(
logs.logs.read().await.as_ref(),
vec!["DERControl Started: 2", "DERControl Complete: 2",]
);
}