From e06894845c61889b10258f619c82baf639708b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Thu, 21 Apr 2022 18:03:49 +0200 Subject: [PATCH] Verify SFTP retries when dealing with peer resets This verifies that Flysystem SFTP adapter goes through all the configured tries before throwing an `UnableToConnectToSftpHost` exception. Reverting the fix applied in https://github.com/thephpleague/flysystem/pull/1451 makes the test to fail due to a unexpected `RuntimeException`. Applying this for phpseclib v2 is a bit tricky, though, due to the lack of knowledge on what has happened in the flow (e.g. `false` is returned when a connection cannot be established or when an authentication error happened). To make it work, the adapter for that version would need to verify if there's a connection or not all the time - which doesn't sound very good to me. --- .../SftpConnectionProviderTest.php | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/PhpseclibV3/SftpConnectionProviderTest.php b/src/PhpseclibV3/SftpConnectionProviderTest.php index 31764c0e5..453bd9cfa 100644 --- a/src/PhpseclibV3/SftpConnectionProviderTest.php +++ b/src/PhpseclibV3/SftpConnectionProviderTest.php @@ -4,6 +4,7 @@ namespace League\Flysystem\PhpseclibV3; +use League\Flysystem\AdapterTestUtilities\ToxiproxyManagement; use phpseclib3\Net\SFTP; use PHPUnit\Framework\TestCase; @@ -241,6 +242,52 @@ public function providing_an_invalid_password(): void $provider->provideConnection(); } + /** + * @test + */ + public function retries_several_times_until_failure(): void + { + $connectivityChecker = new class implements ConnectivityChecker { + /** @var int */ + public $calls = 0; + + public function isConnected(SFTP $connection): bool + { + ++$this->calls; + + return $connection->isConnected(); + } + }; + + $managesConnectionToxics = ToxiproxyManagement::forServer(); + $managesConnectionToxics->resetPeerOnRequest('sftp', 10); + + $maxTries = 5; + + $provider = SftpConnectionProvider::fromArray( + [ + 'host' => 'localhost', + 'username' => 'bar', + 'privateKey' => __DIR__ . '/../../test_files/sftp/id_rsa', + 'passphrase' => 'secret', + 'port' => 8222, + 'maxTries' => $maxTries, + 'timeout' => 1, + 'connectivityChecker' => $connectivityChecker, + ] + ); + + $this->expectException(UnableToConnectToSftpHost::class); + + try { + $provider->provideConnection(); + } finally { + $managesConnectionToxics->removeAllToxics(); + + self::assertSame($maxTries + 1, $connectivityChecker->calls); + } + } + private function computeFingerPrint(string $publicKey): string { $content = explode(' ', $publicKey, 3);