1use super::data::Data;
6use super::trials::{self, Step};
7use super::{puppet, results, PUPPET_MONIKER};
8use anyhow::{bail, Error};
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 };
85 if step_result == StepResult::Stop {
86 break;
87 }
88 }
89 Ok(())
90}
91
92async fn run_actions(
93 actions: &mut [validate::Action],
94 data: &mut Data,
95 puppet: &mut puppet::Puppet,
96 trial_name: &str,
97 step_index: usize,
98 results: &mut results::Results,
99) -> Result<StepResult, Error> {
100 for (action_number, action) in actions.iter_mut().enumerate() {
101 if let Err(e) = data.apply(action) {
102 bail!(
103 "Local-apply error in trial {}, step {}, action {}: {:?} ",
104 trial_name,
105 step_index,
106 action_number,
107 e
108 );
109 }
110 match puppet.apply(action).await {
111 Err(e) => {
112 bail!(
113 "Puppet-apply error in trial {}, step {}, action {}: {:?} ",
114 trial_name,
115 step_index,
116 action_number,
117 e
118 );
119 }
120 Ok(validate::TestResult::Ok) => {}
121 Ok(validate::TestResult::Unimplemented) => {
122 results.unimplemented(puppet.printable_name(), action);
123 return Ok(StepResult::Stop);
124 }
125 Ok(bad_result) => {
126 bail!(
127 "In trial {}, puppet {} reported action {:?} was {:?}",
128 trial_name,
129 puppet.printable_name(),
130 action,
131 bad_result
132 );
133 }
134 }
135 try_compare(
136 data,
137 puppet,
138 trial_name,
139 step_index as i32,
140 Some(action),
141 action_number as i32,
142 results,
143 )
144 .await?;
145 }
146 Ok(StepResult::Continue)
147}
148
149async fn run_lazy_actions(
150 actions: &mut [validate::LazyAction],
151 data: &mut Data,
152 puppet: &mut puppet::Puppet,
153 trial_name: &str,
154 step_index: usize,
155 results: &mut results::Results,
156) -> Result<StepResult, Error> {
157 for (action_number, action) in actions.iter_mut().enumerate() {
158 if let Err(e) = data.apply_lazy(action) {
159 bail!(
160 "Local-apply_lazy error in trial {}, step {}, action {}: {:?} ",
161 trial_name,
162 step_index,
163 action_number,
164 e
165 );
166 }
167 match puppet.apply_lazy(action).await {
168 Err(e) => {
169 bail!(
170 "Puppet-apply_lazy error in trial {}, step {}, action {}: {:?} ",
171 trial_name,
172 step_index,
173 action_number,
174 e
175 );
176 }
177 Ok(validate::TestResult::Ok) => {}
178 Ok(validate::TestResult::Unimplemented) => {
179 results.unimplemented(puppet.printable_name(), action);
180 return Ok(StepResult::Stop);
181 }
182 Ok(bad_result) => {
183 bail!(
184 "In trial {}, puppet {} reported action {:?} was {:?}",
185 trial_name,
186 puppet.printable_name(),
187 action,
188 bad_result
189 );
190 }
191 }
192 try_compare(
193 data,
194 puppet,
195 trial_name,
196 step_index as i32,
197 Some(action),
198 action_number as i32,
199 results,
200 )
201 .await?;
202 }
203 Ok(StepResult::Continue)
204}
205
206async fn try_compare<ActionType: std::fmt::Debug>(
207 data: &mut Data,
208 puppet: &puppet::Puppet,
209 trial_name: &str,
210 step_index: i32,
211 action: Option<&ActionType>,
212 action_number: i32,
213 results: &results::Results,
214) -> Result<(), Error> {
215 if !data.is_empty() {
216 match puppet.read_data().await {
217 Err(e) => {
218 bail!(
219 "Puppet-read error in trial {}, step {}, action {} {:?}: {:?} ",
220 trial_name,
221 step_index,
222 action_number,
223 action,
224 e
225 );
226 }
227 Ok(mut puppet_data) => {
228 if puppet.config.has_runner_node {
229 puppet_data.remove_tree("runner");
230 }
231 if let Err(e) = data.compare(&puppet_data, results.diff_type) {
232 bail!(
233 "Compare error in trial {}, step {}, action {}:\n{:?}:\n{} ",
234 trial_name,
235 step_index,
236 action_number,
237 action,
238 e
239 );
240 }
241 }
242 }
243 if puppet.config.test_archive {
244 let archive_data = match ArchiveReader::inspect()
245 .add_selector(ComponentSelector::new(vec![PUPPET_MONIKER.to_string()]))
246 .snapshot()
247 .await
248 {
249 Ok(archive_data) => archive_data,
250 Err(e) => {
251 bail!(
252 "Archive read error in trial {}, step {}, action {}:\n{:?}:\n{} ",
253 trial_name,
254 step_index,
255 action_number,
256 action,
257 e
258 );
259 }
260 };
261 if archive_data.len() != 1 {
262 bail!(
263 "Expected 1 component in trial {}, step {}, action {}:\n{:?}:\nfound {} ",
264 trial_name,
265 step_index,
266 action_number,
267 action,
268 archive_data.len()
269 );
270 }
271
272 let mut hierarchy_data: Data = archive_data[0].payload.as_ref().unwrap().clone().into();
273 if puppet.config.has_runner_node {
274 hierarchy_data.remove_tree("runner");
275 }
276 if let Err(e) = data.compare_to_json(&hierarchy_data, results.diff_type) {
277 bail!(
278 "Archive compare error in trial {}, step {}, action {}:\n{:?}:\n{} ",
279 trial_name,
280 step_index,
281 action_number,
282 action,
283 e
284 );
285 }
286 }
287 }
288 Ok(())
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294 use crate::trials::tests::trial_with_action;
295 use crate::trials::Trial;
296 use crate::*;
297 use fidl_diagnostics_validate::*;
298
299 #[fuchsia::test]
300 async fn unimplemented_works() {
301 let mut int_maker = trial_with_action(
302 "foo",
303 create_numeric_property!(
304 parent: ROOT_ID, id: 1, name: "int", value: Value::IntT(0)),
305 );
306 let mut uint_maker = trial_with_action(
307 "foo",
308 create_numeric_property!(
309 parent: ROOT_ID, id: 2, name: "uint", value: Value::UintT(0)),
310 );
311 let mut uint_create_delete = Trial {
312 name: "foo".to_string(),
313 steps: vec![
314 Step::Actions(vec![
315 create_numeric_property!(parent: ROOT_ID, id: 2, name: "uint", value: Value::UintT(0)),
316 ]),
317 Step::Actions(vec![delete_property!(id: 2)]),
318 ],
319 };
320 let mut results = results::Results::new();
321 let mut puppet = puppet::tests::local_incomplete_puppet().await.unwrap();
322 {
326 let mut data = Data::new();
327 run_trial(&mut puppet, &mut data, &mut int_maker, &mut results).await.unwrap();
328 }
329 {
330 let mut data = Data::new();
331 run_trial(&mut puppet, &mut data, &mut uint_maker, &mut results).await.unwrap();
332 }
333 {
334 let mut data = Data::new();
335 run_trial(&mut puppet, &mut data, &mut uint_create_delete, &mut results).await.unwrap();
336 }
337 assert!(!results
338 .to_json()
339 .contains(&format!("{}: CreateProperty(Int)", puppet.printable_name())));
340 assert!(results
341 .to_json()
342 .contains(&format!("{}: CreateProperty(Uint)", puppet.printable_name())));
343 }
344}