Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
97df0ab
Correctly pass bookmarks from transaction
pratikshazalte69 May 5, 2025
1a66bb8
feat: Add testkit backend
exaby73 Apr 23, 2025
f6c905a
fix: Disable temporary Cypher path and relationship feature
exaby73 May 1, 2025
44a8ab4
chore: Set up Python virtual environment and install dependencies for…
exaby73 May 1, 2025
fa765ae
temp commit
pratikshazalte69 May 2, 2025
e46e18d
fix(testkit): WIP on testkit tests, added PHP_IDE_CONFIG to enable Xd…
pratikshazalte69 May 2, 2025
1b6a907
working tests for authentication
pratikshazalte69 May 2, 2025
4bb4670
working tests for bookmarks
pratikshazalte69 May 5, 2025
a2efd17
feat: Simplify acquiring and resuing connections
pratikshazalte69 May 7, 2025
427447b
chore: Fix CS and Psalm
p123-stack May 7, 2025
6673b85
feat: Add testkit backend
exaby73 Apr 23, 2025
0b0bf1a
fix: Disable temporary Cypher path and relationship feature
exaby73 May 1, 2025
482129f
chore: Set up Python virtual environment and install dependencies for…
exaby73 May 1, 2025
1e12485
temp commit
pratikshazalte69 May 2, 2025
456aa26
fix(testkit): WIP on testkit tests, added PHP_IDE_CONFIG to enable Xd…
pratikshazalte69 May 2, 2025
f53e338
working tests for authentication
pratikshazalte69 May 2, 2025
3447928
working tests for bookmarks
pratikshazalte69 May 5, 2025
1bc63f8
wip: Test every test till now
pratikshazalte69 May 7, 2025
752259a
Merge branch 'feat/testkit' of github.com:neo4j-php/neo4j-php-client …
p123-stack May 7, 2025
594b3d8
cleanup object model
p123-stack May 7, 2025
3704d08
ci: Add testkit (#258)
exaby73 May 7, 2025
a2beeb5
test: Fix following Testkit tests: Auth basic, Bookmarks, and majorit…
p123-stack May 9, 2025
f947530
ci: Update testkit workflow to include down flags for docker compose
exaby73 May 12, 2025
c2ebeda
ci: Refactor testkit workflow to improve service restart logic
exaby73 May 12, 2025
178cff1
ci: Update integration test workflow to specify docker-compose file
exaby73 May 12, 2025
3b2b863
ci: Update connection string in integration test workflow
exaby73 May 12, 2025
96d5c35
ci: Upgrade hoverkraft-tech/compose-action to version 2.2.0 in integr…
exaby73 May 12, 2025
87f160b
ci: Update Neo4j connection string in integration test workflow
exaby73 May 12, 2025
a26f37e
Merge remote-tracking branch 'origin/main' into feat/testkit
transistive May 12, 2025
80656a4
move testkit dot yaml to new ci
transistive May 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .github/workflows/testkit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Testkit Tests

on:
push:
branches:
- main
pull_request:

jobs:
tests:
runs-on: ubuntu-latest
name: "Run Testkit Tests"

steps:
- uses: actions/checkout@v4

- name: Restore Neo4j Image Cache if it exists
id: cache-docker-neo4j
uses: actions/cache@v4
with:
path: ci/cache/docker/neo4j
key: cache-docker-neo4j-5-enterprise

- name: Update Neo4j Image Cache if cache miss
if: steps.cache-docker-neo4j.outputs.cache-hit != 'true'
run: |
docker pull neo4j:5-enterprise
mkdir -p ci/cache/docker/neo4j
docker image save neo4j:5-enterprise --output ./ci/cache/docker/neo4j/neo4j-5-enterprise.tar

- name: Use Neo4j Image Cache if cache hit
if: steps.cache-docker-neo4j.outputs.cache-hit == 'true'
run: docker image load --input ./ci/cache/docker/neo4j/neo4j-5-enterprise.tar

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Build & cache client image
uses: docker/build-push-action@v3
with:
context: .
file: Dockerfile
load: true
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: PHP_VERSION=8.1
tags: integration-client:8.1

- name: Populate .env
run: |
echo "PHP_VERSION=8.1" > .env
echo "CONNECTION=neo4j://neo4j:testtest@server1" >> .env

- name: Cache PHP deps
id: cache-php-deps
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-php-8.1-${{ hashFiles('**/composer.json') }}
restore-keys: |
${{ runner.os }}-php-8.1-

- name: Install PHP deps
if: steps.cache-php-deps.outputs.cache-hit != 'true'
run: |
docker compose run --rm client composer install

- name: Run integration tests
run: |
docker compose up -d --remove-orphans --wait --no-build \
server1 \
server2 \
server3 \
server4 \
testkit_backend

docker compose run --rm testkit ./testkit.sh
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ composer.lock
/docs/_build
cachegrind.out.*
.phpunit.cache/
/testkit-backend/testkit/
3 changes: 2 additions & 1 deletion .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
try {
$finder = PhpCsFixer\Finder::create()
->in(__DIR__.'/src')
->in(__DIR__.'/tests');
->in(__DIR__.'/tests')
->in(__DIR__.'/testkit-backend');
} catch (Throwable $e) {
echo $e->getMessage()."\n";

Expand Down
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
"cache/integration-tests": "dev-master",
"kubawerlos/php-cs-fixer-custom-fixers": "3.13.*",
"rector/rector": "^1.0",
"psr/log": "^3.0"
"psr/log": "^3.0",
"php-di/php-di": "^6.3"
},
"autoload": {
"psr-4": {
Expand All @@ -66,7 +67,8 @@
},
"autoload-dev": {
"psr-4": {
"Laudis\\Neo4j\\Tests\\": "tests/"
"Laudis\\Neo4j\\Tests\\": "tests/",
"Laudis\\Neo4j\\TestkitBackend\\": "testkit-backend/src"
}
},
"minimum-stability": "stable",
Expand All @@ -81,6 +83,7 @@
},
"scripts": {
"fix-cs": "./vendor/bin/php-cs-fixer fix",
"check-cs": "./vendor/bin/php-cs-fixer fix --dry-run",
"psalm": "./vendor/bin/psalm"
}
}
31 changes: 31 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ services:
NEO4J_server_bolt_advertised__address: neo4j:7687
NEO4J_server_http_advertised__address: neo4j:7474



server1:
<<: *common-cluster
hostname: server1
Expand Down Expand Up @@ -113,3 +115,32 @@ services:
NEO4J_initial_server_mode__constraint: 'SECONDARY'
NEO4J_server_bolt_advertised__address: server4:7687
NEO4J_server_http_advertised__address: server4:7474

testkit:
image: python:3.13
volumes:
- .:/opt/project
working_dir: /opt/project/testkit-backend
networks:
- neo4j
environment:
TEST_NEO4J_HOST: neo4j
TEST_NEO4J_USER: neo4j
TEST_NEO4J_PASS: testtest
TEST_DRIVER_NAME: php
TEST_DRIVER_REPO: /opt/project
TEST_BACKEND_HOST: testkit_backend

testkit_backend:
<<: *common-php
environment:
PHP_IDE_CONFIG: "serverName=myserver"
command: php -d xdebug.mode=debug -d xdebug.start_with_request=yes -d xdebug.client_host=host.docker.internal ./testkit-backend/index.php
networks:
- neo4j
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- neo4j
ports:
- "9876:9876"
19 changes: 15 additions & 4 deletions src/Bolt/BoltConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
use Psr\Http\Message\UriInterface;
use Psr\Log\LogLevel;
use Throwable;
use Traversable;
use WeakReference;

/**
Expand Down Expand Up @@ -209,12 +210,14 @@ public function reset(): void
* Begins a transaction.
*
* Any of the preconditioned states are: 'READY', 'INTERRUPTED'.
*
* @param iterable<string, scalar|array|null>|null $txMetaData
*/
public function begin(?string $database, ?float $timeout, BookmarkHolder $holder): void
public function begin(?string $database, ?float $timeout, BookmarkHolder $holder, ?iterable $txMetaData): void
{
$this->consumeResults();

$extra = $this->buildRunExtra($database, $timeout, $holder, AccessMode::WRITE());
$extra = $this->buildRunExtra($database, $timeout, $holder, AccessMode::WRITE(), $txMetaData);
$message = $this->messageFactory->createBeginMessage($extra);
$response = $message->send()->getResponse();
$this->assertNoFailure($response);
Expand Down Expand Up @@ -248,8 +251,9 @@ public function run(
?float $timeout,
BookmarkHolder $holder,
?AccessMode $mode,
?iterable $tsxMetadata,
): array {
$extra = $this->buildRunExtra($database, $timeout, $holder, $mode);
$extra = $this->buildRunExtra($database, $timeout, $holder, $mode, $tsxMetadata);
$message = $this->messageFactory->createRunMessage($text, $parameters, $extra);
$response = $message->send()->getResponse();
$this->assertNoFailure($response);
Expand Down Expand Up @@ -327,7 +331,7 @@ public function close(): void
}
}

private function buildRunExtra(?string $database, ?float $timeout, BookmarkHolder $holder, ?AccessMode $mode): array
private function buildRunExtra(?string $database, ?float $timeout, BookmarkHolder $holder, ?AccessMode $mode, ?iterable $metadata): array
{
$extra = [];
if ($database !== null) {
Expand All @@ -345,6 +349,13 @@ private function buildRunExtra(?string $database, ?float $timeout, BookmarkHolde
$extra['mode'] = AccessMode::WRITE() === $mode ? 'w' : 'r';
}

if ($metadata !== null) {
$metadataArray = $metadata instanceof Traversable ? iterator_to_array($metadata) : $metadata;
if (count($metadataArray) > 0) {
$extra['tx_metadata'] = $metadataArray;
}
}

return $extra;
}

Expand Down
3 changes: 2 additions & 1 deletion src/Bolt/BoltUnmanagedTransaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ public function runStatement(Statement $statement): SummarizedResult
$this->database,
$this->tsxConfig->getTimeout(),
$this->bookmarkHolder,
$this->config->getAccessMode()
$this->config->getAccessMode(),
$this->tsxConfig->getMetaData()
);
} catch (Throwable $e) {
$this->state = TransactionState::TERMINATED;
Expand Down
2 changes: 1 addition & 1 deletion src/Bolt/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ private function startTransaction(TransactionConfiguration $config, SessionConfi
try {
$connection = $this->acquireConnection($config, $sessionConfig);

$connection->begin($this->config->getDatabase(), $config->getTimeout(), $this->bookmarkHolder);
$connection->begin($this->config->getDatabase(), $config->getTimeout(), $this->bookmarkHolder, $config->getMetaData());
} catch (Neo4jException $e) {
if (isset($connection) && $connection->getServerState() === 'FAILED') {
$connection->reset();
Expand Down
2 changes: 1 addition & 1 deletion src/Databags/ServerInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function toArray(): array
{
return [
'address' => $this->address,
'protocol' => $this->protocol,
'protocolVersion' => $this->protocol,
'agent' => $this->agent,
];
}
Expand Down
5 changes: 3 additions & 2 deletions src/Types/CypherMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,9 @@ public function getAsWGS843DPoint(string $key): WGS843DPoint

public function key(): string
{
/** @var string */
return $this->cacheKey();
// we have to cast to a string, as the value is potentially an integer if the key is numeric:
// https://stackoverflow.com/questions/4100488/a-numeric-string-as-array-key-in-php
return (string) $this->cacheKey();
}

/**
Expand Down
50 changes: 50 additions & 0 deletions testkit-backend/blacklist.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Neo4j PHP Client and Driver package.
*
* (c) Nagels <https://nagels.tech>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

return [
'neo4j' => [
'datatypes' => [
'TestDataTypes' => [
'test_should_echo_very_long_map' => 'Work in progress on testkit frontend',
],
],
'sessionrun' => [
'TestSessionRun' => [
'test_autocommit_transactions_should_support_metadata' => 'Meta data isn\'t supported yet',
'test_autocommit_transactions_should_support_timeout' => 'Waiting on bookmarks isn\'t supported yet',
],
],
'test_direct_driver' => [
'TestDirectDriver' => [
'test_custom_resolver' => 'No custom resolver implemented',
'test_fail_nicely_when_using_http_port' => 'Not implemented yet',
],
],
'test_summary' => [
'TestDirectDriver' => [
'test_agent_string' => 'This is not an official driver yet',
],
],
'txrun' => [
'TestTxRun' => [
'test_should_fail_to_run_query_for_invalid_bookmark' => 'Waiting on bookmarks isn\'t supported yet',
],
],
'txfuncrun' => [
'TestTxFuncRun' => [
'test_iteration_nested' => 'Buffers not supported yet',
'test_updates_last_bookmark_on_commit' => 'Waiting on bookmarks isn\'t supported yet',
],
],
],
];
61 changes: 61 additions & 0 deletions testkit-backend/features.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Neo4j PHP Client and Driver package.
*
* (c) Nagels <https://nagels.tech>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

return [
// === OPTIMIZATIONS ===
// On receiving Neo.ClientError.Security.AuthorizationExpired, the driver
// shouldn't reuse any open connections for anything other than finishing
// a started job. All other connections should be re-established before
// running the next job with them.
'AuthorizationExpiredTreatment' => false,

// Driver doesn't explicitly send message data that is the default value.
// This conserves bandwidth.
'Optimization:ImplicitDefaultArguments' => false,

// The driver sends no more than the strictly necessary RESET messages.
'Optimization:MinimalResets' => false,

// The driver caches connections (e.g., in a pool) and doesn't start a new
// one (with hand-shake, HELLO, etc.) for each query.
'Optimization:ConnectionReuse' => false,

// The driver doesn't wait for a SUCCESS after calling RUN but pipelines a
// PULL right afterwards and consumes two messages after that. This saves a
// full round-trip.
'Optimization:PullPipelining' => false,

// === CONFIGURATION HINTS (BOLT 4.3+) ===
// The driver understands and follow the connection hint
// connection.recv_timeout_seconds which tells it to close the connection
// after not receiving an answer on any request for longer than the given
// time period. On timout, the driver should remove the server from its
// routing table and assume all other connections to the server are dead
// as well.
'ConfHint:connection.recv_timeout_seconds' => false,

// Temporary driver feature that will be removed when all official drivers
// have been unified in their behaviour of when they return a Result object.
// We aim for drivers to not providing a Result until the server replied with
// SUCCESS so that the result keys are already known and attached to the
// Result object without further waiting or communication with the server.
'Temporary:ResultKeys' => false,

// Temporary driver feature that will be removed when all official driver
// backends have implemented all summary response fields.
'Temporary:FullSummary' => false,

// Temporary driver feature that will be removed when all official driver
// backends have implemented path and relationship types
'Temporary:CypherPathAndRelationship' => false,
];
21 changes: 21 additions & 0 deletions testkit-backend/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Neo4j PHP Client and Driver package.
*
* (c) Nagels <https://nagels.tech>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

require_once __DIR__.'/../vendor/autoload.php';

use Laudis\Neo4j\TestkitBackend\Backend;

$backend = Backend::boot();
while (true) {
$backend->handle();
}
Loading