fix(bridge): add Disconnected error variant, fix test race condition

Replace string-matching disconnect detection with explicit
BridgeError::Disconnected variant. Add TcpBridge::accept_on(listener)
that takes a pre-bound TcpListener, eliminating the 100ms sleep hack
in TCP tests. Send errors now also trigger ServerRunning=false.
Add trace logging to generate_snapshot for entity count visibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 21:15:56 +01:00
co-authored by Claude Opus 4.6
parent 058d0352ab
commit 2cd8786036
4 changed files with 65 additions and 94 deletions
+31 -1
View File
@@ -56,6 +56,36 @@ impl TcpBridge {
})
}
/// Server-side: accept one connection on an existing TcpListener.
/// Avoids race conditions in tests by separating bind from accept.
pub fn accept_on(listener: TcpListener) -> Result<Self, BridgeError> {
let local_addr = listener
.local_addr()
.map_err(|e| BridgeError::Transport(format!("failed to get local address: {}", e)))?;
tracing::info!("TcpBridge accepting on {}", local_addr);
let (stream, peer_addr) = listener
.accept()
.map_err(|e| BridgeError::Transport(format!("failed to accept connection: {}", e)))?;
tracing::info!(
"TcpBridge accepted connection from {} on {}",
peer_addr,
local_addr
);
let reader_stream = stream.try_clone().map_err(|e| {
BridgeError::Transport(format!("failed to clone stream for reader: {}", e))
})?;
Ok(Self {
reader: Mutex::new(BufReader::new(reader_stream)),
writer: Mutex::new(BufWriter::new(stream)),
local_addr,
})
}
/// Client-side: connect to TCP address (for tests).
pub fn connect(addr: &str) -> Result<Self, BridgeError> {
tracing::info!("TcpBridge connecting to {}", addr);
@@ -108,7 +138,7 @@ impl SimBridge for TcpBridge {
tracing::trace!("received {} inputs", inputs.len());
Ok(inputs)
}
None => Err(BridgeError::Transport("client disconnected (EOF)".into())),
None => Err(BridgeError::Disconnected),
}
}
}