From ab5e67fc34fb99bfb8ce2d8d779aba3bd8b6ac25 Mon Sep 17 00:00:00 2001 From: Samuel Stancl Date: Fri, 1 May 2026 21:27:21 +0200 Subject: [PATCH] add tests --- tests/DatabasePreparationTest.php | 92 +++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/DatabasePreparationTest.php b/tests/DatabasePreparationTest.php index 1f3a4f09..322539b9 100644 --- a/tests/DatabasePreparationTest.php +++ b/tests/DatabasePreparationTest.php @@ -2,17 +2,27 @@ declare(strict_types=1); +use Illuminate\Database\QueryException; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Schema; use Stancl\JobPipeline\JobPipeline; use Stancl\Tenancy\Events\TenantCreated; +use Stancl\Tenancy\Events\TenantDeleted; use Stancl\Tenancy\Jobs\CreateDatabase; +use Stancl\Tenancy\Jobs\DeleteDatabase; use Stancl\Tenancy\Jobs\MigrateDatabase; use Stancl\Tenancy\Jobs\SeedDatabase; use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Foundation\Auth\User as Authenticable; use Stancl\Tenancy\Tests\Etc\TestSeeder; +beforeEach($cleanup = function () { + DeleteDatabase::$ignoreFailures = false; + DeleteDatabase::$skipWhenCreateDatabaseIsFalse = true; +}); + +afterEach($cleanup); + test('database can be created after tenant creation', function () { config(['tenancy.database.template_tenant_connection' => 'mysql']); @@ -82,6 +92,88 @@ test('custom job can be added to the pipeline', function () { }); }); +test('database can be deleted after tenant deletion', function () { + Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { + return $event->tenant; + })->toListener()); + + Event::listen(TenantDeleted::class, JobPipeline::make([DeleteDatabase::class])->send(function (TenantDeleted $event) { + return $event->tenant; + })->toListener()); + + $tenant = Tenant::create(); + $manager = $tenant->database()->manager(); + + expect($manager->databaseExists($tenant->database()->getName()))->toBeTrue(); + + $tenant->delete(); + + expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); +}); + +test('database deletion is skipped when create_database is false', function (bool $skipWhenCreateDatabaseIsFalse) { + Event::listen(TenantDeleted::class, JobPipeline::make([DeleteDatabase::class])->send(function (TenantDeleted $event) { + return $event->tenant; + })->toListener()); + + // create_database=false means no DB is created (e.g. tenant uses a pre-existing DB) + // On deletion, DeleteDatabase should skip rather than attempting DROP DATABASE on a non-existent DB + $tenant = Tenant::create(['tenancy_create_database' => false, 'tenancy_db_name' => 'non_existing_db']); + + $manager = $tenant->database()->manager(); + expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); + + DeleteDatabase::$skipWhenCreateDatabaseIsFalse = $skipWhenCreateDatabaseIsFalse; + + if ($skipWhenCreateDatabaseIsFalse) { + $tenant->delete(); // no exception + } else { + expect(fn () => $tenant->delete())->toThrow(QueryException::class, "database doesn't exist"); + } + + expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); +})->with([true, false]); + +test('database deletion failures are swallowed when ignoreFailures is true', function () { + Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { + return $event->tenant; + })->toListener()); + + Event::listen(TenantDeleted::class, JobPipeline::make([DeleteDatabase::class])->send(function (TenantDeleted $event) { + return $event->tenant; + })->toListener()); + + DeleteDatabase::$ignoreFailures = true; + + $tenant = Tenant::create(); + $manager = $tenant->database()->manager(); + expect($manager->databaseExists($tenant->database()->getName()))->toBeTrue(); + + $manager->deleteDatabase($tenant); // manually delete so the job fails + expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); + + $tenant->delete(); // would throw without $ignoreFailures +}); + +test('database deletion failures are rethrown when ignoreFailures is false', function () { + Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { + return $event->tenant; + })->toListener()); + + Event::listen(TenantDeleted::class, JobPipeline::make([DeleteDatabase::class])->send(function (TenantDeleted $event) { + return $event->tenant; + })->toListener()); + + $tenant = Tenant::create(); + $manager = $tenant->database()->manager(); + expect($manager->databaseExists($tenant->database()->getName()))->toBeTrue(); + + $manager->deleteDatabase($tenant); // manually delete so the job fails + expect($manager->databaseExists($tenant->database()->getName()))->toBeFalse(); + + expect(fn () => $tenant->delete())->toThrow(QueryException::class, "database doesn't exist"); +}); + class User extends Authenticable { protected $guarded = [];