From f6d7ac13db6aacc75fd6c6e6a9275eea89b9a714 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 30 Jun 2026 06:16:05 +0200 Subject: [PATCH 1/5] Correct the "throw exception while DB_URL is set" test Set the url in the template connection config only after creating a tenant. Before, the url was set before creating a tenant, and because of that, the tenant couldn't be created in the first place. During CreateDatabase, a QueryException (`SQLSTATE[HY000] [1049] Unknown database 'bc.us-east-1.rds.amazonaws.com'`) was thrown, and the test didn't get to exercise the bootstrapper's code branch that should throw an exception if the db url is set --- .../DatabaseTenancyBootstrapperTest.php | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php index 637626721..ca292933a 100644 --- a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php +++ b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php @@ -12,7 +12,6 @@ use Stancl\Tenancy\Tests\Etc\Tenant; use Illuminate\Support\Str; use Illuminate\Support\Facades\DB; -use Illuminate\Database\QueryException; use Stancl\Tenancy\Database\TenantDatabaseManagers\MySQLDatabaseManager; use Stancl\Tenancy\Database\TenantDatabaseManagers\SQLiteDatabaseManager; use Stancl\Tenancy\Database\TenantDatabaseManagers\PostgreSQLDatabaseManager; @@ -129,24 +128,23 @@ ])->with('db_managers'); test('database tenancy bootstrapper throws an exception if DATABASE_URL is set', function (string|null $databaseUrl) { - config(['database.connections.central.url' => $databaseUrl]); - config(['tenancy.bootstrappers' => [DatabaseTenancyBootstrapper::class]]); Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { return $event->tenant; })->toListener()); - if ($databaseUrl) { - expect(fn() => Tenant::create())->toThrow(QueryException::class); - } else { - expect(function() { - $tenant1 = Tenant::create(); + $tenant = Tenant::create(); - pest()->artisan('tenants:migrate'); + pest()->artisan('tenants:migrate'); - tenancy()->initialize($tenant1); - })->not()->toThrow(Throwable::class); + config(['database.connections.central.url' => $databaseUrl]); + + if ($databaseUrl) { + expect(fn() => tenancy()->initialize($tenant)) + ->toThrow(Exception::class, 'The template connection must NOT have URL defined.'); + } else { + expect(fn() => tenancy()->initialize($tenant))->not()->toThrow(Throwable::class); } })->with(['abc.us-east-1.rds.amazonaws.com', null]); From c784a26ceea6076cce4279fd32f3f3a3b3513c80 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 30 Jun 2026 06:18:01 +0200 Subject: [PATCH 2/5] Reference the `DB_URL` env var instead of `DATABASE_URL` The env var got renamed in Laravel 11 to `DB_URL` --- src/Bootstrappers/DatabaseTenancyBootstrapper.php | 4 ++-- tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php | 2 +- tests/TestCase.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Bootstrappers/DatabaseTenancyBootstrapper.php b/src/Bootstrappers/DatabaseTenancyBootstrapper.php index 08b36f1d4..175d8b569 100644 --- a/src/Bootstrappers/DatabaseTenancyBootstrapper.php +++ b/src/Bootstrappers/DatabaseTenancyBootstrapper.php @@ -53,8 +53,8 @@ public function bootstrap(Tenant $tenant): void { /** @var TenantWithDatabase $tenant */ if (data_get($tenant->database()->getTemplateConnection(), 'url')) { - // The package works with individual parts of the database connection config, so DATABASE_URL is not supported. - // When DATABASE_URL is set, this bootstrapper can silently fail i.e. keep using the template connection's database URL + // The package works with individual parts of the database connection config, so DB_URL is not supported. + // When DB_URL is set, this bootstrapper can silently fail i.e. keep using the template connection's database URL // which takes precedence over individual segments of the connection config. This issue can be hard to debug as it can be // production-specific. Therefore, we throw an exception (that effectively blocks all tenant pages) to prevent incorrect DB use. throw new Exception('The template connection must NOT have URL defined. Specify the connection using individual parts instead of a database URL.'); diff --git a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php index ca292933a..c970accc1 100644 --- a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php +++ b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php @@ -127,7 +127,7 @@ 'hardening disabled' => false, ])->with('db_managers'); -test('database tenancy bootstrapper throws an exception if DATABASE_URL is set', function (string|null $databaseUrl) { +test('database tenancy bootstrapper throws an exception if DB_URL is set', function (string|null $databaseUrl) { config(['tenancy.bootstrappers' => [DatabaseTenancyBootstrapper::class]]); Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) { diff --git a/tests/TestCase.php b/tests/TestCase.php index cbc6f57ec..eb58a0d9c 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -131,7 +131,7 @@ protected function getEnvironmentSetUp($app) 'cache.stores.apc' => ['driver' => 'apc'], 'database.connections.central' => [ 'driver' => 'mysql', - 'url' => env('DATABASE_URL'), + 'url' => env('DB_URL'), 'host' => 'mysql', 'port' => env('DB_PORT', '3306'), 'database' => 'main', From e75ac3875170481bd2f76cd95cbbfaa19f00129a Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 30 Jun 2026 06:22:48 +0200 Subject: [PATCH 3/5] Grab the central connection name from the config in harden test Other tests grab the central connection from the config instead of hardcoding 'central'. Doing the same in 'harden prevents tenants from using the database of another tenant' for consistency. --- tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php index c970accc1..44229069d 100644 --- a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php +++ b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php @@ -115,7 +115,7 @@ expect(fn () => tenancy()->initialize($tenant))->toThrow(RuntimeException::class); // Connection should be reverted back to central - expect(DB::connection()->getName())->toBe('central'); + expect(DB::connection()->getName())->toBe(config('tenancy.database.central_connection')); } else { expect(fn() => tenancy()->initialize($tenant))->not()->toThrow(Throwable::class); From 184348924f5155794d715fef098f3f2e79cb7af1 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 30 Jun 2026 07:07:11 +0200 Subject: [PATCH 4/5] Delete redundant tenants:migrate from the DB_URL exception test --- tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php index 44229069d..3376a581f 100644 --- a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php +++ b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php @@ -136,8 +136,6 @@ $tenant = Tenant::create(); - pest()->artisan('tenants:migrate'); - config(['database.connections.central.url' => $databaseUrl]); if ($databaseUrl) { From 59ab773aa8aed13c4c9f25de040fcc74ab3e5075 Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 30 Jun 2026 07:12:12 +0200 Subject: [PATCH 5/5] Use `$centralConnection` variable in both hardening tests for consistency Decided to go with the variable assignment instead of inlining the config(...) call in the assertion since it's a bit more readable imo --- tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php index 3376a581f..4debea9e4 100644 --- a/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php +++ b/tests/Bootstrappers/DatabaseTenancyBootstrapperTest.php @@ -115,7 +115,9 @@ expect(fn () => tenancy()->initialize($tenant))->toThrow(RuntimeException::class); // Connection should be reverted back to central - expect(DB::connection()->getName())->toBe(config('tenancy.database.central_connection')); + $centralConnection = config('tenancy.database.central_connection'); + + expect(DB::connection()->getName())->toBe($centralConnection); } else { expect(fn() => tenancy()->initialize($tenant))->not()->toThrow(Throwable::class);