Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.

Commit e4c10fb

Browse files
test: Add Rust-to-Rust TCP roundtrip test for codegen
Add integration test that verifies generated Rust code can communicate over TCP: server using CalculatorDispatcher, client sending requests with generated method IDs. Note: Found that roam-codegen encodes raw results instead of Result<T, RoamError<E>> as required by spec r[unary.response.encoding]. Added TODO to fix this discrepancy with the #[service] macro.
1 parent 5bb5268 commit e4c10fb

3 files changed

Lines changed: 96 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/codegen-test-consumer/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ codegen-test-proto = { path = "../codegen-test-proto" }
1515
roam = { path = "../roam" }
1616
roam-tcp = { path = "../roam-tcp" }
1717

18+
[dev-dependencies]
19+
tokio = { workspace = true, features = ["rt", "net", "macros"] }
20+
1821
[build-dependencies]
1922
codegen-test-proto = { path = "../codegen-test-proto" }
2023
roam-codegen = { path = "../roam-codegen" }

rust/codegen-test-consumer/src/lib.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,96 @@ mod tests {
6565
let _dispatcher = CalculatorDispatcher::new(TestCalculator);
6666
// Dispatcher implements ServiceDispatcher trait
6767
}
68+
69+
/// Test that Rust-generated client can talk to Rust-generated server over TCP.
70+
#[tokio::test]
71+
async fn rust_to_rust_tcp_roundtrip() {
72+
use roam::__private::facet_postcard;
73+
use roam_tcp::{Message, Server};
74+
use std::time::Duration;
75+
use tokio::net::TcpListener;
76+
77+
// 1. Bind listener on random port
78+
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
79+
let addr = listener.local_addr().unwrap();
80+
81+
// 2. Spawn server task with CalculatorDispatcher
82+
let server_handle = tokio::spawn(async move {
83+
let server = Server::new();
84+
let mut conn = server.accept(&listener).await.unwrap();
85+
let dispatcher = CalculatorDispatcher::new(TestCalculator);
86+
conn.run(&dispatcher).await
87+
});
88+
89+
// 3. Connect as client
90+
let client = Server::new();
91+
let mut conn = client.connect(&addr.to_string()).await.unwrap();
92+
93+
// 4. Test add(2, 3) = 5
94+
let payload = facet_postcard::to_vec(&(2i32, 3i32)).unwrap();
95+
conn.io()
96+
.send(&Message::Request {
97+
request_id: 1,
98+
method_id: method_id::ADD,
99+
metadata: vec![],
100+
payload,
101+
})
102+
.await
103+
.unwrap();
104+
105+
let resp = conn
106+
.io()
107+
.recv_timeout(Duration::from_secs(1))
108+
.await
109+
.unwrap()
110+
.unwrap();
111+
let Message::Response {
112+
request_id,
113+
payload,
114+
..
115+
} = resp
116+
else {
117+
panic!("expected Response, got {resp:?}")
118+
};
119+
assert_eq!(request_id, 1);
120+
// Note: roam-codegen currently encodes just the raw result, not Result<T, RoamError<E>>
121+
// This differs from the spec (r[unary.response.encoding]) and from #[service] macro output.
122+
// TODO: Fix roam-codegen to wrap results in Result<T, RoamError<Never>>
123+
let result: i32 = facet_postcard::from_slice(&payload).unwrap();
124+
assert_eq!(result, 5);
125+
126+
// 5. Test multiply(4, 7) = 28
127+
let payload = facet_postcard::to_vec(&(4i32, 7i32)).unwrap();
128+
conn.io()
129+
.send(&Message::Request {
130+
request_id: 2,
131+
method_id: method_id::MULTIPLY,
132+
metadata: vec![],
133+
payload,
134+
})
135+
.await
136+
.unwrap();
137+
138+
let resp = conn
139+
.io()
140+
.recv_timeout(Duration::from_secs(1))
141+
.await
142+
.unwrap()
143+
.unwrap();
144+
let Message::Response {
145+
request_id,
146+
payload,
147+
..
148+
} = resp
149+
else {
150+
panic!("expected Response, got {resp:?}")
151+
};
152+
assert_eq!(request_id, 2);
153+
let result: i32 = facet_postcard::from_slice(&payload).unwrap();
154+
assert_eq!(result, 28);
155+
156+
// 6. Drop connection - server will see clean shutdown
157+
drop(conn);
158+
let _ = server_handle.await;
159+
}
68160
}

0 commit comments

Comments
 (0)