From 4aad0a5443e2fb99689cf3215b47184e5f7e771c Mon Sep 17 00:00:00 2001 From: Thiery Laverdure Date: Fri, 7 Nov 2025 10:52:30 -0500 Subject: [PATCH 1/8] Add LitebasePDO integration test and update docs Introduces tests/Integration/LitebasePDOTest.php to verify LitebasePDO functionality with transactions and queries. Updates README with installation, usage, and integration test instructions. Adjusts test commands in composer.json and CI workflow to separate unit and integration tests. Adds integration test directory to phpunit.xml and improves error messages in ApiClientTest.php. --- .github/workflows/tests.yml | 2 +- README.md | 45 +++++++++++++++-- composer.json | 3 +- phpunit.xml | 1 + tests/Integration/ApiClientTest.php | 4 +- tests/Integration/LitebasePDOTest.php | 72 +++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 tests/Integration/LitebasePDOTest.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 84f03e1..fca5723 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,4 +21,4 @@ jobs: run: composer install --no-interaction --prefer-dist --optimize-autoloader - name: Tests - run: ./vendor/bin/pest --ci + run: ./vendor/bin/pest tests/Unit tests/Feature --ci diff --git a/README.md b/README.md index 6b541b8..714a332 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,45 @@ A PHP SDK for interacting with [Litebase](https://github.com/litebase/litebase), You can install the package via composer: ```bash -composer require ... +composer require litebase/litebase-php ``` ## Usage -``` php -// Usage description here +```php +use Litebase\Configuration; +use Litebase\LitebasePDO; + +$pdo = new LitebasePDO([ + 'host' => 'localhost', + 'port' => 8888, + 'token' => 'your_api_token', + 'database' => 'your_database_name/main', +]); + +$statement = $pdo->prepare('SELECT * FROM users WHERE id = ?'); +$statement->execute([1]); +$result = $statement->fetchAll(PDO::FETCH_ASSOC); + +foreach ($result as $row) { + print_r($row); +} + +// Use transactions +$pdo = $pdo->beginTransaction(); + +try { + $statement = $pdo->prepare('INSERT INTO users (name, email) VALUES (?, ?)'); + $statement->execute(['John Doe', 'john@example.com']); + + $statement = $pdo->prepare('INSERT INTO logs (user_id, action) VALUES (?, ?)'); + $statement->execute([$pdo->lastInsertId(), 'user_created']); + + $pdo->commit(); +} catch (\Exception $e) { + $pdo->rollBack(); + throw $e; +} ``` ## Contributing @@ -24,10 +56,17 @@ Please see [CONTRIBUTING](https://github.com/litebase/litebase-php?tab=contribut ### Testing +You can run the tests with: ``` bash composer test ``` +Integration test requires a running Litebase instance. You can start one using Docker: + +```bash +docker run -d -p 8888:8888 --name litebase litebase/litebase:latest +``` + ## Code of Conduct Please see [CODE OF CONDUCT](https://github.com/litebase/litebase-php?tab=coc-ov-file) for details. diff --git a/composer.json b/composer.json index 8969c1c..4a8652d 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,8 @@ "generate_open_api": "openapi-generator-cli generate -c openapi_config.yaml", "phpstan": "vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=512M src tests", "pint": "vendor/bin/pint --no-interaction", - "test": "vendor/bin/pest", + "test": "vendor/bin/pest tests/Unit", + "test-integration": "vendor/bin/pest tests/Integration", "test-coverage": "vendor/bin/pest --coverage-html coverage" } } diff --git a/phpunit.xml b/phpunit.xml index 57d0b5d..aa1f42e 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,6 +9,7 @@ > + tests/Integration tests/Unit diff --git a/tests/Integration/ApiClientTest.php b/tests/Integration/ApiClientTest.php index ef1eae0..b9c3967 100644 --- a/tests/Integration/ApiClientTest.php +++ b/tests/Integration/ApiClientTest.php @@ -32,7 +32,7 @@ $logs = implode("\n", $lines); - throw new \RuntimeException('Failed to connect to Litebase server for integration tests: '.$e->getMessage()."\nContainer logs:\n{$logs}"); + throw new \RuntimeException('Failed to connect to Litebase server for integration tests: ' . $e->getMessage() . "\nContainer logs:\n{$logs}"); } if ($response->getStatus() !== 'success') { @@ -42,7 +42,7 @@ $logs = implode("\n", $lines); - throw new \RuntimeException('Failed to connect to Litebase server for integration tests.'."Container logs:\n{$logs}"); + throw new \RuntimeException('Failed to connect to Litebase server for integration tests.' . "Container logs:\n{$logs}"); } }); diff --git a/tests/Integration/LitebasePDOTest.php b/tests/Integration/LitebasePDOTest.php new file mode 100644 index 0000000..a735073 --- /dev/null +++ b/tests/Integration/LitebasePDOTest.php @@ -0,0 +1,72 @@ +setHost('127.0.0.1') + ->setPort('8888') + ->setUsername('root') + ->setPassword('password'); + + $client = new ApiClient($configuration); + + $client->database()->createDatabase(new DatabaseStoreRequest([ + 'name' => 'test', + ])); +}); + +afterAll(function () { + exec('docker compose -f ./tests/docker-compose.test.yml down -v'); + // Delete the .litebase directory to clean up any persisted data + exec('rm -rf ./tests/.litebase'); +}); + +describe('LitebasePDO', function () { + $pdo = new LitebasePDO([ + 'host' => 'localhost', + 'port' => '8888', + 'username' => 'root', + 'password' => 'password', + 'database' => 'test/main', + ]); + + test('can perform a transaction', function () use ($pdo) { + $result = $pdo->beginTransaction(); + expect($result)->toBeTrue(); + + $affectedRows = $pdo->exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, email TEXT)'); + + expect($affectedRows)->toBeGreaterThanOrEqual(0); + + $statement = $pdo->prepare('INSERT INTO users (name, email) VALUES (?, ?)'); + + $insertResult = $statement->execute(['Alice', 'alice@example.com']); + + expect($insertResult)->toBeTrue(); + + $result = $pdo->commit(); + expect($result)->toBeTrue(); + + $statement = $pdo->prepare('SELECT * FROM users WHERE email = ?'); + $statement->execute(['alice@example.com']); + + /** @var array $user */ + $user = $statement->fetch(PDO::FETCH_ASSOC); + + expect($user['name'])->toBe('Alice'); + expect($user['email'])->toBe('alice@example.com'); + }); +}); From 10e28bbab314c207ec9ddb370bb4bfc04bd469dd Mon Sep 17 00:00:00 2001 From: Thiery Laverdure Date: Fri, 7 Nov 2025 15:51:39 -0500 Subject: [PATCH 2/8] wip --- .github/workflows/integration-tests.yml | 7 +------ .github/workflows/tests.yml | 2 +- tests/Integration/ApiClientTest.php | 9 ++++++--- tests/Integration/LitebasePDOTest.php | 25 ++++++++++++++++++++++--- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 16e655f..eba8e4f 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -6,7 +6,7 @@ on: workflow_dispatch: jobs: - test: + integration-tests: runs-on: ubuntu-latest steps: @@ -24,11 +24,6 @@ jobs: - name: Set up Docker Compose uses: docker/setup-compose-action@v1 - - name: Prepare data directory with correct permissions - run: | - mkdir -p ./tests/.litebase - chmod 777 ./tests/.litebase - - name: Run integration tests run: vendor/bin/pest tests/Integration diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fca5723..2a52f3b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,4 +21,4 @@ jobs: run: composer install --no-interaction --prefer-dist --optimize-autoloader - name: Tests - run: ./vendor/bin/pest tests/Unit tests/Feature --ci + run: ./vendor/bin/pest tests/Unit --ci diff --git a/tests/Integration/ApiClientTest.php b/tests/Integration/ApiClientTest.php index b9c3967..be5335e 100644 --- a/tests/Integration/ApiClientTest.php +++ b/tests/Integration/ApiClientTest.php @@ -18,7 +18,11 @@ $client = new ApiClient($configuration); beforeAll(function () use ($client) { - exec('docker compose -f ./tests/docker-compose.test.yml up -d'); + if (file_exists('./tests/.litebase')) { + exec('rm -rf ./tests/.litebase'); + } + + exec('mkdir -p ./tests/.litebase'); // Give the container a moment to initialize sleep(2); @@ -27,7 +31,6 @@ $response = $client->clusterStatus()->listClusterStatuses(); } catch (\Exception $e) { $lines = []; - exec('docker ps -a'); exec('docker compose -f ./tests/docker-compose.test.yml logs --tail=200 --no-color', $lines, $rc); $logs = implode("\n", $lines); @@ -37,7 +40,6 @@ if ($response->getStatus() !== 'success') { $lines = []; - exec('docker ps -a'); exec('docker compose -f ./tests/docker-compose.test.yml logs --tail=200 --no-color', $lines, $rc); $logs = implode("\n", $lines); @@ -48,6 +50,7 @@ afterAll(function () { exec('docker compose -f ./tests/docker-compose.test.yml down -v'); + // Delete the .litebase directory to clean up any persisted data exec('rm -rf ./tests/.litebase'); }); diff --git a/tests/Integration/LitebasePDOTest.php b/tests/Integration/LitebasePDOTest.php index a735073..5d039da 100644 --- a/tests/Integration/LitebasePDOTest.php +++ b/tests/Integration/LitebasePDOTest.php @@ -11,8 +11,16 @@ use PDO; beforeAll(function () { + // Create Test directory + if (file_exists('./tests/.litebase')) { + exec('rm -rf ./tests/.litebase'); + } + + exec('mkdir -p ./tests/.litebase'); + exec('docker compose -f ./tests/docker-compose.test.yml up -d'); sleep(2); + $configuration = new Configuration(); $configuration @@ -23,13 +31,24 @@ $client = new ApiClient($configuration); - $client->database()->createDatabase(new DatabaseStoreRequest([ - 'name' => 'test', - ])); + + try { + $client->database()->createDatabase(new DatabaseStoreRequest([ + 'name' => 'test', + ])); + } catch (\Exception $e) { + $lines = []; + exec('docker compose -f ./tests/docker-compose.test.yml logs --tail=200 --no-color', $lines, $rc); + + $logs = implode("\n", $lines); + + throw new \RuntimeException('Failed to connect to Litebase server for integration tests: ' . $e->getMessage() . "\nContainer logs:\n{$logs}"); + } }); afterAll(function () { exec('docker compose -f ./tests/docker-compose.test.yml down -v'); + // Delete the .litebase directory to clean up any persisted data exec('rm -rf ./tests/.litebase'); }); From cef7174620ea5f21783c5c263b1180db26b6e254 Mon Sep 17 00:00:00 2001 From: Thiery Laverdure Date: Fri, 7 Nov 2025 15:54:41 -0500 Subject: [PATCH 3/8] Update ApiClientTest.php --- tests/Integration/ApiClientTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Integration/ApiClientTest.php b/tests/Integration/ApiClientTest.php index be5335e..5264fd0 100644 --- a/tests/Integration/ApiClientTest.php +++ b/tests/Integration/ApiClientTest.php @@ -23,6 +23,7 @@ } exec('mkdir -p ./tests/.litebase'); + exec('docker compose -f ./tests/docker-compose.test.yml up -d'); // Give the container a moment to initialize sleep(2); From 44c7170ca0f9e53965033ff114b748b26ad94362 Mon Sep 17 00:00:00 2001 From: Thiery Laverdure Date: Fri, 7 Nov 2025 15:56:20 -0500 Subject: [PATCH 4/8] Update docker-compose.test.yml --- tests/docker-compose.test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/docker-compose.test.yml b/tests/docker-compose.test.yml index a6361e9..24eebdf 100644 --- a/tests/docker-compose.test.yml +++ b/tests/docker-compose.test.yml @@ -4,13 +4,13 @@ services: ports: - "8888:8888" volumes: - - ./.litebase:/home/litebase/data + - ./.litebase:/home/litebase environment: - LITEBASE_CLUSTER_ID=cluster-1 - LITEBASE_DEBUG=true - LITEBASE_ENV=development - - LITEBASE_DATA_PATH=/home/litebase/data - - LITEBASE_STORAGE_NETWORK_PATH=/home/litebase/data/_network + - LITEBASE_DATA_PATH=/home/litebase/ + - LITEBASE_STORAGE_NETWORK_PATH=/home/litebase/_network - LITEBASE_PORT=8888 - LITEBASE_ROOT_PASSWORD=password - LITEBASE_ROOT_USERNAME=root From c839c7e1c953d36b42471ac16dee8ffb37aaedd0 Mon Sep 17 00:00:00 2001 From: Thiery Laverdure Date: Sat, 8 Nov 2025 11:18:39 -0500 Subject: [PATCH 5/8] Update docker-compose.test.yml --- tests/docker-compose.test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/docker-compose.test.yml b/tests/docker-compose.test.yml index 24eebdf..a6361e9 100644 --- a/tests/docker-compose.test.yml +++ b/tests/docker-compose.test.yml @@ -4,13 +4,13 @@ services: ports: - "8888:8888" volumes: - - ./.litebase:/home/litebase + - ./.litebase:/home/litebase/data environment: - LITEBASE_CLUSTER_ID=cluster-1 - LITEBASE_DEBUG=true - LITEBASE_ENV=development - - LITEBASE_DATA_PATH=/home/litebase/ - - LITEBASE_STORAGE_NETWORK_PATH=/home/litebase/_network + - LITEBASE_DATA_PATH=/home/litebase/data + - LITEBASE_STORAGE_NETWORK_PATH=/home/litebase/data/_network - LITEBASE_PORT=8888 - LITEBASE_ROOT_PASSWORD=password - LITEBASE_ROOT_USERNAME=root From 82897be960574290d97a08fe48b6737fd5ffe842 Mon Sep 17 00:00:00 2001 From: Thiery Laverdure Date: Sat, 8 Nov 2025 11:27:00 -0500 Subject: [PATCH 6/8] wip --- tests/Integration/ApiClientTest.php | 1 + tests/Integration/LitebasePDOTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/Integration/ApiClientTest.php b/tests/Integration/ApiClientTest.php index 5264fd0..919354c 100644 --- a/tests/Integration/ApiClientTest.php +++ b/tests/Integration/ApiClientTest.php @@ -23,6 +23,7 @@ } exec('mkdir -p ./tests/.litebase'); + exec('chmod 777 ./tests/.litebase'); exec('docker compose -f ./tests/docker-compose.test.yml up -d'); // Give the container a moment to initialize diff --git a/tests/Integration/LitebasePDOTest.php b/tests/Integration/LitebasePDOTest.php index 5d039da..15538c3 100644 --- a/tests/Integration/LitebasePDOTest.php +++ b/tests/Integration/LitebasePDOTest.php @@ -17,6 +17,7 @@ } exec('mkdir -p ./tests/.litebase'); + exec('chmod 777 ./tests/.litebase'); exec('docker compose -f ./tests/docker-compose.test.yml up -d'); sleep(2); From ba4a6c735efcc5db57bf58d3e952320b89c232e0 Mon Sep 17 00:00:00 2001 From: Thiery Laverdure Date: Mon, 10 Nov 2025 08:57:04 -0500 Subject: [PATCH 7/8] Refactor integration tests to use LitebaseContainer class Replaces Docker Compose setup with a custom LitebaseContainer class for starting and stopping the Litebase test container in integration tests. Removes the docker-compose.test.yml file and related workflow steps, simplifying test environment management. --- .github/workflows/integration-tests.yml | 3 --- tests/Integration/ApiClientTest.php | 30 +++------------------- tests/Integration/LitebaseContainer.php | 34 +++++++++++++++++++++++++ tests/Integration/LitebasePDOTest.php | 24 +++-------------- tests/docker-compose.test.yml | 22 ---------------- 5 files changed, 41 insertions(+), 72 deletions(-) create mode 100644 tests/Integration/LitebaseContainer.php delete mode 100644 tests/docker-compose.test.yml diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index eba8e4f..f271d3e 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -21,9 +21,6 @@ jobs: - name: Install dependencies run: composer install - - name: Set up Docker Compose - uses: docker/setup-compose-action@v1 - - name: Run integration tests run: vendor/bin/pest tests/Integration diff --git a/tests/Integration/ApiClientTest.php b/tests/Integration/ApiClientTest.php index 919354c..adc918e 100644 --- a/tests/Integration/ApiClientTest.php +++ b/tests/Integration/ApiClientTest.php @@ -18,43 +18,21 @@ $client = new ApiClient($configuration); beforeAll(function () use ($client) { - if (file_exists('./tests/.litebase')) { - exec('rm -rf ./tests/.litebase'); - } - - exec('mkdir -p ./tests/.litebase'); - exec('chmod 777 ./tests/.litebase'); - exec('docker compose -f ./tests/docker-compose.test.yml up -d'); - - // Give the container a moment to initialize - sleep(2); + LitebaseContainer::start(); try { $response = $client->clusterStatus()->listClusterStatuses(); } catch (\Exception $e) { - $lines = []; - exec('docker compose -f ./tests/docker-compose.test.yml logs --tail=200 --no-color', $lines, $rc); - - $logs = implode("\n", $lines); - - throw new \RuntimeException('Failed to connect to Litebase server for integration tests: ' . $e->getMessage() . "\nContainer logs:\n{$logs}"); + throw new \RuntimeException('Failed to connect to Litebase server for integration tests: ' . $e->getMessage()); } if ($response->getStatus() !== 'success') { - $lines = []; - exec('docker compose -f ./tests/docker-compose.test.yml logs --tail=200 --no-color', $lines, $rc); - - $logs = implode("\n", $lines); - - throw new \RuntimeException('Failed to connect to Litebase server for integration tests.' . "Container logs:\n{$logs}"); + throw new \RuntimeException('Failed to connect to Litebase server for integration tests.'); } }); afterAll(function () { - exec('docker compose -f ./tests/docker-compose.test.yml down -v'); - - // Delete the .litebase directory to clean up any persisted data - exec('rm -rf ./tests/.litebase'); + LitebaseContainer::stop(); }); describe('ApiClient', function () use ($client) { diff --git a/tests/Integration/LitebaseContainer.php b/tests/Integration/LitebaseContainer.php new file mode 100644 index 0000000..ed512dc --- /dev/null +++ b/tests/Integration/LitebaseContainer.php @@ -0,0 +1,34 @@ +database()->createDatabase(new DatabaseStoreRequest([ 'name' => 'test', ])); } catch (\Exception $e) { - $lines = []; - exec('docker compose -f ./tests/docker-compose.test.yml logs --tail=200 --no-color', $lines, $rc); - - $logs = implode("\n", $lines); - - throw new \RuntimeException('Failed to connect to Litebase server for integration tests: ' . $e->getMessage() . "\nContainer logs:\n{$logs}"); + throw new \RuntimeException('Failed to connect to Litebase server for integration tests: ' . $e->getMessage()); } }); afterAll(function () { - exec('docker compose -f ./tests/docker-compose.test.yml down -v'); - - // Delete the .litebase directory to clean up any persisted data - exec('rm -rf ./tests/.litebase'); + LitebaseContainer::stop(); }); describe('LitebasePDO', function () { diff --git a/tests/docker-compose.test.yml b/tests/docker-compose.test.yml deleted file mode 100644 index a6361e9..0000000 --- a/tests/docker-compose.test.yml +++ /dev/null @@ -1,22 +0,0 @@ -services: - database: - image: litebase/litebase - ports: - - "8888:8888" - volumes: - - ./.litebase:/home/litebase/data - environment: - - LITEBASE_CLUSTER_ID=cluster-1 - - LITEBASE_DEBUG=true - - LITEBASE_ENV=development - - LITEBASE_DATA_PATH=/home/litebase/data - - LITEBASE_STORAGE_NETWORK_PATH=/home/litebase/data/_network - - LITEBASE_PORT=8888 - - LITEBASE_ROOT_PASSWORD=password - - LITEBASE_ROOT_USERNAME=root - - LITEBASE_ENCRYPTION_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - - LITEBASE_STORAGE_OBJECT_MODE=local - - LITEBASE_STORAGE_TMP_PATH=/tmp - -volumes: - litebase_data: From 6b6143014b990e10eb5fb741fdf1c46399715f1a Mon Sep 17 00:00:00 2001 From: Thiery Laverdure Date: Mon, 10 Nov 2025 09:02:35 -0500 Subject: [PATCH 8/8] Ensure Litebase test container is removed before start --- tests/Integration/LitebaseContainer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Integration/LitebaseContainer.php b/tests/Integration/LitebaseContainer.php index ed512dc..d33a093 100644 --- a/tests/Integration/LitebaseContainer.php +++ b/tests/Integration/LitebaseContainer.php @@ -8,6 +8,9 @@ class LitebaseContainer { public static function start(): void { + // Remove any existing container first + shell_exec("docker rm -f litebase-test 2>/dev/null || true"); + $startCommand = "docker run -d --rm --name litebase-test -p 8888:8888 \\ -e LITEBASE_CLUSTER_ID=cluster-1 \\ -e LITEBASE_DATA_PATH=/tmp/data \\