github-actions[bot]
chore: sync uc-hospital Space
7596726
//! Unit tests for the retained-job SSE payload contract.
use super::*;
use crate::domain::{Employee, Shift};
use serde_json::Value;
use solverforge::{
SolverLifecycleState, SolverSnapshot, SolverStatus, SolverTelemetry, SolverTerminalReason,
};
#[test]
fn failed_events_use_stock_payload_fields() {
let payload: Value = serde_json::from_str(&event_payload(
7,
"failed",
&SolverEventMetadata {
job_id: 7,
event_sequence: 4,
lifecycle_state: SolverLifecycleState::Failed,
terminal_reason: Some(SolverTerminalReason::Failed),
snapshot_revision: Some(3),
current_score: None,
best_score: None,
telemetry: SolverTelemetry::default(),
},
None,
Some("boom"),
))
.unwrap();
assert_eq!(payload["id"], "7");
assert_eq!(payload["jobId"], "7");
assert_eq!(payload["eventType"], "failed");
assert_eq!(payload["lifecycleState"], "FAILED");
assert_eq!(payload["terminalReason"], "failed");
assert_eq!(payload["error"], "boom");
}
#[test]
fn event_payload_derives_stock_telemetry_fields_from_exact_runtime_telemetry() {
let payload: Value = serde_json::from_str(&event_payload(
5,
"progress",
&SolverEventMetadata {
job_id: 5,
event_sequence: 2,
lifecycle_state: SolverLifecycleState::Solving,
terminal_reason: None,
snapshot_revision: Some(1),
current_score: Some(HardSoftDecimalScore::ZERO),
best_score: Some(HardSoftDecimalScore::ZERO),
telemetry: SolverTelemetry {
elapsed: std::time::Duration::from_millis(2_500),
step_count: 9,
moves_generated: 300,
moves_evaluated: 200,
moves_accepted: 50,
score_calculations: 80,
generation_time: std::time::Duration::from_millis(400),
evaluation_time: std::time::Duration::from_millis(900),
..SolverTelemetry::default()
},
},
None,
None,
))
.unwrap();
assert_eq!(payload["telemetry"]["elapsedMs"], 2500);
assert_eq!(payload["telemetry"]["stepCount"], 9);
assert_eq!(payload["telemetry"]["movesGenerated"], 300);
assert_eq!(payload["telemetry"]["movesEvaluated"], 200);
assert_eq!(payload["telemetry"]["movesAccepted"], 50);
assert_eq!(payload["telemetry"]["scoreCalculations"], 80);
assert_eq!(payload["telemetry"]["generationMs"], 400);
assert_eq!(payload["telemetry"]["evaluationMs"], 900);
assert_eq!(payload["telemetry"]["movesPerSecond"], 80);
assert_eq!(payload["telemetry"]["acceptanceRate"], 0.25);
}
#[test]
fn snapshot_bootstrap_payload_exposes_live_solution_and_ui_score_fields() {
let mut solution = Plan::new(
vec![Employee::new(0, "Alex").with_skill("Doctor")],
vec![{
let mut shift = Shift::new(
"shift-1",
chrono::NaiveDate::from_ymd_opt(2024, 1, 1)
.unwrap()
.and_hms_opt(8, 0, 0)
.unwrap(),
chrono::NaiveDate::from_ymd_opt(2024, 1, 1)
.unwrap()
.and_hms_opt(16, 0, 0)
.unwrap(),
"ER",
"Doctor",
);
shift.employee_idx = Some(0);
shift
}],
);
solution.score = Some(HardSoftDecimalScore::ZERO);
let status = SolverStatus {
job_id: 11,
lifecycle_state: SolverLifecycleState::Solving,
terminal_reason: None,
checkpoint_available: true,
event_sequence: 9,
latest_snapshot_revision: Some(4),
current_score: None,
best_score: None,
telemetry: SolverTelemetry::default(),
};
let snapshot = SolverSnapshot {
job_id: 11,
snapshot_revision: 4,
lifecycle_state: SolverLifecycleState::Solving,
terminal_reason: None,
current_score: Some(HardSoftDecimalScore::ZERO),
best_score: Some(HardSoftDecimalScore::ZERO),
telemetry: SolverTelemetry::default(),
solution,
};
let payload: Value = serde_json::from_str(&snapshot_status_event_payload(
11,
bootstrap_snapshot_event_type(status.lifecycle_state),
&status,
&snapshot,
))
.unwrap();
assert_eq!(payload["eventType"], "best_solution");
assert_eq!(payload["lifecycleState"], "SOLVING");
assert_eq!(payload["snapshotRevision"], 4);
assert_eq!(payload["currentScore"], "0hard/0soft");
assert_eq!(payload["bestScore"], "0hard/0soft");
assert!(payload["solution"].is_object());
assert_eq!(payload["solution"]["shifts"][0]["employeeIdx"], 0);
assert_eq!(payload["solution"]["score"], "0hard/0soft");
}