Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ jobs:
- run: composer remove react/mysql --dev --no-interaction # do not install react/mysql example on legacy PHP
if: ${{ matrix.php == 5.3 }}
- run: composer install
- run: vendor/bin/phpunit --coverage-text ${{ matrix.php < 7.3 && '-c phpunit.xml.legacy' || '' }}
- run: vendor/bin/phpunit --coverage-text --coverage-clover clover.xml ${{ matrix.php < 7.3 && '-c phpunit.xml.legacy' || '' }}
- name: Check 100% code coverage
shell: php {0}
run: |
<?php
$metrics = simplexml_load_file('clover.xml')->project->metrics;
exit((int) $metrics['statements'] === (int) $metrics['coveredstatements'] ? 0 : 1);
Comment thread
clue marked this conversation as resolved.

PHPUnit-hhvm:
name: PHPUnit (HHVM)
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# clue/reactphp-ssh-proxy

[![CI status](https://github.com/clue/reactphp-ssh-proxy/actions/workflows/ci.yml/badge.svg)](https://github.com/clue/reactphp-ssh-proxy/actions)
[![code coverage](https://img.shields.io/badge/code%20coverage-100%25-success)](#tests)
[![installs on Packagist](https://img.shields.io/packagist/dt/clue/reactphp-ssh-proxy?color=blue&label=installs%20on%20Packagist)](https://packagist.org/packages/clue/reactphp-ssh-proxy)

Async SSH proxy connector and forwarder, tunnel any TCP/IP-based protocol through an SSH server,
Expand Down Expand Up @@ -603,6 +604,14 @@ To run the test suite, go to the project root and run:
vendor/bin/phpunit
```

The test suite is set up to always ensure 100% code coverage across all
supported environments. If you have the Xdebug extension installed, you can also
generate a code coverage report locally like this:

```bash
XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text
```

The test suite contains a number of tests that require an actual SSH proxy server.
These tests will be skipped unless you configure your SSH login credentials to
be able to create some actual test connections. You can assign the `SSH_PROXY`
Expand Down
13 changes: 10 additions & 3 deletions src/SshProcessConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ public function connect($uri)
$process = Io\processWithoutFds($command);
$process->start($this->loop);

// @codeCoverageIgnoreStart
if ($this->debug) {
echo 'Launched "' . $command . '" with PID ' . $process->getPid() . PHP_EOL; // @codeCoverageIgnore
echo 'Launched "' . $command . '" with PID ' . $process->getPid() . PHP_EOL;
}
// @codeCoverageIgnoreEnd

$deferred = new Deferred(function () use ($process, $uri) {
$process->stdin->close();
Expand All @@ -106,9 +108,11 @@ public function connect($uri)
// remember last line for error output in case process exits
$last = $line;

// @codeCoverageIgnoreStart
if ($debug) {
echo \addcslashes($line, "\0..\032") . PHP_EOL; // @codeCoverageIgnore
echo \addcslashes($line, "\0..\032") . PHP_EOL;
}
// @codeCoverageIgnoreEnd

// match everything related to our forwarding channel
// forwarding error will be printed right to stderr
Expand Down Expand Up @@ -154,9 +158,12 @@ public function connect($uri)
});

$process->on('exit', function ($code) use ($deferred, $uri, &$last, $debug) {
// @codeCoverageIgnoreStart
if ($debug) {
echo 'Process exit with code ' . $code . PHP_EOL; // @codeCoverageIgnore
echo 'Process exit with code ' . $code . PHP_EOL;
}
// @codeCoverageIgnoreEnd

$deferred->reject(new \RuntimeException(
'Connection to ' . $uri . ' failed because SSH client died (' . $last . ')',
(int) $code
Expand Down
8 changes: 6 additions & 2 deletions src/SshSocksConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,11 @@ public function idle()
$listen->cancel();
$listen = null;

// @codeCoverageIgnoreStart
if ($debug) {
echo 'Stopped listening' . PHP_EOL; // @codeCoverageIgnore
echo 'Stopped listening' . PHP_EOL;
}
// @codeCoverageIgnoreEnd
});
}
}
Expand All @@ -232,9 +234,11 @@ private function listen()
// Could not request local forwarding.
$last = $line;

// @codeCoverageIgnoreStart
if ($debug) {
echo \addcslashes($line, "\0..\032") . PHP_EOL; // @codeCoverageIgnore
echo \addcslashes($line, "\0..\032") . PHP_EOL;
}
// @codeCoverageIgnoreEnd

// match everything related to our forwarding channel
// forwarding success will only be reported to stderr via debug1 / -v
Expand Down
16 changes: 16 additions & 0 deletions tests/IntegrationSshProcessConnectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ public function testConnectWillRejectWithExceptionWhenProcessOutputsEndsWithoutC
Loop::run();
}

public function testConnectWillRejectWithExceptionWhenProcessOutputsEndsAfterChannelMessageWithoutOpenConfirm()
{
$connector = new SshProcessConnector('host');

$ref = new \ReflectionProperty($connector, 'cmd');
if (PHP_VERSION_ID < 80100) {
$ref->setAccessible(true);
}
$ref->setValue($connector, 'echo "debug1: channel 0: new stdio-forward [stdio-forward] (inactive timeout: 0)" >&2; #');

$promise = $connector->connect('example.com:80');
$promise->then(null, $this->expectCallableOnceWith($this->isInstanceOf('RuntimeException')));

Loop::run();
}

public function testConnectCancellationWillRejectWithException()
{
$connector = new SshProcessConnector('host');
Expand Down