From b1b1604c731ec0364f16e38b8e930342d97c555a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=9C=AA=E6=9D=A5?= Date: Sat, 12 Oct 2024 14:53:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 徐未来 --- ylong_runtime/src/fs/async_file.rs | 233 +++++++++++++++++++-- ylong_runtime/src/io/stdio.rs | 41 +--- ylong_runtime/src/macros.rs | 18 ++ ylong_runtime/src/net/sys/unix/datagram.rs | 15 +- ylong_runtime/src/net/sys/unix/listener.rs | 84 -------- ylong_runtime/tests/async_buf_write.rs | 30 --- ylong_runtime/tests/entry.rs | 3 + ylong_runtime/tests/stdio_cargo_test.rs | 84 ++++++++ ylong_runtime/tests/uds_cargo_test.rs | 192 +++++++++++++++++ ylong_runtime/tests/uds_test.rs | 129 +----------- 10 files changed, 518 insertions(+), 311 deletions(-) create mode 100644 ylong_runtime/tests/stdio_cargo_test.rs create mode 100644 ylong_runtime/tests/uds_cargo_test.rs diff --git a/ylong_runtime/src/fs/async_file.rs b/ylong_runtime/src/fs/async_file.rs index 7ded604..d974887 100644 --- a/ylong_runtime/src/fs/async_file.rs +++ b/ylong_runtime/src/fs/async_file.rs @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::fmt::{Debug, Formatter}; use std::fs::{File as SyncFile, Metadata, Permissions}; use std::future::Future; use std::io; @@ -97,6 +98,12 @@ impl FileState { const DEFAULT_BUF_LIMIT: usize = 2 * 1024 * 1024; +impl Debug for File { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("YlongFile").field(&self.file).finish() + } +} + impl File { /// Creates a new [`File`] struct. pub fn new(file: SyncFile) -> File { @@ -210,9 +217,7 @@ impl File { /// ``` pub async fn sync_all(&self) -> io::Result<()> { let mut file = self.inner.lock().await; - if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await { - file.write_err = Some(e.kind()); - } + file.flush().await; let file = self.file.clone(); async_op(move || file.sync_all()).await } @@ -240,9 +245,7 @@ impl File { /// ``` pub async fn sync_data(&self) -> io::Result<()> { let mut file = self.inner.lock().await; - if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await { - file.write_err = Some(e.kind()); - } + file.flush().await; let file = self.file.clone(); async_op(move || file.sync_data()).await } @@ -274,9 +277,7 @@ impl File { /// ``` pub async fn set_len(&self, size: u64) -> io::Result<()> { let mut file = self.inner.lock().await; - if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await { - file.write_err = Some(e.kind()); - } + file.flush().await; let mut buf = match file.state { // after each take, buf will be set right back @@ -370,6 +371,102 @@ impl File { pub fn set_buffer_size_limit(&mut self, buf_size_limit: usize) { self.buf_size_limit = buf_size_limit; } + + /// Takes the ownership of the `File` and turns it into a [`std::fs::File`]. + /// Before the transition, any in-flight operations will be completed. + /// + /// # Examples + /// + /// ```no_run + /// use ylong_runtime::fs::File; + /// + /// # async fn file_into_std() -> std::io::Result<()> { + /// let file = File::open("foo.txt").await?; + /// let std = file.into_std().await; + /// # Ok(()) + /// # } + pub async fn into_std(mut self) -> SyncFile { + let file = self.inner.get_mut(); + file.flush().await; + Arc::try_unwrap(self.file).expect("into_std Arc::try_unwrap failed") + } + + /// Turns the `File` into [`std::fs::File`] immediately without awaiting any + /// in-flight operation to complete. + /// + /// # Errors + /// This method wil return an error containing the file if some operation + /// is still in-flight + /// + /// # Examples + /// + /// ```no_run + /// use ylong_runtime::fs::File; + /// + /// # async fn file_try_into_std() -> std::io::Result<()> { + /// let file = File::open("foo.txt").await?; + /// let std = file.try_into_std().unwrap(); + /// # Ok(()) + /// # } + pub fn try_into_std(mut self) -> Result { + match Arc::try_unwrap(self.file) { + Ok(file) => Ok(file), + Err(arc_file) => { + self.file = arc_file; + Err(self) + } + } + } +} + +impl From for File { + fn from(file: SyncFile) -> Self { + Self::new(file) + } +} + +cfg_unix! { + use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, BorrowedFd, RawFd}; + + impl AsRawFd for File { + fn as_raw_fd(&self) -> RawFd { + self.file.as_raw_fd() + } + } + + impl AsFd for File { + fn as_fd(&self) -> BorrowedFd<'_> { + unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } + } + } + + impl FromRawFd for File { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + SyncFile::from_raw_fd(fd).into() + } + } +} + +cfg_windows! { + use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle, AsHandle, BorrowedHandle}; + + impl AsRawHandle for File { + fn as_raw_handle(&self) -> RawHandle { + self.file.as_raw_handle() + } + } + + impl AsHandle for File { + fn as_handle(&self) -> BorrowedHandle<'_> { + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } + } + } + + impl FromRawHandle for File { + unsafe fn from_raw_handle(handle: RawHandle) -> Self { + SyncFile::from_raw_handle(handle).into() + } + } } impl AsyncSeek for File { @@ -547,6 +644,12 @@ impl AsyncWrite for File { } impl FileInner { + async fn flush(&mut self) { + if let Err(e) = poll_fn(|cx| self.poll_flush(cx)).await { + self.write_err = Some(e.kind()); + } + } + fn poll_flush(&mut self, cx: &mut Context) -> Poll> { if let Some(e) = self.write_err { return Poll::Ready(Err(e.into())); @@ -573,7 +676,7 @@ mod test { use std::io::SeekFrom; use crate::fs::async_file::DEFAULT_BUF_LIMIT; - use crate::fs::{remove_file, File}; + use crate::fs::{remove_file, File, OpenOptions}; use crate::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; /// UT test for `set_len` @@ -759,14 +862,6 @@ mod test { std::fs::remove_file(file_path).unwrap(); } - use std::fmt::{Debug, Formatter}; - - impl Debug for File { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.file.fmt(f) - } - } - /// UT for opening an non-existed file /// /// # Brief @@ -780,4 +875,106 @@ mod test { }); crate::block_on(handle).unwrap(); } + + /// UT for `into_std` + /// + /// # Brief + /// 1. Creates an async File + /// 2. Turns the async File into a std File + /// 3. Check if the std file functions correctly + #[test] + fn ut_file_into_std() { + use std::io::{Read, Seek}; + + let file_path = "file17.txt"; + let handle = crate::spawn(async move { + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(file_path) + .await + .unwrap(); + + let res = file.write_all(b"hello").await; + assert!(res.is_ok()); + + let mut std = file.into_std().await; + let ret = std.seek(SeekFrom::Start(0)).unwrap(); + assert_eq!(ret, 0); + let mut buf = [0; 5]; + let ret = std.read_exact(&mut buf); + assert!(ret.is_ok()); + assert_eq!(&buf, b"hello"); + }); + crate::block_on(handle).unwrap(); + std::fs::remove_file(file_path).unwrap(); + } + + /// UT for `try_into_std` + /// + /// # Brief + /// 1. Creates an async File + /// 2. Uses the async file to write without flushing + /// 3. Tries to turn the async file into a std file + /// 4. Check if the attempt fails + /// 5. Flushes the file + /// 6. Tries to turn the async file into a std file + /// 7. Check if the attempt succeeds + #[test] + fn ut_file_try_into_std() { + let file_path = "file18.txt"; + let handle = crate::spawn(async move { + let mut file = File::create(file_path).await.unwrap(); + let res = file.write_all(b"hello").await; + assert!(res.is_ok()); + + let std = file.try_into_std(); + assert!(std.is_err()); + + let mut file = std.unwrap_err(); + let ret = file.flush().await; + assert!(ret.is_ok()); + + let std = file.try_into_std(); + assert!(std.is_ok()); + }); + crate::block_on(handle).unwrap(); + std::fs::remove_file(file_path).unwrap(); + } + + /// UT for `as_raw_fd` + /// + /// # Brief + /// 1. Creates an async File and turns it into a std file + /// 2. Gets the raw fd from the std file + /// 3. Turns the std file back to an async file + /// 4. Check if the fds are equal + /// 5. Creates a new async file from the raw fd + /// 6. Check if the fd of the new async file is correct + #[test] + #[cfg(unix)] + fn ut_file_as_raw_fd() { + use std::os::fd::{AsFd, AsRawFd}; + use std::os::unix::io::FromRawFd; + + let file_path = "file19.txt"; + let handle = crate::spawn(async move { + let file = File::create(file_path).await.unwrap(); + let std = file.into_std().await; + let fd = std.as_raw_fd(); + let file = File::from(std); + let fd2 = file.as_raw_fd(); + assert_eq!(fd, fd2); + let fd3 = file.as_fd().as_raw_fd(); + assert_eq!(fd, fd3); + + let file2 = unsafe { File::from_raw_fd(fd) }; + let fd4 = file2.as_raw_fd(); + assert_eq!(fd, fd4); + }); + + crate::block_on(handle).unwrap(); + std::fs::remove_file(file_path).unwrap(); + } } diff --git a/ylong_runtime/src/io/stdio.rs b/ylong_runtime/src/io/stdio.rs index 82e3dda..8c493e3 100644 --- a/ylong_runtime/src/io/stdio.rs +++ b/ylong_runtime/src/io/stdio.rs @@ -194,11 +194,8 @@ pub(crate) use std_async_write; #[cfg(test)] mod test { - #[cfg(unix)] - use std::os::fd::{AsFd, AsRawFd}; - use crate::io::stdio::BufInner; - use crate::io::{AsyncWriteExt, ReadBuf}; + use crate::io::ReadBuf; /// UT test cases for `stdout` and `stderr``. /// @@ -223,40 +220,4 @@ mod test { let n = buf_inner.clone_into(&mut read_buf); assert_eq!(n, 10); } - - /// UT test cases for `stdout` and `stderr``. - /// - /// # Brief - /// 1. create a `stdout` and a `stderr`. - /// 2. write something into `stdout` and `stderr`. - /// 3. check operation is ok. - #[test] - fn ut_test_stdio_write() { - let handle = crate::spawn(async { - let mut stdout = crate::io::stdout(); - #[cfg(unix)] - assert!(stdout.as_fd().as_raw_fd() >= 0); - #[cfg(unix)] - assert!(stdout.as_raw_fd() >= 0); - let res = stdout.write_all(b"something").await; - assert!(res.is_ok()); - let res = stdout.flush().await; - assert!(res.is_ok()); - let res = stdout.shutdown().await; - assert!(res.is_ok()); - - let mut stderr = crate::io::stderr(); - #[cfg(unix)] - assert!(stderr.as_fd().as_raw_fd() >= 0); - #[cfg(unix)] - assert!(stderr.as_raw_fd() >= 0); - let res = stderr.write_all(b"something").await; - assert!(res.is_ok()); - let res = stderr.flush().await; - assert!(res.is_ok()); - let res = stderr.shutdown().await; - assert!(res.is_ok()); - }); - let _ = crate::block_on(handle); - } } diff --git a/ylong_runtime/src/macros.rs b/ylong_runtime/src/macros.rs index df6c38e..ae06bd4 100644 --- a/ylong_runtime/src/macros.rs +++ b/ylong_runtime/src/macros.rs @@ -112,6 +112,24 @@ macro_rules! cfg_metrics { } } +macro_rules! cfg_unix { + ($($item:item)*) => { + $( + #[cfg(unix)] + $item + )* + } +} + +macro_rules! cfg_windows { + ($($item:item)*) => { + $( + #[cfg(windows)] + $item + )* + } +} + #[cfg(all(target_os = "linux", any(feature = "net", feature = "process")))] macro_rules! syscall { ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{ diff --git a/ylong_runtime/src/net/sys/unix/datagram.rs b/ylong_runtime/src/net/sys/unix/datagram.rs index ab3990a..af3078c 100644 --- a/ylong_runtime/src/net/sys/unix/datagram.rs +++ b/ylong_runtime/src/net/sys/unix/datagram.rs @@ -493,21 +493,15 @@ mod test { /// otherwise the next bind operation will fail. #[test] fn ut_uds_datagram_read_write_test() { - const PATH: &str = "/tmp/uds_datagram_test_path1"; - let _ = std::fs::remove_file(PATH); - let handle2 = crate::spawn(async { - let socket = UnixDatagram::bind(PATH).unwrap(); - - let handle = crate::spawn(async { - let socket = UnixDatagram::unbound().unwrap(); - socket.connect(PATH).unwrap(); + let (server, client) = UnixDatagram::pair().unwrap(); - socket.send(b"hello world").await.expect("send failed"); + let handle = crate::spawn(async move { + client.send(b"hello world").await.expect("send failed"); }); let mut buf = vec![0; 11]; - socket.recv(buf.as_mut_slice()).await.expect("recv failed"); + server.recv(buf.as_mut_slice()).await.expect("recv failed"); assert_eq!( std::str::from_utf8(&buf).unwrap(), "hello world".to_string() @@ -516,7 +510,6 @@ mod test { handle.await.unwrap(); }); crate::block_on(handle2).unwrap(); - let _ = std::fs::remove_file(PATH); } /// Uds UnixDatagram try_xxx() test case. diff --git a/ylong_runtime/src/net/sys/unix/listener.rs b/ylong_runtime/src/net/sys/unix/listener.rs index a610277..e0465b0 100644 --- a/ylong_runtime/src/net/sys/unix/listener.rs +++ b/ylong_runtime/src/net/sys/unix/listener.rs @@ -125,87 +125,3 @@ impl AsFd for UnixListener { unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } } } - -#[cfg(test)] -mod test { - use std::os::fd::{AsFd, AsRawFd}; - - use crate::io::{AsyncReadExt, AsyncWriteExt}; - use crate::net::{UnixListener, UnixStream}; - - /// Uds UnixListener test case. - /// - /// # Title - /// ut_uds_listener_baisc_test - /// - /// # Brief - /// 1. Create a std UnixListener with `bind()`. - /// 2. Convert std UnixListener to Ylong_runtime UnixListener. - /// 3. Check result is correct. - #[test] - fn ut_uds_listener_baisc_test() { - const PATH: &str = "/tmp/uds_listener_path1"; - let _ = std::fs::remove_file(PATH); - let listener = std::os::unix::net::UnixListener::bind(PATH).unwrap(); - let handle = crate::spawn(async { - let res = UnixListener::from_std(listener); - assert!(res.is_ok()); - let listener = res.unwrap(); - assert!(listener.as_fd().as_raw_fd() >= 0); - assert!(listener.as_raw_fd() >= 0); - assert!(listener.take_error().is_ok()); - }); - crate::block_on(handle).unwrap(); - let _ = std::fs::remove_file(PATH); - } - - /// Uds UnixListener test case. - /// - /// # Title - /// ut_uds_listener_read_write_test - /// - /// # Brief - /// 1. Create a server with `bind()` and `accept()`. - /// 2. Create a client with `connect()`. - /// 3. Server Sends message and client recv it. - #[test] - fn ut_uds_listener_read_write_test() { - const PATH: &str = "/tmp/uds_listener_path2"; - let _ = std::fs::remove_file(PATH); - let client_msg = "hello client"; - let server_msg = "hello server"; - - crate::block_on(async { - let mut read_buf = [0_u8; 12]; - let listener = UnixListener::bind(PATH).unwrap(); - - let handle = crate::spawn(async { - let mut stream = UnixStream::connect(PATH).await; - while stream.is_err() { - stream = UnixStream::connect(PATH).await; - } - let mut stream = stream.unwrap(); - let mut read_buf = [0_u8; 12]; - stream.read_exact(&mut read_buf).await.unwrap(); - assert_eq!( - std::str::from_utf8(&read_buf).unwrap(), - client_msg.to_string() - ); - stream.write_all(server_msg.as_bytes()).await.unwrap(); - }); - - let (mut stream, _) = listener.accept().await.unwrap(); - stream.write_all(client_msg.as_bytes()).await.unwrap(); - - stream.read_exact(&mut read_buf).await.unwrap(); - assert_eq!( - std::str::from_utf8(&read_buf).unwrap(), - server_msg.to_string() - ); - - handle.await.unwrap(); - }); - - let _ = std::fs::remove_file(PATH); - } -} diff --git a/ylong_runtime/tests/async_buf_write.rs b/ylong_runtime/tests/async_buf_write.rs index fdaac5a..40d0bce 100644 --- a/ylong_runtime/tests/async_buf_write.rs +++ b/ylong_runtime/tests/async_buf_write.rs @@ -193,33 +193,3 @@ fn sdv_buf_writer_write_vectored_2() { ylong_runtime::block_on(server).unwrap(); ylong_runtime::block_on(client).unwrap(); } - -/// SDV test cases for `stdout` and `stderr``. -/// -/// # Brief -/// 1. create a `stdout` and a `stderr`. -/// 2. write something into `stdout` and `stderr`. -/// 3. check operation is ok. -#[test] -fn sdv_buf_writer_stdio_write() { - let handle = ylong_runtime::spawn(async { - let stdout = ylong_runtime::io::stdout(); - let mut buf_writer = AsyncBufWriter::new(stdout); - let res = buf_writer.write_all(b"something").await; - assert!(res.is_ok()); - let res = buf_writer.flush().await; - assert!(res.is_ok()); - let res = buf_writer.shutdown().await; - assert!(res.is_ok()); - - let stderr = ylong_runtime::io::stderr(); - let mut buf_writer = AsyncBufWriter::new(stderr); - let res = buf_writer.write_all(b"something").await; - assert!(res.is_ok()); - let res = buf_writer.flush().await; - assert!(res.is_ok()); - let res = buf_writer.shutdown().await; - assert!(res.is_ok()); - }); - ylong_runtime::block_on(handle).unwrap(); -} diff --git a/ylong_runtime/tests/entry.rs b/ylong_runtime/tests/entry.rs index a525e24..860d91e 100644 --- a/ylong_runtime/tests/entry.rs +++ b/ylong_runtime/tests/entry.rs @@ -22,6 +22,7 @@ mod async_fs; mod async_pool; mod async_read; mod block_on; +mod builder; mod error; mod join_set; mod mpsc_test; @@ -29,6 +30,7 @@ mod mutex; mod par_iter; mod process; mod pty_process; +mod select; mod semaphore_test; mod signal; mod singleton_runtime; @@ -39,3 +41,4 @@ mod task_cancel; mod tcp_test; mod timer_test; mod udp_test; +mod uds_test; diff --git a/ylong_runtime/tests/stdio_cargo_test.rs b/ylong_runtime/tests/stdio_cargo_test.rs new file mode 100644 index 0000000..a3280a5 --- /dev/null +++ b/ylong_runtime/tests/stdio_cargo_test.rs @@ -0,0 +1,84 @@ +// Copyright (c) 2023 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This test can only run in cargo. + +#[cfg(unix)] +use std::os::fd::{AsFd, AsRawFd}; + +use ylong_runtime::io::{AsyncBufWriter, AsyncWriteExt}; + +/// UT test cases for `stdout` and `stderr``. +/// +/// # Brief +/// 1. create a `stdout` and a `stderr`. +/// 2. write something into `stdout` and `stderr`. +/// 3. check operation is ok. +#[test] +fn sdv_stdio_write() { + ylong_runtime::block_on(async { + let mut stdout = ylong_runtime::io::stdout(); + #[cfg(unix)] + assert!(stdout.as_fd().as_raw_fd() >= 0); + #[cfg(unix)] + assert!(stdout.as_raw_fd() >= 0); + let res = stdout.write_all(b"something").await; + assert!(res.is_ok()); + let res = stdout.flush().await; + assert!(res.is_ok()); + let res = stdout.shutdown().await; + assert!(res.is_ok()); + + let mut stderr = ylong_runtime::io::stderr(); + #[cfg(unix)] + assert!(stderr.as_fd().as_raw_fd() >= 0); + #[cfg(unix)] + assert!(stderr.as_raw_fd() >= 0); + let res = stderr.write_all(b"something").await; + assert!(res.is_ok()); + let res = stderr.flush().await; + assert!(res.is_ok()); + let res = stderr.shutdown().await; + assert!(res.is_ok()); + }); +} + +/// SDV test cases for `stdout` and `stderr``. +/// +/// # Brief +/// 1. create a `stdout` and a `stderr`. +/// 2. write something into `stdout` and `stderr`. +/// 3. check operation is ok. +#[test] +fn sdv_stdio_buf_writer_write() { + let handle = ylong_runtime::spawn(async { + let stdout = ylong_runtime::io::stdout(); + let mut buf_writer = AsyncBufWriter::new(stdout); + let res = buf_writer.write_all(b"something").await; + assert!(res.is_ok()); + let res = buf_writer.flush().await; + assert!(res.is_ok()); + let res = buf_writer.shutdown().await; + assert!(res.is_ok()); + + let stderr = ylong_runtime::io::stderr(); + let mut buf_writer = AsyncBufWriter::new(stderr); + let res = buf_writer.write_all(b"something").await; + assert!(res.is_ok()); + let res = buf_writer.flush().await; + assert!(res.is_ok()); + let res = buf_writer.shutdown().await; + assert!(res.is_ok()); + }); + ylong_runtime::block_on(handle).unwrap(); +} diff --git a/ylong_runtime/tests/uds_cargo_test.rs b/ylong_runtime/tests/uds_cargo_test.rs new file mode 100644 index 0000000..b482c57 --- /dev/null +++ b/ylong_runtime/tests/uds_cargo_test.rs @@ -0,0 +1,192 @@ +// Copyright (c) 2023 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! This test can only run in cargo. + +#![cfg(all(target_family = "unix", feature = "net"))] + +use std::os::fd::{AsFd, AsRawFd}; + +use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt}; +use ylong_runtime::net::{UnixDatagram, UnixListener, UnixStream}; + +/// Uds UnixListener test case. +/// +/// # Brief +/// 1. Create a std UnixListener with `bind()`. +/// 2. Convert std UnixListener to Ylong_runtime UnixListener. +/// 3. Check result is correct. +#[test] +fn sdv_uds_listener_baisc_test() { + const PATH: &str = "/tmp/uds_listener_path1"; + let _ = std::fs::remove_file(PATH); + let listener = std::os::unix::net::UnixListener::bind(PATH).unwrap(); + let handle = ylong_runtime::spawn(async { + let res = UnixListener::from_std(listener); + assert!(res.is_ok()); + let listener = res.unwrap(); + assert!(listener.as_fd().as_raw_fd() >= 0); + assert!(listener.as_raw_fd() >= 0); + assert!(listener.take_error().is_ok()); + }); + ylong_runtime::block_on(handle).unwrap(); + let _ = std::fs::remove_file(PATH); +} + +/// Uds UnixListener test case. +/// +/// # Brief +/// 1. Create a server with `bind()` and `accept()`. +/// 2. Create a client with `connect()`. +/// 3. Server Sends message and client recv it. +#[test] +fn sdv_uds_listener_read_write_test() { + const PATH: &str = "/tmp/uds_listener_path2"; + let _ = std::fs::remove_file(PATH); + let client_msg = "hello client"; + let server_msg = "hello server"; + + ylong_runtime::block_on(async { + let mut read_buf = [0_u8; 12]; + let listener = UnixListener::bind(PATH).unwrap(); + + let handle = ylong_runtime::spawn(async { + let mut stream = UnixStream::connect(PATH).await; + while stream.is_err() { + stream = UnixStream::connect(PATH).await; + } + let mut stream = stream.unwrap(); + let mut read_buf = [0_u8; 12]; + stream.read_exact(&mut read_buf).await.unwrap(); + assert_eq!( + std::str::from_utf8(&read_buf).unwrap(), + client_msg.to_string() + ); + stream.write_all(server_msg.as_bytes()).await.unwrap(); + }); + + let (mut stream, _) = listener.accept().await.unwrap(); + stream.write_all(client_msg.as_bytes()).await.unwrap(); + + stream.read_exact(&mut read_buf).await.unwrap(); + assert_eq!( + std::str::from_utf8(&read_buf).unwrap(), + server_msg.to_string() + ); + + handle.await.unwrap(); + }); + + let _ = std::fs::remove_file(PATH); +} + +/// uds UnixListener/UnixStream test case. +/// +/// # Title +/// sdv_uds_stream_test +/// +/// # Brief +/// 1. Creates a server and a client. +/// 2. Sends and writes message to each other. +/// +/// # Note +/// Each execution will leave a file under PATH which must be deleted, +/// otherwise the next bind operation will fail. +#[test] +fn sdv_uds_stream_test() { + const PATH: &str = "/tmp/uds_path1"; + let _ = std::fs::remove_file(PATH); + + async fn server() { + let mut read_buf = [0_u8; 12]; + let listener = UnixListener::bind(PATH).unwrap(); + let (mut stream, _) = listener.accept().await.unwrap(); + let n = stream.write(b"hello client").await.unwrap(); + assert_eq!(n, "hello client".len()); + let n = stream.read(&mut read_buf).await.unwrap(); + assert_eq!(n, "hello server".len()); + assert_eq!( + std::str::from_utf8(&read_buf).unwrap(), + "hello server".to_string() + ); + } + + async fn client() { + let mut read_buf = [0_u8; 12]; + loop { + if let Ok(mut stream) = UnixStream::connect(PATH).await { + let n = stream.read(&mut read_buf).await.unwrap(); + assert_eq!(n, "hello server".len()); + assert_eq!( + std::str::from_utf8(&read_buf).unwrap(), + "hello client".to_string() + ); + + let n = stream.write(b"hello server").await.unwrap(); + assert_eq!(n, "hello client".len()); + break; + } + } + } + + let handle = ylong_runtime::spawn(client()); + ylong_runtime::block_on(server()); + ylong_runtime::block_on(handle).unwrap(); + + std::fs::remove_file(PATH).unwrap(); +} + +/// uds UnixDatagram test case. +/// +/// # Title +/// sdv_uds_datagram_test +/// +/// # Brief +/// 1. Creates a server and a client. +/// 2. Client Sends message and server recv it. +/// +/// # Note +/// Each execution will leave a file under PATH which must be deleted, +/// otherwise the next bind operation will fail. +#[test] +fn sdv_uds_datagram_test() { + const PATH: &str = "/tmp/uds_path2"; + let _ = std::fs::remove_file(PATH); + + async fn server() { + let socket = UnixDatagram::bind(PATH).unwrap(); + + let mut buf = vec![0; 11]; + socket.recv(buf.as_mut_slice()).await.expect("recv failed"); + assert_eq!( + std::str::from_utf8(&buf).unwrap(), + "hello world".to_string() + ); + } + + async fn client() { + let socket = UnixDatagram::unbound().unwrap(); + loop { + if socket.connect(PATH).is_ok() { + socket.send(b"hello world").await.expect("send failed"); + break; + }; + } + } + + let handle = ylong_runtime::spawn(client()); + ylong_runtime::block_on(server()); + ylong_runtime::block_on(handle).unwrap(); + + std::fs::remove_file(PATH).unwrap(); +} diff --git a/ylong_runtime/tests/uds_test.rs b/ylong_runtime/tests/uds_test.rs index 346bc7f..4d5a687 100644 --- a/ylong_runtime/tests/uds_test.rs +++ b/ylong_runtime/tests/uds_test.rs @@ -16,109 +16,7 @@ use std::io; use std::os::fd::AsRawFd; -use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt}; -use ylong_runtime::net::{UnixDatagram, UnixListener, UnixStream}; - -#[test] -/// uds UnixListener/UnixStream test case. -/// -/// # Title -/// sdv_uds_stream_test -/// -/// # Brief -/// 1. Creates a server and a client. -/// 2. Sends and writes message to each other. -/// -/// # Note -/// Each execution will leave a file under PATH which must be deleted, -/// otherwise the next bind operation will fail. -fn sdv_uds_stream_test() { - const PATH: &str = "/tmp/uds_path1"; - let _ = std::fs::remove_file(PATH); - - async fn server() { - let mut read_buf = [0_u8; 12]; - let listener = UnixListener::bind(PATH).unwrap(); - let (mut stream, _) = listener.accept().await.unwrap(); - let n = stream.write(b"hello client").await.unwrap(); - assert_eq!(n, "hello client".len()); - let n = stream.read(&mut read_buf).await.unwrap(); - assert_eq!(n, "hello server".len()); - assert_eq!( - std::str::from_utf8(&read_buf).unwrap(), - "hello server".to_string() - ); - } - - async fn client() { - let mut read_buf = [0_u8; 12]; - loop { - if let Ok(mut stream) = UnixStream::connect(PATH).await { - let n = stream.read(&mut read_buf).await.unwrap(); - assert_eq!(n, "hello server".len()); - assert_eq!( - std::str::from_utf8(&read_buf).unwrap(), - "hello client".to_string() - ); - - let n = stream.write(b"hello server").await.unwrap(); - assert_eq!(n, "hello client".len()); - break; - } - } - } - - let handle = ylong_runtime::spawn(client()); - ylong_runtime::block_on(server()); - ylong_runtime::block_on(handle).unwrap(); - - std::fs::remove_file(PATH).unwrap(); -} - -/// uds UnixDatagram test case. -/// -/// # Title -/// sdv_uds_datagram_test -/// -/// # Brief -/// 1. Creates a server and a client. -/// 2. Client Sends message and server recv it. -/// -/// # Note -/// Each execution will leave a file under PATH which must be deleted, -/// otherwise the next bind operation will fail. -#[test] -fn sdv_uds_datagram_test() { - const PATH: &str = "/tmp/uds_path2"; - let _ = std::fs::remove_file(PATH); - - async fn server() { - let socket = UnixDatagram::bind(PATH).unwrap(); - - let mut buf = vec![0; 11]; - socket.recv(buf.as_mut_slice()).await.expect("recv failed"); - assert_eq!( - std::str::from_utf8(&buf).unwrap(), - "hello world".to_string() - ); - } - - async fn client() { - let socket = UnixDatagram::unbound().unwrap(); - loop { - if socket.connect(PATH).is_ok() { - socket.send(b"hello world").await.expect("send failed"); - break; - }; - } - } - - let handle = ylong_runtime::spawn(client()); - ylong_runtime::block_on(server()); - ylong_runtime::block_on(handle).unwrap(); - - std::fs::remove_file(PATH).unwrap(); -} +use ylong_runtime::net::{UnixDatagram, UnixStream}; /// Uds UnixStream try_xxx() test case. /// @@ -204,31 +102,6 @@ fn sdv_uds_datagram_try_test() { ylong_runtime::block_on(handle).unwrap(); } -/// Uds UnixListener test case. -/// -/// # Title -/// sdv_uds_listener_baisc_test -/// -/// # Brief -/// 1. Create a std UnixListener with `bind()`. -/// 2. Convert std UnixListener to Ylong_runtime UnixListener. -/// 3. Check result is correct. -#[test] -fn sdv_uds_listener_baisc_test() { - const PATH: &str = "/tmp/uds_path3"; - let _ = std::fs::remove_file(PATH); - let listener = std::os::unix::net::UnixListener::bind(PATH).unwrap(); - let handle = ylong_runtime::spawn(async { - let res = UnixListener::from_std(listener); - assert!(res.is_ok()); - let listener = res.unwrap(); - assert!(listener.as_raw_fd() >= 0); - assert!(listener.take_error().is_ok()); - }); - ylong_runtime::block_on(handle).unwrap(); - let _ = std::fs::remove_file(PATH); -} - /// Uds UnixStream test case. /// /// # Title -- Gitee