175 lines
5.8 KiB
Rust
175 lines
5.8 KiB
Rust
mod common;
|
|
|
|
#[cfg(test)]
|
|
mod integration_tests {
|
|
use crate::common::validate_all_constraints;
|
|
use rota_lib::{
|
|
config::UserConfig,
|
|
fixtures::{
|
|
complex_config, hard_config, manual_shifts_heavy_config, maximal_config, minimal_config,
|
|
},
|
|
schedule::MonthlySchedule,
|
|
scheduler::Scheduler,
|
|
workload::WorkloadTracker,
|
|
};
|
|
use rstest::rstest;
|
|
|
|
#[ctor::ctor]
|
|
fn global_setup() {
|
|
env_logger::builder()
|
|
.filter_level(log::LevelFilter::Info)
|
|
.init();
|
|
}
|
|
|
|
#[rstest]
|
|
fn test_minimal_config(
|
|
#[values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)] month_idx: u8,
|
|
mut minimal_config: UserConfig,
|
|
) -> anyhow::Result<()> {
|
|
minimal_config.update_month(month_idx);
|
|
let scheduler = Scheduler::new_with_config(minimal_config.clone());
|
|
let mut schedule = MonthlySchedule::new();
|
|
let mut tracker = WorkloadTracker::default();
|
|
|
|
let solved = scheduler.run(&mut schedule, &mut tracker)?;
|
|
println!(
|
|
"{}",
|
|
schedule.report(&schedule.metrics(&minimal_config, &tracker))
|
|
);
|
|
assert!(solved);
|
|
validate_all_constraints(&schedule, &tracker, &minimal_config);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[rstest]
|
|
fn test_maximal_config(
|
|
#[values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)] month_idx: u8,
|
|
mut maximal_config: UserConfig,
|
|
) -> anyhow::Result<()> {
|
|
maximal_config.update_month(month_idx);
|
|
let scheduler = Scheduler::new_with_config(maximal_config.clone());
|
|
let mut schedule = MonthlySchedule::new();
|
|
let mut tracker = WorkloadTracker::default();
|
|
|
|
let solved = scheduler.run(&mut schedule, &mut tracker)?;
|
|
println!(
|
|
"{}",
|
|
schedule.report(&schedule.metrics(&maximal_config, &tracker))
|
|
);
|
|
assert!(solved);
|
|
validate_all_constraints(&schedule, &tracker, &maximal_config);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[rstest]
|
|
fn test_manual_shifts_heavy_config(
|
|
#[values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)] month_idx: u8,
|
|
mut manual_shifts_heavy_config: UserConfig,
|
|
) -> anyhow::Result<()> {
|
|
manual_shifts_heavy_config.update_month(month_idx);
|
|
let scheduler = Scheduler::new_with_config(manual_shifts_heavy_config.clone());
|
|
let mut schedule = MonthlySchedule::new();
|
|
let mut tracker = WorkloadTracker::default();
|
|
|
|
let solved = scheduler.run(&mut schedule, &mut tracker)?;
|
|
println!(
|
|
"{}",
|
|
schedule.report(&schedule.metrics(&manual_shifts_heavy_config, &tracker))
|
|
);
|
|
assert!(solved);
|
|
validate_all_constraints(&schedule, &tracker, &manual_shifts_heavy_config);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[rstest]
|
|
fn test_complex_config(
|
|
#[values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)] month_idx: u8,
|
|
mut complex_config: UserConfig,
|
|
) -> anyhow::Result<()> {
|
|
complex_config.update_month(month_idx);
|
|
let scheduler = Scheduler::new_with_config(complex_config.clone());
|
|
let mut schedule = MonthlySchedule::new();
|
|
let mut tracker = WorkloadTracker::default();
|
|
|
|
let solved = scheduler.run(&mut schedule, &mut tracker)?;
|
|
println!(
|
|
"{}",
|
|
schedule.report(&schedule.metrics(&complex_config, &tracker))
|
|
);
|
|
assert!(solved);
|
|
validate_all_constraints(&schedule, &tracker, &complex_config);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[rstest]
|
|
fn test_hard_config(
|
|
#[values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)] month_idx: u8,
|
|
mut hard_config: UserConfig,
|
|
) -> anyhow::Result<()> {
|
|
hard_config.update_month(month_idx);
|
|
let scheduler = Scheduler::new_with_config(hard_config.clone());
|
|
let mut schedule = MonthlySchedule::new();
|
|
let mut tracker = WorkloadTracker::default();
|
|
|
|
let solved = scheduler.run(&mut schedule, &mut tracker)?;
|
|
println!(
|
|
"{}",
|
|
schedule.report(&schedule.metrics(&hard_config, &tracker))
|
|
);
|
|
assert!(solved);
|
|
validate_all_constraints(&schedule, &tracker, &hard_config);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[rstest]
|
|
fn test_swap_preserves_constraints(
|
|
#[values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)] month_idx: u8,
|
|
mut minimal_config: UserConfig,
|
|
) -> anyhow::Result<()> {
|
|
minimal_config.update_month(month_idx);
|
|
let scheduler = Scheduler::new_with_config(minimal_config.clone());
|
|
let mut schedule = MonthlySchedule::new();
|
|
let mut tracker = WorkloadTracker::default();
|
|
assert!(scheduler.run(&mut schedule, &mut tracker)?);
|
|
|
|
let slots: Vec<_> = schedule.0.keys().copied().collect();
|
|
let mut swapped = false;
|
|
for slot in slots {
|
|
let candidates = schedule.possible_swaps(slot, &minimal_config);
|
|
if let Some(&(swap_target, _)) = candidates.first() {
|
|
schedule
|
|
.apply_swap(slot, swap_target, &minimal_config, &mut tracker)
|
|
.expect("apply_swap failed for a candidate returned by possible_swaps");
|
|
swapped = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert!(swapped, "No valid swap found in generated schedule");
|
|
validate_all_constraints(&schedule, &tracker, &minimal_config);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[rstest]
|
|
fn test_export_pipeline(minimal_config: UserConfig) -> anyhow::Result<()> {
|
|
let scheduler = Scheduler::new_with_config(minimal_config.clone());
|
|
let mut schedule = MonthlySchedule::new();
|
|
let mut tracker = WorkloadTracker::default();
|
|
assert!(scheduler.run(&mut schedule, &mut tracker)?);
|
|
|
|
schedule.export_as_docx(&minimal_config)?;
|
|
|
|
let metadata = std::fs::metadata("rota.docx")?;
|
|
assert!(metadata.len() > 0);
|
|
std::fs::remove_file("rota.docx")?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|