1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker //! Testing virtio-console multiport feature.
6*bb4ee6a4SAndroid Build Coastguard Worker
7*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(any(target_os = "android", target_os = "linux"))]
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::CString;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::read_to_string;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::OpenOptions;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Read;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Write;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
15*bb4ee6a4SAndroid Build Coastguard Worker
16*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
20*bb4ee6a4SAndroid Build Coastguard Worker use fixture::utils::create_vu_console_multiport_config;
21*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vhost_user::VhostUserBackend;
22*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vm::Config as VmConfig;
23*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vm::TestVm;
24*bb4ee6a4SAndroid Build Coastguard Worker use tempfile::NamedTempFile;
25*bb4ee6a4SAndroid Build Coastguard Worker use tempfile::TempDir;
26*bb4ee6a4SAndroid Build Coastguard Worker
run_vhost_user_console_multiport_test_portname(config: VmConfig) -> anyhow::Result<()>27*bb4ee6a4SAndroid Build Coastguard Worker fn run_vhost_user_console_multiport_test_portname(config: VmConfig) -> anyhow::Result<()> {
28*bb4ee6a4SAndroid Build Coastguard Worker let socket = NamedTempFile::new().unwrap();
29*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new()?;
30*bb4ee6a4SAndroid Build Coastguard Worker
31*bb4ee6a4SAndroid Build Coastguard Worker // Prepare 2 virtio-console with only output
32*bb4ee6a4SAndroid Build Coastguard Worker let file_path = vec![
33*bb4ee6a4SAndroid Build Coastguard Worker (temp_dir.path().join("vconsole0.out"), PathBuf::new()),
34*bb4ee6a4SAndroid Build Coastguard Worker (temp_dir.path().join("vconsole1.out"), PathBuf::new()),
35*bb4ee6a4SAndroid Build Coastguard Worker ];
36*bb4ee6a4SAndroid Build Coastguard Worker let vu_config = create_vu_console_multiport_config(socket.path(), file_path.clone());
37*bb4ee6a4SAndroid Build Coastguard Worker let _vu_device = VhostUserBackend::new(vu_config).unwrap();
38*bb4ee6a4SAndroid Build Coastguard Worker
39*bb4ee6a4SAndroid Build Coastguard Worker let config = config.extra_args(vec![
40*bb4ee6a4SAndroid Build Coastguard Worker "--mem".to_owned(),
41*bb4ee6a4SAndroid Build Coastguard Worker "512".to_owned(),
42*bb4ee6a4SAndroid Build Coastguard Worker "--vhost-user-console".to_string(),
43*bb4ee6a4SAndroid Build Coastguard Worker socket.path().to_str().unwrap().to_string(),
44*bb4ee6a4SAndroid Build Coastguard Worker ]);
45*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
46*bb4ee6a4SAndroid Build Coastguard Worker
47*bb4ee6a4SAndroid Build Coastguard Worker // mount sysfs to check details
48*bb4ee6a4SAndroid Build Coastguard Worker vm.exec_in_guest("mount -t sysfs sysfs /sys")?;
49*bb4ee6a4SAndroid Build Coastguard Worker
50*bb4ee6a4SAndroid Build Coastguard Worker // Get portlist
51*bb4ee6a4SAndroid Build Coastguard Worker let result = vm
52*bb4ee6a4SAndroid Build Coastguard Worker .exec_in_guest("ls /sys/class/virtio-ports/")
53*bb4ee6a4SAndroid Build Coastguard Worker .expect("No virtio-ports dir");
54*bb4ee6a4SAndroid Build Coastguard Worker let mut portlist: Vec<&str> = result.stdout.trim_end().split('\n').collect();
55*bb4ee6a4SAndroid Build Coastguard Worker // Remove serial virtio-console created defaultly
56*bb4ee6a4SAndroid Build Coastguard Worker portlist.remove(0);
57*bb4ee6a4SAndroid Build Coastguard Worker for (i, port) in portlist.into_iter().enumerate() {
58*bb4ee6a4SAndroid Build Coastguard Worker let portname = vm
59*bb4ee6a4SAndroid Build Coastguard Worker .exec_in_guest(format!("cat /sys/class/virtio-ports/{}/name", port).as_str())
60*bb4ee6a4SAndroid Build Coastguard Worker .expect("Failed to read portname")
61*bb4ee6a4SAndroid Build Coastguard Worker .stdout;
62*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(portname.trim_end(), format!("port{}", i).as_str());
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
65*bb4ee6a4SAndroid Build Coastguard Worker }
66*bb4ee6a4SAndroid Build Coastguard Worker
67*bb4ee6a4SAndroid Build Coastguard Worker /// Tests vhost-user console device with `crosvm device`.
68*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vhost_user_console_portname_check() -> anyhow::Result<()>69*bb4ee6a4SAndroid Build Coastguard Worker fn vhost_user_console_portname_check() -> anyhow::Result<()> {
70*bb4ee6a4SAndroid Build Coastguard Worker let config = VmConfig::new();
71*bb4ee6a4SAndroid Build Coastguard Worker run_vhost_user_console_multiport_test_portname(config)?;
72*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
73*bb4ee6a4SAndroid Build Coastguard Worker }
74*bb4ee6a4SAndroid Build Coastguard Worker
run_vhost_user_console_multiport_test_output(config: VmConfig) -> anyhow::Result<()>75*bb4ee6a4SAndroid Build Coastguard Worker fn run_vhost_user_console_multiport_test_output(config: VmConfig) -> anyhow::Result<()> {
76*bb4ee6a4SAndroid Build Coastguard Worker let socket = NamedTempFile::new().unwrap();
77*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new()?;
78*bb4ee6a4SAndroid Build Coastguard Worker
79*bb4ee6a4SAndroid Build Coastguard Worker // Prepare 2 virtio-console with only output
80*bb4ee6a4SAndroid Build Coastguard Worker let file_path = vec![
81*bb4ee6a4SAndroid Build Coastguard Worker (temp_dir.path().join("vconsole0.out"), PathBuf::new()),
82*bb4ee6a4SAndroid Build Coastguard Worker (temp_dir.path().join("vconsole1.out"), PathBuf::new()),
83*bb4ee6a4SAndroid Build Coastguard Worker ];
84*bb4ee6a4SAndroid Build Coastguard Worker let vu_config = create_vu_console_multiport_config(socket.path(), file_path.clone());
85*bb4ee6a4SAndroid Build Coastguard Worker let _vu_device = VhostUserBackend::new(vu_config).unwrap();
86*bb4ee6a4SAndroid Build Coastguard Worker
87*bb4ee6a4SAndroid Build Coastguard Worker let config = config.extra_args(vec![
88*bb4ee6a4SAndroid Build Coastguard Worker "--mem".to_owned(),
89*bb4ee6a4SAndroid Build Coastguard Worker "512".to_owned(),
90*bb4ee6a4SAndroid Build Coastguard Worker "--vhost-user-console".to_string(),
91*bb4ee6a4SAndroid Build Coastguard Worker socket.path().to_str().unwrap().to_string(),
92*bb4ee6a4SAndroid Build Coastguard Worker ]);
93*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
94*bb4ee6a4SAndroid Build Coastguard Worker
95*bb4ee6a4SAndroid Build Coastguard Worker // mount sysfs to check details
96*bb4ee6a4SAndroid Build Coastguard Worker vm.exec_in_guest("mount -t sysfs sysfs /sys")?;
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker // Get portlist
99*bb4ee6a4SAndroid Build Coastguard Worker let result = vm
100*bb4ee6a4SAndroid Build Coastguard Worker .exec_in_guest("ls /sys/class/virtio-ports/")
101*bb4ee6a4SAndroid Build Coastguard Worker .expect("No virtio-ports dir");
102*bb4ee6a4SAndroid Build Coastguard Worker let mut portlist: Vec<&str> = result.stdout.trim_end().split('\n').collect();
103*bb4ee6a4SAndroid Build Coastguard Worker // Remove serial virtio-console created defaultly
104*bb4ee6a4SAndroid Build Coastguard Worker portlist.remove(0);
105*bb4ee6a4SAndroid Build Coastguard Worker
106*bb4ee6a4SAndroid Build Coastguard Worker // Test output flow.
107*bb4ee6a4SAndroid Build Coastguard Worker for (i, port) in portlist.into_iter().enumerate() {
108*bb4ee6a4SAndroid Build Coastguard Worker vm.exec_in_guest(format!("echo \"hello {}\" > /dev/{}", port, port).as_str())
109*bb4ee6a4SAndroid Build Coastguard Worker .expect("Failed to echo data to port");
110*bb4ee6a4SAndroid Build Coastguard Worker
111*bb4ee6a4SAndroid Build Coastguard Worker let data = read_to_string(&file_path[i].0).expect("vu-console: read output failed");
112*bb4ee6a4SAndroid Build Coastguard Worker
113*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(data.trim(), format!("hello {}", port).as_str());
114*bb4ee6a4SAndroid Build Coastguard Worker }
115*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
116*bb4ee6a4SAndroid Build Coastguard Worker }
117*bb4ee6a4SAndroid Build Coastguard Worker
118*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vhost_user_console_check_output() -> anyhow::Result<()>119*bb4ee6a4SAndroid Build Coastguard Worker fn vhost_user_console_check_output() -> anyhow::Result<()> {
120*bb4ee6a4SAndroid Build Coastguard Worker let config = VmConfig::new();
121*bb4ee6a4SAndroid Build Coastguard Worker run_vhost_user_console_multiport_test_output(config)?;
122*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
123*bb4ee6a4SAndroid Build Coastguard Worker }
124*bb4ee6a4SAndroid Build Coastguard Worker
125*bb4ee6a4SAndroid Build Coastguard Worker /// Generate the workthread to monitor input and transmit data to output fifo
126*bb4ee6a4SAndroid Build Coastguard Worker ///
127*bb4ee6a4SAndroid Build Coastguard Worker /// Create fifo according to input and output name.
128*bb4ee6a4SAndroid Build Coastguard Worker /// Then spawn a thread to monitor them, simultaneously watch a kill_event to stop thread.
generate_workthread_to_monitor_fifo( idx: usize, infile: PathBuf, outfile: PathBuf, ) -> WorkerThread<()>129*bb4ee6a4SAndroid Build Coastguard Worker fn generate_workthread_to_monitor_fifo(
130*bb4ee6a4SAndroid Build Coastguard Worker idx: usize,
131*bb4ee6a4SAndroid Build Coastguard Worker infile: PathBuf,
132*bb4ee6a4SAndroid Build Coastguard Worker outfile: PathBuf,
133*bb4ee6a4SAndroid Build Coastguard Worker ) -> WorkerThread<()> {
134*bb4ee6a4SAndroid Build Coastguard Worker #[derive(EventToken)]
135*bb4ee6a4SAndroid Build Coastguard Worker enum Token {
136*bb4ee6a4SAndroid Build Coastguard Worker InputDataAvailable,
137*bb4ee6a4SAndroid Build Coastguard Worker Kill,
138*bb4ee6a4SAndroid Build Coastguard Worker }
139*bb4ee6a4SAndroid Build Coastguard Worker let cpath_in = CString::new(infile.to_str().unwrap()).unwrap();
140*bb4ee6a4SAndroid Build Coastguard Worker let cpath_out = CString::new(outfile.to_str().unwrap()).unwrap();
141*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: make two fifos here for monitor thread, path is guaranteed to be valid
142*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
143*bb4ee6a4SAndroid Build Coastguard Worker libc::mkfifo(cpath_in.as_ptr(), 0o777);
144*bb4ee6a4SAndroid Build Coastguard Worker libc::mkfifo(cpath_out.as_ptr(), 0o777);
145*bb4ee6a4SAndroid Build Coastguard Worker }
146*bb4ee6a4SAndroid Build Coastguard Worker WorkerThread::start(format!("monitor_vconsole{}", idx), move |kill_event| {
147*bb4ee6a4SAndroid Build Coastguard Worker let mut tx = OpenOptions::new().write(true).open(outfile).unwrap();
148*bb4ee6a4SAndroid Build Coastguard Worker let mut rx = OpenOptions::new().read(true).open(infile).unwrap();
149*bb4ee6a4SAndroid Build Coastguard Worker let mut msg = vec![0; 256];
150*bb4ee6a4SAndroid Build Coastguard Worker let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
151*bb4ee6a4SAndroid Build Coastguard Worker (&rx, Token::InputDataAvailable),
152*bb4ee6a4SAndroid Build Coastguard Worker (&kill_event, Token::Kill),
153*bb4ee6a4SAndroid Build Coastguard Worker ]) {
154*bb4ee6a4SAndroid Build Coastguard Worker Ok(wait_ctx) => wait_ctx,
155*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
156*bb4ee6a4SAndroid Build Coastguard Worker error!("failed creating WaitContext: {}", e);
157*bb4ee6a4SAndroid Build Coastguard Worker return;
158*bb4ee6a4SAndroid Build Coastguard Worker }
159*bb4ee6a4SAndroid Build Coastguard Worker };
160*bb4ee6a4SAndroid Build Coastguard Worker 'monitor_loop: loop {
161*bb4ee6a4SAndroid Build Coastguard Worker let wait_events = match wait_ctx.wait() {
162*bb4ee6a4SAndroid Build Coastguard Worker Ok(wait_events) => wait_events,
163*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
164*bb4ee6a4SAndroid Build Coastguard Worker error!("failed polling for events: {}", e);
165*bb4ee6a4SAndroid Build Coastguard Worker break;
166*bb4ee6a4SAndroid Build Coastguard Worker }
167*bb4ee6a4SAndroid Build Coastguard Worker };
168*bb4ee6a4SAndroid Build Coastguard Worker for wait_event in wait_events.iter().filter(|e| e.is_readable) {
169*bb4ee6a4SAndroid Build Coastguard Worker match wait_event.token {
170*bb4ee6a4SAndroid Build Coastguard Worker Token::InputDataAvailable => {
171*bb4ee6a4SAndroid Build Coastguard Worker let bytes = rx.read(&mut msg).expect("Failed to read from port");
172*bb4ee6a4SAndroid Build Coastguard Worker if bytes > 0 {
173*bb4ee6a4SAndroid Build Coastguard Worker if tx.write_all(&msg.to_ascii_uppercase()[..bytes]).is_err() {
174*bb4ee6a4SAndroid Build Coastguard Worker break 'monitor_loop;
175*bb4ee6a4SAndroid Build Coastguard Worker }
176*bb4ee6a4SAndroid Build Coastguard Worker }
177*bb4ee6a4SAndroid Build Coastguard Worker }
178*bb4ee6a4SAndroid Build Coastguard Worker Token::Kill => break 'monitor_loop,
179*bb4ee6a4SAndroid Build Coastguard Worker }
180*bb4ee6a4SAndroid Build Coastguard Worker }
181*bb4ee6a4SAndroid Build Coastguard Worker }
182*bb4ee6a4SAndroid Build Coastguard Worker })
183*bb4ee6a4SAndroid Build Coastguard Worker }
184*bb4ee6a4SAndroid Build Coastguard Worker
185*bb4ee6a4SAndroid Build Coastguard Worker /// Tests vhost-user-console input function with multiport feature.
186*bb4ee6a4SAndroid Build Coastguard Worker ///
187*bb4ee6a4SAndroid Build Coastguard Worker /// If we want to test multiport function about input flow,
188*bb4ee6a4SAndroid Build Coastguard Worker /// we need to prepare monitor threads for each ports.
189*bb4ee6a4SAndroid Build Coastguard Worker /// The purpose of this thread is to get all data from rx queue, and transmit them to tx queue.
190*bb4ee6a4SAndroid Build Coastguard Worker /// To increase reliability, monitor thread changes data to uppercase.
191*bb4ee6a4SAndroid Build Coastguard Worker ///
192*bb4ee6a4SAndroid Build Coastguard Worker /// Once monitor threads created, VhostUserBackend for console will work as expected.
run_vhost_user_console_multiport_test_input(config: VmConfig) -> anyhow::Result<()>193*bb4ee6a4SAndroid Build Coastguard Worker fn run_vhost_user_console_multiport_test_input(config: VmConfig) -> anyhow::Result<()> {
194*bb4ee6a4SAndroid Build Coastguard Worker let socket = NamedTempFile::new().unwrap();
195*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new()?;
196*bb4ee6a4SAndroid Build Coastguard Worker
197*bb4ee6a4SAndroid Build Coastguard Worker // Prepare 2 virtio-console with both input and output
198*bb4ee6a4SAndroid Build Coastguard Worker let mut file_path = vec![];
199*bb4ee6a4SAndroid Build Coastguard Worker for idx in 0..2 {
200*bb4ee6a4SAndroid Build Coastguard Worker let fifo_name_out = format!("vconsole{}.out", idx);
201*bb4ee6a4SAndroid Build Coastguard Worker let fifo_name_in = format!("vconsole{}.in", idx);
202*bb4ee6a4SAndroid Build Coastguard Worker file_path.push((
203*bb4ee6a4SAndroid Build Coastguard Worker temp_dir.path().join(fifo_name_out),
204*bb4ee6a4SAndroid Build Coastguard Worker temp_dir.path().join(fifo_name_in),
205*bb4ee6a4SAndroid Build Coastguard Worker ));
206*bb4ee6a4SAndroid Build Coastguard Worker }
207*bb4ee6a4SAndroid Build Coastguard Worker
208*bb4ee6a4SAndroid Build Coastguard Worker let mut thread_vec = vec![];
209*bb4ee6a4SAndroid Build Coastguard Worker for idx in 0..2 {
210*bb4ee6a4SAndroid Build Coastguard Worker thread_vec.push(generate_workthread_to_monitor_fifo(
211*bb4ee6a4SAndroid Build Coastguard Worker idx,
212*bb4ee6a4SAndroid Build Coastguard Worker (*file_path.get(idx).unwrap().0).to_path_buf(),
213*bb4ee6a4SAndroid Build Coastguard Worker (*file_path.get(idx).unwrap().1).to_path_buf(),
214*bb4ee6a4SAndroid Build Coastguard Worker ));
215*bb4ee6a4SAndroid Build Coastguard Worker }
216*bb4ee6a4SAndroid Build Coastguard Worker
217*bb4ee6a4SAndroid Build Coastguard Worker let vu_config = create_vu_console_multiport_config(socket.path(), file_path.clone());
218*bb4ee6a4SAndroid Build Coastguard Worker let _vu_device = VhostUserBackend::new(vu_config).unwrap();
219*bb4ee6a4SAndroid Build Coastguard Worker
220*bb4ee6a4SAndroid Build Coastguard Worker let config = config.extra_args(vec![
221*bb4ee6a4SAndroid Build Coastguard Worker "--mem".to_owned(),
222*bb4ee6a4SAndroid Build Coastguard Worker "512".to_owned(),
223*bb4ee6a4SAndroid Build Coastguard Worker "--vhost-user-console".to_string(),
224*bb4ee6a4SAndroid Build Coastguard Worker socket.path().to_str().unwrap().to_string(),
225*bb4ee6a4SAndroid Build Coastguard Worker ]);
226*bb4ee6a4SAndroid Build Coastguard Worker let mut vm = TestVm::new(config).unwrap();
227*bb4ee6a4SAndroid Build Coastguard Worker
228*bb4ee6a4SAndroid Build Coastguard Worker // mount sysfs to check details
229*bb4ee6a4SAndroid Build Coastguard Worker vm.exec_in_guest("mount -t sysfs sysfs /sys")?;
230*bb4ee6a4SAndroid Build Coastguard Worker
231*bb4ee6a4SAndroid Build Coastguard Worker // Get portlist
232*bb4ee6a4SAndroid Build Coastguard Worker let result = vm
233*bb4ee6a4SAndroid Build Coastguard Worker .exec_in_guest("ls /sys/class/virtio-ports/")
234*bb4ee6a4SAndroid Build Coastguard Worker .expect("No virtio-ports dir");
235*bb4ee6a4SAndroid Build Coastguard Worker let mut portlist: Vec<&str> = result.stdout.trim_end().split('\n').collect();
236*bb4ee6a4SAndroid Build Coastguard Worker // Remove serial virtio-console created defaultly
237*bb4ee6a4SAndroid Build Coastguard Worker portlist.remove(0);
238*bb4ee6a4SAndroid Build Coastguard Worker
239*bb4ee6a4SAndroid Build Coastguard Worker let file_fd = 5;
240*bb4ee6a4SAndroid Build Coastguard Worker // Test input flow.
241*bb4ee6a4SAndroid Build Coastguard Worker for port in portlist.into_iter() {
242*bb4ee6a4SAndroid Build Coastguard Worker // Bind file_fd to operate /dev/vportXpX, then write to fd, finnally read it.
243*bb4ee6a4SAndroid Build Coastguard Worker let result = vm
244*bb4ee6a4SAndroid Build Coastguard Worker .exec_in_guest(
245*bb4ee6a4SAndroid Build Coastguard Worker format!(
246*bb4ee6a4SAndroid Build Coastguard Worker "exec {}<>/dev/{} && echo \"hello {}\" >&{} && head -1 <&{}",
247*bb4ee6a4SAndroid Build Coastguard Worker file_fd, port, port, file_fd, file_fd
248*bb4ee6a4SAndroid Build Coastguard Worker )
249*bb4ee6a4SAndroid Build Coastguard Worker .as_str(),
250*bb4ee6a4SAndroid Build Coastguard Worker )
251*bb4ee6a4SAndroid Build Coastguard Worker .expect("Failed to echo data to port")
252*bb4ee6a4SAndroid Build Coastguard Worker .stdout;
253*bb4ee6a4SAndroid Build Coastguard Worker // Close this fd
254*bb4ee6a4SAndroid Build Coastguard Worker vm.exec_in_guest(format!("exec {}>&-", file_fd).as_str())
255*bb4ee6a4SAndroid Build Coastguard Worker .expect("Failed to close device fd");
256*bb4ee6a4SAndroid Build Coastguard Worker // In monitor thread, tx message will change to uppercase
257*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
258*bb4ee6a4SAndroid Build Coastguard Worker result.trim_end(),
259*bb4ee6a4SAndroid Build Coastguard Worker format!("hello {}", port).to_uppercase().as_str()
260*bb4ee6a4SAndroid Build Coastguard Worker );
261*bb4ee6a4SAndroid Build Coastguard Worker }
262*bb4ee6a4SAndroid Build Coastguard Worker for handler in thread_vec.into_iter() {
263*bb4ee6a4SAndroid Build Coastguard Worker handler.stop();
264*bb4ee6a4SAndroid Build Coastguard Worker }
265*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
266*bb4ee6a4SAndroid Build Coastguard Worker }
267*bb4ee6a4SAndroid Build Coastguard Worker
268*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vhost_user_console_check_input() -> anyhow::Result<()>269*bb4ee6a4SAndroid Build Coastguard Worker fn vhost_user_console_check_input() -> anyhow::Result<()> {
270*bb4ee6a4SAndroid Build Coastguard Worker let config = VmConfig::new();
271*bb4ee6a4SAndroid Build Coastguard Worker run_vhost_user_console_multiport_test_input(config)?;
272*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
273*bb4ee6a4SAndroid Build Coastguard Worker }
274