From b8c2b5903157382eb4b189e31bf3022f3fe498b3 Mon Sep 17 00:00:00 2001 From: zackees Date: Sun, 23 Aug 2026 11:58:51 -0700 Subject: [PATCH] fix(test): block accepted sockets so Windows test servers stop flaking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Check (windows-latest)` failed on an unrelated PR with: usb::data::tests::populate_online_cache_falls_back_to_json_when_proto_is_missing thread '' panicked at crates\fbuild-core\src\usb\data.rs:643:55: called `Result::unwrap()` on an `Err` value: Os { code: 10035, kind: WouldBlock, message: "A non-blocking socket operation could not be completed immediately." } Both test servers set their listener non-blocking and handle `WouldBlock` around `accept()`. What neither handled is that **Windows gives back an accepted socket that inherits the listener's non-blocking mode**, where Unix gives back a blocking one. So `stream.read(..).unwrap()` on the fresh connection returns WSAEWOULDBLOCK whenever the client's bytes have not landed in the microsecond between accept and read — a timing-dependent failure whose message points at sockets rather than at the socket *mode*, on a test about USB VID overlays. The accepted socket is now put back into blocking mode explicitly, which is what the loop already assumes. `test_emu_exit_code.rs`'s mock daemon has guarded this way from the start ("blocking per-connection"); these two just never got the same treatment. `usb/profiles.rs` has the same listener shape but only counts accepts and never reads from the stream, so it is unaffected and left alone. Co-Authored-By: Claude Opus 5 (1M context) --- crates/fbuild-cli/src/cli/port_scan.rs | 12 ++++++++++++ crates/fbuild-core/src/usb/data.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/crates/fbuild-cli/src/cli/port_scan.rs b/crates/fbuild-cli/src/cli/port_scan.rs index 6c0d6eac2..648bd93c4 100644 --- a/crates/fbuild-cli/src/cli/port_scan.rs +++ b/crates/fbuild-cli/src/cli/port_scan.rs @@ -520,6 +520,18 @@ mod tests { while request_count < 2 { match listener.accept() { Ok((mut stream, _)) => { + // Windows hands back an accepted socket that inherits + // the listener's non-blocking mode, unlike Unix. The + // read below then returns WSAEWOULDBLOCK (os error + // 10035) whenever the client's bytes have not landed + // yet, and `unwrap` turns that into a flaky failure + // that looks nothing like a socket-mode problem. + // FastLED/fbuild#1349 CI run 32658416728 hit it; the + // mock daemon in `test_emu_exit_code.rs` already + // guards the same way. + stream + .set_nonblocking(false) + .expect("accepted socket must block for the exchange below"); let mut request = [0_u8; 1024]; let _ = stream.read(&mut request).unwrap(); request_count += 1; diff --git a/crates/fbuild-core/src/usb/data.rs b/crates/fbuild-core/src/usb/data.rs index b593ca4a5..e64c241d5 100644 --- a/crates/fbuild-core/src/usb/data.rs +++ b/crates/fbuild-core/src/usb/data.rs @@ -639,6 +639,18 @@ mod tests { while request_count < 2 { match listener.accept() { Ok((mut stream, _)) => { + // Windows hands back an accepted socket that inherits + // the listener's non-blocking mode, unlike Unix. The + // read below then returns WSAEWOULDBLOCK (os error + // 10035) whenever the client's bytes have not landed + // yet, and `unwrap` turns that into a flaky failure + // that looks nothing like a socket-mode problem. + // FastLED/fbuild#1349 CI run 32658416728 hit it; the + // mock daemon in `test_emu_exit_code.rs` already + // guards the same way. + stream + .set_nonblocking(false) + .expect("accepted socket must block for the exchange below"); let mut buf = [0_u8; 1024]; let _ = stream.read(&mut buf).unwrap(); request_count += 1;