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