traverse_contracts/
usage_telemetry.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum UsageEventKind {
9 Resolve,
11 Execute,
13}
14
15#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct UsageEvent {
20 pub kind: UsageEventKind,
22 pub capability_ref: String,
24 pub timestamp: String,
26}
27
28pub trait UsageTelemetrySink: Send + Sync {
34 fn record(&self, event: UsageEvent);
36}
37
38#[derive(Debug, Clone, Copy, Default)]
43pub struct NoOpUsageTelemetrySink;
44
45impl UsageTelemetrySink for NoOpUsageTelemetrySink {
46 fn record(&self, _event: UsageEvent) {}
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn no_op_sink_records_without_side_effects() {
55 let sink = NoOpUsageTelemetrySink;
56 sink.record(UsageEvent {
57 kind: UsageEventKind::Resolve,
58 capability_ref: "hello.world/say-hello@1.0.0".to_string(),
59 timestamp: "2026-08-04T00:00:00Z".to_string(),
60 });
61 sink.record(UsageEvent {
62 kind: UsageEventKind::Execute,
63 capability_ref: "hello.world/say-hello@1.0.0".to_string(),
64 timestamp: "2026-08-04T00:00:00Z".to_string(),
65 });
66 }
67
68 #[test]
69 #[allow(clippy::clone_on_copy, clippy::default_constructed_unit_structs)]
70 fn no_op_sink_default_clone_and_debug_are_stable() {
71 let sink = NoOpUsageTelemetrySink::default();
72 let cloned = sink.clone();
73 assert_eq!(format!("{sink:?}"), format!("{cloned:?}"));
74 assert_eq!(format!("{sink:?}"), "NoOpUsageTelemetrySink");
75 }
76
77 #[test]
78 fn no_op_sink_is_usable_as_a_trait_object() {
79 let sink: Box<dyn UsageTelemetrySink> = Box::new(NoOpUsageTelemetrySink);
80 sink.record(UsageEvent {
81 kind: UsageEventKind::Resolve,
82 capability_ref: "a.b/c@1.0.0".to_string(),
83 timestamp: "t".to_string(),
84 });
85 }
86
87 #[test]
88 fn usage_event_kind_equality_and_debug() {
89 assert_eq!(UsageEventKind::Resolve, UsageEventKind::Resolve);
90 assert_ne!(UsageEventKind::Resolve, UsageEventKind::Execute);
91 assert_eq!(format!("{:?}", UsageEventKind::Resolve), "Resolve");
92 assert_eq!(format!("{:?}", UsageEventKind::Execute), "Execute");
93 assert_eq!(UsageEventKind::Execute.clone(), UsageEventKind::Execute);
94 }
95
96 #[test]
97 fn usage_event_equality_clone_and_debug() {
98 let event = UsageEvent {
99 kind: UsageEventKind::Resolve,
100 capability_ref: "a.b/c@1.0.0".to_string(),
101 timestamp: "t".to_string(),
102 };
103 let cloned = event.clone();
104 assert_eq!(event, cloned);
105 assert!(format!("{event:?}").contains("Resolve"));
106
107 let different = UsageEvent {
108 kind: UsageEventKind::Execute,
109 ..event.clone()
110 };
111 assert_ne!(event, different);
112 }
113}