entrenar/integrity/lineage/
event.rs1use super::timestamp::LamportTimestamp;
4use serde::{Deserialize, Serialize};
5use std::cmp::Ordering;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub enum LineageEventType {
10 RunStarted,
12 MetricLogged,
14 ArtifactSaved,
16 RunCompleted,
18 ModelPromoted,
20 ModelRolledBack,
22}
23
24impl LineageEventType {
25 pub fn description(&self) -> &'static str {
27 match self {
28 Self::RunStarted => "Run started",
29 Self::MetricLogged => "Metric logged",
30 Self::ArtifactSaved => "Artifact saved",
31 Self::RunCompleted => "Run completed",
32 Self::ModelPromoted => "Model promoted",
33 Self::ModelRolledBack => "Model rolled back",
34 }
35 }
36}
37
38impl std::fmt::Display for LineageEventType {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(f, "{}", self.description())
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46pub struct LineageEvent {
47 pub timestamp: LamportTimestamp,
49 pub event_type: LineageEventType,
51 pub run_id: String,
53 pub context: Option<String>,
55}
56
57impl LineageEvent {
58 pub fn new(timestamp: LamportTimestamp, event_type: LineageEventType, run_id: &str) -> Self {
60 Self { timestamp, event_type, run_id: run_id.to_string(), context: None }
61 }
62
63 pub fn with_context(mut self, context: impl Into<String>) -> Self {
65 self.context = Some(context.into());
66 self
67 }
68}
69
70impl PartialOrd for LineageEvent {
71 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
72 Some(self.cmp(other))
73 }
74}
75
76impl Ord for LineageEvent {
77 fn cmp(&self, other: &Self) -> Ordering {
78 self.timestamp.cmp(&other.timestamp)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_lineage_event_type_description_run_started() {
88 assert_eq!(LineageEventType::RunStarted.description(), "Run started");
89 }
90
91 #[test]
92 fn test_lineage_event_type_description_metric_logged() {
93 assert_eq!(LineageEventType::MetricLogged.description(), "Metric logged");
94 }
95
96 #[test]
97 fn test_lineage_event_type_description_artifact_saved() {
98 assert_eq!(LineageEventType::ArtifactSaved.description(), "Artifact saved");
99 }
100
101 #[test]
102 fn test_lineage_event_type_description_run_completed() {
103 assert_eq!(LineageEventType::RunCompleted.description(), "Run completed");
104 }
105
106 #[test]
107 fn test_lineage_event_type_description_model_promoted() {
108 assert_eq!(LineageEventType::ModelPromoted.description(), "Model promoted");
109 }
110
111 #[test]
112 fn test_lineage_event_type_description_model_rolled_back() {
113 assert_eq!(LineageEventType::ModelRolledBack.description(), "Model rolled back");
114 }
115
116 #[test]
117 fn test_lineage_event_type_display() {
118 assert_eq!(LineageEventType::RunStarted.to_string(), "Run started");
119 assert_eq!(LineageEventType::MetricLogged.to_string(), "Metric logged");
120 assert_eq!(LineageEventType::ArtifactSaved.to_string(), "Artifact saved");
121 assert_eq!(LineageEventType::RunCompleted.to_string(), "Run completed");
122 assert_eq!(LineageEventType::ModelPromoted.to_string(), "Model promoted");
123 assert_eq!(LineageEventType::ModelRolledBack.to_string(), "Model rolled back");
124 }
125
126 #[test]
127 fn test_lineage_event_type_clone() {
128 let et = LineageEventType::RunStarted;
129 let cloned = et;
130 assert_eq!(et, cloned);
131 }
132
133 #[test]
134 fn test_lineage_event_type_hash() {
135 use std::collections::HashSet;
136 let mut set = HashSet::new();
137 set.insert(LineageEventType::RunStarted);
138 set.insert(LineageEventType::RunStarted);
139 assert_eq!(set.len(), 1);
140 set.insert(LineageEventType::RunCompleted);
141 assert_eq!(set.len(), 2);
142 }
143
144 #[test]
145 fn test_lineage_event_new() {
146 let ts = LamportTimestamp::new("node1");
147 let event = LineageEvent::new(ts, LineageEventType::RunStarted, "run-123");
148 assert_eq!(event.run_id, "run-123");
149 assert_eq!(event.event_type, LineageEventType::RunStarted);
150 assert!(event.context.is_none());
151 }
152
153 #[test]
154 fn test_lineage_event_with_context() {
155 let ts = LamportTimestamp::new("node1");
156 let event = LineageEvent::new(ts, LineageEventType::MetricLogged, "run-456")
157 .with_context("loss=0.5");
158 assert_eq!(event.context, Some("loss=0.5".to_string()));
159 }
160
161 #[test]
162 fn test_lineage_event_ordering() {
163 let ts1 = LamportTimestamp::with_counter("node1", 1);
164 let ts2 = LamportTimestamp::with_counter("node1", 2);
165
166 let event1 = LineageEvent::new(ts1, LineageEventType::RunStarted, "run-1");
167 let event2 = LineageEvent::new(ts2, LineageEventType::MetricLogged, "run-1");
168
169 assert!(event1 < event2);
170 assert!(event2 > event1);
171 assert_eq!(event1.cmp(&event2), Ordering::Less);
172 }
173
174 #[test]
175 fn test_lineage_event_partial_ord() {
176 let ts1 = LamportTimestamp::with_counter("node1", 1);
177 let ts2 = LamportTimestamp::with_counter("node1", 2);
178
179 let event1 = LineageEvent::new(ts1, LineageEventType::RunStarted, "run-1");
180 let event2 = LineageEvent::new(ts2, LineageEventType::MetricLogged, "run-1");
181
182 assert_eq!(event1.partial_cmp(&event2), Some(Ordering::Less));
183 }
184
185 #[test]
186 fn test_lineage_event_clone() {
187 let ts = LamportTimestamp::new("node1");
188 let event =
189 LineageEvent::new(ts, LineageEventType::RunStarted, "run-123").with_context("test");
190 let cloned = event.clone();
191 assert_eq!(event.run_id, cloned.run_id);
192 assert_eq!(event.event_type, cloned.event_type);
193 assert_eq!(event.context, cloned.context);
194 }
195
196 #[test]
197 fn test_lineage_event_eq() {
198 let ts = LamportTimestamp::new("node1");
199 let event1 = LineageEvent::new(ts.clone(), LineageEventType::RunStarted, "run-123");
200 let event2 = LineageEvent::new(ts, LineageEventType::RunStarted, "run-123");
201 assert_eq!(event1, event2);
202 }
203
204 #[test]
205 fn test_lineage_event_serde() {
206 let ts = LamportTimestamp::new("node1");
207 let event = LineageEvent::new(ts, LineageEventType::ArtifactSaved, "run-789")
208 .with_context("model.gguf");
209
210 let json = serde_json::to_string(&event).expect("JSON serialization should succeed");
211 let deserialized: LineageEvent =
212 serde_json::from_str(&json).expect("JSON deserialization should succeed");
213 assert_eq!(event.run_id, deserialized.run_id);
214 assert_eq!(event.event_type, deserialized.event_type);
215 assert_eq!(event.context, deserialized.context);
216 }
217
218 #[test]
219 fn test_lineage_event_type_serde() {
220 let et = LineageEventType::ModelPromoted;
221 let json = serde_json::to_string(&et).expect("JSON serialization should succeed");
222 let deserialized: LineageEventType =
223 serde_json::from_str(&json).expect("JSON deserialization should succeed");
224 assert_eq!(et, deserialized);
225 }
226
227 #[test]
228 fn test_lineage_event_type_debug() {
229 assert_eq!(format!("{:?}", LineageEventType::RunStarted), "RunStarted");
230 assert_eq!(format!("{:?}", LineageEventType::MetricLogged), "MetricLogged");
231 assert_eq!(format!("{:?}", LineageEventType::ArtifactSaved), "ArtifactSaved");
232 assert_eq!(format!("{:?}", LineageEventType::RunCompleted), "RunCompleted");
233 assert_eq!(format!("{:?}", LineageEventType::ModelPromoted), "ModelPromoted");
234 assert_eq!(format!("{:?}", LineageEventType::ModelRolledBack), "ModelRolledBack");
235 }
236}