Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 78fc752

Browse files
committed
tests
1 parent 5c4f359 commit 78fc752

File tree

7 files changed

+857
-2
lines changed

7 files changed

+857
-2
lines changed

crates/test-programs/src/bin/sockets_0_3_tcp_bind.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use futures::{stream, try_join, SinkExt as _, StreamExt as _};
1+
use futures::{SinkExt as _, StreamExt as _};
22
use test_programs::p3::wasi::sockets::types::{
33
ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, TcpSocket,
44
};
55
use test_programs::p3::{sockets::attempt_random_port, wit_stream};
6-
use wit_bindgen_rt::async_support::StreamReader;
76

87
struct Component;
98

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use test_programs::p3::wasi::sockets::types::{
2+
ErrorCode, IpAddress, IpAddressFamily, IpSocketAddress, TcpSocket,
3+
};
4+
5+
struct Component;
6+
7+
test_programs::p3::export!(Component);
8+
9+
const SOME_PORT: u16 = 47; // If the tests pass, this will never actually be connected to.
10+
11+
impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
12+
async fn run() -> Result<(), ()> {
13+
test_tcp_connect_unspec(IpAddressFamily::Ipv4).await;
14+
test_tcp_connect_unspec(IpAddressFamily::Ipv6).await;
15+
16+
test_tcp_connect_port_0(IpAddressFamily::Ipv4).await;
17+
test_tcp_connect_port_0(IpAddressFamily::Ipv6).await;
18+
19+
test_tcp_connect_wrong_family(IpAddressFamily::Ipv4).await;
20+
test_tcp_connect_wrong_family(IpAddressFamily::Ipv6).await;
21+
22+
test_tcp_connect_non_unicast().await;
23+
24+
test_tcp_connect_dual_stack().await;
25+
26+
test_tcp_connect_explicit_bind(IpAddressFamily::Ipv4).await;
27+
test_tcp_connect_explicit_bind(IpAddressFamily::Ipv6).await;
28+
Ok(())
29+
}
30+
}
31+
32+
/// `0.0.0.0` / `::` is not a valid remote address in WASI.
33+
async fn test_tcp_connect_unspec(family: IpAddressFamily) {
34+
let addr = IpSocketAddress::new(IpAddress::new_unspecified(family), SOME_PORT);
35+
let sock = TcpSocket::new(family);
36+
37+
assert!(matches!(
38+
sock.connect(addr).await,
39+
Err(ErrorCode::InvalidArgument)
40+
));
41+
}
42+
43+
/// 0 is not a valid remote port.
44+
async fn test_tcp_connect_port_0(family: IpAddressFamily) {
45+
let addr = IpSocketAddress::new(IpAddress::new_loopback(family), 0);
46+
let sock = TcpSocket::new(family);
47+
48+
assert!(matches!(
49+
sock.connect(addr).await,
50+
Err(ErrorCode::InvalidArgument)
51+
));
52+
}
53+
54+
/// Connect should validate the address family.
55+
async fn test_tcp_connect_wrong_family(family: IpAddressFamily) {
56+
let wrong_ip = match family {
57+
IpAddressFamily::Ipv4 => IpAddress::IPV6_LOOPBACK,
58+
IpAddressFamily::Ipv6 => IpAddress::IPV4_LOOPBACK,
59+
};
60+
let remote_addr = IpSocketAddress::new(wrong_ip, SOME_PORT);
61+
62+
let sock = TcpSocket::new(family);
63+
64+
assert!(matches!(
65+
sock.connect(remote_addr).await,
66+
Err(ErrorCode::InvalidArgument)
67+
));
68+
}
69+
70+
/// Can only connect to unicast addresses.
71+
async fn test_tcp_connect_non_unicast() {
72+
let ipv4_broadcast = IpSocketAddress::new(IpAddress::IPV4_BROADCAST, SOME_PORT);
73+
let ipv4_multicast = IpSocketAddress::new(IpAddress::Ipv4((224, 254, 0, 0)), SOME_PORT);
74+
let ipv6_multicast =
75+
IpSocketAddress::new(IpAddress::Ipv6((0xff00, 0, 0, 0, 0, 0, 0, 0)), SOME_PORT);
76+
77+
let sock_v4 = TcpSocket::new(IpAddressFamily::Ipv4);
78+
let sock_v6 = TcpSocket::new(IpAddressFamily::Ipv6);
79+
80+
assert!(matches!(
81+
sock_v4.connect(ipv4_broadcast).await,
82+
Err(ErrorCode::InvalidArgument)
83+
));
84+
assert!(matches!(
85+
sock_v4.connect(ipv4_multicast).await,
86+
Err(ErrorCode::InvalidArgument)
87+
));
88+
assert!(matches!(
89+
sock_v6.connect(ipv6_multicast).await,
90+
Err(ErrorCode::InvalidArgument)
91+
));
92+
}
93+
94+
async fn test_tcp_connect_dual_stack() {
95+
// Set-up:
96+
let v4_listener = TcpSocket::new(IpAddressFamily::Ipv4);
97+
v4_listener
98+
.bind(IpSocketAddress::new(IpAddress::IPV4_LOOPBACK, 0))
99+
.await
100+
.unwrap();
101+
v4_listener.listen().unwrap();
102+
103+
let v4_listener_addr = v4_listener.local_address().unwrap();
104+
let v6_listener_addr =
105+
IpSocketAddress::new(IpAddress::IPV4_MAPPED_LOOPBACK, v4_listener_addr.port());
106+
107+
let v6_client = TcpSocket::new(IpAddressFamily::Ipv6);
108+
109+
// Tests:
110+
111+
// Connecting to an IPv4 address on an IPv6 socket should fail:
112+
assert!(matches!(
113+
v6_client.connect(v4_listener_addr).await,
114+
Err(ErrorCode::InvalidArgument)
115+
));
116+
// Connecting to an IPv4-mapped-IPv6 address on an IPv6 socket should fail:
117+
assert!(matches!(
118+
v6_client.connect(v6_listener_addr).await,
119+
Err(ErrorCode::InvalidArgument)
120+
));
121+
}
122+
123+
/// Client sockets can be explicitly bound.
124+
async fn test_tcp_connect_explicit_bind(family: IpAddressFamily) {
125+
let ip = IpAddress::new_loopback(family);
126+
127+
let listener = {
128+
let bind_address = IpSocketAddress::new(ip, 0);
129+
let listener = TcpSocket::new(family);
130+
listener.bind(bind_address).await.unwrap();
131+
listener.listen().unwrap();
132+
listener
133+
};
134+
135+
let listener_address = listener.local_address().unwrap();
136+
let client = TcpSocket::new(family);
137+
138+
// Manually bind the client:
139+
client.bind(IpSocketAddress::new(ip, 0)).await.unwrap();
140+
141+
// Connect should work:
142+
client.connect(listener_address).await.unwrap();
143+
}
144+
145+
fn main() {}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use futures::{SinkExt as _, StreamExt as _};
2+
use test_programs::p3::wasi::sockets::types::{
3+
IpAddressFamily, IpSocketAddress, Ipv4SocketAddress, Ipv6SocketAddress, TcpSocket,
4+
};
5+
use test_programs::p3::wit_stream;
6+
7+
struct Component;
8+
9+
test_programs::p3::export!(Component);
10+
11+
impl test_programs::p3::exports::wasi::cli::run::Guest for Component {
12+
async fn run() -> Result<(), ()> {
13+
test_tcp_sample_application(
14+
IpAddressFamily::Ipv4,
15+
IpSocketAddress::Ipv4(Ipv4SocketAddress {
16+
port: 0, // use any free port
17+
address: (127, 0, 0, 1), // localhost
18+
}),
19+
)
20+
.await;
21+
test_tcp_sample_application(
22+
IpAddressFamily::Ipv6,
23+
IpSocketAddress::Ipv6(Ipv6SocketAddress {
24+
port: 0, // use any free port
25+
address: (0, 0, 0, 0, 0, 0, 0, 1), // localhost
26+
flow_info: 0,
27+
scope_id: 0,
28+
}),
29+
)
30+
.await;
31+
Ok(())
32+
}
33+
}
34+
35+
async fn test_tcp_sample_application(family: IpAddressFamily, bind_address: IpSocketAddress) {
36+
let first_message = b"Hello, world!";
37+
let second_message = b"Greetings, planet!";
38+
39+
let listener = TcpSocket::new(family);
40+
41+
listener.bind(bind_address).await.unwrap();
42+
listener.set_listen_backlog_size(32).unwrap();
43+
let mut accept = listener.listen().unwrap();
44+
45+
let addr = listener.local_address().unwrap();
46+
47+
{
48+
let client = TcpSocket::new(family);
49+
client.connect(addr).await.unwrap();
50+
let (mut data_tx, data_rx) = wit_stream::new();
51+
client.send(data_rx).unwrap();
52+
data_tx.send(vec![]).await.unwrap();
53+
data_tx.send(first_message.into()).await.unwrap();
54+
}
55+
56+
{
57+
let mut sock = accept.next().await.unwrap();
58+
assert_eq!(sock.len(), 1);
59+
let sock = sock.pop().unwrap();
60+
61+
let (mut data_rx, fut) = sock.receive();
62+
let data = data_rx.next().await.unwrap();
63+
64+
// Check that we sent and received our message!
65+
assert_eq!(data, first_message); // Not guaranteed to work but should work in practice.
66+
fut.await.unwrap().unwrap()
67+
}
68+
69+
// Another client
70+
{
71+
let client = TcpSocket::new(family);
72+
client.connect(addr).await.unwrap();
73+
let (mut data_tx, data_rx) = wit_stream::new();
74+
client.send(data_rx).unwrap();
75+
data_tx.send(second_message.into()).await.unwrap();
76+
}
77+
78+
{
79+
let mut sock = accept.next().await.unwrap();
80+
assert_eq!(sock.len(), 1);
81+
let sock = sock.pop().unwrap();
82+
let (mut data_rx, fut) = sock.receive();
83+
let data = data_rx.next().await.unwrap();
84+
85+
// Check that we sent and received our message!
86+
assert_eq!(data, second_message); // Not guaranteed to work but should work in practice.
87+
fut.await.unwrap().unwrap()
88+
}
89+
}
90+
91+
fn main() {}

0 commit comments

Comments
 (0)