1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 20:34:03 +00:00
tenancy/tests/Bootstrappers/DatabaseSessionBootstrapperTest.php
Samuel Štancl eecf6f21c8
Cache prefixing logic rewrite, session scoping improvements, tests refactor (#43)
* Run cache tests on all supported drivers

* update ci healthcheck for memcached

* remove memcached healthcheck

* fix typos in test comments, expand internal.md [ci skip]

* add empty line [ci skip]

* switch to using $store->setPrefix()

* add dynamodb

* refactor try-finally to try-catch

* remove unnecessary clearResolvedInstances() call

* add dual Cache:: and cache() assertions

* add apc

* Flush APCu cache in test setup

* Revert "add dual Cache:: and cache() assertions"

This reverts commit a0bab162fbe2dd0d25e7056ceca4fb7ce54efc77.

* phpstan fix

* Add logic for scoping 'file' disks to FilesystemTenancyBootstrapper

* minor changes, add todos

* refactor how the session.connection is used in the DB session bootstrapper

* add session forgery prevention logic to the db session bootstrapper

* only use the fs bootstrapper for file disk in 'cache data is separated' dataset

* minor session scoping test changes

* Add session scoping logic to FilesystemTenancyBootstrapper, correctly update disk roots even with storage_path_tenancy disabled

* Fix code style (php-cs-fixer)

* update docblock

* make not-null check more explicit

* separate bootstrapper tests, fix swapped test names for two tests

* refactor cache bootstrapper tests

* resolve global cache todo

* expand tests: session separation tests, more filesystem separation assertions; change prefix_base-type config keys to templates/formats

* add apc session scoping test, various session separation bugfixes

* phpstan + minor logic fixes

* prefix_format -> prefix

* fix database session separation test

* revert composer.json changes, update laravel dependencies to expected next release

* only run session scoping logic in cache bootstrapper for redis, memcached, dynamodb, apc; update gitattributes

* tenancy.central_domains -> tenancy.identification.central_domains

* db session separation test: add datasets

---------

Co-authored-by: PHP CS Fixer <phpcsfixer@example.com>
2024-04-09 20:40:27 +02:00

145 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
use Stancl\JobPipeline\JobPipeline;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\DatabaseSessionBootstrapper;
use Stancl\Tenancy\Events;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Jobs\CreateDatabase;
use Stancl\Tenancy\Listeners;
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
use Stancl\Tenancy\Tests\Etc\Tenant;
/**
* This collection of regression tests verifies that SessionTenancyBootstrapper
* fully fixes the issue described here https://github.com/archtechx/tenancy/issues/547
*
* This means: using the DB session driver and:
* 1) switching to the central context from tenant requests, OR
* 2) switching to the tenant context from central requests
*/
beforeEach(function () {
config(['session.driver' => 'database']);
config(['tenancy.bootstrappers' => [DatabaseTenancyBootstrapper::class]]);
Event::listen(
TenantCreated::class,
JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
return $event->tenant;
})->toListener()
);
Event::listen(Events\TenancyInitialized::class, Listeners\BootstrapTenancy::class);
Event::listen(Events\TenancyEnded::class, Listeners\RevertToCentralContext::class);
// Sessions table for central database
pest()->artisan('migrate', [
'--path' => __DIR__ . '/../Etc/session_migrations',
'--realpath' => true,
])->assertExitCode(0);
});
test('central helper can be used in tenant requests', function (bool $enabled, bool $shouldThrow) {
if ($enabled) {
config()->set(
'tenancy.bootstrappers',
array_merge(config('tenancy.bootstrappers'), [DatabaseSessionBootstrapper::class]),
);
}
$tenant = Tenant::create();
$tenant->domains()->create(['domain' => 'foo.localhost']);
// run for tenants
pest()->artisan('tenants:migrate', [
'--path' => __DIR__ . '/../Etc/session_migrations',
'--realpath' => true,
])->assertExitCode(0);
Route::middleware(['web', InitializeTenancyByDomain::class])->get('/bar', function () {
session(['message' => 'tenant session']);
tenancy()->central(function () {
return 'central results';
});
return session('message');
});
// We initialize tenancy before making the request, since sessions work a bit differently in tests
// and we need the DB session handler to use the tenant connection (as it does in a real app on tenant requests).
tenancy()->initialize($tenant);
try {
$this->withoutExceptionHandling()
->get('http://foo.localhost/bar')
->assertOk()
->assertSee('tenant session');
if ($shouldThrow) {
pest()->fail('Exception not thrown');
}
} catch (Throwable $e) {
if ($shouldThrow) {
pest()->assertTrue(true); // empty assertion to make the test pass
} else {
pest()->fail('Exception thrown: ' . $e->getMessage());
}
}
})->with([
['enabled' => false, 'shouldThrow' => true],
['enabled' => true, 'shouldThrow' => false],
]);
test('tenant run helper can be used on central requests', function (bool $enabled, bool $shouldThrow) {
if ($enabled) {
config()->set(
'tenancy.bootstrappers',
array_merge(config('tenancy.bootstrappers'), [DatabaseSessionBootstrapper::class]),
);
}
Tenant::create();
// run for tenants
pest()->artisan('tenants:migrate', [
'--path' => __DIR__ . '/../Etc/session_migrations',
'--realpath' => true,
])->assertExitCode(0);
Route::middleware(['web'])->get('/bar', function () {
session(['message' => 'central session']);
Tenant::first()->run(function () {
return 'tenant results';
});
return session('message');
});
try {
$this->withoutExceptionHandling()
->get('http://localhost/bar')
->assertOk()
->assertSee('central session');
if ($shouldThrow) {
pest()->fail('Exception not thrown');
}
} catch (Throwable $e) {
if ($shouldThrow) {
pest()->assertTrue(true); // empty assertion to make the test pass
} else {
pest()->fail('Exception thrown: ' . $e->getMessage());
}
}
})->with([
['enabled' => false, 'shouldThrow' => true],
['enabled' => true, 'shouldThrow' => false],
]);