From 5676a7a7788d7dd81a936aa91b12cb33fdd2e743 Mon Sep 17 00:00:00 2001 From: Ghlen Nagels Date: Fri, 22 Nov 2024 18:00:00 +0530 Subject: [PATCH 1/8] initial kickoff --- docker-compose-neo4j-4.yml | 4 +-- docker-compose.yml | 2 +- src/Bolt/BoltDriver.php | 4 ++- src/Common/DriverSetupManager.php | 9 +++++- src/Neo4j/Neo4jDriver.php | 7 +++-- tests/Integration/ClientIntegrationTest.php | 32 +++++++++++++++++++++ 6 files changed, 51 insertions(+), 7 deletions(-) diff --git a/docker-compose-neo4j-4.yml b/docker-compose-neo4j-4.yml index aee57ad1..06a391b9 100644 --- a/docker-compose-neo4j-4.yml +++ b/docker-compose-neo4j-4.yml @@ -31,7 +31,7 @@ services: context: . dockerfile: Dockerfile args: - PHP_VERSION: ${PHP_VERSION} + PHP_VERSION: "${PHP_VERSION-8.1}" networks: - neo4j volumes: @@ -46,7 +46,7 @@ services: context: . dockerfile: Dockerfile args: - PHP_VERSION: ${PHP_VERSION} + PHP_VERSION: "${PHP_VERSION-8.1}" WITH_XDEBUG: true working_dir: /opt/project volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 8ed1ef45..1be8fd81 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,7 @@ x-definitions: context: . dockerfile: Dockerfile args: - PHP_VERSION: ${PHP_VERSION} + PHP_VERSION: "${PHP_VERSION-8.1}" volumes: - .:/opt/project x-common-cluster: diff --git a/src/Bolt/BoltDriver.php b/src/Bolt/BoltDriver.php index 54db4925..ae4ddd4b 100644 --- a/src/Bolt/BoltDriver.php +++ b/src/Bolt/BoltDriver.php @@ -15,6 +15,7 @@ use Exception; +use Psr\Log\LogLevel; use function is_string; use Laudis\Neo4j\Authentication\Authenticate; @@ -103,7 +104,8 @@ public function verifyConnectivity(?SessionConfiguration $config = null): bool $config ??= SessionConfiguration::default(); try { GeneratorHelper::getReturnFromGenerator($this->pool->acquire($config)); - } catch (Throwable) { + } catch (ConnectException $e) { + $this->pool->getLogger()->log(LogLevel::WARNING, 'Could not connect to server on URI ' . $this->parsedUrl->__toString(), ['error' => $e]); return false; } diff --git a/src/Common/DriverSetupManager.php b/src/Common/DriverSetupManager.php index a6ab7a85..43dd9366 100644 --- a/src/Common/DriverSetupManager.php +++ b/src/Common/DriverSetupManager.php @@ -13,6 +13,8 @@ namespace Laudis\Neo4j\Common; +use Bolt\error\ConnectException; +use Psr\Log\LogLevel; use function array_key_exists; use function array_key_first; use function array_reduce; @@ -144,7 +146,12 @@ public function verifyConnectivity(SessionConfiguration $config, ?string $alias { try { $this->getDriver($config, $alias); - } catch (RuntimeException) { + } catch (ConnectException $e) { + $this->getLogger()->log( + LogLevel::WARNING, + sprintf('Could not connect to server using alias (%s)', $alias ?? ''), + ['exception' => $e] + ); return false; } diff --git a/src/Neo4j/Neo4jDriver.php b/src/Neo4j/Neo4jDriver.php index 0f3d11b0..29ef2391 100644 --- a/src/Neo4j/Neo4jDriver.php +++ b/src/Neo4j/Neo4jDriver.php @@ -13,8 +13,10 @@ namespace Laudis\Neo4j\Neo4j; +use Bolt\error\ConnectException; use Exception; +use Psr\Log\LogLevel; use function is_string; use Laudis\Neo4j\Authentication\Authenticate; @@ -31,7 +33,6 @@ use Laudis\Neo4j\Databags\SessionConfiguration; use Laudis\Neo4j\Formatter\OGMFormatter; use Psr\Http\Message\UriInterface; -use Throwable; /** * Driver for auto client-side routing. @@ -105,7 +106,9 @@ public function verifyConnectivity(?SessionConfiguration $config = null): bool $config ??= SessionConfiguration::default(); try { GeneratorHelper::getReturnFromGenerator($this->pool->acquire($config)); - } catch (Throwable) { + } catch (ConnectException $e) { + $this->pool->getLogger()->log(LogLevel::WARNING, 'Could not connect to server on URI ' . $this->parsedUrl->__toString(), ['error' => $e]); + return false; } diff --git a/tests/Integration/ClientIntegrationTest.php b/tests/Integration/ClientIntegrationTest.php index 183d5f10..3b285090 100644 --- a/tests/Integration/ClientIntegrationTest.php +++ b/tests/Integration/ClientIntegrationTest.php @@ -19,16 +19,48 @@ use Laudis\Neo4j\Bolt\BoltDriver; use Laudis\Neo4j\Bolt\ConnectionPool; use Laudis\Neo4j\ClientBuilder; +use Laudis\Neo4j\Common\Uri; use Laudis\Neo4j\Contracts\DriverInterface; use Laudis\Neo4j\Contracts\TransactionInterface; +use Laudis\Neo4j\Databags\DriverConfiguration; use Laudis\Neo4j\Databags\SessionConfiguration; use Laudis\Neo4j\Databags\Statement; use Laudis\Neo4j\Exception\Neo4jException; use Laudis\Neo4j\Tests\EnvironmentAwareIntegrationTest; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; use ReflectionClass; final class ClientIntegrationTest extends EnvironmentAwareIntegrationTest { + public function testDriverAuthFailureVerifyConnectivity(): void + { + $connection = $_ENV['CONNECTION'] ?? false; + if (str_starts_with($connection, 'http')) { + $this->markTestSkipped('HTTP does not support auth failure connectivity passing'); + } + + if (!is_string($connection)) { + $connection = 'bolt://localhost'; + } + + $uri = Uri::create($connection); + $uri = $uri->withUserInfo('neo4j', 'absolutelyonehundredpercentawrongpassword'); + + /** @noinspection PhpUnhandledExceptionInspection */ + $conf = DriverConfiguration::default()->withLogger(LogLevel::DEBUG, $this->createMock(LoggerInterface::class)); + $logger = $conf->getLogger(); + if ($logger === null) { + throw new RuntimeException('Logger not set'); + } + + $driver = Driver::create($uri, $conf); + + $this->expectException(Neo4jException::class); + $this->expectExceptionMessage('Neo4j errors detected. First one with code "Neo.ClientError.Security.Unauthorized" and message "The client is unauthorized due to authentication failure."'); + $driver->verifyConnectivity(); + } + public function testDifferentAuth(): void { $auth = Authenticate::fromUrl($this->getUri()); From 5306c171d670d5370cffcf093fb27de942c8eff4 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 25 Nov 2024 13:53:29 +0530 Subject: [PATCH 2/8] test: Add test for Client --- src/Bolt/BoltDriver.php | 6 +-- src/Common/DriverSetupManager.php | 5 ++- src/Neo4j/Neo4jDriver.php | 4 +- tests/Integration/ClientIntegrationTest.php | 43 +++++++++++++++++++++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/Bolt/BoltDriver.php b/src/Bolt/BoltDriver.php index ae4ddd4b..0919f0e8 100644 --- a/src/Bolt/BoltDriver.php +++ b/src/Bolt/BoltDriver.php @@ -15,7 +15,6 @@ use Exception; -use Psr\Log\LogLevel; use function is_string; use Laudis\Neo4j\Authentication\Authenticate; @@ -29,7 +28,7 @@ use Laudis\Neo4j\Databags\SessionConfiguration; use Laudis\Neo4j\Formatter\OGMFormatter; use Psr\Http\Message\UriInterface; -use Throwable; +use Psr\Log\LogLevel; /** * Drives a singular bolt connections. @@ -105,7 +104,8 @@ public function verifyConnectivity(?SessionConfiguration $config = null): bool try { GeneratorHelper::getReturnFromGenerator($this->pool->acquire($config)); } catch (ConnectException $e) { - $this->pool->getLogger()->log(LogLevel::WARNING, 'Could not connect to server on URI ' . $this->parsedUrl->__toString(), ['error' => $e]); + $this->pool->getLogger()->log(LogLevel::WARNING, 'Could not connect to server on URI '.$this->parsedUrl->__toString(), ['error' => $e]); + return false; } diff --git a/src/Common/DriverSetupManager.php b/src/Common/DriverSetupManager.php index 43dd9366..6e43605a 100644 --- a/src/Common/DriverSetupManager.php +++ b/src/Common/DriverSetupManager.php @@ -13,12 +13,11 @@ namespace Laudis\Neo4j\Common; -use Bolt\error\ConnectException; -use Psr\Log\LogLevel; use function array_key_exists; use function array_key_first; use function array_reduce; +use Bolt\error\ConnectException; use Countable; use InvalidArgumentException; use Laudis\Neo4j\Authentication\Authenticate; @@ -31,6 +30,7 @@ use const PHP_INT_MIN; +use Psr\Log\LogLevel; use RuntimeException; use SplPriorityQueue; @@ -152,6 +152,7 @@ public function verifyConnectivity(SessionConfiguration $config, ?string $alias sprintf('Could not connect to server using alias (%s)', $alias ?? ''), ['exception' => $e] ); + return false; } diff --git a/src/Neo4j/Neo4jDriver.php b/src/Neo4j/Neo4jDriver.php index 29ef2391..677f185f 100644 --- a/src/Neo4j/Neo4jDriver.php +++ b/src/Neo4j/Neo4jDriver.php @@ -16,7 +16,6 @@ use Bolt\error\ConnectException; use Exception; -use Psr\Log\LogLevel; use function is_string; use Laudis\Neo4j\Authentication\Authenticate; @@ -33,6 +32,7 @@ use Laudis\Neo4j\Databags\SessionConfiguration; use Laudis\Neo4j\Formatter\OGMFormatter; use Psr\Http\Message\UriInterface; +use Psr\Log\LogLevel; /** * Driver for auto client-side routing. @@ -107,7 +107,7 @@ public function verifyConnectivity(?SessionConfiguration $config = null): bool try { GeneratorHelper::getReturnFromGenerator($this->pool->acquire($config)); } catch (ConnectException $e) { - $this->pool->getLogger()->log(LogLevel::WARNING, 'Could not connect to server on URI ' . $this->parsedUrl->__toString(), ['error' => $e]); + $this->pool->getLogger()->log(LogLevel::WARNING, 'Could not connect to server on URI '.$this->parsedUrl->__toString(), ['error' => $e]); return false; } diff --git a/tests/Integration/ClientIntegrationTest.php b/tests/Integration/ClientIntegrationTest.php index 3b285090..f276212b 100644 --- a/tests/Integration/ClientIntegrationTest.php +++ b/tests/Integration/ClientIntegrationTest.php @@ -19,13 +19,17 @@ use Laudis\Neo4j\Bolt\BoltDriver; use Laudis\Neo4j\Bolt\ConnectionPool; use Laudis\Neo4j\ClientBuilder; +use Laudis\Neo4j\Common\DriverSetupManager; use Laudis\Neo4j\Common\Uri; use Laudis\Neo4j\Contracts\DriverInterface; use Laudis\Neo4j\Contracts\TransactionInterface; use Laudis\Neo4j\Databags\DriverConfiguration; +use Laudis\Neo4j\Databags\DriverSetup; use Laudis\Neo4j\Databags\SessionConfiguration; use Laudis\Neo4j\Databags\Statement; +use Laudis\Neo4j\Databags\TransactionConfiguration; use Laudis\Neo4j\Exception\Neo4jException; +use Laudis\Neo4j\Formatter\SummarizedResultFormatter; use Laudis\Neo4j\Tests\EnvironmentAwareIntegrationTest; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; @@ -61,6 +65,45 @@ public function testDriverAuthFailureVerifyConnectivity(): void $driver->verifyConnectivity(); } + public function testClientAuthFailureVerifyConnectivity(): void + { + $connection = $_ENV['CONNECTION'] ?? false; + if (str_starts_with($connection, 'http')) { + $this->markTestSkipped('HTTP does not support auth failure connectivity passing'); + } + + if (!is_string($connection)) { + $connection = 'bolt://localhost'; + } + + $uri = Uri::create($connection); + $uri = $uri->withUserInfo('neo4j', 'absolutelyonehundredpercentawrongpassword'); + + /** @noinspection PhpUnhandledExceptionInspection */ + $conf = DriverConfiguration::default()->withLogger(LogLevel::DEBUG, $this->createMock(LoggerInterface::class)); + $logger = $conf->getLogger(); + if ($logger === null) { + throw new RuntimeException('Logger not set'); + } + + $client = (new ClientBuilder( + SessionConfiguration::create(), + TransactionConfiguration::create(), + (new DriverSetupManager( + SummarizedResultFormatter::create(), + $conf, + ))->withSetup( + new DriverSetup($uri, Authenticate::fromUrl($uri, $logger)) + ) + ))->build(); + + $driver = $client->getDriver(null); + + $this->expectException(Neo4jException::class); + $this->expectExceptionMessage('Neo4j errors detected. First one with code "Neo.ClientError.Security.Unauthorized" and message "The client is unauthorized due to authentication failure."'); + $driver->verifyConnectivity(); + } + public function testDifferentAuth(): void { $auth = Authenticate::fromUrl($this->getUri()); From dfb7eff92556fb3d8850157f1c4fe23d5ec78f6e Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 25 Nov 2024 14:00:53 +0530 Subject: [PATCH 3/8] refactor: Fix Psalm errors --- src/Bolt/BoltDriver.php | 3 +- src/Common/DriverSetupManager.php | 2 +- src/Neo4j/Neo4jDriver.php | 2 +- tests/Integration/ClientIntegrationTest.php | 48 +++++++++++++++------ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/Bolt/BoltDriver.php b/src/Bolt/BoltDriver.php index 0919f0e8..7c21c484 100644 --- a/src/Bolt/BoltDriver.php +++ b/src/Bolt/BoltDriver.php @@ -13,6 +13,7 @@ namespace Laudis\Neo4j\Bolt; +use Bolt\error\ConnectException; use Exception; use function is_string; @@ -104,7 +105,7 @@ public function verifyConnectivity(?SessionConfiguration $config = null): bool try { GeneratorHelper::getReturnFromGenerator($this->pool->acquire($config)); } catch (ConnectException $e) { - $this->pool->getLogger()->log(LogLevel::WARNING, 'Could not connect to server on URI '.$this->parsedUrl->__toString(), ['error' => $e]); + $this->pool->getLogger()?->log(LogLevel::WARNING, 'Could not connect to server on URI '.$this->parsedUrl->__toString(), ['error' => $e]); return false; } diff --git a/src/Common/DriverSetupManager.php b/src/Common/DriverSetupManager.php index 6e43605a..bb2639d2 100644 --- a/src/Common/DriverSetupManager.php +++ b/src/Common/DriverSetupManager.php @@ -147,7 +147,7 @@ public function verifyConnectivity(SessionConfiguration $config, ?string $alias try { $this->getDriver($config, $alias); } catch (ConnectException $e) { - $this->getLogger()->log( + $this->getLogger()?->log( LogLevel::WARNING, sprintf('Could not connect to server using alias (%s)', $alias ?? ''), ['exception' => $e] diff --git a/src/Neo4j/Neo4jDriver.php b/src/Neo4j/Neo4jDriver.php index 677f185f..004be4d7 100644 --- a/src/Neo4j/Neo4jDriver.php +++ b/src/Neo4j/Neo4jDriver.php @@ -107,7 +107,7 @@ public function verifyConnectivity(?SessionConfiguration $config = null): bool try { GeneratorHelper::getReturnFromGenerator($this->pool->acquire($config)); } catch (ConnectException $e) { - $this->pool->getLogger()->log(LogLevel::WARNING, 'Could not connect to server on URI '.$this->parsedUrl->__toString(), ['error' => $e]); + $this->pool->getLogger()?->log(LogLevel::WARNING, 'Could not connect to server on URI '.$this->parsedUrl->__toString(), ['error' => $e]); return false; } diff --git a/tests/Integration/ClientIntegrationTest.php b/tests/Integration/ClientIntegrationTest.php index f276212b..01477c32 100644 --- a/tests/Integration/ClientIntegrationTest.php +++ b/tests/Integration/ClientIntegrationTest.php @@ -34,13 +34,14 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use ReflectionClass; +use RuntimeException; final class ClientIntegrationTest extends EnvironmentAwareIntegrationTest { public function testDriverAuthFailureVerifyConnectivity(): void { $connection = $_ENV['CONNECTION'] ?? false; - if (str_starts_with($connection, 'http')) { + if (str_starts_with((string) $connection, 'http')) { $this->markTestSkipped('HTTP does not support auth failure connectivity passing'); } @@ -61,14 +62,16 @@ public function testDriverAuthFailureVerifyConnectivity(): void $driver = Driver::create($uri, $conf); $this->expectException(Neo4jException::class); - $this->expectExceptionMessage('Neo4j errors detected. First one with code "Neo.ClientError.Security.Unauthorized" and message "The client is unauthorized due to authentication failure."'); + $this->expectExceptionMessage( + 'Neo4j errors detected. First one with code "Neo.ClientError.Security.Unauthorized" and message "The client is unauthorized due to authentication failure."' + ); $driver->verifyConnectivity(); } public function testClientAuthFailureVerifyConnectivity(): void { $connection = $_ENV['CONNECTION'] ?? false; - if (str_starts_with($connection, 'http')) { + if (str_starts_with((string) $connection, 'http')) { $this->markTestSkipped('HTTP does not support auth failure connectivity passing'); } @@ -100,7 +103,9 @@ public function testClientAuthFailureVerifyConnectivity(): void $driver = $client->getDriver(null); $this->expectException(Neo4jException::class); - $this->expectExceptionMessage('Neo4j errors detected. First one with code "Neo.ClientError.Security.Unauthorized" and message "The client is unauthorized due to authentication failure."'); + $this->expectExceptionMessage( + 'Neo4j errors detected. First one with code "Neo.ClientError.Security.Unauthorized" and message "The client is unauthorized due to authentication failure."' + ); $driver->verifyConnectivity(); } @@ -128,28 +133,37 @@ public function testAvailabilityFullImplementation(): void public function testTransactionFunction(): void { - $result = $this->getSession()->transaction(static fn (TransactionInterface $tsx) => $tsx->run('UNWIND [1] AS x RETURN x')->first()->getAsInt('x')); + $result = $this->getSession()->transaction( + static fn (TransactionInterface $tsx) => $tsx->run('UNWIND [1] AS x RETURN x')->first()->getAsInt('x') + ); self::assertEquals(1, $result); - $result = $this->getSession()->readTransaction(static fn (TransactionInterface $tsx) => $tsx->run('UNWIND [1] AS x RETURN x')->first()->getAsInt('x')); + $result = $this->getSession()->readTransaction( + static fn (TransactionInterface $tsx) => $tsx->run('UNWIND [1] AS x RETURN x')->first()->getAsInt('x') + ); self::assertEquals(1, $result); - $result = $this->getSession()->writeTransaction(static fn (TransactionInterface $tsx) => $tsx->run('UNWIND [1] AS x RETURN x')->first()->getAsInt('x')); + $result = $this->getSession()->writeTransaction( + static fn (TransactionInterface $tsx) => $tsx->run('UNWIND [1] AS x RETURN x')->first()->getAsInt('x') + ); self::assertEquals(1, $result); } public function testValidRun(): void { - $response = $this->getSession()->transaction(static fn (TransactionInterface $tsx) => $tsx->run(<<<'CYPHER' + $response = $this->getSession()->transaction(static fn (TransactionInterface $tsx) => $tsx->run( + <<<'CYPHER' MERGE (x:TestNode {test: $test}) WITH x MERGE (y:OtherTestNode {test: $otherTest}) WITH x, y, {c: 'd'} AS map, [1, 2, 3] AS list RETURN x, y, x.test AS test, map, list -CYPHER, ['test' => 'a', 'otherTest' => 'b'])); +CYPHER, + ['test' => 'a', 'otherTest' => 'b'] + )); self::assertEquals(1, $response->count()); $map = $response->first(); @@ -164,7 +178,12 @@ public function testValidRun(): void public function testInvalidRun(): void { $this->expectException(Neo4jException::class); - $this->getSession()->transaction(static fn (TransactionInterface $tsx) => $tsx->run('MERGE (x:Tes0342hdm21.())', ['test' => 'a', 'otherTest' => 'b'])); + $this->getSession()->transaction( + static fn (TransactionInterface $tsx) => $tsx->run( + 'MERGE (x:Tes0342hdm21.())', + ['test' => 'a', 'otherTest' => 'b'] + ) + ); } public function testInvalidRunRetry(): void @@ -183,13 +202,18 @@ public function testInvalidRunRetry(): void public function testValidStatement(): void { - $response = $this->getSession()->transaction(static fn (TransactionInterface $tsx) => $tsx->runStatement(Statement::create(<<<'CYPHER' + $response = $this->getSession()->transaction(static fn (TransactionInterface $tsx) => $tsx->runStatement( + Statement::create( + <<<'CYPHER' MERGE (x:TestNode {test: $test}) WITH x MERGE (y:OtherTestNode {test: $otherTest}) WITH x, y, {c: 'd'} AS map, [1, 2, 3] AS list RETURN x, y, x.test AS test, map, list -CYPHER, ['test' => 'a', 'otherTest' => 'b']))); +CYPHER, + ['test' => 'a', 'otherTest' => 'b'] + ) + )); self::assertEquals(1, $response->count()); $map = $response->first(); From a1dce41743d934a460b8c5fb4386cad3c402a040 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Mon, 25 Nov 2024 16:52:00 +0530 Subject: [PATCH 4/8] test: Fix invalid connection test --- tests/Integration/ClientIntegrationTest.php | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/Integration/ClientIntegrationTest.php b/tests/Integration/ClientIntegrationTest.php index 01477c32..6e6b5d50 100644 --- a/tests/Integration/ClientIntegrationTest.php +++ b/tests/Integration/ClientIntegrationTest.php @@ -13,6 +13,7 @@ namespace Laudis\Neo4j\Tests\Integration; +use Exception; use InvalidArgumentException; use Laudis\Neo4j\Authentication\Authenticate; use Laudis\Neo4j\Basic\Driver; @@ -46,7 +47,7 @@ public function testDriverAuthFailureVerifyConnectivity(): void } if (!is_string($connection)) { - $connection = 'bolt://localhost'; + $connection = 'bolt://neo4j'; } $uri = Uri::create($connection); @@ -286,9 +287,21 @@ public function testInvalidConnectionCheck(): void ->withDriver('http', 'http://localboast') ->build(); - self::assertFalse($client->verifyConnectivity('bolt')); - self::assertFalse($client->verifyConnectivity('neo4j')); - self::assertFalse($client->verifyConnectivity('http')); + try { + self::assertFalse($client->verifyConnectivity('bolt')); + } catch (Exception $e) { + self::assertInstanceOf(RuntimeException::class, $e); + } + try { + self::assertFalse($client->verifyConnectivity('neo4j')); + } catch (Exception $e) { + self::assertInstanceOf(RuntimeException::class, $e); + } + try { + self::assertFalse($client->verifyConnectivity('http')); + } catch (Exception $e) { + self::assertInstanceOf(RuntimeException::class, $e); + } } public function testValidConnectionCheck(): void From 2a85094895a24ae6fa1fdd53865e6ff9041d94ce Mon Sep 17 00:00:00 2001 From: exaby73 Date: Thu, 28 Nov 2024 15:50:35 +0530 Subject: [PATCH 5/8] test: Refactor tests --- tests/Integration/ClientIntegrationTest.php | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/tests/Integration/ClientIntegrationTest.php b/tests/Integration/ClientIntegrationTest.php index 6e6b5d50..8259a1c0 100644 --- a/tests/Integration/ClientIntegrationTest.php +++ b/tests/Integration/ClientIntegrationTest.php @@ -41,17 +41,11 @@ final class ClientIntegrationTest extends EnvironmentAwareIntegrationTest { public function testDriverAuthFailureVerifyConnectivity(): void { - $connection = $_ENV['CONNECTION'] ?? false; - if (str_starts_with((string) $connection, 'http')) { + if (str_starts_with($this->uri->getScheme(), 'http')) { $this->markTestSkipped('HTTP does not support auth failure connectivity passing'); } - if (!is_string($connection)) { - $connection = 'bolt://neo4j'; - } - - $uri = Uri::create($connection); - $uri = $uri->withUserInfo('neo4j', 'absolutelyonehundredpercentawrongpassword'); + $uri = $this->uri->withUserInfo('neo4j', 'absolutelyonehundredpercentawrongpassword'); /** @noinspection PhpUnhandledExceptionInspection */ $conf = DriverConfiguration::default()->withLogger(LogLevel::DEBUG, $this->createMock(LoggerInterface::class)); @@ -71,17 +65,11 @@ public function testDriverAuthFailureVerifyConnectivity(): void public function testClientAuthFailureVerifyConnectivity(): void { - $connection = $_ENV['CONNECTION'] ?? false; - if (str_starts_with((string) $connection, 'http')) { + if (str_starts_with($this->uri->getScheme(), 'http')) { $this->markTestSkipped('HTTP does not support auth failure connectivity passing'); } - if (!is_string($connection)) { - $connection = 'bolt://localhost'; - } - - $uri = Uri::create($connection); - $uri = $uri->withUserInfo('neo4j', 'absolutelyonehundredpercentawrongpassword'); + $uri = $this->uri->withUserInfo('neo4j', 'absolutelyonehundredpercentawrongpassword'); /** @noinspection PhpUnhandledExceptionInspection */ $conf = DriverConfiguration::default()->withLogger(LogLevel::DEBUG, $this->createMock(LoggerInterface::class)); From 8cffce8cae7ab7262d2d6c552805b0b0f4647103 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Fri, 29 Nov 2024 11:39:18 +0530 Subject: [PATCH 6/8] test: Fix auth tests --- docker-compose-neo4j-4.yml | 1 + docker-compose.yml | 1 + src/Neo4j/Neo4jConnectionPool.php | 3 ++- tests/Integration/ClientIntegrationTest.php | 14 +++++++++----- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docker-compose-neo4j-4.yml b/docker-compose-neo4j-4.yml index 06a391b9..95dee8cd 100644 --- a/docker-compose-neo4j-4.yml +++ b/docker-compose-neo4j-4.yml @@ -3,6 +3,7 @@ x-shared: NEO4J_AUTH: neo4j/testtest NEO4J_ACCEPT_LICENSE_AGREEMENT: "yes" NEO4J_dbms_security_allow__csv__import__from__file__urls: "true" + NEO4J_dbms_security_auth__lock__time: 0s NEO4JLABS_PLUGINS: '["apoc"]' x-shared-cluster: diff --git a/docker-compose.yml b/docker-compose.yml index 1be8fd81..91a1ed84 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,7 @@ x-definitions: x-shared-env: &common-env NEO4J_AUTH: neo4j/testtest + NEO4J_dbms_security_auth__lock__time: 0s NEO4J_PLUGINS: '["apoc"]' x-shared-cluster-env: &common-cluster-env diff --git a/src/Neo4j/Neo4jConnectionPool.php b/src/Neo4j/Neo4jConnectionPool.php index 75de8213..caa72d09 100644 --- a/src/Neo4j/Neo4jConnectionPool.php +++ b/src/Neo4j/Neo4jConnectionPool.php @@ -13,6 +13,7 @@ namespace Laudis\Neo4j\Neo4j; +use Bolt\error\ConnectException; use function array_unique; use function count; @@ -146,7 +147,7 @@ public function acquire(SessionConfiguration $config): Generator /** @var BoltConnection $connection */ $connection = GeneratorHelper::getReturnFromGenerator($pool->acquire($config)); $table = $this->routingTable($connection, $config); - } catch (Throwable $e) { + } catch (ConnectException $e) { // todo - once client side logging is implemented it must be conveyed here. $latestError = $e; continue; // We continue if something is wrong with the current server diff --git a/tests/Integration/ClientIntegrationTest.php b/tests/Integration/ClientIntegrationTest.php index 8259a1c0..52d10f76 100644 --- a/tests/Integration/ClientIntegrationTest.php +++ b/tests/Integration/ClientIntegrationTest.php @@ -21,7 +21,6 @@ use Laudis\Neo4j\Bolt\ConnectionPool; use Laudis\Neo4j\ClientBuilder; use Laudis\Neo4j\Common\DriverSetupManager; -use Laudis\Neo4j\Common\Uri; use Laudis\Neo4j\Contracts\DriverInterface; use Laudis\Neo4j\Contracts\TransactionInterface; use Laudis\Neo4j\Databags\DriverConfiguration; @@ -39,6 +38,12 @@ final class ClientIntegrationTest extends EnvironmentAwareIntegrationTest { + public function setUp(): void + { + parent::setUp(); + $this->driver->closeConnections(); + } + public function testDriverAuthFailureVerifyConnectivity(): void { if (str_starts_with($this->uri->getScheme(), 'http')) { @@ -47,7 +52,6 @@ public function testDriverAuthFailureVerifyConnectivity(): void $uri = $this->uri->withUserInfo('neo4j', 'absolutelyonehundredpercentawrongpassword'); - /** @noinspection PhpUnhandledExceptionInspection */ $conf = DriverConfiguration::default()->withLogger(LogLevel::DEBUG, $this->createMock(LoggerInterface::class)); $logger = $conf->getLogger(); if ($logger === null) { @@ -60,6 +64,7 @@ public function testDriverAuthFailureVerifyConnectivity(): void $this->expectExceptionMessage( 'Neo4j errors detected. First one with code "Neo.ClientError.Security.Unauthorized" and message "The client is unauthorized due to authentication failure."' ); + $driver->verifyConnectivity(); } @@ -89,13 +94,12 @@ public function testClientAuthFailureVerifyConnectivity(): void ) ))->build(); - $driver = $client->getDriver(null); - $this->expectException(Neo4jException::class); $this->expectExceptionMessage( 'Neo4j errors detected. First one with code "Neo.ClientError.Security.Unauthorized" and message "The client is unauthorized due to authentication failure."' ); - $driver->verifyConnectivity(); + + $client->getDriver(null); } public function testDifferentAuth(): void From 779c74bbed267e1d2a10334d584aaca6f2f6cdc7 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Fri, 29 Nov 2024 11:41:03 +0530 Subject: [PATCH 7/8] style: Run CS fix --- src/Neo4j/Neo4jConnectionPool.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Neo4j/Neo4jConnectionPool.php b/src/Neo4j/Neo4jConnectionPool.php index caa72d09..0a725321 100644 --- a/src/Neo4j/Neo4jConnectionPool.php +++ b/src/Neo4j/Neo4jConnectionPool.php @@ -13,8 +13,10 @@ namespace Laudis\Neo4j\Neo4j; -use Bolt\error\ConnectException; use function array_unique; + +use Bolt\error\ConnectException; + use function count; use Exception; @@ -51,9 +53,6 @@ use function sprintf; use function str_replace; - -use Throwable; - use function time; /** From f24c5bdc3a107e35f567487e23f437bee6fd6635 Mon Sep 17 00:00:00 2001 From: exaby73 Date: Fri, 29 Nov 2024 13:27:28 +0530 Subject: [PATCH 8/8] test: Assert that 3 exceptions are thrown in invalid connection test --- tests/Integration/ClientIntegrationTest.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/Integration/ClientIntegrationTest.php b/tests/Integration/ClientIntegrationTest.php index 52d10f76..1e1e072a 100644 --- a/tests/Integration/ClientIntegrationTest.php +++ b/tests/Integration/ClientIntegrationTest.php @@ -279,21 +279,27 @@ public function testInvalidConnectionCheck(): void ->withDriver('http', 'http://localboast') ->build(); + $exceptionThrownCount = 0; try { - self::assertFalse($client->verifyConnectivity('bolt')); + $client->verifyConnectivity('bolt'); } catch (Exception $e) { self::assertInstanceOf(RuntimeException::class, $e); + ++$exceptionThrownCount; } try { - self::assertFalse($client->verifyConnectivity('neo4j')); + $client->verifyConnectivity('neo4j'); } catch (Exception $e) { self::assertInstanceOf(RuntimeException::class, $e); + ++$exceptionThrownCount; } try { - self::assertFalse($client->verifyConnectivity('http')); + $client->verifyConnectivity('http'); } catch (Exception $e) { self::assertInstanceOf(RuntimeException::class, $e); + ++$exceptionThrownCount; } + + self::assertEquals(3, $exceptionThrownCount); } public function testValidConnectionCheck(): void