• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 use std::ffi::OsStr;
15 use std::future::Future;
16 use std::io;
17 use std::path::Path;
18 use std::process::{Command as StdCommand, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio};
19 
20 use crate::process::child::{Child, ChildStderr, ChildStdin, ChildStdout};
21 
22 /// Async version of std::process::Command
23 #[derive(Debug)]
24 pub struct Command {
25     std: StdCommand,
26     kill: bool,
27 }
28 
29 /// # Example
30 ///
31 /// ```
32 /// use std::process::Command;
33 /// let command = Command::new("echo");
34 /// let ylong_command = ylong_runtime::process::Command::new("hello");
35 /// ```
36 impl From<StdCommand> for Command {
from(value: StdCommand) -> Self37     fn from(value: StdCommand) -> Self {
38         Self {
39             std: value,
40             kill: false,
41         }
42     }
43 }
44 
45 impl Command {
46     /// Constructs a new Command for launching the program at path program, with
47     /// the following default configuration:
48     /// * No arguments to the program
49     /// * Inherit the current process's environment
50     /// * Inherit the current process's working directory
51     /// * Inherit stdin/stdout/stderr for spawn or status, but create pipes for
52     ///   output
53     ///
54     /// Builder methods are provided to change these defaults and otherwise
55     /// configure the process. If program is not an absolute path, the PATH
56     /// will be searched in an OS-defined way. The search path to be used
57     /// may be controlled by setting the PATH environment variable on the
58     /// Command, but this has some implementation limitations on Windows (see
59     /// issue [#37519]).
60     ///
61     /// # Example
62     /// ```
63     /// use ylong_runtime::process::Command;
64     /// let _command = Command::new("sh");
65     /// ```
66     ///
67     /// [#37519]: https://github.com/rust-lang/rust/issues/37519
new<S: AsRef<OsStr>>(program: S) -> Self68     pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
69         Self {
70             std: StdCommand::new(program),
71             kill: false,
72         }
73     }
74 
75     /// Gets std::process::Command from async `Command`
76     ///
77     /// # Example
78     ///
79     /// ```
80     /// use ylong_runtime::process::Command;
81     /// let command = Command::new("echo");
82     /// let std_command = command.as_std();
83     /// ```
as_std(&self) -> &StdCommand84     pub fn as_std(&self) -> &StdCommand {
85         &self.std
86     }
87 
88     /// Sets whether kill the child process when `Child` drop.
89     /// The default value is false, it's similar to the behavior of the std.
kill_on_drop(&mut self, kill: bool) -> &mut Command90     pub fn kill_on_drop(&mut self, kill: bool) -> &mut Command {
91         self.kill = kill;
92         self
93     }
94 
95     /// Adds a parameter to pass to the program.
96     ///
97     /// It's same as std.
98     ///
99     /// # Example
100     ///
101     /// ```no_run
102     /// use ylong_runtime::process::Command;
103     ///
104     /// Command::new("ls")
105     ///     .arg("-l")
106     ///     .arg("-a")
107     ///     .spawn()
108     ///     .expect("ls command failed to start");
109     /// ```
arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command110     pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
111         self.std.arg(arg);
112         self
113     }
114 
115     /// Adds multiple parameters to pass to the program.
116     ///
117     /// It's same as std.
118     ///
119     /// # Example
120     ///
121     /// ```no_run
122     /// use ylong_runtime::process::Command;
123     ///
124     /// Command::new("ls")
125     ///     .args(["-l", "-a"])
126     ///     .spawn()
127     ///     .expect("ls command failed to start");
128     /// ```
args<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(&mut self, args: I) -> &mut Command129     pub fn args<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(&mut self, args: I) -> &mut Command {
130         self.std.args(args);
131         self
132     }
133 
134     /// Inserts or updates an environment variable mapping.
135     ///
136     /// It's same as std.
137     ///
138     /// # Example
139     ///
140     /// ```no_run
141     /// use ylong_runtime::process::Command;
142     ///
143     /// Command::new("ls")
144     ///     .env("PATH", "/bin")
145     ///     .spawn()
146     ///     .expect("ls command failed to start");
147     /// ```
env<K: AsRef<OsStr>, V: AsRef<OsStr>>(&mut self, key: K, val: V) -> &mut Command148     pub fn env<K: AsRef<OsStr>, V: AsRef<OsStr>>(&mut self, key: K, val: V) -> &mut Command {
149         self.std.env(key, val);
150         self
151     }
152 
153     /// Adds or updates multiple environment variable mappings.
154     ///
155     /// It's same as std.
156     ///
157     /// # Example
158     ///
159     /// ```no_run
160     /// use std::collections::HashMap;
161     /// use std::env;
162     /// use std::process::Stdio;
163     ///
164     /// use ylong_runtime::process::Command;
165     ///
166     /// let filtered_env: HashMap<String, String> = env::vars()
167     ///     .filter(|&(ref k, _)| k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH")
168     ///     .collect();
169     ///
170     /// Command::new("printenv")
171     ///     .stdin(Stdio::null())
172     ///     .stdout(Stdio::inherit())
173     ///     .env_clear()
174     ///     .envs(&filtered_env)
175     ///     .spawn()
176     ///     .expect("printenv failed to start");
177     /// ```
envs<I, S, V>(&mut self, vars: I) -> &mut Command where I: IntoIterator<Item = (S, V)>, S: AsRef<OsStr>, V: AsRef<OsStr>,178     pub fn envs<I, S, V>(&mut self, vars: I) -> &mut Command
179     where
180         I: IntoIterator<Item = (S, V)>,
181         S: AsRef<OsStr>,
182         V: AsRef<OsStr>,
183     {
184         self.std.envs(vars);
185         self
186     }
187 
188     /// Removes an environment variable mapping.
189     ///
190     /// It's same as std.
191     ///
192     /// # Example
193     ///
194     /// ```no_run
195     /// use ylong_runtime::process::Command;
196     ///
197     /// Command::new("ls")
198     ///     .env_remove("PATH")
199     ///     .spawn()
200     ///     .expect("ls command failed to start");
201     /// ```
env_remove<S: AsRef<OsStr>>(&mut self, key: S) -> &mut Command202     pub fn env_remove<S: AsRef<OsStr>>(&mut self, key: S) -> &mut Command {
203         self.std.env_remove(key);
204         self
205     }
206 
207     /// Clears the entire environment map for the child process.
208     ///
209     /// It's same as std.
210     ///
211     /// # Example
212     ///
213     /// ```no_run
214     /// use ylong_runtime::process::Command;
215     ///
216     /// Command::new("ls")
217     ///     .env_clear()
218     ///     .spawn()
219     ///     .expect("ls command failed to start");
220     /// ```
env_clear(&mut self) -> &mut Command221     pub fn env_clear(&mut self) -> &mut Command {
222         self.std.env_clear();
223         self
224     }
225 
226     /// Sets the child process's working directory.
227     ///
228     /// It's same as std.
229     ///
230     /// # Example
231     ///
232     /// ```no_run
233     /// use ylong_runtime::process::Command;
234     ///
235     /// Command::new("ls")
236     ///     .current_dir("/bin")
237     ///     .spawn()
238     ///     .expect("ls command failed to start");
239     /// ```
current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command240     pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command {
241         self.std.current_dir(dir);
242         self
243     }
244 
245     /// Configuration for the child process's standard input (stdin) handle.
246     /// Defaults to inherit when used with spawn or status, and defaults to
247     /// piped when used with output.
248     ///
249     /// It's same as std.
250     ///
251     /// # Example
252     ///
253     /// ```no_run
254     /// use std::process::Stdio;
255     ///
256     /// use ylong_runtime::process::Command;
257     ///
258     /// Command::new("ls")
259     ///     .stdin(Stdio::null())
260     ///     .spawn()
261     ///     .expect("ls command failed to start");
262     /// ```
stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command263     pub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
264         self.std.stdin(cfg);
265         self
266     }
267 
268     /// Configuration for the child process's standard output (stdout) handle.
269     /// Defaults to inherit when used with spawn or status, and defaults to
270     /// piped when used with output.
271     ///
272     /// It's same as std.
273     ///
274     /// # Example
275     ///
276     /// ```no_run
277     /// use std::process::Stdio;
278     ///
279     /// use ylong_runtime::process::Command;
280     ///
281     /// Command::new("ls")
282     ///     .stdout(Stdio::null())
283     ///     .spawn()
284     ///     .expect("ls command failed to start");
285     /// ```
stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command286     pub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
287         self.std.stdout(cfg);
288         self
289     }
290 
291     /// Configuration for the child process's standard error (stderr) handle.
292     /// Defaults to inherit when used with spawn or status, and defaults to
293     /// piped when used with output.
294     ///
295     /// It's same as std.
296     ///
297     /// # Example
298     ///
299     /// ```no_run
300     /// use std::process::Stdio;
301     ///
302     /// use ylong_runtime::process::Command;
303     ///
304     /// Command::new("ls")
305     ///     .stderr(Stdio::null())
306     ///     .spawn()
307     ///     .expect("ls command failed to start");
308     /// ```
stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command309     pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
310         self.std.stderr(cfg);
311         self
312     }
313 
314     /// Executes the command as a child process, returning a handle to it.
315     /// By default, stdin, stdout and stderr are inherited from the parent.
316     ///
317     /// This will spawn the child process synchronously and return a Future
318     /// handle of child process.
319     ///
320     /// # Example
321     ///
322     /// ```no_run
323     /// use ylong_runtime::process::Command;
324     ///
325     /// async fn command() -> std::process::ExitStatus {
326     ///     let mut child = Command::new("ls")
327     ///         .spawn()
328     ///         .expect("ls command failed to start");
329     ///     child.wait().await.expect("ls command failed to run")
330     /// }
331     /// ```
spawn(&mut self) -> io::Result<Child>332     pub fn spawn(&mut self) -> io::Result<Child> {
333         let mut child = self.std.spawn()?;
334         let stdin = child
335             .stdin
336             .take()
337             .map(super::sys::stdio)
338             .transpose()?
339             .map(ChildStdin::new);
340         let stdout = child
341             .stdout
342             .take()
343             .map(super::sys::stdio)
344             .transpose()?
345             .map(ChildStdout::new);
346         let stderr = child
347             .stderr
348             .take()
349             .map(super::sys::stdio)
350             .transpose()?
351             .map(ChildStderr::new);
352 
353         Child::new(child, self.kill, stdin, stdout, stderr)
354     }
355 
356     /// Executes the command as a child process, waiting for it to finish and
357     /// collecting all of its output. By default, stdout and stderr are
358     /// captured (and used to provide the resulting output). Stdin is not
359     /// inherited from the parent and any attempt by the child process to read
360     /// from the stdin stream will result in the stream immediately closing.
361     ///
362     /// If set `kill_on_drop()`, the child will be killed when this method
363     /// return.
364     ///
365     /// # Example
366     ///
367     /// ```no_run
368     /// use ylong_runtime::process::Command;
369     ///
370     /// async fn command() {
371     ///     let output = Command::new("ls")
372     ///         .output()
373     ///         .await
374     ///         .expect("ls command failed to run");
375     ///     println!("stdout of ls: {:?}", output.stdout);
376     /// }
377     /// ```
output(&mut self) -> impl Future<Output = io::Result<Output>>378     pub fn output(&mut self) -> impl Future<Output = io::Result<Output>> {
379         self.stdout(Stdio::piped());
380         self.stderr(Stdio::piped());
381 
382         let child = self.spawn();
383 
384         async { child?.output_wait().await }
385     }
386 
387     /// Executes a command as a child process, waiting for it to finish and
388     /// collecting its status. By default, stdin, stdout and stderr are
389     /// inherited from the parent.
390     ///
391     /// If set `kill_on_drop()`, the child will be killed when this method
392     /// return.
393     ///
394     /// # Example
395     ///
396     /// ```no_run
397     /// use ylong_runtime::process::Command;
398     ///
399     /// async fn command() -> std::process::ExitStatus {
400     ///     Command::new("ls")
401     ///         .status()
402     ///         .await
403     ///         .expect("Command status failed!")
404     /// }
405     /// ```
406     /// This fn can only obtain `ExitStatus`. To obtain the `Output`, please use
407     /// `output()`
status(&mut self) -> impl Future<Output = io::Result<ExitStatus>>408     pub fn status(&mut self) -> impl Future<Output = io::Result<ExitStatus>> {
409         let child = self.spawn();
410 
411         async {
412             let mut child = child?;
413 
414             drop(child.take_stdin());
415             drop(child.take_stdout());
416             drop(child.take_stderr());
417 
418             child.wait().await
419         }
420     }
421 
422     /// Returns the path to the program that was given to Command::new.
423     ///
424     /// It's same as std.
425     ///
426     /// # Example
427     ///
428     /// ```
429     /// use ylong_runtime::process::Command;
430     ///
431     /// let cmd = Command::new("echo");
432     /// assert_eq!(cmd.get_program(), "echo");
433     /// ```
434     #[must_use]
get_program(&self) -> &OsStr435     pub fn get_program(&self) -> &OsStr {
436         self.std.get_program()
437     }
438 
439     /// Returns an iterator of the arguments that will be passed to the program.
440     ///
441     /// This does not include the path to the program as the first argument;
442     /// it only includes the arguments specified with Command::arg and
443     /// Command::args.
444     ///
445     /// It's same as std.
446     ///
447     /// # Example
448     ///
449     /// ```
450     /// use std::ffi::OsStr;
451     ///
452     /// use ylong_runtime::process::Command;
453     ///
454     /// let mut cmd = Command::new("echo");
455     /// cmd.arg("first").arg("second");
456     /// let args: Vec<&OsStr> = cmd.get_args().collect();
457     /// assert_eq!(args, &["first", "second"]);
458     /// ```
get_args(&self) -> CommandArgs<'_>459     pub fn get_args(&self) -> CommandArgs<'_> {
460         self.std.get_args()
461     }
462 
463     /// Returns an iterator of the environment variables that will be set when
464     /// the process is spawned.
465     ///
466     /// It's same as std.
467     ///
468     /// # Example
469     ///
470     /// ```
471     /// use std::ffi::OsStr;
472     ///
473     /// use ylong_runtime::process::Command;
474     ///
475     /// let mut cmd = Command::new("ls");
476     /// cmd.env("TERM", "dumb").env_remove("TZ");
477     /// let envs: Vec<(&OsStr, Option<&OsStr>)> = cmd.get_envs().collect();
478     /// assert_eq!(
479     ///     envs,
480     ///     &[
481     ///         (OsStr::new("TERM"), Some(OsStr::new("dumb"))),
482     ///         (OsStr::new("TZ"), None)
483     ///     ]
484     /// );
485     /// ```
get_envs(&self) -> CommandEnvs<'_>486     pub fn get_envs(&self) -> CommandEnvs<'_> {
487         self.std.get_envs()
488     }
489 
490     /// Returns the working directory for the child process.
491     ///
492     /// This returns None if the working directory will not be changed.
493     ///
494     /// It's same as std.
495     ///
496     /// # Example
497     ///
498     /// ```
499     /// use std::ffi::OsStr;
500     /// use std::path::Path;
501     ///
502     /// use ylong_runtime::process::Command;
503     ///
504     /// let mut cmd = Command::new("ls");
505     /// assert_eq!(cmd.get_current_dir(), None);
506     /// cmd.current_dir("/bin");
507     /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin")))
508     /// ```
509     #[must_use]
get_current_dir(&self) -> Option<&Path>510     pub fn get_current_dir(&self) -> Option<&Path> {
511         self.std.get_current_dir()
512     }
513 }
514 
515 #[cfg(unix)]
516 use std::os::unix::process::CommandExt;
517 
518 #[cfg(unix)]
519 impl Command {
520     /// Sets the child process's user ID. This translates to a `setuid` call in
521     /// the child process. Failure in the `setuid` call will cause the spawn to
522     /// fail.
523     ///
524     /// It's same as std.
uid(&mut self, id: u32) -> &mut Command525     pub fn uid(&mut self, id: u32) -> &mut Command {
526         self.std.uid(id);
527         self
528     }
529 
530     /// Similar to `uid`, but sets the group ID of the child process. This has
531     /// the same semantics as the `uid` field.
532     ///
533     /// It's same as std.
gid(&mut self, id: u32) -> &mut Command534     pub fn gid(&mut self, id: u32) -> &mut Command {
535         self.std.gid(id);
536         self
537     }
538 
539     /// Sets executable argument
540     /// Sets the first process argument `argv[0]`, to something other than the
541     /// default executable path.
542     ///
543     /// It's same as std.
arg0<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command544     pub fn arg0<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
545         self.std.arg0(arg);
546         self
547     }
548 
549     /// Schedules a closure to be run just before the exec function is invoked.
550     /// The closure is allowed to return an I/O error whose OS error code will
551     /// be communicated back to the parent and returned as an error from when
552     /// the spawn was requested. Multiple closures can be registered and
553     /// they will be called in order of their registration. If a closure
554     /// returns Err then no further closures will be called and the spawn
555     /// operation will immediately return with a failure.
556     ///
557     /// It's same as std.
558     ///
559     /// # Safety
560     ///
561     /// This closure will be run in the context of the child process after a
562     /// `fork`. This primarily means that any modifications made to memory on
563     /// behalf of this closure will ***not*** be visible to the parent process.
564     /// This is often a very constrained environment where normal operations
565     /// like `malloc`, accessing environment variables through [`mod@std::env`]
566     /// or acquiring a mutex are not guaranteed to work (due to other
567     /// threads perhaps still running when the `fork` was run).
pre_exec<F>(&mut self, f: F) -> &mut Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static,568     pub unsafe fn pre_exec<F>(&mut self, f: F) -> &mut Command
569     where
570         F: FnMut() -> io::Result<()> + Send + Sync + 'static,
571     {
572         self.std.pre_exec(f);
573         self
574     }
575 
576     /// Sets the process group ID (PGID) of the child process.
577     /// Equivalent to a setpgid call in the child process, but may be more
578     /// efficient. Process groups determine which processes receive signals.
579     ///
580     /// It's same as std.
process_group(&mut self, pgroup: i32) -> &mut Command581     pub fn process_group(&mut self, pgroup: i32) -> &mut Command {
582         self.std.process_group(pgroup);
583         self
584     }
585 }
586 
587 #[cfg(test)]
588 mod test {
589     use std::io::IoSlice;
590     use std::process::Stdio;
591 
592     use crate::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
593     use crate::process::Command;
594 
595     /// UT test cases for Command.
596     ///
597     /// # Brief
598     /// 1. Create a `Command`.
599     /// 2. Call `kill_on_drop()` set true and check command.kill.
600     /// 3. Call `kill_on_drop()` set false and check command.kill.
601     /// 4. Check command.std.
602     #[test]
ut_process_basic_test()603     fn ut_process_basic_test() {
604         let mut command = Command::new("echo");
605         assert!(!command.kill);
606         command.kill_on_drop(true);
607         assert!(command.kill);
608         command.kill_on_drop(false);
609         assert!(!command.kill);
610         assert_eq!(command.std.get_program(), "echo");
611     }
612 
613     /// UT test cases for `output()`.
614     ///
615     /// # Brief
616     /// 1. Create a `Command` with arg.
617     /// 2. Use `output()` waiting result.
618     #[test]
ut_process_output_test()619     fn ut_process_output_test() {
620         let handle = crate::spawn(async {
621             let mut command = Command::new("echo");
622             command.arg("Hello, world!");
623             let output = command.output().await.unwrap();
624 
625             assert!(output.status.success());
626             assert_eq!(output.stdout.as_slice(), b"Hello, world!\n");
627             assert!(output.stderr.is_empty());
628         });
629         crate::block_on(handle).unwrap();
630     }
631 
632     /// UT test cases for `status()`.
633     ///
634     /// # Brief
635     /// 1. Create a `Command` with arg.
636     /// 2. Use `status()` waiting result.
637     #[test]
ut_process_status_test()638     fn ut_process_status_test() {
639         let handle = crate::spawn(async {
640             let mut command = Command::new("echo");
641             command.arg("Hello, world!");
642 
643             let status = command.status().await.unwrap();
644             assert!(status.success());
645         });
646         crate::block_on(handle).unwrap();
647     }
648 
649     /// UT test cases for Command.
650     ///
651     /// # Brief
652     /// 1. Create a `Command` and `spawn()`.
653     /// 2. Take `child.stdin` and write something in it.
654     /// 3. Take `child.stdout` and read it, check the result.
655     /// 4. Check child's result.
656     #[test]
ut_process_child_stdio_test()657     fn ut_process_child_stdio_test() {
658         let handle = crate::spawn(async {
659             let mut child = Command::new("rev")
660                 .stdin(Stdio::piped())
661                 .stdout(Stdio::piped())
662                 .stderr(Stdio::piped())
663                 .spawn()
664                 .expect("Failed to spawn child process");
665 
666             let mut stdin = child.take_stdin().expect("Failed to open stdin");
667             let stdin_handle = crate::spawn(async move {
668                 assert!(stdin.is_write_vectored());
669                 stdin
670                     .write_vectored(&[IoSlice::new(b"Hello, world!")])
671                     .await
672                     .unwrap();
673                 stdin.flush().await.unwrap();
674                 stdin.shutdown().await.unwrap();
675             });
676 
677             let mut stdout = child.take_stdout().expect("Failed to open stdout");
678             let stdout_handle = crate::spawn(async move {
679                 let mut buf = Vec::new();
680                 stdout.read_to_end(&mut buf).await.unwrap();
681                 let str = "!dlrow ,olleH";
682                 assert!(String::from_utf8(buf).unwrap().contains(str));
683             });
684 
685             let mut stderr = child.take_stderr().expect("Failed to open stderr");
686             let stderr_handle = crate::spawn(async move {
687                 let mut buf = Vec::new();
688                 stderr.read_to_end(&mut buf).await.unwrap();
689                 assert!(buf.is_empty());
690             });
691 
692             let status = child.wait().await.unwrap();
693             assert!(status.success());
694 
695             stdin_handle.await.unwrap();
696             stdout_handle.await.unwrap();
697             stderr_handle.await.unwrap();
698         });
699         crate::block_on(handle).unwrap();
700     }
701 
702     /// Ut test cases for `kill()`.
703     ///
704     /// # Brief
705     /// 1. Create a `Command` with arg.
706     /// 2. Use `spawn()` create a child handle
707     /// 3. Use `kill()` to kill the child handle.
708     #[test]
ut_process_kill_test()709     fn ut_process_kill_test() {
710         let handle = crate::spawn(async {
711             let mut command = Command::new("echo");
712             command.arg("Hello, world!");
713             let mut child = command.spawn().unwrap();
714 
715             assert!(child.kill().await.is_ok());
716         });
717         crate::block_on(handle).unwrap();
718     }
719 
720     /// UT test cases for drop.
721     ///
722     /// # Brief
723     /// 1. Create a `Command` with kill_on_drop.
724     /// 2. Use `spawn()` create a child handle
725     /// 3. Use `drop()` to drop the child handle.
726     #[test]
ut_process_drop_test()727     fn ut_process_drop_test() {
728         let handle = crate::spawn(async {
729             let mut command = Command::new("echo");
730             command.arg("Hello, world!").kill_on_drop(true);
731             let child = command.spawn();
732             assert!(child.is_ok());
733             drop(child.unwrap());
734 
735             let mut command = Command::new("echo");
736             command.arg("Hello, world!");
737             let child = command.spawn();
738             assert!(child.is_ok());
739             drop(child.unwrap());
740         });
741         crate::block_on(handle).unwrap();
742     }
743 
744     /// UT test cases for command debug.
745     ///
746     /// # Brief
747     /// 1. Debug Command and Child.
748     /// 2. Check format is correct.
749     #[test]
ut_process_debug_test()750     fn ut_process_debug_test() {
751         let handle = crate::spawn(async {
752             let mut command = Command::new("echo");
753             assert_eq!(
754                 format!("{command:?}"),
755                 "Command { std: \"echo\", kill: false }"
756             );
757             let mut child = command.spawn().unwrap();
758 
759             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 }");
760             let status = child.wait().await.unwrap();
761             assert!(status.success());
762         });
763         crate::block_on(handle).unwrap();
764     }
765 }
766