test_runners_lib/elf/
server.rs1use crate::cases::TestCaseInfo;
9use crate::elf::Component;
10use crate::errors::{EnumerationError, RunTestError};
11use async_trait::async_trait;
12use futures::future::{AbortHandle, Shared};
13use futures::lock::Mutex;
14use futures::prelude::*;
15use log::{error, warn};
16use rust_measure_tape_for_case::Measurable as _;
17use std::pin::Pin;
18use std::sync::{Arc, Weak};
19use thiserror::Error;
20use zx::sys::ZX_CHANNEL_MAX_MSG_BYTES;
21use {fidl_fuchsia_test as ftest, fuchsia_async as fasync};
22
23pub type PinnedFuture<T, E> = Pin<Box<dyn Future<Output = Result<T, E>> + Send>>;
25type SharedFuture<T, E> = Shared<PinnedFuture<T, E>>;
27pub type MemoizedFutureContainer<T, E> = Arc<Mutex<Option<SharedFuture<T, E>>>>;
30pub type EnumeratedTestCases = Arc<Vec<TestCaseInfo>>;
32
33#[async_trait]
35pub trait SuiteServer: Sized + Sync + Send {
36 fn run(
44 self,
45 component: Weak<Component>,
46 test_url: &str,
47 stream: ftest::SuiteRequestStream,
48 ) -> AbortHandle;
49
50 async fn enumerate_tests(
56 &self,
57 test_component: Arc<Component>,
58 ) -> Result<EnumeratedTestCases, EnumerationError>;
59
60 async fn run_tests(
62 &self,
63 invocations: Vec<ftest::Invocation>,
64 run_options: ftest::RunOptions,
65 test_component: Arc<Component>,
66 run_listener: &ftest::RunListenerProxy,
67 ) -> Result<(), RunTestError>;
68
69 fn get_parallel_count(parallel: u16) -> usize {
70 if parallel == 0 {
71 warn!("Client passed number of concurrent tests as 0, setting it to 1.");
72 return 1;
73 }
74 parallel.into()
75 }
76
77 async fn serve_test_suite(
79 mut self,
80 mut stream: ftest::SuiteRequestStream,
81 component: Weak<Component>,
82 ) -> Result<(), SuiteServerError> {
83 while let Some(event) = stream.try_next().await.map_err(SuiteServerError::Stream)? {
84 match event {
85 ftest::SuiteRequest::GetTests { iterator, control_handle: _ } => {
86 let component = component.upgrade();
87 if component.is_none() {
88 break;
90 }
91 let mut stream = iterator.into_stream();
92 let tests = self.enumerate_tests(component.unwrap()).await?;
93
94 fasync::Task::spawn(
95 async move {
96 let cases: Vec<_> = tests
97 .iter()
98 .map(|TestCaseInfo { name, enabled }| ftest::Case {
99 name: Some(name.clone()),
100 enabled: Some(*enabled),
101 ..Default::default()
102 })
103 .collect();
104 let mut remaining_cases = &cases[..];
105 while let Some(ftest::CaseIteratorRequest::GetNext { responder }) =
106 stream.try_next().await?
107 {
108 let mut bytes_used: usize = 32;
111 let mut case_count = 0;
112 for case in remaining_cases {
113 bytes_used += case.measure().num_bytes;
114 if bytes_used > ZX_CHANNEL_MAX_MSG_BYTES as usize {
115 break;
116 }
117 case_count += 1;
118 }
119 responder
120 .send(&remaining_cases[..case_count])
121 .map_err(SuiteServerError::Response)?;
122 remaining_cases = &remaining_cases[case_count..];
123 }
124 Ok(())
125 }
126 .unwrap_or_else(|e: anyhow::Error| error!("error serving tests: {:?}", e)),
127 )
128 .detach();
129 }
130 ftest::SuiteRequest::Run { tests, options, listener, .. } => {
131 let component = component.upgrade();
132 if component.is_none() {
133 break;
135 }
136
137 let listener = listener.into_proxy();
138
139 self.run_tests(tests, options, component.unwrap(), &listener).await?;
140 listener.on_finished().map_err(RunTestError::SendFinishAllTests).unwrap();
141 }
142 }
143 }
144 Ok(())
145 }
146}
147
148#[derive(Debug, Error)]
150pub enum SuiteServerError {
151 #[error("test enumeration failed: {:?}", _0)]
152 Enumeration(crate::errors::EnumerationError),
153
154 #[error("error running test: {:?}", _0)]
155 RunTest(crate::errors::RunTestError),
156
157 #[error("stream failed: {:?}", _0)]
158 Stream(fidl::Error),
159
160 #[error("Cannot send fidl response: {:?}", _0)]
161 Response(fidl::Error),
162}
163
164impl From<EnumerationError> for SuiteServerError {
165 fn from(error: crate::errors::EnumerationError) -> Self {
166 SuiteServerError::Enumeration(error)
167 }
168}
169
170impl From<RunTestError> for SuiteServerError {
171 fn from(error: crate::errors::RunTestError) -> Self {
172 SuiteServerError::RunTest(error)
173 }
174}
175
176#[derive(Debug, Error)]
178pub enum FidlError {
179 #[error("cannot convert proxy to channel")]
180 ProxyToChannel,
181
182 #[error("cannot convert client end to proxy: {:?}", _0)]
183 ClientEndToProxy(fidl::Error),
184
185 #[error("cannot create fidl proxy: {:?}", _0)]
186 CreateProxy(fidl::Error),
187}
188
189#[derive(Debug, Error)]
191pub enum KernelError {
192 #[error("job creation failed: {:?}", _0)]
193 CreateJob(zx::Status),
194
195 #[error("error waiting for test process to exit: {:?}", _0)]
196 ProcessExit(zx::Status),
197
198 #[error("error getting info from process: {:?}", _0)]
199 ProcessInfo(zx::Status),
200
201 #[error("error creating socket: {:?}", _0)]
202 CreateSocket(zx::Status),
203
204 #[error("cannot convert zircon socket to async socket: {:?}", _0)]
205 SocketToAsync(zx::Status),
206}