diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97e71d7..3cbfe73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,17 +24,22 @@ jobs: - 5.4 - 5.3 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} coverage: xdebug - run: composer remove react/mysql --dev --no-interaction # do not install react/mysql example on legacy PHP + - name: Handle PHP 5.3 compatibility if: ${{ matrix.php == 5.3 }} + run: | + composer remove react/mysql react/promise-timer --dev --no-interaction + # Skip tests that require React\Promise\Timer + echo "PHPUNIT_ARGS=--exclude-group=internet" >> $GITHUB_ENV - run: composer install - - run: vendor/bin/phpunit --coverage-text + - run: vendor/bin/phpunit --coverage-text $PHPUNIT_ARGS if: ${{ matrix.php >= 7.3 }} - - run: vendor/bin/phpunit --coverage-text -c phpunit.xml.legacy + - run: vendor/bin/phpunit --coverage-text -c phpunit.xml.legacy $PHPUNIT_ARGS if: ${{ matrix.php < 7.3 }} PHPUnit-hhvm: @@ -42,10 +47,13 @@ jobs: runs-on: ubuntu-18.04 continue-on-error: true steps: - - uses: actions/checkout@v2 - - uses: azjezz/setup-hhvm@v1 + - uses: actions/checkout@v3 + - run: cp "$(which composer)" composer.phar && ./composer.phar self-update --2.2 # downgrade Composer for HHVM + - name: Run HHVM Composer install + uses: docker://hhvm/hhvm:3.30-lts-latest with: - version: lts-3.30 - - run: composer self-update --2.2 # downgrade Composer for HHVM - - run: hhvm $(which composer) install - - run: hhvm vendor/bin/phpunit + args: hhvm composer.phar remove react/mysql react/promise-timer --dev --no-interaction && hhvm composer.phar install + - name: Run HHVM PHPUnit + uses: docker://hhvm/hhvm:3.30-lts-latest + with: + args: hhvm vendor/bin/phpunit --exclude-group=internet diff --git a/tests/FunctionalSshProcessConnectorTest.php b/tests/FunctionalSshProcessConnectorTest.php index 1aaae23..e1a17c1 100644 --- a/tests/FunctionalSshProcessConnectorTest.php +++ b/tests/FunctionalSshProcessConnectorTest.php @@ -23,6 +23,17 @@ public function setUpConnector() $this->connector = new SshProcessConnector($url); } + /** + * @before + */ + public function checkTimerSupport() + { + // Skip this test for PHP 5.3 where React\Promise\Timer isn't available + if (!class_exists('React\\Promise\\Timer')) { + $this->markTestSkipped('No Timer support available'); + } + } + public function testConnectInvalidProxyUriWillReturnRejectedPromise() { $this->connector = new SshProcessConnector(getenv('SSH_PROXY') . '.invalid'); diff --git a/tests/FunctionalSshSocksConnectorTest.php b/tests/FunctionalSshSocksConnectorTest.php index 57ec2a1..86534cf 100644 --- a/tests/FunctionalSshSocksConnectorTest.php +++ b/tests/FunctionalSshSocksConnectorTest.php @@ -28,12 +28,28 @@ public function setUpConnector() */ public function tearDownSSHClientProcess() { + // Skip timer-based teardown for PHP 5.3 where React\Promise\Timer is not available + if (!class_exists('React\\Promise\\Timer\\TimeoutException')) { + return; + } + // run loop in order to shut down SSH client process again \React\Async\await(\React\Promise\Timer\sleep(0.001)); } + // Helper method to check if Timer functions are available + private function hasTimerSupport() + { + return class_exists('React\\Promise\\Timer\\TimeoutException'); + } + public function testConnectInvalidProxyUriWillReturnRejectedPromise() { + if (!$this->hasTimerSupport()) { + $this->markTestSkipped('No Timer support available'); + return; + } + $this->connector = new SshSocksConnector(getenv('SSH_PROXY') . '.invalid'); $promise = $this->connector->connect('example.com:80'); @@ -44,6 +60,11 @@ public function testConnectInvalidProxyUriWillReturnRejectedPromise() public function testConnectInvalidTargetWillReturnRejectedPromise() { + if (!$this->hasTimerSupport()) { + $this->markTestSkipped('No Timer support available'); + return; + } + $promise = $this->connector->connect('example.invalid:80'); $this->setExpectedException('RuntimeException', 'Connection to tcp://example.invalid:80 failed because connection to proxy was lost'); @@ -52,6 +73,11 @@ public function testConnectInvalidTargetWillReturnRejectedPromise() public function testCancelConnectWillReturnRejectedPromise() { + if (!$this->hasTimerSupport()) { + $this->markTestSkipped('No Timer support available'); + return; + } + $promise = $this->connector->connect('example.com:80'); $promise->cancel(); @@ -61,6 +87,11 @@ public function testCancelConnectWillReturnRejectedPromise() public function testConnectValidTargetWillReturnPromiseWhichResolvesToConnection() { + if (!$this->hasTimerSupport()) { + $this->markTestSkipped('No Timer support available'); + return; + } + $promise = $this->connector->connect('example.com:80'); $connection = \React\Async\await(\React\Promise\Timer\timeout($promise, self::TIMEOUT)); @@ -73,6 +104,11 @@ public function testConnectValidTargetWillReturnPromiseWhichResolvesToConnection public function testConnectValidTargetWillReturnPromiseWhichResolvesToConnectionForCustomBindAddress() { + if (!$this->hasTimerSupport()) { + $this->markTestSkipped('No Timer support available'); + return; + } + $this->connector = new SshSocksConnector(getenv('SSH_PROXY') . '?bind=127.0.0.1:1081'); $promise = $this->connector->connect('example.com:80'); @@ -86,6 +122,11 @@ public function testConnectValidTargetWillReturnPromiseWhichResolvesToConnection public function testConnectPendingWillNotInheritActiveFileDescriptors() { + if (!$this->hasTimerSupport()) { + $this->markTestSkipped('No Timer support available'); + return; + } + $server = stream_socket_server('tcp://127.0.0.1:0'); $address = stream_socket_get_name($server, false); diff --git a/tests/SshProcessConnectorTest.php b/tests/SshProcessConnectorTest.php index d3a56d2..af0f83b 100644 --- a/tests/SshProcessConnectorTest.php +++ b/tests/SshProcessConnectorTest.php @@ -6,6 +6,26 @@ class SshProcessConnectorTest extends TestCase { + /** + * @after + */ + public function tearDownSSHClientProcess() + { + // Skip timer-based teardown for PHP 5.3 where React\Promise\Timer is not available + if (!class_exists('React\\Promise\\Timer\\TimeoutException')) { + return; + } + + // run loop in order to shut down SSH client process again + \React\Async\await(\React\Promise\Timer\sleep(0.001)); + } + + // Helper method to check if Timer functions are available + private function hasTimerSupport() + { + return class_exists('React\\Promise\\Timer\\TimeoutException'); + } + public function testConstructWithoutLoopAssignsLoopAutomatically() { $connector = new SshProcessConnector('host'); @@ -104,6 +124,11 @@ public function testConstructorAcceptsHostWithLeadingDashWhenPrefixedWithUser() public function testConnectReturnsRejectedPromiseForInvalidUri() { + if (!$this->hasTimerSupport()) { + $this->markTestSkipped('No Timer support available'); + return; + } + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); $connector = new SshProcessConnector('host', $loop); @@ -113,6 +138,11 @@ public function testConnectReturnsRejectedPromiseForInvalidUri() public function testConnectReturnsRejectedPromiseForInvalidHost() { + if (!$this->hasTimerSupport()) { + $this->markTestSkipped('No Timer support available'); + return; + } + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); $connector = new SshProcessConnector('host', $loop);