diff --git a/.github/workflows/memgraph.yml b/.github/workflows/memgraph.yml new file mode 100644 index 0000000..53df456 --- /dev/null +++ b/.github/workflows/memgraph.yml @@ -0,0 +1,34 @@ +name: Tests with Memgraph on PHP 8.5 + +on: + pull_request: + branches: [ master ] + +jobs: + memgraph-tests: + runs-on: ubuntu-22.04 + name: "Running Integration tests for PHP on Memgraph" + + services: + memgraph: + image: memgraph/memgraph + ports: + - 7687:7687 + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.5' + extensions: mbstring, sockets + coverage: xdebug + ini-values: max_execution_time=0 + + - name: Install dependencies + run: composer install --no-progress + + - name: Test with phpunit + run: vendor/bin/phpunit --configuration phpunit.xml --testsuite "Memgraph" diff --git a/.github/workflows/neo4j.2025.yml b/.github/workflows/neo4j.2025.yml index 16efd6b..fd548c0 100644 --- a/.github/workflows/neo4j.2025.yml +++ b/.github/workflows/neo4j.2025.yml @@ -45,4 +45,4 @@ jobs: env: GDB_USERNAME: neo4j GDB_PASSWORD: nothing123 - run: vendor/bin/phpunit --configuration phpunit.xml --testsuite "Database" + run: vendor/bin/phpunit --configuration phpunit.xml --testsuite "Neo4j" diff --git a/.github/workflows/neo4j.4.4.yml b/.github/workflows/neo4j.4.4.yml index 0fad3d1..2c86b0e 100644 --- a/.github/workflows/neo4j.4.4.yml +++ b/.github/workflows/neo4j.4.4.yml @@ -45,4 +45,4 @@ jobs: env: GDB_USERNAME: neo4j GDB_PASSWORD: nothing - run: vendor/bin/phpunit --configuration phpunit.xml --testsuite "Database" + run: vendor/bin/phpunit --configuration phpunit.xml --testsuite "Neo4j" diff --git a/.github/workflows/neo4j.5.yml b/.github/workflows/neo4j.5.yml index 050ff58..c245b27 100644 --- a/.github/workflows/neo4j.5.yml +++ b/.github/workflows/neo4j.5.yml @@ -45,4 +45,4 @@ jobs: env: GDB_USERNAME: neo4j GDB_PASSWORD: nothing123 - run: vendor/bin/phpunit --configuration phpunit.xml --testsuite "Database" + run: vendor/bin/phpunit --configuration phpunit.xml --testsuite "Neo4j" diff --git a/phpunit.xml b/phpunit.xml index ebe8738..9343afc 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,7 +1,7 @@ - + ./tests/BoltTest.php ./tests/connection ./tests/error @@ -13,6 +13,9 @@ ./tests/protocol ./tests/helpers/FileCacheTest.php + + ./tests/MemgraphTest.php + diff --git a/tests/MemgraphTest.php b/tests/MemgraphTest.php new file mode 100644 index 0000000..182010f --- /dev/null +++ b/tests/MemgraphTest.php @@ -0,0 +1,153 @@ +markTestSkipped('Sockets extension not available'); + + $conn = new \Bolt\connection\Socket('127.0.0.1', 7687, 3); + $this->assertInstanceOf(\Bolt\connection\Socket::class, $conn); + + $bolt = new Bolt($conn); + $this->assertInstanceOf(Bolt::class, $bolt); + + $protocol = $bolt->setProtocolVersions(5.2, 4.3, 4.1, 4.0)->build(); + $this->assertInstanceOf(AProtocol::class, $protocol); + + if (version_compare($protocol->getVersion(), '5.2', '>=')) { + $protocol->hello()->getResponse(); + $protocol->logon(['scheme' => 'none'])->getResponse(); + } else { + $protocol->hello(['scheme' => 'none'])->getResponse(); + } + + return $protocol; + } + + /** + * Basic query test with basic data types + * @depends testConnection + * @param AProtocol $protocol + */ + public function testQuery(AProtocol $protocol): void + { + $params = [ + 'number' => 123, + 'string' => 'abc', + 'null' => null, + 'bool' => true, + 'float' => 0.4591563, + 'list' => [1, 2, 3], + 'dictionary' => ['a' => 1, 'b' => 2, 'c' => 3] + ]; + + $query = implode(', ', array_map(function (string $key) { + return '$' . $key . ' AS ' . $key; + }, array_keys($params))); + + $runResponse = $protocol->run('RETURN ' . $query, $params)->getResponse(); + $this->assertEquals(Signature::SUCCESS, $runResponse->signature); + + $pullResponses = iterator_to_array($protocol->pull()->getResponses(), false); + $this->assertCount(2, $pullResponses); + $this->assertEquals(Signature::RECORD, $pullResponses[0]->signature); + $this->assertEquals(Signature::SUCCESS, $pullResponses[1]->signature); + + $this->assertEquals($params, array_combine($runResponse->content['fields'], $pullResponses[0]->content)); + } + /** + * Test transaction handling + * @depends testConnection + * @param AProtocol $protocol + */ + public function testTransaction(AProtocol $protocol): void + { + if (version_compare($protocol->getVersion(), 3, '<')) { + $this->markTestSkipped('Old Memgraph version does not support transactions'); + } + + $res = iterator_to_array( + $protocol + ->begin() + ->run('CREATE (a:Test) RETURN a, ID(a)') + ->pull() + ->rollback() + ->getResponses(), + false + ); + + $id = $res[2]->content[1]; + $this->assertIsInt($id); + + $res = iterator_to_array( + $protocol + ->run('MATCH (a:Test) WHERE ID(a) = ' + . (version_compare($protocol->getVersion(), 4, '<') ? '{a}' : '$a') + . ' RETURN COUNT(a)', [ + 'a' => $id + ]) + ->pull() + ->getResponses(), + false + ); + + $this->assertEquals(0, $res[1]->content[0]); + } + + /** + * Test additional data types + * @depends testConnection + * @dataProvider structureProvider + * @param IStructure $structure + * @param AProtocol $protocol + */ + public function testStructure(IStructure $structure, AProtocol $protocol): void + { + $responses = iterator_to_array( + $protocol + ->run('RETURN $s', [ + 's' => $structure + ]) + ->pull() + ->getResponses(), + false + ); + + $this->assertInstanceOf(get_class($structure), $responses[1]->content[0]); + $this->assertEquals((string)$structure, (string)$responses[1]->content[0]); + } + + public function structureProvider(): \Generator + { + yield 'Duration' => [new Duration(0, 4, 3, 2)]; + yield 'Date' => [new Date(intval(floor(time() / 86400)))]; + yield 'LocalTime' => [new LocalTime(intval(microtime(true) * 1000))]; + yield 'LocalDateTime' => [new LocalDateTime(time(), 1234)]; + } +}