diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c89878a..1aa931e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,10 +11,13 @@ jobs: build: name: Build runs-on: ubuntu-latest + env: + APP_ENV: ci + strategy: max-parallel: 10 matrix: - php: [ '8.1', '8.2', '8.3'] + php: [ '8.1', '8.2', '8.3' ] sf_version: [ '5.4', '6.4', '7.1' ] exclude: - php: 8.1 @@ -40,3 +43,19 @@ jobs: memory_limit: 1024M version: 9 bootstrap: vendor/autoload.php + + services: + neo4j: + image: neo4j:5.22 + env: + NEO4J_AUTH: neo4j/testtest + options: >- + --hostname neo4j + --health-cmd "wget -q --method=HEAD http://localhost:7474 || exit 1" + --health-start-period "60s" + --health-interval "30s" + --health-timeout "15s" + --health-retries "5" + ports: + - 7474:7474 + - 7687:7687 diff --git a/docker-compose.yml b/docker-compose.yml index ae9637b..8e5b808 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,9 @@ -version: '3.7' networks: neo4j-symfony: services: app: - user: ${UID-1000}:${GID-1000} + user: root:${UID-1000}:${GID-1000} build: context: . ports: @@ -24,7 +23,7 @@ services: neo4j: environment: - NEO4J_AUTH=neo4j/testtest - image: neo4j:5 + image: neo4j:5.22 ports: - ${DOCKER_HOST_NEO4J_HTTP_PORT:-7474}:7474 - ${DOCKER_HOST_NEO4J_BOLT_PORT:-7687}:7687 diff --git a/tests/App/TestKernel.php b/tests/App/TestKernel.php index 8c2e86c..d8192cd 100644 --- a/tests/App/TestKernel.php +++ b/tests/App/TestKernel.php @@ -22,5 +22,8 @@ public function registerBundles(): array public function registerContainerConfiguration(LoaderInterface $loader): void { $loader->load(__DIR__.'/config/default.yml'); + if ('ci' === $this->environment) { + $loader->load(__DIR__.'/config/ci/default.yml'); + } } } diff --git a/tests/App/config/ci/default.yml b/tests/App/config/ci/default.yml new file mode 100644 index 0000000..df59b2c --- /dev/null +++ b/tests/App/config/ci/default.yml @@ -0,0 +1,4 @@ +parameters: + neo4j.dsn.badname: bolt://localhostt + neo4j.dsn.test: neo4j://neo4j:testtest@localhost + neo4j.dsn.auth: neo4j://localhost diff --git a/tests/App/config/default.yml b/tests/App/config/default.yml index 8fc729e..323ae51 100644 --- a/tests/App/config/default.yml +++ b/tests/App/config/default.yml @@ -1,46 +1,58 @@ framework: - secret: test - test: true - -neo4j: - default_driver: neo4j-test - default_driver_config: - acquire_connection_timeout: 10 - user_agent: 'Neo4j Symfony Bundle/testing' - pool_size: 256 - ssl: - mode: enable - verify_peer: false - default_session_config: - fetch_size: 999 - access_mode: read - database: symfony - default_transaction_config: - timeout: 40 - - drivers: - - alias: neo4j_undefined_configs - dsn: bolt://localhost - - - alias: neo4j-enforced-defaults - dsn: bolt://localhost - priority: null - - - alias: neo4j-partly-enforced-defaults - dsn: neo4j://neo4j:secret@localhost:7688 - - - alias: neo4j-simple - dsn: 'bolt://test:test@localhost' - - - alias: neo4j-fallback-mechanism - priority: 100 - dsn: bolt://localhost - - - alias: neo4j-fallback-mechanism - priority: 1000 - dsn: bolt://localhost - - - alias: neo4j-test - dsn: neo4j://neo4j:testtest@neo4j + secret: test + test: true +parameters: + neo4j.dsn.badname: bolt://localhost + neo4j.dsn.secret: neo4j://neo4j:secret@localhost:7688 + neo4j.dsn.test: neo4j://neo4j:testtest@neo4j + neo4j.dsn.auth: neo4j://neo4j + neo4j.dsn.simple: bolt://test:test@localhost +neo4j: + default_driver: neo4j-test + default_driver_config: + acquire_connection_timeout: 10 + user_agent: "Neo4j Symfony Bundle/testing" + pool_size: 256 + ssl: + mode: disable + verify_peer: false + default_session_config: + fetch_size: 999 + access_mode: read + database: neo4j + default_transaction_config: + timeout: 40 + + drivers: + - alias: neo4j_undefined_configs + dsn: "%neo4j.dsn.badname%" + + - alias: neo4j-enforced-defaults + dsn: "%neo4j.dsn.badname%" + priority: null + + - alias: neo4j-partly-enforced-defaults + dsn: "%neo4j.dsn.secret%" + + - alias: neo4j-simple + dsn: "%neo4j.dsn.simple%" + + - alias: neo4j-fallback-mechanism + priority: 100 + dsn: "%neo4j.dsn.badname%" + + - alias: neo4j-fallback-mechanism + priority: 1000 + dsn: "%neo4j.dsn.badname%" + + - alias: neo4j-test + dsn: "%neo4j.dsn.test%" + + - alias: neo4j-auth + dsn: "%neo4j.dsn.auth%" + authentication: + type: basic + username: neo4j + password: testtest diff --git a/tests/Functional/Integration.php b/tests/Functional/Integration.php deleted file mode 100644 index be817d6..0000000 --- a/tests/Functional/Integration.php +++ /dev/null @@ -1,76 +0,0 @@ -assertTrue($container->has('neo4j.client')); - $client = $container->get('neo4j.client'); - $this->assertInstanceOf(ClientInterface::class, $client); - - $this->assertTrue($container->has(ClientInterface::class)); - $this->assertInstanceOf(ClientInterface::class, $client); - - $this->assertSame($client, $container->get('neo4j.client')); - } - - public function testDriver(): void - { - static::bootKernel(); - $container = static::getContainer(); - - $this->assertTrue($container->has('neo4j.driver')); - $driver = $container->get('neo4j.driver'); - $this->assertInstanceOf(DriverInterface::class, $driver); - - $this->assertTrue($container->has(DriverInterface::class)); - $this->assertInstanceOf(DriverInterface::class, $driver); - - $this->assertSame($driver, $container->get('neo4j.driver')); - } - - public function testDefaultDsn(): void - { - static::bootKernel(); - $container = static::getContainer(); - - $client = $container->get('neo4j.client'); - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage("Cannot connect to any server on alias: neo4j_undefined_configs with Uris: ('bolt://localhost')"); - $client->getDriver('default'); - } - - public function testDsn(): void - { - static::bootKernel(); - $container = static::getContainer(); - - $this->expectException(\RuntimeException::class); - $this->expectExceptionMessage("Cannot connect to any server on alias: neo4j_undefined_configs with Uris: ('bolt://localhost')"); - - $container->get('neo4j.driver'); - } -} diff --git a/tests/Functional/IntegrationTest.php b/tests/Functional/IntegrationTest.php new file mode 100644 index 0000000..ece543a --- /dev/null +++ b/tests/Functional/IntegrationTest.php @@ -0,0 +1,237 @@ +assertTrue($container->has('neo4j.client')); + $client = $container->get('neo4j.client'); + $this->assertInstanceOf(ClientInterface::class, $client); + + $this->assertTrue($container->has(ClientInterface::class)); + $this->assertInstanceOf(ClientInterface::class, $client); + + $this->assertSame($client, $container->get('neo4j.client')); + } + + public function testDriver(): void + { + static::bootKernel(); + $container = static::getContainer(); + + $this->assertTrue($container->has('neo4j.driver')); + $driver = $container->get('neo4j.driver'); + $this->assertInstanceOf(DriverInterface::class, $driver); + + $this->assertTrue($container->has(DriverInterface::class)); + $this->assertInstanceOf(DriverInterface::class, $driver); + + $this->assertSame($driver, $container->get('neo4j.driver')); + } + + public function testDefaultDsn(): void + { + static::bootKernel(); + $container = static::getContainer(); + + /** + * @var ClientInterface $client + */ + $client = $container->get('neo4j.client'); + /** + * @var Neo4jDriver $driver + */ + $driver = $client->getDriver('default'); + /** + * @var UriInterface $uri + */ + $uri = $this->getPrivateProperty($driver, 'parsedUrl'); + + $this->assertSame($uri->getScheme(), 'neo4j'); + } + + public function testDsn(): void + { + static::bootKernel(); + $container = static::getContainer(); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessageMatches( + "/Cannot connect to any server on alias: neo4j_undefined_configs with Uris: \('bolt:\/\/(localhost|localhostt)'\)/" + ); + + /** + * @var ClientInterface $client + */ + $client = $container->get('neo4j.client'); + $client->getDriver('neo4j_undefined_configs'); + } + + public function testDriverAuthentication(): void + { + static::bootKernel(); + $container = static::getContainer(); + + /** + * @var ClientInterface $client + */ + $client = $container->get('neo4j.client'); + /** @var Neo4jDriver $driver */ + $driver = $client->getDriver('neo4j-auth'); + /** @var Neo4jConnectionPool $pool */ + $pool = $this->getPrivateProperty($driver, 'pool'); + /** @var ConnectionRequestData $data */ + $data = $this->getPrivateProperty($pool, 'data'); + $auth = $data->getAuth(); + /** @var string $username */ + $username = $this->getPrivateProperty($auth, 'username'); + /** @var string $password */ + $password = $this->getPrivateProperty($auth, 'password'); + + $this->assertSame($username, 'neo4j'); + $this->assertSame($password, 'testtest'); + } + + public function testDefaultDriverConfig(): void + { + static::bootKernel(); + $container = static::getContainer(); + + /** + * @var ClientInterface $client + */ + $client = $container->get('neo4j.client'); + /** @var Neo4jDriver $driver */ + $driver = $client->getDriver('default'); + /** @var Neo4jConnectionPool $pool */ + $pool = $this->getPrivateProperty($driver, 'pool'); + /** @var SingleThreadedSemaphore $semaphore */ + $semaphore = $this->getPrivateProperty($pool, 'semaphore'); + /** @var int $max */ + $max = $this->getPrivateProperty($semaphore, 'max'); + + // default_driver_config.pool_size + $this->assertSame($max, 256); + + /** @var ConnectionRequestData $data */ + $data = $this->getPrivateProperty($pool, 'data'); + + $this->assertSame($data->getUserAgent(), 'Neo4j Symfony Bundle/testing'); + + /** @var SslConfiguration $sslConfig */ + $sslConfig = $this->getPrivateProperty($data, 'config'); + /** @var SslMode $sslMode */ + $sslMode = $this->getPrivateProperty($sslConfig, 'mode'); + /** @var bool $verifyPeer */ + $verifyPeer = $this->getPrivateProperty($sslConfig, 'verifyPeer'); + + $this->assertSame($sslMode, SslMode::DISABLE()); + $this->assertFalse($verifyPeer); + } + + public function testDefaultSessionConfig(): void + { + static::bootKernel(); + $container = static::getContainer(); + + /** + * @var ClientInterface $client + */ + $client = $container->get('neo4j.client'); + /** @var Client $innerClient */ + $innerClient = $this->getPrivateProperty($client, 'client'); + $sessionConfig = $innerClient->getDefaultSessionConfiguration(); + + $this->assertSame($sessionConfig->getFetchSize(), 999); + } + + public function testDefaultTransactionConfig(): void + { + static::bootKernel(); + $container = static::getContainer(); + + /** + * @var ClientInterface $client + */ + $client = $container->get('neo4j.client'); + /** @var Client $innerClient */ + $innerClient = $this->getPrivateProperty($client, 'client'); + $transactionConfig = $innerClient->getDefaultTransactionConfiguration(); + + $this->assertSame($transactionConfig->getTimeout(), 40.0); + } + + public function testPriority(): void + { + static::bootKernel(); + $container = static::getContainer(); + + /** + * @var ClientInterface $client + */ + $client = $container->get('neo4j.client'); + /** @var Client $innerClient */ + $innerClient = $this->getPrivateProperty($client, 'client'); + /** @var DriverSetupManager $drivers */ + $drivers = $this->getPrivateProperty($innerClient, 'driverSetups'); + /** @var array<\SplPriorityQueue> $fallbackDriverQueue */ + $driverSetups = $this->getPrivateProperty($drivers, 'driverSetups'); + /** @var \SplPriorityQueue $fallbackDriverQueue */ + $fallbackDriverQueue = $driverSetups['neo4j-fallback-mechanism']; + $fallbackDriverQueue->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); + /** @var array{data: DriverSetup, priority: int} $extractedValue */ + $extractedValue = $fallbackDriverQueue->extract(); + + $this->assertSame($extractedValue['priority'], 1000); + } + + /** + * @template T + * + * @return T + * + * @noinspection PhpDocMissingThrowsInspection + */ + private function getPrivateProperty(object $object, string $property): mixed + { + $reflection = new \ReflectionClass($object); + $property = $reflection->getProperty($property); + + return $property->getValue($object); + } +}