Spaces:
Sleeping
Sleeping
File size: 4,931 Bytes
7596726 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | //! 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");
}
|