nextest_runner/reporter/structured/
recorder.rs1use crate::{
7 errors::RecordReporterError,
8 output_spec::LiveSpec,
9 record::{RecordOpts, RunRecorder, StoreSizes, TestEventSummary},
10 reporter::events::TestEvent,
11};
12use nextest_metadata::TestListSummary;
13use std::{
14 any::Any,
15 sync::{Arc, mpsc},
16 thread::JoinHandle,
17};
18
19#[derive(Debug)]
25pub struct RecordReporter {
26 sender: mpsc::SyncSender<RecordEvent>,
27 handle: JoinHandle<Result<StoreSizes, RecordReporterError>>,
28}
29
30impl RecordReporter {
31 pub fn new(run_recorder: RunRecorder) -> Self {
33 let (sender, receiver) = mpsc::sync_channel(128);
35 let handle = std::thread::spawn(move || {
36 let mut writer = RecordReporterWriter { run_recorder };
37 while let Ok(event) = receiver.recv() {
38 writer.handle_event(event)?;
39 }
40
41 writer.finish()
43 });
44
45 Self { sender, handle }
46 }
47
48 pub fn write_meta(
52 &self,
53 cargo_metadata_json: Arc<String>,
54 test_list: TestListSummary,
55 opts: RecordOpts,
56 ) {
57 let event = RecordEvent::Meta {
58 cargo_metadata_json,
59 test_list,
60 opts,
61 };
62 _ = self.sender.send(event);
65 }
66
67 pub fn write_event(&self, event: TestEvent<'_>) {
72 let Some(summary) = TestEventSummary::from_test_event(event) else {
73 return;
75 };
76 let event = RecordEvent::TestEvent(summary);
77 _ = self.sender.send(event);
80 }
81
82 pub fn finish(self) -> Result<StoreSizes, RecordReporterError> {
89 std::mem::drop(self.sender);
91
92 match self.handle.join() {
94 Ok(result) => result,
95 Err(panic_payload) => Err(RecordReporterError::WriterPanic {
96 message: panic_payload_to_string(panic_payload),
97 }),
98 }
99 }
100}
101
102fn panic_payload_to_string(payload: Box<dyn Any + Send + 'static>) -> String {
104 if let Some(s) = payload.downcast_ref::<&str>() {
105 (*s).to_owned()
106 } else if let Some(s) = payload.downcast_ref::<String>() {
107 s.clone()
108 } else {
109 "(unknown panic payload)".to_owned()
110 }
111}
112
113struct RecordReporterWriter {
115 run_recorder: RunRecorder,
116}
117
118impl RecordReporterWriter {
119 fn handle_event(&mut self, event: RecordEvent) -> Result<(), RecordReporterError> {
120 match event {
121 RecordEvent::Meta {
122 cargo_metadata_json,
123 test_list,
124 opts,
125 } => self
126 .run_recorder
127 .write_meta(&cargo_metadata_json, &test_list, &opts)
128 .map_err(RecordReporterError::RunStore),
129 RecordEvent::TestEvent(event) => self
130 .run_recorder
131 .write_event(event)
132 .map_err(RecordReporterError::RunStore),
133 }
134 }
135
136 fn finish(self) -> Result<StoreSizes, RecordReporterError> {
137 self.run_recorder
138 .finish()
139 .map_err(RecordReporterError::RunStore)
140 }
141}
142
143#[derive(Debug)]
145enum RecordEvent {
146 Meta {
148 cargo_metadata_json: Arc<String>,
149 test_list: TestListSummary,
150 opts: RecordOpts,
151 },
152 TestEvent(TestEventSummary<LiveSpec>),
154}