From 680d0d6b74fea98b8265e553fc22d51df4bee633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20HOUZ=C3=89?= Date: Thu, 30 Nov 2017 20:45:42 +0100 Subject: [PATCH] :hammer: [Healthcheck] Introduce a Destination value object Thus don't repeating ourself in destination validation --- Destination.php | 45 +++++++++++++++++++++++++++++++++ Healthcheck.php | 5 ++-- HttpHealthcheck.php | 15 +++++------ InvalidDestination.php | 4 +-- TcpHealthcheck.php | 11 +++----- tests/Units/Destination.php | 43 +++++++++++++++++++++++++++++++ tests/Units/HttpHealthcheck.php | 19 +++----------- tests/Units/TcpHealthcheck.php | 29 ++++++++------------- 8 files changed, 115 insertions(+), 56 deletions(-) create mode 100644 Destination.php create mode 100644 tests/Units/Destination.php diff --git a/Destination.php b/Destination.php new file mode 100644 index 0000000..5840458 --- /dev/null +++ b/Destination.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Ubirak\Component\Healthcheck; + +final class Destination +{ + private $uri; + + /** + * Informs if a destination is reachable + * + * @param string $destination A destination to join for the health check + * + * @throws InvalidDestination when the destination is not supported. + */ + public function __construct(string $uri) + { + $this->uri = filter_var($uri, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED); + + if ($this->uri === false) { + throw InvalidDestination::forUri($uri); + } + } + + public function parse(): array + { + return parse_url($this->uri); + } + + public function __toString(): string + { + return $this->uri; + } +} diff --git a/Healthcheck.php b/Healthcheck.php index 42fe0f7..84ba848 100644 --- a/Healthcheck.php +++ b/Healthcheck.php @@ -18,10 +18,9 @@ interface Healthcheck /** * Informs if a destination is reachable * - * @param string $destination A destination to join for the health check + * @param Destination $destination A destination to join for the health check * - * @throws InvalidDestination when the destination is not supported by health check implementation. * @throws HealthcheckFailure when a non expected health check failure occurs. */ - public function isReachable(string $destination): bool; + public function isReachable(Destination $destination): bool; } diff --git a/HttpHealthcheck.php b/HttpHealthcheck.php index a18f22a..7a9cb19 100644 --- a/HttpHealthcheck.php +++ b/HttpHealthcheck.php @@ -30,25 +30,22 @@ public function __construct(HttpClient $httpClient, LoggerInterface $logger = nu $this->logger = $logger ?? new NullLogger(); } - public function isReachable(string $destination): bool + public function isReachable(Destination $destination): bool { - if (false === filter_var($destination, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED)) { - throw InvalidDestination::ofProtocol('http'); - } - - $this->logger->info('Start HTTP healthcheck', ['destination' => $destination]); + $url = (string) $destination; + $this->logger->info('Start HTTP healthcheck', ['destination' => $url]); try { - $response = $this->httpClient->sendRequest(new Request('GET', $destination)); + $response = $this->httpClient->sendRequest(new Request('GET', $url)); } catch (\Exception $e) { - $this->logger->info('[Fail] HTTP healthcheck', ['destination' => $destination]); + $this->logger->info('[Fail] HTTP healthcheck', ['destination' => $url]); return false; } $result = 200 === $response->getStatusCode(); $resultAsString = $result ? 'OK' : 'Fail'; - $this->logger->info("[${resultAsString}] HTTP healthcheck", ['destination' => $destination]); + $this->logger->info("[${resultAsString}] HTTP healthcheck", ['destination' => $url]); return $result; } diff --git a/InvalidDestination.php b/InvalidDestination.php index b5e66b0..b16262a 100644 --- a/InvalidDestination.php +++ b/InvalidDestination.php @@ -15,8 +15,8 @@ final class InvalidDestination extends \InvalidArgumentException { - public static function ofProtocol(string $protocol) + public static function forUri(string $uri) { - return new static("Destination must be a valid ${protocol} uri."); + return new static("Invalid destination: $uri."); } } diff --git a/TcpHealthcheck.php b/TcpHealthcheck.php index 89ccf55..e5db0fa 100644 --- a/TcpHealthcheck.php +++ b/TcpHealthcheck.php @@ -43,12 +43,9 @@ public function __construct(float $initialExponent, float $step, float $maxExecu $this->logger = $logger ?? new NullLogger(); } - public function isReachable(string $destination): bool + public function isReachable(Destination $destination): bool { - if (false === filter_var($destination, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED)) { - throw InvalidDestination::ofProtocol('tcp'); - } - ['host' => $host, 'port' => $port] = parse_url($destination); + ['host' => $host, 'port' => $port] = $destination->parse(); $uri = "tcp://${host}:${port}"; $this->logger->info('Start TCP healthcheck', ['destination' => $uri]); @@ -71,10 +68,10 @@ public function isReachable(string $destination): bool @fclose($socket); return true; })); - $this->logger->info('[OK] TCP healthcheck', ['destination' => $destination]); + $this->logger->info('[OK] TCP healthcheck', ['destination' => $uri]); return true; } catch (\Exception $e) { - $this->logger->info('[Fail] TCP healthcheck', ['destination' => $destination]); + $this->logger->info('[Fail] TCP healthcheck', ['destination' => $uri]); return false; } } diff --git a/tests/Units/Destination.php b/tests/Units/Destination.php new file mode 100644 index 0000000..1e4b671 --- /dev/null +++ b/tests/Units/Destination.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Ubirak\Component\Healthcheck\Tests\Units; + +use atoum; + +class Destination extends atoum +{ + /** + * @dataProvider invalidUri + */ + public function test it fails with invalid uri($uri) + { + $this + ->exception(function () use ($uri) { + $this->newTestedInstance($uri); + }) + ->hasMessage("Invalid destination: $uri."); + ; + } + + protected function invalidUri(): array + { + return [ + 'whithout scheme' => ['localhost'], + 'whithout host #1' => ['http://'], + 'whithout host #2' => ['https://'], + 'whithout host #3' => ['tcp://'], + 'empty' => [''], + ]; + } +} diff --git a/tests/Units/HttpHealthcheck.php b/tests/Units/HttpHealthcheck.php index 44a5fba..6e157b3 100644 --- a/tests/Units/HttpHealthcheck.php +++ b/tests/Units/HttpHealthcheck.php @@ -14,13 +14,14 @@ namespace Ubirak\Component\Healthcheck\Tests\Units; use atoum; +use Ubirak\Component\Healthcheck\Destination; class HttpHealthcheck extends atoum { /** * @dataProvider reachability */ - public function test reachability(string $destination, int $statusCode, bool $expectedReachability) + public function test reachability(string $uri, int $statusCode, bool $expectedReachability) { $this ->given( @@ -32,7 +33,7 @@ public function test reachability(string $destination, int $statusCode, bool $e $this->calling($response)->getStatusCode = $statusCode ) ->when( - $reachable = $this->testedInstance->isReachable($destination) + $reachable = $this->testedInstance->isReachable(new Destination($uri)) ) ->then ->boolean($reachable)->isIdenticalTo($expectedReachability) @@ -42,20 +43,6 @@ public function test reachability(string $destination, int $statusCode, bool $e ; } - public function test it requires complete uri() - { - $this - ->given( - $httpClient = new \mock\Http\Client\HttpClient(), - $this->newTestedInstance($httpClient) - ) - ->exception(function () { - $this->testedInstance->isReachable('localhost'); - }) - ->hasMessage('Destination must be a valid http uri.') - ; - } - protected function reachability(): array { return [ diff --git a/tests/Units/TcpHealthcheck.php b/tests/Units/TcpHealthcheck.php index 1342391..e48251a 100644 --- a/tests/Units/TcpHealthcheck.php +++ b/tests/Units/TcpHealthcheck.php @@ -14,6 +14,7 @@ namespace Ubirak\Component\Healthcheck\Tests\Units; use atoum; +use Ubirak\Component\Healthcheck\Destination; class TcpHealthcheck extends atoum { @@ -22,10 +23,11 @@ public function test it tries multiple time to create socket() $this ->given( $this->function->stream_socket_client = false, - $this->newTestedInstance(0.5, 0.5, 3.0) + $this->newTestedInstance(0.5, 0.5, 3.0), + $destination = new Destination('tcp://localhost:1000') ) ->when( - $result = $this->testedInstance->isReachable('tcp://localhost:1000') + $result = $this->testedInstance->isReachable($destination) ) ->then ->boolean($result) @@ -40,10 +42,11 @@ public function test first successful try is enough() ->given( $this->function->stream_socket_client = true, $this->function->fclose = true, - $this->newTestedInstance(0.5, 0.5, 3.0) + $this->newTestedInstance(0.5, 0.5, 3.0), + $destination = new Destination('http://localhost:1000') ) ->when( - $result = $this->testedInstance->isReachable('http://localhost:1000') + $result = $this->testedInstance->isReachable($destination) ) ->then ->boolean($result) @@ -59,10 +62,11 @@ public function test next successful try is enough() $this->function->stream_socket_client = false, $this->function->stream_socket_client[2] = true, $this->function->fclose = true, - $this->newTestedInstance(0.5, 0.5, 3.0) + $this->newTestedInstance(0.5, 0.5, 3.0), + $destination = new Destination('http://localhost:1000') ) ->when( - $result = $this->testedInstance->isReachable('http://localhost:1000') + $result = $this->testedInstance->isReachable($destination) ) ->then ->boolean($result) @@ -70,17 +74,4 @@ public function test next successful try is enough() ->function('stream_socket_client')->wasCalled()->twice() ; } - - public function test it requires complete uri() - { - $this - ->given( - $this->newTestedInstance(0.5, 0.5, 3.0) - ) - ->exception(function () { - $this->testedInstance->isReachable('localhost'); - }) - ->hasMessage('Destination must be a valid tcp uri.') - ; - } }