1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #![cfg(all(target_os = "linux", feature = "process"))]
15 
16 use std::os::fd::{AsFd, AsRawFd};
17 use std::process::Stdio;
18 
19 use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
20 use ylong_runtime::process::{ChildStderr, ChildStdin, ChildStdout, Command};
21 
22 /// SDV test cases for `output()`.
23 ///
24 /// # Brief
25 /// 1. Create a `Command` with arg.
26 /// 2. Use `output()` waiting result.
27 #[test]
sdv_process_output_test()28 fn sdv_process_output_test() {
29     let handle = ylong_runtime::spawn(async {
30         let mut command = Command::new("echo");
31         command.arg("Hello, world!");
32         let output = command.output().await.unwrap();
33 
34         assert!(output.status.success());
35         assert_eq!(output.stdout.as_slice(), b"Hello, world!\n");
36         assert!(output.stderr.is_empty());
37     });
38     ylong_runtime::block_on(handle).unwrap();
39 }
40 
41 /// SDV test cases for `status()`.
42 ///
43 /// # Brief
44 /// 1. Create a `Command` with arg.
45 /// 2. Use `status()` waiting result.
46 #[test]
sdv_process_status_test()47 fn sdv_process_status_test() {
48     let handle = ylong_runtime::spawn(async {
49         let mut command = Command::new("echo");
50         command.arg("Hello, world!");
51 
52         let status = command.status().await.unwrap();
53         assert!(status.success());
54     });
55     ylong_runtime::block_on(handle).unwrap();
56 }
57 
58 /// SDV test cases for `spawn()`.
59 ///
60 /// # Brief
61 /// 1. Create a `Command` with arg.
62 /// 2. Use `spawn()` create a child handle
63 /// 3. Use `wait()` waiting result.
64 #[test]
sdv_process_spawn_test()65 fn sdv_process_spawn_test() {
66     let handle = ylong_runtime::spawn(async {
67         let mut command = Command::new("echo");
68         command.arg("Hello, world!");
69         let mut child = command.spawn().unwrap();
70         assert!(child.id().is_some());
71 
72         let status = child.wait().await.unwrap();
73         assert!(status.success());
74         assert!(child.start_kill().is_err());
75         assert!(child.id().is_none());
76 
77         let status = child.wait().await.unwrap();
78         assert!(status.success());
79     });
80     ylong_runtime::block_on(handle).unwrap();
81 }
82 
83 /// SDV test cases for ChildStdio.
84 ///
85 /// # Brief
86 /// 1. Create a `Command` and `spawn()`.
87 /// 2. Take `child.stdin` and write something in it.
88 /// 3. Take `child.stdout` and read it, check the result.
89 /// 4. Check child's result.
90 #[test]
sdv_process_child_stdio_test()91 fn sdv_process_child_stdio_test() {
92     let handle = ylong_runtime::spawn(async {
93         let mut child = Command::new("rev")
94             .stdin(Stdio::piped())
95             .stdout(Stdio::piped())
96             .stderr(Stdio::piped())
97             .spawn()
98             .expect("Failed to spawn child process");
99 
100         let mut stdin = child.take_stdin().expect("Failed to open stdin");
101         let stdin_handle = ylong_runtime::spawn(async move {
102             stdin.write_all(b"Hello, world!").await.unwrap();
103             stdin.flush().await.unwrap();
104             stdin.shutdown().await.unwrap();
105         });
106 
107         let mut stdout = child.take_stdout().expect("Failed to open stdout");
108         let stdout_handle = ylong_runtime::spawn(async move {
109             let mut buf = Vec::new();
110             stdout.read_to_end(&mut buf).await.unwrap();
111             let str = "!dlrow ,olleH";
112             assert!(String::from_utf8(buf).unwrap().contains(str));
113         });
114 
115         let mut stderr = child.take_stderr().expect("Failed to open stderr");
116         let stderr_handle = ylong_runtime::spawn(async move {
117             let mut buf = Vec::new();
118             stderr.read_to_end(&mut buf).await.unwrap();
119             assert!(buf.is_empty());
120         });
121 
122         let status = child.wait().await.unwrap();
123         assert!(status.success());
124 
125         stdin_handle.await.unwrap();
126         stdout_handle.await.unwrap();
127         stderr_handle.await.unwrap();
128     });
129     ylong_runtime::block_on(handle).unwrap();
130 }
131 
132 /// SDV test cases for `kill()`.
133 ///
134 /// # Brief
135 /// 1. Create a `Command` with arg.
136 /// 2. Use `spawn()` create a child handle
137 /// 3. Use `kill()` to kill the child handle.
138 #[test]
sdv_process_kill_test()139 fn sdv_process_kill_test() {
140     let handle = ylong_runtime::spawn(async {
141         let mut command = Command::new("echo");
142         command.arg("Hello, world!");
143         let mut child = command.spawn().unwrap();
144 
145         assert!(child.kill().await.is_ok());
146     });
147     ylong_runtime::block_on(handle).unwrap();
148 }
149 
150 /// SDV test cases for `try_wait()`.
151 ///
152 /// # Brief
153 /// 1. Create a `Command` with arg.
154 /// 2. Use `spawn()` create a child handle
155 /// 3. Use `try_wait()` waiting result until the child handle is ok.
156 #[test]
sdv_process_try_wait_test()157 fn sdv_process_try_wait_test() {
158     let handle = ylong_runtime::spawn(async {
159         let mut command = Command::new("echo");
160         command.arg("Hello, world!");
161         let mut child = command.spawn().unwrap();
162 
163         loop {
164             if child.try_wait().unwrap().is_some() {
165                 break;
166             }
167         }
168         assert!(child.try_wait().unwrap().is_some());
169     });
170     ylong_runtime::block_on(handle).unwrap();
171 }
172 
173 /// SDV test cases for drop.
174 ///
175 /// # Brief
176 /// 1. Create a `Command` with kill_on_drop.
177 /// 2. Use `spawn()` create a child handle
178 /// 3. Use `drop()` to drop the child handle.
179 #[test]
sdv_process_drop_test()180 fn sdv_process_drop_test() {
181     let handle = ylong_runtime::spawn(async {
182         let mut command = Command::new("echo");
183         command.arg("Hello, world!").kill_on_drop(true);
184         let child = command.spawn();
185         assert!(child.is_ok());
186         drop(child.unwrap());
187 
188         let mut command = Command::new("echo");
189         command.arg("Hello, world!");
190         let child = command.spawn();
191         assert!(child.is_ok());
192         drop(child.unwrap());
193     });
194     ylong_runtime::block_on(handle).unwrap();
195 }
196 
197 /// SDV test cases for stdio.
198 ///
199 /// # Brief
200 /// 1. Create a `Command` with arg.
201 /// 2. Use `spawn()` create a child handle
202 /// 3. Use `wait()` waiting result.
203 #[test]
sdv_process_stdio_test()204 fn sdv_process_stdio_test() {
205     let handle = ylong_runtime::spawn(async {
206         let mut command = Command::new("echo");
207         command
208             .arg("Hello, world!")
209             .stdin(Stdio::piped())
210             .stdout(Stdio::piped())
211             .stderr(Stdio::piped());
212         let mut child = command.spawn().unwrap();
213 
214         let child_stdin = child.take_stdin().unwrap();
215         assert!(child_stdin.into_owned_fd().is_ok());
216         let child_stdout = child.take_stdout().unwrap();
217         assert!(child_stdout.into_owned_fd().is_ok());
218         let child_stderr = child.take_stderr().unwrap();
219         assert!(child_stderr.into_owned_fd().is_ok());
220 
221         drop(child);
222 
223         let mut child = command.spawn().unwrap();
224 
225         let child_stdin = child.take_stdin().unwrap();
226         assert!(child_stdin.as_fd().as_raw_fd() >= 0);
227         assert!(child_stdin.as_raw_fd() >= 0);
228         assert!(TryInto::<Stdio>::try_into(child_stdin).is_ok());
229 
230         let child_stdout = child.take_stdout().unwrap();
231         assert!(child_stdout.as_fd().as_raw_fd() >= 0);
232         assert!(child_stdout.as_raw_fd() >= 0);
233         assert!(TryInto::<Stdio>::try_into(child_stdout).is_ok());
234 
235         let child_stderr = child.take_stderr().unwrap();
236         assert!(child_stderr.as_fd().as_raw_fd() >= 0);
237         assert!(child_stderr.as_raw_fd() >= 0);
238         assert!(TryInto::<Stdio>::try_into(child_stderr).is_ok());
239         drop(child);
240     });
241     ylong_runtime::block_on(handle).unwrap();
242 }
243 
244 /// SDV test cases for ChildStd.
245 ///
246 /// # Brief
247 /// 1. Create a `std::process::Command`.
248 /// 2. Use `spawn()` create a child handle
249 /// 3. Use `from_std()` to convert std to ylong_runtime::process::ChildStd.
250 #[test]
sdv_process_child_stdio_convert_test()251 fn sdv_process_child_stdio_convert_test() {
252     let handle = ylong_runtime::spawn(async {
253         let mut command = std::process::Command::new("echo");
254         command
255             .stdin(Stdio::piped())
256             .stdout(Stdio::piped())
257             .stderr(Stdio::piped());
258         let mut child = command.spawn().unwrap();
259         let stdin = child.stdin.take().unwrap();
260         assert!(ChildStdin::from_std(stdin).is_ok());
261         let stdout = child.stdout.take().unwrap();
262         assert!(ChildStdout::from_std(stdout).is_ok());
263         let stderr = child.stderr.take().unwrap();
264         assert!(ChildStderr::from_std(stderr).is_ok());
265     });
266     ylong_runtime::block_on(handle).unwrap();
267 }
268 
269 /// SDV test cases for command debug.
270 ///
271 /// # Brief
272 /// 1. Debug Command and Child.
273 /// 2. Check format is correct.
274 #[test]
sdv_process_debug_test()275 fn sdv_process_debug_test() {
276     let handle = ylong_runtime::spawn(async {
277         let mut command = Command::new("echo");
278         assert_eq!(
279             format!("{command:?}"),
280             "Command { std: \"echo\", kill: false }"
281         );
282         let mut child = command.spawn().unwrap();
283 
284         assert_eq!(format!("{child:?}"), "Child { state: Pending(Some(Child { stdin: None, stdout: None, stderr: None, .. })), kill_on_drop: false, stdin: None, stdout: None, stderr: None }");
285         let status = child.wait().await.unwrap();
286         assert!(status.success());
287     });
288     ylong_runtime::block_on(handle).unwrap();
289 }
290