#![cfg(feature = "native")]
use dtact_util::io::{DtactTcpListener, DtactTcpStream, init_runtime};
use std::net::TcpListener;
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
static INIT: std::sync::Once = std::sync::Once::new();
fn ensure_runtime() {
INIT.call_once(|| {
init_runtime(2, 128, 1024, 4096, &[]);
});
}
#[dtact::dtact_init(workers = 4, capacity = 2048, safety = "Safety1")]
#[test]
fn test_io_driver_tcp() {
ensure_runtime();
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let local_addr = listener.local_addr().unwrap();
println!("Bound std TcpListener to {}", local_addr);
let dtact_listener = DtactTcpListener::from_std(listener).unwrap();
println!("Converted to DtactTcpListener successfully");
let server_finished = Arc::new(AtomicU32::new(0));
let server_finished_clone = server_finished.clone();
dtact::spawn(async move {
println!("Server: starting accept");
let (stream, client_addr) = dtact_listener.accept().await.unwrap();
println!("Server: accepted connection from {}", client_addr);
let msg = b"hello from dtact-io server";
let mut written = 0;
while written < msg.len() {
println!("Server: writing bytes...");
let n = stream.write(&msg[written..]).await.unwrap();
println!("Server: wrote {} bytes", n);
written += n;
}
println!("Server: finished successfully");
server_finished_clone.store(1, Ordering::SeqCst);
});
let client_finished = Arc::new(AtomicU32::new(0));
let client_finished_clone = client_finished.clone();
dtact::spawn(async move {
println!("Client: connecting to {}", local_addr);
let stream = DtactTcpStream::connect(local_addr).await.unwrap();
println!("Client: connected successfully");
let mut buf = [0u8; 100];
let mut total_read = 0;
while total_read < 26 {
println!("Client: reading bytes...");
let n = stream.read(&mut buf[total_read..]).await.unwrap();
println!("Client: read {} bytes", n);
if n == 0 {
break;
}
total_read += n;
}
println!(
"Client: read total {} bytes: {:?}",
total_read,
String::from_utf8_lossy(&buf[0..total_read])
);
assert_eq!(&buf[0..26], b"hello from dtact-io server");
client_finished_clone.store(1, Ordering::SeqCst);
});
for i in 0..100 {
if server_finished.load(Ordering::SeqCst) == 1
&& client_finished.load(Ordering::SeqCst) == 1
{
println!("Both finished on iteration {}", i);
break;
}
std::thread::sleep(std::time::Duration::from_millis(50));
}
assert_eq!(server_finished.load(Ordering::SeqCst), 1);
assert_eq!(client_finished.load(Ordering::SeqCst), 1);
}
fn block_on<F: std::future::Future>(fut: F) -> F::Output {
use std::pin::pin;
use std::task::{Context, Poll, Wake};
struct NoopWaker;
impl Wake for NoopWaker {
fn wake(self: Arc<Self>) {}
}
let waker = Arc::new(NoopWaker).into();
let mut cx = Context::from_waker(&waker);
let mut fut = pin!(fut);
loop {
match fut.as_mut().poll(&mut cx) {
Poll::Ready(v) => return v,
Poll::Pending => std::thread::yield_now(),
}
}
}
#[test]
fn test_io_connect_refused_when_nothing_listening() {
ensure_runtime();
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
drop(listener);
let result = block_on(DtactTcpStream::connect(addr));
match result {
Ok(_) => panic!("connecting to a closed/nonexistent listener must return Err"),
Err(e) => {
assert_ne!(
e.kind(),
std::io::ErrorKind::Other,
"unexpected error: {e:?}"
);
}
}
}
#[test]
fn test_io_zero_length_read_write() {
dtact_autostart();
ensure_runtime();
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let local_addr = listener.local_addr().unwrap();
let dtact_listener = DtactTcpListener::from_std(listener).unwrap();
let done = Arc::new(AtomicU32::new(0));
let done_clone = done.clone();
dtact::spawn(async move {
let (stream, _addr) = dtact_listener.accept().await.unwrap();
let n = stream.write(&[]).await.unwrap();
assert_eq!(n, 0, "writing an empty buffer must report 0 bytes written");
let mut buf = [0u8; 8];
let n = stream.read(&mut buf[..0]).await.unwrap();
assert_eq!(
n, 0,
"reading into an empty buffer must report 0 bytes read"
);
let n = stream.write(b"still-alive").await.unwrap();
assert_eq!(n, 11);
done_clone.store(1, Ordering::SeqCst);
});
dtact::spawn(async move {
let client = DtactTcpStream::connect(local_addr).await.unwrap();
let mut buf = [0u8; 32];
let mut total = 0;
while total < 11 {
let n = client.read(&mut buf[total..]).await.unwrap();
if n == 0 {
break;
}
total += n;
}
assert_eq!(&buf[..11], b"still-alive");
});
for _ in 0..100 {
if done.load(Ordering::SeqCst) == 1 {
break;
}
std::thread::sleep(std::time::Duration::from_millis(20));
}
assert_eq!(done.load(Ordering::SeqCst), 1);
}