1use crate::above_root_capabilities::AboveRootCapabilitiesForTest;
6use crate::debug_data_processor::{DebugDataDirectory, DebugDataProcessor};
7use crate::error::TestManagerError;
8use crate::offers::map_offers;
9use crate::running_suite::{RunningSuite, enumerate_test_cases};
10use crate::self_diagnostics::RootDiagnosticNode;
11use crate::test_suite::{Suite, SuiteRealm, TestRunBuilder};
12use crate::{constants, debug_data_server, facet};
13use fidl::Error;
14use fidl_fuchsia_component_resolution::ResolverProxy;
15use fidl_fuchsia_pkg::PackageResolverProxy;
16use fidl_fuchsia_test_manager as ftest_manager;
17use fidl_fuchsia_test_manager::{QueryEnumerateInRealmResponder, QueryEnumerateResponder};
18use ftest_manager::LaunchError;
19use fuchsia_async::{self as fasync};
20use futures::prelude::*;
21use log::{error, warn};
22use std::sync::Arc;
23
24pub async fn run_test_manager_run_builder_server(
26 mut stream: ftest_manager::RunBuilderRequestStream,
27 resolver: Arc<ResolverProxy>,
28 pkg_resolver: Arc<PackageResolverProxy>,
29 above_root_capabilities_for_test: Arc<AboveRootCapabilitiesForTest>,
30 root_diagnostics: &RootDiagnosticNode,
31) -> Result<(), TestManagerError> {
32 let mut builder = TestRunBuilder { suites: vec![] };
33 let mut scheduling_options: Option<ftest_manager::SchedulingOptions> = None;
34 while let Some(event) = stream.try_next().await.map_err(TestManagerError::Stream)? {
35 match event {
36 ftest_manager::RunBuilderRequest::AddSuite {
37 test_url,
38 options,
39 controller,
40 control_handle: _,
41 } => {
42 let controller = controller.into_stream();
43
44 builder.suites.push(Suite {
45 realm: None,
46 test_url,
47 options,
48 controller,
49 resolver: resolver.clone(),
50 pkg_resolver: pkg_resolver.clone(),
51 above_root_capabilities_for_test: above_root_capabilities_for_test.clone(),
52 facets: facet::ResolveStatus::Unresolved,
53 });
54 }
55 ftest_manager::RunBuilderRequest::AddSuiteInRealm {
56 realm,
57 offers,
58 test_collection,
59 test_url,
60 options,
61 controller,
62 control_handle,
63 } => {
64 let realm_proxy = realm.into_proxy();
65 let controller = controller.into_stream();
66 let offers = match map_offers(offers) {
67 Ok(offers) => offers,
68 Err(e) => {
69 warn!("Cannot add suite {}, invalid offers. error: {}", test_url, e);
70 control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
71 break;
72 }
73 };
74
75 builder.suites.push(Suite {
76 realm: SuiteRealm { realm_proxy, offers, test_collection }.into(),
77 test_url,
78 options,
79 controller,
80 resolver: resolver.clone(),
81 pkg_resolver: pkg_resolver.clone(),
82 above_root_capabilities_for_test: above_root_capabilities_for_test.clone(),
83 facets: facet::ResolveStatus::Unresolved,
84 });
85 }
86 ftest_manager::RunBuilderRequest::WithSchedulingOptions { options, .. } => {
87 scheduling_options = Some(options);
88 }
89 ftest_manager::RunBuilderRequest::Build { controller, control_handle: _ } => {
90 let controller = controller.into_stream();
91
92 let persist_diagnostics =
93 match scheduling_options.as_ref().map(|options| options.max_parallel_suites) {
94 Some(Some(_)) => true,
95 Some(None) | None => false,
96 };
97 let diagnostics = match persist_diagnostics {
98 true => root_diagnostics.persistent_child(),
99 false => root_diagnostics.child(),
100 };
101
102 builder.run(controller, diagnostics, scheduling_options).await;
103 break;
105 }
106 ftest_manager::RunBuilderRequest::_UnknownMethod {
107 ordinal, control_handle, ..
108 } => {
109 warn!("Unknown run builder request received: {}, closing connection", ordinal);
110 control_handle.shutdown_with_epitaph(zx::Status::NOT_SUPPORTED);
111 break;
112 }
113 }
114 }
115 Ok(())
116}
117
118enum QueryResponder {
119 Enumerate(QueryEnumerateResponder),
120 EnumerateInRealm(QueryEnumerateInRealmResponder),
121}
122
123impl QueryResponder {
124 fn send(self, result: Result<(), LaunchError>) -> Result<(), fidl::Error> {
125 match self {
126 QueryResponder::Enumerate(responder) => responder.send(result),
127 QueryResponder::EnumerateInRealm(responder) => responder.send(result),
128 }
129 }
130}
131
132pub async fn run_test_manager_query_server(
134 mut stream: ftest_manager::QueryRequestStream,
135 resolver: Arc<ResolverProxy>,
136 pkg_resolver: Arc<PackageResolverProxy>,
137 above_root_capabilities_for_test: Arc<AboveRootCapabilitiesForTest>,
138 root_diagnostics: &RootDiagnosticNode,
139) -> Result<(), TestManagerError> {
140 while let Some(event) = stream.try_next().await.map_err(TestManagerError::Stream)? {
141 let (test_url, iterator, realm, responder) = match event {
142 ftest_manager::QueryRequest::Enumerate { test_url, iterator, responder } => {
143 (test_url, iterator, None, QueryResponder::Enumerate(responder))
144 }
145 ftest_manager::QueryRequest::EnumerateInRealm {
146 test_url,
147 realm,
148 offers,
149 test_collection,
150 iterator,
151 responder,
152 } => {
153 let realm_proxy = realm.into_proxy();
154 let offers = match map_offers(offers) {
155 Ok(offers) => offers,
156 Err(e) => {
157 warn!("Cannot add suite {}, invalid offers. error: {}", test_url, e);
158 responder.send(Err(LaunchError::InvalidArgs)).ok();
159 break;
160 }
161 };
162 (
163 test_url,
164 iterator,
165 SuiteRealm { realm_proxy, offers, test_collection }.into(),
166 QueryResponder::EnumerateInRealm(responder),
167 )
168 }
169
170 ftest_manager::QueryRequest::_UnknownMethod { ordinal, control_handle, .. } => {
171 warn!("Unknown query request received: {}, closing connection", ordinal);
172 control_handle.shutdown_with_epitaph(zx::Status::NOT_SUPPORTED);
173 break;
174 }
175 };
176 let mut iterator = iterator.into_stream();
177 let (_processor, sender) = DebugDataProcessor::new(DebugDataDirectory::Isolated {
178 parent: constants::ISOLATED_TMP,
179 });
180 let diagnostics = root_diagnostics.child();
181 let launch_fut =
182 facet::get_suite_facets(test_url.clone(), resolver.clone()).and_then(|facets| {
183 RunningSuite::launch(
184 &test_url,
185 facets,
186 resolver.clone(),
187 pkg_resolver.clone(),
188 above_root_capabilities_for_test.clone(),
189 sender,
190 &diagnostics,
191 &realm,
192 false, )
194 });
195 match launch_fut.await {
196 Ok(suite_instance) => {
197 let suite = match suite_instance.connect_to_suite() {
198 Ok(proxy) => proxy,
199 Err(e) => {
200 responder.send(Err(e.into())).ok();
201 continue;
202 }
203 };
204 let enumeration_result = enumerate_test_cases(&suite, None).await;
205 let t = fasync::Task::spawn(suite_instance.destroy(root_diagnostics.child()));
206 match enumeration_result {
207 Ok(invocations) => {
208 const NAMES_CHUNK: usize = 50;
209 let mut names = Vec::with_capacity(invocations.len());
210 if let Ok(_) = invocations.into_iter().try_for_each(|i| match i.name {
211 Some(name) => {
212 names.push(name);
213 Ok(())
214 }
215 None => {
216 warn!("no name for a invocation in {}", test_url);
217 Err(())
218 }
219 }) {
220 responder.send(Ok(())).ok();
221 let mut names = names.chunks(NAMES_CHUNK);
222 while let Ok(Some(request)) = iterator.try_next().await {
223 match request {
224 ftest_manager::CaseIteratorRequest::GetNext { responder } => {
225 match names.next() {
226 Some(names) => {
227 responder
228 .send(
229 &names
230 .iter()
231 .map(|s| ftest_manager::Case {
232 name: Some(s.into()),
233 ..Default::default()
234 })
235 .collect::<Vec<_>>(),
236 )
237 .ok();
238 }
239 None => {
240 responder.send(&[]).ok();
241 }
242 }
243 }
244 }
245 }
246 } else {
247 responder.send(Err(LaunchError::CaseEnumeration)).ok();
248 }
249 }
250 Err(err) => {
251 warn!(err:?; "cannot enumerate tests for {}", test_url);
252 responder.send(Err(LaunchError::CaseEnumeration)).ok();
253 }
254 }
255 if let Err(err) = t.await {
256 warn!(err:?; "Error destroying test realm for {}", test_url);
257 }
258 }
259 Err(e) => {
260 responder.send(Err(e.into())).ok();
261 }
262 }
263 }
264 Ok(())
265}
266
267pub async fn serve_early_boot_profiles(
268 mut stream: ftest_manager::EarlyBootProfileRequestStream,
269) -> Result<(), TestManagerError> {
270 while let Some(req) = stream.try_next().await.map_err(TestManagerError::Stream)? {
271 match req {
272 ftest_manager::EarlyBootProfileRequest::RegisterWatcher {
273 iterator,
274 control_handle,
275 } => {
276 let iterator = iterator.into_stream();
277 if let Err(e) = debug_data_server::send_kernel_debug_data(iterator).await {
278 warn!("Err serving kernel profiles: {}", e);
279 control_handle.shutdown_with_epitaph(zx::Status::INTERNAL);
280 break;
281 }
282 }
283 ftest_manager::EarlyBootProfileRequest::_UnknownMethod {
284 ordinal,
285 control_handle,
286 ..
287 } => {
288 warn!("Unknown EarlyBootProfile request received: {}, closing connection", ordinal);
289 control_handle.shutdown_with_epitaph(zx::Status::NOT_SUPPORTED);
290 break;
291 }
292 }
293 }
294 Ok(())
295}
296
297pub async fn run_test_manager_test_case_enumerator_server(
299 mut stream: ftest_manager::TestCaseEnumeratorRequestStream,
300 resolver: Arc<ResolverProxy>,
301 pkg_resolver: Arc<PackageResolverProxy>,
302 above_root_capabilities_for_test: Arc<AboveRootCapabilitiesForTest>,
303 root_diagnostics: &RootDiagnosticNode,
304) -> Result<(), TestManagerError> {
305 while let Some(req) = stream.try_next().await.map_err(TestManagerError::Stream)? {
306 match req {
307 ftest_manager::TestCaseEnumeratorRequest::Enumerate {
308 test_suite_url,
309 options,
310 iterator,
311 responder,
312 } => {
313 let realm = if let Some(realm_options) = options.realm_options {
314 let realm_proxy = match realm_options
315 .realm
316 .map(|r| Ok(r.into_proxy()))
317 .unwrap_or(Err(Error::NotNullable))
318 {
319 Ok(r) => r,
320 Err(e) => {
321 warn!(
322 "Cannot enumerate test cases {}, invalid realm. Closing connection. error: {}",
323 test_suite_url, e
324 );
325 responder.send(Err(LaunchError::InvalidArgs)).ok();
326 break;
327 }
328 };
329 let offers = match realm_options
330 .offers
331 .map(map_offers)
332 .unwrap_or(Err(Error::NotNullable.into()))
333 {
334 Ok(offers) => offers,
335 Err(e) => {
336 warn!(
337 "Cannot enumerate test cases {}, invalid offers. error: {}",
338 test_suite_url, e
339 );
340 responder.send(Err(LaunchError::InvalidArgs)).ok();
341 break;
342 }
343 };
344 let test_collection = match realm_options.test_collection {
345 Some(test_collection) => test_collection,
346 None => {
347 warn!(
348 "Cannot enumerate test cases {}, missing test collection.",
349 test_suite_url
350 );
351 responder.send(Err(LaunchError::InvalidArgs)).ok();
352 break;
353 }
354 };
355 Some(SuiteRealm { realm_proxy, offers, test_collection })
356 } else {
357 None
358 };
359
360 let iterator = iterator.into_stream();
361 let (_processor, sender) = DebugDataProcessor::new(DebugDataDirectory::Isolated {
362 parent: constants::ISOLATED_TMP,
363 });
364 let diagnostics = root_diagnostics.child();
365 let launch_fut = facet::get_suite_facets(test_suite_url.clone(), resolver.clone())
366 .and_then(|facets| {
367 RunningSuite::launch(
368 &test_suite_url,
369 facets,
370 resolver.clone(),
371 pkg_resolver.clone(),
372 above_root_capabilities_for_test.clone(),
373 sender,
374 &diagnostics,
375 &realm,
376 false, )
378 });
379 match launch_fut.await {
380 Ok(suite_instance) => {
381 let suite = match suite_instance.connect_to_suite() {
382 Ok(proxy) => proxy,
383 Err(e) => {
384 responder.send(Err(e.into())).ok();
385 continue;
386 }
387 };
388 let enumeration_result = enumerate_test_cases(&suite, None).await;
389 let t = fasync::Task::spawn(suite_instance.destroy(diagnostics));
390 match enumeration_result {
391 Ok(invocations) => {
392 if let Ok(names) = invocations
393 .into_iter()
394 .map(|i| i.name.ok_or(()))
395 .collect::<Result<Vec<String>, ()>>()
396 {
397 responder.send(Ok(())).ok();
398 drain_test_case_names(iterator, names).await;
399 } else {
400 responder.send(Err(LaunchError::CaseEnumeration)).ok();
401 }
402 }
403 Err(err) => {
404 warn!(err:?; "cannot enumerate tests for {}", test_suite_url);
405 responder.send(Err(LaunchError::CaseEnumeration)).ok();
406 }
407 }
408 if let Err(err) = t.await {
409 warn!(err:?; "Error destroying test realm for {}", test_suite_url);
410 }
411 }
412 Err(e) => {
413 responder.send(Err(e.into())).ok();
414 }
415 }
416 }
417
418 ftest_manager::TestCaseEnumeratorRequest::_UnknownMethod {
419 ordinal,
420 control_handle,
421 ..
422 } => {
423 warn!("Unknown query request received: {}, closing connection", ordinal);
424 control_handle.shutdown_with_epitaph(zx::Status::NOT_SUPPORTED);
425 break;
426 }
427 };
428 }
429 Ok(())
430}
431
432async fn drain_test_case_names(
433 mut iterator: ftest_manager::TestCaseIteratorRequestStream,
434 names: Vec<String>,
435) {
436 const NAMES_CHUNK: usize = 50;
437 let mut names = names.chunks(NAMES_CHUNK);
438 while let Ok(Some(request)) = iterator.try_next().await {
439 match request {
440 ftest_manager::TestCaseIteratorRequest::GetNext { responder } => match names.next() {
441 Some(names) => {
442 responder
443 .send(
444 &names
445 .iter()
446 .map(|s| ftest_manager::TestCase {
447 name: Some(s.into()),
448 ..Default::default()
449 })
450 .collect::<Vec<_>>(),
451 )
452 .ok();
453 }
454 None => {
455 responder.send(&[]).ok();
456 }
457 },
458 }
459 }
460}
461
462pub async fn run_test_manager_suite_runner_server(
464 mut stream: ftest_manager::SuiteRunnerRequestStream,
465 resolver: Arc<ResolverProxy>,
466 pkg_resolver: Arc<PackageResolverProxy>,
467 above_root_capabilities_for_test: Arc<AboveRootCapabilitiesForTest>,
468 root_diagnostics: &RootDiagnosticNode,
469) -> Result<(), TestManagerError> {
470 while let Some(req) = stream.try_next().await.map_err(TestManagerError::Stream)? {
471 match req {
472 ftest_manager::SuiteRunnerRequest::Run {
473 test_suite_url,
474 options,
475 controller,
476 control_handle,
477 } => {
478 let realm = if let Some(realm_options) = options.realm_options {
479 let realm_proxy = match realm_options
480 .realm
481 .map(|r| Ok(r.into_proxy()))
482 .unwrap_or(Err(Error::NotNullable))
483 {
484 Ok(r) => r,
485 Err(e) => {
486 warn!(
487 "Cannot run suite {}, invalid realm. Closing connection. error: {}",
488 test_suite_url, e
489 );
490 control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
491 break;
492 }
493 };
494 let offers = match realm_options
495 .offers
496 .map(map_offers)
497 .unwrap_or(Err(Error::NotNullable.into()))
498 {
499 Ok(offers) => offers,
500 Err(e) => {
501 warn!(
502 "Cannot run suite {}, invalid offers. error: {}",
503 test_suite_url, e
504 );
505 control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
506 break;
507 }
508 };
509 let test_collection = match realm_options.test_collection {
510 Some(test_collection) => test_collection,
511 None => {
512 warn!("Cannot run suite {}, missing test collection.", test_suite_url);
513 control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
514 break;
515 }
516 };
517 Some(SuiteRealm { realm_proxy, offers, test_collection })
518 } else {
519 None
520 };
521
522 match options.logs_iterator_type {
524 Some(ftest_manager::LogsIteratorType::Batch)
525 | Some(ftest_manager::LogsIteratorType::Socket)
526 | None => {
527 }
529 Some(t) => {
530 error!("Unrecognized log iterator type {:?}.", t);
531 control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
532 break;
533 }
534 }
535
536 let controller = controller.into_stream();
537
538 let suite = Suite {
539 realm: realm.into(),
540 test_url: test_suite_url,
541 options: ftest_manager::RunOptions {
542 run_disabled_tests: options.run_disabled_tests,
543 parallel: options.max_concurrent_test_case_runs,
544 arguments: options.arguments,
545 timeout: options.timeout,
546 case_filters_to_run: options.test_case_filters,
547 log_iterator: options.logs_iterator_type.map(convert),
548 log_interest: options.log_interest,
549 break_on_failure: options.break_on_failure,
550 no_exception_channel: options.no_exception_channel,
551 ..Default::default()
552 },
553 controller,
554 resolver: resolver.clone(),
555 pkg_resolver: pkg_resolver.clone(),
556 above_root_capabilities_for_test: above_root_capabilities_for_test.clone(),
557 facets: facet::ResolveStatus::Unresolved,
558 };
559
560 let diagnostics = root_diagnostics.child();
561
562 suite.run(diagnostics, options.accumulate_debug_data.unwrap_or(false)).await;
563 }
564
565 ftest_manager::SuiteRunnerRequest::_UnknownMethod {
566 ordinal, control_handle, ..
567 } => {
568 warn!("Unknown run builder request received: {}, closing connection", ordinal);
569 control_handle.shutdown_with_epitaph(zx::Status::NOT_SUPPORTED);
570 break;
571 }
572 }
573 }
574 Ok(())
575}
576
577fn convert(item: ftest_manager::LogsIteratorType) -> ftest_manager::LogsIteratorOption {
578 match item {
579 ftest_manager::LogsIteratorType::Batch => ftest_manager::LogsIteratorOption::BatchIterator,
580 ftest_manager::LogsIteratorType::Socket => {
581 ftest_manager::LogsIteratorOption::SocketBatchIterator
582 }
583 _ => todo!(),
584 }
585}