1use super::data::Data;
6use super::trials::{self, Step};
7use super::{PUPPET_MONIKER, puppet, results};
8use anyhow::{Error, bail};
9use diagnostics_reader::{ArchiveReader, ComponentSelector};
10use fidl_diagnostics_validate as validate;
11
12pub async fn run_all_trials() -> results::Results {
13 let trial_set = trials::real_trials();
14 let mut results = results::Results::new();
15 for mut trial in trial_set {
16 match puppet::Puppet::connect().await {
17 Ok(mut puppet) => {
18 results.diff_type = puppet.config.diff_type;
19 if puppet.config.test_archive {
20 match puppet.publish().await {
21 Ok(validate::TestResult::Ok) => {}
22 Ok(result) => {
23 results.error(format!("Publish reported {result:?}"));
24 return results;
25 }
26 Err(e) => {
27 results.error(format!("Publish error: {e:?}"));
28 return results;
29 }
30 }
31 }
32 let mut data = Data::new();
33 if let Err(e) = run_trial(&mut puppet, &mut data, &mut trial, &mut results).await {
34 results.error(format!("Running trial {}, got failure:\n{}", trial.name, e));
35 } else {
36 results.log(format!("Trial {} succeeds", trial.name));
37 }
38
39 puppet.shutdown().await;
43 }
44 Err(e) => {
45 results.error(format!("Failed to form Puppet - error {e:?}."));
46 }
47 }
48 }
49 results
50}
51
52#[derive(PartialEq)]
53enum StepResult {
54 Continue,
56 Stop,
59}
60
61async fn run_trial(
62 puppet: &mut puppet::Puppet,
63 data: &mut Data,
64 trial: &mut trials::Trial,
65 results: &mut results::Results,
66) -> Result<(), Error> {
67 let trial_name = format!("{}:{}", puppet.printable_name(), trial.name);
68 try_compare::<validate::Action>(data, puppet, &trial_name, -1, None, -1, results).await?;
70 for (step_index, step) in trial.steps.iter_mut().enumerate() {
71 let step_result = match step {
72 Step::Actions(actions) => {
73 run_actions(actions, data, puppet, &trial.name, step_index, results).await?
74 }
75 Step::WithMetrics(actions, step_name) => {
76 let r =
77 run_actions(actions, data, puppet, &trial.name, step_index, results).await?;
78 results.remember_metrics(puppet.metrics()?, &trial.name, step_index, step_name);
79 r
80 }
81 Step::LazyActions(actions) => {
82 run_lazy_actions(actions, data, puppet, &trial.name, step_index, results).await?
83 }
84 Step::ActLazyThreadLocalActions(actions) => {
85 run_act_lazy_thread_local_actions(
86 actions,
87 data,
88 puppet,
89 &trial.name,
90 step_index,
91 results,
92 )
93 .await?
94 }
95 };
96 if step_result == StepResult::Stop {
97 break;
98 }
99 }
100 Ok(())
101}
102
103async fn run_actions(
104 actions: &mut [validate::Action],
105 data: &mut Data,
106 puppet: &mut puppet::Puppet,
107 trial_name: &str,
108 step_index: usize,
109 results: &mut results::Results,
110) -> Result<StepResult, Error> {
111 for (action_number, action) in actions.iter_mut().enumerate() {
112 if let Err(e) = data.apply(action) {
113 bail!(
114 "Local-apply error in trial {}, step {}, action {}: {:?} ",
115 trial_name,
116 step_index,
117 action_number,
118 e
119 );
120 }
121 match puppet.apply(action).await {
122 Err(e) => {
123 bail!(
124 "Puppet-apply error in trial {}, step {}, action {}: {:?} ",
125 trial_name,
126 step_index,
127 action_number,
128 e
129 );
130 }
131 Ok(validate::TestResult::Ok) => {}
132 Ok(validate::TestResult::Unimplemented) => {
133 results.unimplemented(puppet.printable_name(), action);
134 return Ok(StepResult::Stop);
135 }
136 Ok(bad_result) => {
137 bail!(
138 "In trial {}, puppet {} reported action {:?} was {:?}",
139 trial_name,
140 puppet.printable_name(),
141 action,
142 bad_result
143 );
144 }
145 }
146 try_compare(
147 data,
148 puppet,
149 trial_name,
150 step_index as i32,
151 Some(action),
152 action_number as i32,
153 results,
154 )
155 .await?;
156 }
157 Ok(StepResult::Continue)
158}
159
160async fn run_lazy_actions(
161 actions: &mut [validate::LazyAction],
162 data: &mut Data,
163 puppet: &mut puppet::Puppet,
164 trial_name: &str,
165 step_index: usize,
166 results: &mut results::Results,
167) -> Result<StepResult, Error> {
168 for (action_number, action) in actions.iter_mut().enumerate() {
169 if let Err(e) = data.apply_lazy(action) {
170 bail!(
171 "Local-apply_lazy error in trial {}, step {}, action {}: {:?} ",
172 trial_name,
173 step_index,
174 action_number,
175 e
176 );
177 }
178 match puppet.apply_lazy(action).await {
179 Err(e) => {
180 bail!(
181 "Puppet-apply_lazy error in trial {}, step {}, action {}: {:?} ",
182 trial_name,
183 step_index,
184 action_number,
185 e
186 );
187 }
188 Ok(validate::TestResult::Ok) => {}
189 Ok(validate::TestResult::Unimplemented) => {
190 results.unimplemented(puppet.printable_name(), action);
191 return Ok(StepResult::Stop);
192 }
193 Ok(bad_result) => {
194 bail!(
195 "In trial {}, puppet {} reported action {:?} was {:?}",
196 trial_name,
197 puppet.printable_name(),
198 action,
199 bad_result
200 );
201 }
202 }
203 try_compare(
204 data,
205 puppet,
206 trial_name,
207 step_index as i32,
208 Some(action),
209 action_number as i32,
210 results,
211 )
212 .await?;
213 }
214 Ok(StepResult::Continue)
215}
216
217async fn run_act_lazy_thread_local_actions(
218 actions: &mut [validate::LazyAction],
219 data: &mut Data,
220 puppet: &mut puppet::Puppet,
221 trial_name: &str,
222 step_index: usize,
223 results: &mut results::Results,
224) -> Result<StepResult, Error> {
225 for (action_number, action) in actions.iter_mut().enumerate() {
226 if let Err(e) = data.apply_lazy(action) {
227 bail!(
228 "Local-apply_lazy error in trial {}, step {}, action {}: {:?} ",
229 trial_name,
230 step_index,
231 action_number,
232 e
233 );
234 }
235 match puppet.act_lazy_thread_local(action).await {
236 Err(e) => {
237 bail!(
238 "Puppet-apply_lazy error in trial {}, step {}, action {}: {:?} ",
239 trial_name,
240 step_index,
241 action_number,
242 e
243 );
244 }
245 Ok(validate::TestResult::Ok) => {}
246 Ok(validate::TestResult::Unimplemented) => {
247 results.unimplemented(puppet.printable_name(), action);
248 return Ok(StepResult::Stop);
249 }
250 Ok(bad_result) => {
251 bail!(
252 "In trial {}, puppet {} reported action {:?} was {:?}",
253 trial_name,
254 puppet.printable_name(),
255 action,
256 bad_result
257 );
258 }
259 }
260 try_compare(
261 data,
262 puppet,
263 trial_name,
264 step_index as i32,
265 Some(action),
266 action_number as i32,
267 results,
268 )
269 .await?;
270 }
271 Ok(StepResult::Continue)
272}
273
274async fn try_compare<ActionType: std::fmt::Debug>(
275 data: &mut Data,
276 puppet: &puppet::Puppet,
277 trial_name: &str,
278 step_index: i32,
279 action: Option<&ActionType>,
280 action_number: i32,
281 results: &results::Results,
282) -> Result<(), Error> {
283 if !data.is_empty() {
284 match puppet.read_data().await {
285 Err(e) => {
286 bail!(
287 "Puppet-read error in trial {}, step {}, action {} {:?}: {:?} ",
288 trial_name,
289 step_index,
290 action_number,
291 action,
292 e
293 );
294 }
295 Ok(mut puppet_data) => {
296 if puppet.config.has_runner_node {
297 puppet_data.remove_tree("runner");
298 }
299 if let Err(e) = data.compare(&puppet_data, results.diff_type) {
300 bail!(
301 "Compare error in trial {}, step {}, action {}:\n{:?}:\n{} ",
302 trial_name,
303 step_index,
304 action_number,
305 action,
306 e
307 );
308 }
309 }
310 }
311 if puppet.config.test_archive {
312 let archive_data = match ArchiveReader::inspect()
313 .add_selector(ComponentSelector::new(vec![PUPPET_MONIKER.to_string()]))
314 .snapshot()
315 .await
316 {
317 Ok(archive_data) => archive_data,
318 Err(e) => {
319 bail!(
320 "Archive read error in trial {}, step {}, action {}:\n{:?}:\n{} ",
321 trial_name,
322 step_index,
323 action_number,
324 action,
325 e
326 );
327 }
328 };
329 if archive_data.len() != 1 {
330 bail!(
331 "Expected 1 component in trial {}, step {}, action {}:\n{:?}:\nfound {} ",
332 trial_name,
333 step_index,
334 action_number,
335 action,
336 archive_data.len()
337 );
338 }
339
340 let mut hierarchy_data: Data = archive_data[0].payload.as_ref().unwrap().clone().into();
341 if puppet.config.has_runner_node {
342 hierarchy_data.remove_tree("runner");
343 }
344 if let Err(e) = data.compare_to_json(&hierarchy_data, results.diff_type) {
345 bail!(
346 "Archive compare error in trial {}, step {}, action {}:\n{:?}:\n{} ",
347 trial_name,
348 step_index,
349 action_number,
350 action,
351 e
352 );
353 }
354 }
355 }
356 Ok(())
357}
358
359#[cfg(test)]
360mod tests {
361 use super::*;
362 use crate::trials::Trial;
363 use crate::trials::tests::trial_with_action;
364 use crate::*;
365 use fidl_diagnostics_validate::*;
366
367 #[fuchsia::test]
368 async fn unimplemented_works() {
369 let mut int_maker = trial_with_action(
370 "foo",
371 create_numeric_property!(
372 parent: ROOT_ID, id: 1, name: "int", value: Value::IntT(0)),
373 );
374 let mut uint_maker = trial_with_action(
375 "foo",
376 create_numeric_property!(
377 parent: ROOT_ID, id: 2, name: "uint", value: Value::UintT(0)),
378 );
379 let mut uint_create_delete = Trial {
380 name: "foo".to_string(),
381 steps: vec![
382 Step::Actions(vec![
383 create_numeric_property!(parent: ROOT_ID, id: 2, name: "uint", value: Value::UintT(0)),
384 ]),
385 Step::Actions(vec![delete_property!(id: 2)]),
386 ],
387 };
388 let mut results = results::Results::new();
389 let mut puppet = puppet::tests::local_incomplete_puppet().await.unwrap();
390 {
394 let mut data = Data::new();
395 run_trial(&mut puppet, &mut data, &mut int_maker, &mut results).await.unwrap();
396 }
397 {
398 let mut data = Data::new();
399 run_trial(&mut puppet, &mut data, &mut uint_maker, &mut results).await.unwrap();
400 }
401 {
402 let mut data = Data::new();
403 run_trial(&mut puppet, &mut data, &mut uint_create_delete, &mut results).await.unwrap();
404 }
405 assert!(
406 !results
407 .to_json()
408 .contains(&format!("{}: CreateProperty(Int)", puppet.printable_name()))
409 );
410 assert!(
411 results
412 .to_json()
413 .contains(&format!("{}: CreateProperty(Uint)", puppet.printable_name()))
414 );
415 }
416}