diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 39170e3..0cf38b0 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -161,7 +161,7 @@ jobs: id: composer-cache run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ matrix.php }} diff --git a/README.md b/README.md index b86dac5..5ddb704 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Integrate with applications ### Dependency Injection -You can easy integrate this library to Symfony application, or application with DependencyInjection support. +You can easily integrate this library to Symfony application, or application with DependencyInjection support. For integrate, you can add the compiler pass to your container builder: @@ -121,7 +121,7 @@ $containerBuilder->addCompilerPass(new AddDiagnosticToBuilderCheckPass()); $containerBuilder->compile(); ``` -Add add check services: +And add check services: ```yaml services: @@ -176,7 +176,9 @@ Before create the PR or merge into develop, please run next commands for validat ./bin/phpunit ./bin/phpcs --config-set show_warnings 0 -./bin/phpcs --standard=vendor/escapestudios/symfony2-coding-standard/Symfony/ src/ +./bin/phpcs --standard=src/phpcs-ruleset.xml src/ ./bin/phpcs --standard=tests/phpcs-ruleset.xml tests/ +php -d memory_limit=-1 ./bin/phpstan + ``` diff --git a/src/Check/Redis/Predis/PredisPingPongCheck.php b/src/Check/Redis/Predis/PredisPingPongCheck.php new file mode 100644 index 0000000..872512e --- /dev/null +++ b/src/Check/Redis/Predis/PredisPingPongCheck.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types = 1); + +namespace FiveLab\Component\Diagnostic\Check\Redis\Predis; + +use FiveLab\Component\Diagnostic\Check\CheckInterface; +use FiveLab\Component\Diagnostic\Result\Failure; +use FiveLab\Component\Diagnostic\Result\Result; +use FiveLab\Component\Diagnostic\Result\Success; +use Predis\Client; + +readonly class PredisPingPongCheck implements CheckInterface +{ + public function __construct(private string $host, private int $port, private ?string $password = null) + { + } + + public function check(): Result + { + if (!\class_exists(Client::class)) { + return new Failure('The predis/predis not installed.'); + } + + $parameters = [ + 'host' => $this->host, + 'port' => $this->port, + ]; + + if ($this->password) { + $parameters['password'] = $this->password; + } + + try { + $client = new Client($parameters); + $client->ping(); + } catch (\Throwable $e) { + return new Failure(\sprintf( + 'Cannot connect to Redis: %s.', + \rtrim($e->getMessage(), '.') + )); + } + + return new Success('Success connect to Redis.'); + } + + public function getExtraParameters(): array + { + // By security we not return password (because many redis instances work in internal network). + return [ + 'host' => $this->host, + 'port' => $this->port, + ]; + } +} diff --git a/src/Check/Redis/RedisExt/RedisPingPongCheck.php b/src/Check/Redis/RedisExt/RedisPingPongCheck.php new file mode 100644 index 0000000..1f17a96 --- /dev/null +++ b/src/Check/Redis/RedisExt/RedisPingPongCheck.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types = 1); + +namespace FiveLab\Component\Diagnostic\Check\Redis\RedisExt; + +use FiveLab\Component\Diagnostic\Check\CheckInterface; +use FiveLab\Component\Diagnostic\Result\Failure; +use FiveLab\Component\Diagnostic\Result\Result; +use FiveLab\Component\Diagnostic\Result\Success; + +readonly class RedisPingPongCheck implements CheckInterface +{ + public function __construct(private string $host, private int $port, private ?string $password = null) + { + } + + public function check(): Result + { + if (!\class_exists(\Redis::class)) { + return new Failure('The ext-redis not installed.'); + } + + $redis = new \Redis(); + + \set_error_handler(static function (int $errno, string $errstr) { + throw new \Exception($errstr); + }); + + try { + $this->connect($redis); + $redis->ping(); + } catch (\Throwable $e) { + return new Failure(\sprintf( + 'Cannot connect to Redis: %s.', + \rtrim($e->getMessage(), '.') + )); + } finally { + \restore_error_handler(); + } + + return new Success('Success connect to Redis.'); + } + + public function getExtraParameters(): array + { + // By security we not return password (because many redis instances work in internal network). + return [ + 'host' => $this->host, + 'port' => $this->port, + ]; + } + + private function connect(\Redis $redis): void + { + $redis->connect($this->host, $this->port); + + if ($this->password) { + $redis->auth($this->password); + } + } +} diff --git a/tests/Check/Redis/Predis/PredisPingPongCheckTest.php b/tests/Check/Redis/Predis/PredisPingPongCheckTest.php new file mode 100644 index 0000000..bee4923 --- /dev/null +++ b/tests/Check/Redis/Predis/PredisPingPongCheckTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types = 1); + +namespace FiveLab\Component\Diagnostic\Tests\Check\Redis\Predis; + +use FiveLab\Component\Diagnostic\Check\Redis\Predis\PredisPingPongCheck; +use FiveLab\Component\Diagnostic\Result\Failure; +use FiveLab\Component\Diagnostic\Result\Success; +use FiveLab\Component\Diagnostic\Tests\Check\AbstractRedisTestCase; +use PHPUnit\Framework\Attributes\Test; + +class PredisPingPongCheckTest extends AbstractRedisTestCase +{ + protected function setUp(): void + { + if (!$this->canTestingWithRedis()) { + self::markTestSkipped('The Redis is not configured.'); + } + + if (!\class_exists(\Redis::class)) { + self::markTestSkipped('The ext-redis not installed.'); + } + } + + #[Test] + public function shouldSuccessCheck(): void + { + $check = new PredisPingPongCheck( + $this->getRedisHost(), + $this->getRedisPort(), + $this->getRedisPassword() + ); + + $result = $check->check(); + + self::assertEquals(new Success('Success connect to Redis.'), $result); + } + + #[Test] + public function shouldSuccessGetExtraParameters(): void + { + $check = new PredisPingPongCheck( + $this->getRedisHost(), + $this->getRedisPort(), + $this->getRedisPassword() + ); + + self::assertEquals([ + 'host' => $this->getRedisHost(), + 'port' => $this->getRedisPort(), + ], $check->getExtraParameters()); + } + + #[Test] + public function shouldFailIfHostIsWrong(): void + { + $check = new PredisPingPongCheck( + $this->getRedisHost().'some', + $this->getRedisPort(), + $this->getRedisPassword() + ); + + $result = $check->check(); + + self::assertInstanceOf(Failure::class, $result); + self::assertStringStartsWith('Cannot connect to Redis: php_network_getaddresses:', $result->message); + } +} diff --git a/tests/Check/Redis/RedisExt/RedisPingPongCheckTest.php b/tests/Check/Redis/RedisExt/RedisPingPongCheckTest.php new file mode 100644 index 0000000..16f38bf --- /dev/null +++ b/tests/Check/Redis/RedisExt/RedisPingPongCheckTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types = 1); + +namespace FiveLab\Component\Diagnostic\Tests\Check\Redis\RedisExt; + +use FiveLab\Component\Diagnostic\Check\Redis\RedisExt\RedisPingPongCheck; +use FiveLab\Component\Diagnostic\Result\Failure; +use FiveLab\Component\Diagnostic\Result\Success; +use FiveLab\Component\Diagnostic\Tests\Check\AbstractRedisTestCase; +use PHPUnit\Framework\Attributes\Test; + +class RedisPingPongCheckTest extends AbstractRedisTestCase +{ + protected function setUp(): void + { + if (!$this->canTestingWithRedis()) { + self::markTestSkipped('The Redis is not configured.'); + } + + if (!\class_exists(\Redis::class)) { + self::markTestSkipped('The ext-redis not installed.'); + } + } + + #[Test] + public function shouldSuccessCheck(): void + { + $check = new RedisPingPongCheck( + $this->getRedisHost(), + $this->getRedisPort(), + $this->getRedisPassword() + ); + + $result = $check->check(); + + self::assertEquals(new Success('Success connect to Redis.'), $result); + } + + #[Test] + public function shouldSuccessGetExtraParameters(): void + { + $check = new RedisPingPongCheck( + $this->getRedisHost(), + $this->getRedisPort(), + $this->getRedisPassword() + ); + + self::assertEquals([ + 'host' => $this->getRedisHost(), + 'port' => $this->getRedisPort(), + ], $check->getExtraParameters()); + } + + #[Test] + public function shouldFailIfHostIsWrong(): void + { + $check = new RedisPingPongCheck( + $this->getRedisHost().'some', + $this->getRedisPort(), + $this->getRedisPassword() + ); + + $result = $check->check(); + + self::assertInstanceOf(Failure::class, $result); + self::assertStringStartsWith('Cannot connect to Redis: php_network_getaddresses:', $result->message); + } +} diff --git a/tests/DependencyInjection/AddDiagnosticToBuilderCheckPassTest.php b/tests/DependencyInjection/AddDiagnosticToBuilderCheckPassTest.php index b5bbaac..a271d09 100644 --- a/tests/DependencyInjection/AddDiagnosticToBuilderCheckPassTest.php +++ b/tests/DependencyInjection/AddDiagnosticToBuilderCheckPassTest.php @@ -99,11 +99,13 @@ public function shouldSuccessProcessWithGroups(): void $containerBuilder = $this->createContainerBuilderWithDefinitionsBuilder(); $checkContainerDefinition1 = new Definition(StubCheck::class); + $checkContainerDefinition1->addTag('diagnostic.check', [ 'group' => 'foo', ]); $checkContainerDefinition2 = new Definition(StubCheck::class); + $checkContainerDefinition2->addTag('diagnostic.check', [ 'group' => 'bar', ]); @@ -147,12 +149,14 @@ public function shouldSuccessProcessWithCustomKeys(): void $containerBuilder = $this->createContainerBuilderWithDefinitionsBuilder(); $checkContainerDefinition1 = new Definition(StubCheck::class); + $checkContainerDefinition1->addTag('diagnostic.check', [ 'key' => 'foo', 'error_on_failure' => true, ]); $checkContainerDefinition2 = new Definition(StubCheck::class); + $checkContainerDefinition2->addTag('diagnostic.check', [ 'key' => 'bar', 'error_on_failure' => false, @@ -197,6 +201,7 @@ public function shouldSuccessWithMultipleTagsForOneService(): void $containerBuilder = $this->createContainerBuilderWithDefinitionsBuilder(); $checkContainerDefinition = new Definition(StubCheck::class); + $checkContainerDefinition->addTag('diagnostic.check', [ 'group' => 'foo', ]);