#![cfg(feature = "pricing")]
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::{
mrid_gen,
packages::{
identification::ResponseStatus,
objects::EventStatusType,
pricing::{RateComponent, TariffProfile, TimeTariffInterval},
primitives::{HexBinary128, Int64, Uint32},
types::{DeviceCategoryType, PrimacyType},
},
traits::SEIdentifiedObject,
};
use tokio::sync::RwLock;
fn test_setup() -> (
Schedule<TimeTariffInterval>,
TimeTariffIntervalHandler,
(TariffProfile, RateComponent),
) {
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 = TimeTariffIntervalHandler {
logs: Arc::new(RwLock::new(vec![])),
};
(
Schedule::new(
client,
Arc::new(RwLock::new(device)),
handler.clone(),
Duration::from_secs(0),
),
handler,
(TariffProfile::default(), RateComponent::default()),
)
}
#[derive(Clone)]
struct TimeTariffIntervalHandler {
logs: Arc<RwLock<Vec<String>>>,
}
impl EventCallback<TimeTariffInterval> for TimeTariffIntervalHandler {
async fn event_update(&self, event: &EventInstance<TimeTariffInterval>) -> ResponseStatus {
let log = match event.status() {
EIStatus::Scheduled => {
format!("Received TimeTariffInterval: {}", event.event().mrid().0)
}
EIStatus::Active => {
format!("TimeTariffInterval Started: {}", event.event().mrid().0)
}
EIStatus::Cancelled => {
format!("TimeTariffInterval Cancelled: {}", event.event().mrid().0)
}
EIStatus::Complete => {
format!("TimeTariffInterval Complete: {}", event.event().mrid().0)
}
EIStatus::CancelledRandom => {
format!("TimeTariffInterval Cancelled: {}", event.event().mrid().0)
}
EIStatus::Superseded => {
format!("TimeTariffInterval 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,
) -> TimeTariffInterval {
let mut out = TimeTariffInterval::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_pricing_scheduler() {
let (mut schedule, logs, program) = 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![
"TimeTariffInterval Started: 1",
"TimeTariffInterval Complete: 1",
"TimeTariffInterval Started: 2",
"TimeTariffInterval Complete: 2",
"TimeTariffInterval Started: 3",
"TimeTariffInterval Complete: 3"
]
);
}
#[tokio::test]
async fn superseded_pricing_scheduler() {
let (mut schedule, logs, program) = 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![
"TimeTariffInterval Started: 1",
"TimeTariffInterval Superseded: 1",
"TimeTariffInterval Started: 2",
"TimeTariffInterval Complete: 2",
"TimeTariffInterval Started: 3",
"TimeTariffInterval Complete: 3"
]
);
}
#[tokio::test]
async fn cancelling_pricing_scheduler() {
let (mut schedule, logs, program) = 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![
"TimeTariffInterval Started: 1",
"TimeTariffInterval Cancelled: 1",
"TimeTariffInterval Started: 2",
"TimeTariffInterval Cancelled: 2",
]
);
}
#[tokio::test]
async fn unsupersede_pricing_scheduler() {
let (mut schedule, logs, program) = 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![
"TimeTariffInterval Started: 1",
"TimeTariffInterval Cancelled: 1",
"TimeTariffInterval Started: 0",
"TimeTariffInterval Complete: 0",
"TimeTariffInterval Started: 3",
"TimeTariffInterval Complete: 3"
]
);
}
#[tokio::test]
async fn schedule_pricing_differing_primacy() {
let (program1, mut program2, mut program3) = (
(TariffProfile::default(), RateComponent::default()),
(TariffProfile::default(), RateComponent::default()),
(TariffProfile::default(), RateComponent::default()),
);
program2.0.primacy = PrimacyType::ContractedPremisesServiceProvider;
program3.0.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![
"TimeTariffInterval Started: 2",
"TimeTariffInterval Complete: 2",
]
);
}
#[tokio::test]
async fn schedule_pricing_differing_rate_components() {
let (program1, mut program2, mut program3) = (
(TariffProfile::default(), RateComponent::default()),
(TariffProfile::default(), RateComponent::default()),
(TariffProfile::default(), RateComponent::default()),
);
program2.1.mrid = mrid_gen(32);
program3.1.mrid = mrid_gen(32);
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()) + 2,
2,
);
let third = create_event(
EventStatusType::Scheduled,
3,
i64::from(current_time()) + 5,
1,
);
schedule.add_event(first, &program1, 0).await;
schedule.add_event(second, &program2, 0).await;
schedule.add_event(third, &program3, 0).await;
tokio::time::sleep(Duration::from_secs(7)).await;
assert_eq!(
logs.logs.read().await.as_ref(),
vec![
"TimeTariffInterval Started: 1",
"TimeTariffInterval Started: 2",
"TimeTariffInterval Complete: 1",
"TimeTariffInterval Complete: 2",
"TimeTariffInterval Started: 3",
"TimeTariffInterval Complete: 3"
]
);
}