All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 13s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 9s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 7s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 5s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 4s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 5s
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 3m32s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 3m35s
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (pull_request) Successful in 1m2s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 2m58s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 6m31s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 40s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 8m46s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 1m47s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 7m47s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 4m30s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 12m15s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 10m49s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 1m15s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 14m35s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 8m32s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 17m57s
The edge relay's link to its upstream runs over wss through a tunnel that closes a connection it sees idle. With no one watching, the link carried nothing, and the tunnel cut it every two minutes; the edge redialled within two seconds each time. Each end now sends a WebSocket ping (RFC 6455 §5.5.2) every 30 s while the session lasts, and the peer's WebSocket answers with a pong. The binding's README gains the step. Co-Authored-By: Claude Opus 5.5 <[email protected]>
42 lines
1.8 KiB
Rust
42 lines
1.8 KiB
Rust
//! Two publishers and three subscribers through the relay over the WebSocket fallback
|
|
//! (`draft-ietf-webtrans-http2-15` capsules, one to each message).
|
|
|
|
mod common;
|
|
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
|
|
async fn two_publishers_three_subscribers_over_websocket() {
|
|
tokio::time::timeout(std::time::Duration::from_secs(120), common::two_publishers_three_subscribers(common::Via::WebSocket))
|
|
.await
|
|
.expect("the scenario finishes in time");
|
|
}
|
|
|
|
/// A session with nothing to carry pings its peer, so a front that closes idle connections
|
|
/// keeps it; the peer's pongs come back and the session stays open.
|
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn an_idle_session_pings_its_peer() {
|
|
use futures::StreamExt;
|
|
use joule_moq_relay::transport::mux::MuxConfig;
|
|
use joule_moq_relay::transport::websocket::session_pinging;
|
|
use std::time::Duration;
|
|
use tokio_tungstenite::tungstenite::protocol::Role;
|
|
use tokio_tungstenite::tungstenite::Message;
|
|
use tokio_tungstenite::WebSocketStream;
|
|
|
|
let (relay_end, peer_end) = tokio::io::duplex(1 << 16);
|
|
let ws = WebSocketStream::from_raw_socket(relay_end, Role::Server, None).await;
|
|
let mut peer = WebSocketStream::from_raw_socket(peer_end, Role::Client, None).await;
|
|
let _session = session_pinging(ws, false, "peer".into(), MuxConfig::default(), Duration::from_millis(50));
|
|
|
|
let mut pings = 0;
|
|
let read = tokio::time::timeout(Duration::from_secs(10), async {
|
|
while pings < 3 {
|
|
match peer.next().await {
|
|
Some(Ok(Message::Ping(_))) => pings += 1,
|
|
Some(Ok(_)) => {}
|
|
other => panic!("the session ended before its pings: {other:?}"),
|
|
}
|
|
}
|
|
})
|
|
.await;
|
|
assert!(read.is_ok(), "three pings at a 50 ms interval within 10 s; {pings} arrived");
|
|
}
|