1use std::collections::BTreeMap;
18
19use serde::{Deserialize, Serialize};
20
21use crate::flight::Flight;
22use crate::pipeline::PipelineName;
23
24#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
26pub struct Queued {
27 pub flight: Flight,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub pipeline: Option<PipelineName>,
32 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
37 pub flags: BTreeMap<String, bool>,
38}
39
40impl Queued {
41 #[must_use]
43 pub fn new(
44 flight: Flight,
45 pipeline: Option<PipelineName>,
46 flags: BTreeMap<String, bool>,
47 ) -> Self {
48 Self {
49 flight,
50 pipeline,
51 flags,
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use crate::agent::AgentName;
60 use crate::flight::{ItineraryId, Origin};
61
62 fn flight() -> Flight {
63 Flight::new(
64 ItineraryId::generate(),
65 Origin::Human,
66 AgentName::new("analyst"),
67 "look at 4821",
68 8,
69 )
70 }
71
72 #[test]
73 fn flags_survive_a_round_trip_through_storage() {
74 let mut flags = BTreeMap::new();
75 flags.insert("run_e2e".to_owned(), true);
76 flags.insert("draft_pr".to_owned(), false);
77
78 let queued = Queued::new(flight(), Some(PipelineName::new("development")), flags);
79
80 let json = serde_json::to_string(&queued).expect("serialises");
81 let read: Queued = serde_json::from_str(&json).expect("deserialises");
82
83 assert_eq!(read, queued);
84 assert_eq!(
85 read.flags.get("run_e2e"),
86 Some(&true),
87 "the operator set this and the run must see it"
88 );
89 assert_eq!(
90 read.flags.get("draft_pr"),
91 Some(&false),
92 "a flag left at its default is still a decision, and is recorded as one"
93 );
94 }
95
96 #[test]
97 fn a_bare_agent_trigger_carries_no_pipeline_and_no_flags() {
98 let queued = Queued::new(flight(), None, BTreeMap::new());
99 let json = serde_json::to_string(&queued).expect("serialises");
100
101 assert!(!json.contains("pipeline"), "{json}");
102 assert!(!json.contains("flags"), "{json}");
103 }
104}