From f44922de65acff9da8d75caedff165e3f303c0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Wed, 15 May 2019 21:28:38 +0200 Subject: [PATCH] Avoid race condition for forked process in test suite There's a very short race condition where the forked php process first has to `dup()` the file descriptor specs before invoking `exec()` to switch to the actual `ssh` child process. We don't need to wait for the child process to be ready, but only for the forked process to close the file descriptors. This happens ~80% of times on single core machines and almost never on multi core systems, so simply wait 5ms (plenty of time!) and retry again. Builds on top of https://github.com/clue/reactphp-sqlite/pull/15 --- tests/FunctionalSshProcessConnectorTest.php | 15 ++++++++++++++- tests/FunctionalSshSocksConnectorTest.php | 20 +++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/tests/FunctionalSshProcessConnectorTest.php b/tests/FunctionalSshProcessConnectorTest.php index 553595e..37d19af 100644 --- a/tests/FunctionalSshProcessConnectorTest.php +++ b/tests/FunctionalSshProcessConnectorTest.php @@ -88,7 +88,20 @@ public function testConnectPendingWillNotInheritActiveFileDescriptors() // close server and ensure we can start a new server on the previous address // the pending SSH connection process should not inherit the existing server socket fclose($server); - $server = stream_socket_server('tcp://' . $address); + + $server = @stream_socket_server('tcp://' . $address); + if ($server === false) { + // There's a very short race condition where the forked php process + // first has to `dup()` the file descriptor specs before invoking + // `exec()` to switch to the actual `ssh` child process. We don't + // need to wait for the child process to be ready, but only for the + // forked process to close the file descriptors. This happens ~80% + // of times on single core machines and almost never on multi core + // systems, so simply wait 5ms (plenty of time!) and retry again. + usleep(5000); + $server = stream_socket_server('tcp://' . $address); + } + $this->assertTrue(is_resource($server)); fclose($server); diff --git a/tests/FunctionalSshSocksConnectorTest.php b/tests/FunctionalSshSocksConnectorTest.php index 2379ade..a11121b 100644 --- a/tests/FunctionalSshSocksConnectorTest.php +++ b/tests/FunctionalSshSocksConnectorTest.php @@ -108,7 +108,25 @@ public function testConnectPendingWillNotInheritActiveFileDescriptors() // close server and ensure we can start a new server on the previous address // the pending SSH connection process should not inherit the existing server socket fclose($server); - $server = stream_socket_server('tcp://' . $address); + + $server = @stream_socket_server('tcp://' . $address); + if ($server === false) { + // There's a very short race condition where the forked php process + // first has to `dup()` the file descriptor specs before invoking + // `exec()` to switch to the actual `ssh` child process. We don't + // need to wait for the child process to be ready, but only for the + // forked process to close the file descriptors. This happens ~80% + // of times on single core machines and almost never on multi core + // systems, so simply wait 5ms (plenty of time!) and retry again twice. + usleep(5000); + $server = @stream_socket_server('tcp://' . $address); + + if ($server === false) { + usleep(5000); + $server = stream_socket_server('tcp://' . $address); + } + } + $this->assertTrue(is_resource($server)); fclose($server);