Skip to content

Commit

Permalink
Provide way to simulate network issues for tests
Browse files Browse the repository at this point in the history
This introduces a proxy that simulates different network issues and a
client to manage it. That is handy to be able to test for issues that
can only be reproduced in specific scenarios/environments.

The management API provided here is slimmed down to only reproduce peer
resets but can be further extended if/when necessary.

More information: https://github.com/shopify/toxiproxy
  • Loading branch information
lcobucci committed Apr 22, 2022
1 parent 8ce6dd9 commit 3d7706a
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 0 deletions.
12 changes: 12 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,15 @@ services:
- "2122:21"
- "30000-30009:30000-30009"
command: "/run.sh -l puredb:/etc/pure-ftpd/pureftpd.pdb -E -j -P localhost"
toxiproxy:
container_name: toxiproxy
restart: unless-stopped
image: ghcr.io/shopify/toxiproxy
command: "-host 0.0.0.0 -config /opt/toxiproxy/config.json"
volumes:
- ./test_files/toxiproxy/toxiproxy.json:/opt/toxiproxy/config.json:ro
ports:
- "8474:8474" # HTTP API
- "8222:8222" # SFTP
- "8121:8121" # FTP
- "8122:8122" # FTPD
75 changes: 75 additions & 0 deletions src/AdapterTestUtilities/ToxiproxyManagement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace League\Flysystem\AdapterTestUtilities;

use GuzzleHttp\Client;

/**
* This class provides a client for the HTTP API provided by the proxy that simulates network issues.
*
* @see https://github.com/shopify/toxiproxy#http-api
*
* @phpstan-type RegisteredProxies 'ftp'|'sftp'|'ftpd'
* @phpstan-type StreamDirection 'upstream'|'downstream'
* @phpstan-type Type 'latency'|'bandwidth'|'slow_close'|'timeout'|'reset_peer'|'slicer'|'limit_data'
* @phpstan-type Attributes array{latency?: int, jitter?: int, rate?: int, delay?: int}
* @phpstan-type Toxic array{name?: string, type: Type, stream?: StreamDirection, toxicity?: float, attributes: Attributes}
*/
final class ToxiproxyManagement
{
/** @var Client */
private $apiClient;

public function __construct(Client $apiClient)
{
$this->apiClient = $apiClient;
}

public static function forServer(string $apiUri = 'http://localhost:8474'): self
{
return new self(
new Client(
[
'base_uri' => $apiUri,
'base_url' => $apiUri, // Compatibility with older versions of Guzzle
]
)
);
}

public function removeAllToxics(): void
{
$this->apiClient->post('/reset');
}

/**
* Simulates a peer reset on the client->server direction.
*
* @param RegisteredProxies $proxyName
*/
public function resetPeerOnRequest(
string $proxyName,
int $timeoutInMilliseconds
): void {
$configuration = [
'type' => 'reset_peer',
'stream' => 'upstream',
'attributes' => ['timeout' => $timeoutInMilliseconds],
];

$this->addToxic($proxyName, $configuration);
}

/**
* Registers a network toxic for the given proxy.
*
* @param RegisteredProxies $proxyName
* @param Toxic $configuration
*/
private function addToxic(string $proxyName, array $configuration): void
{
$this->apiClient->post('/proxies/' . $proxyName . '/toxics', ['json' => $configuration]);
}
}
20 changes: 20 additions & 0 deletions test_files/toxiproxy/toxiproxy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[
{
"name": "sftp",
"listen": "[::]:8222",
"upstream": "sftp:22",
"enabled": true
},
{
"name": "ftp",
"listen": "[::]:8121",
"upstream": "ftp:21",
"enabled": true
},
{
"name": "ftpd",
"listen": "[::]:8122",
"upstream": "ftpd:21",
"enabled": true
}
]

0 comments on commit 3d7706a

Please sign in to comment.