1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 21:34:04 +00:00

Run all cached resolver/global cache tests with DatabaseCacheBootstrapper

This commit is contained in:
Samuel Štancl 2025-08-06 18:44:56 +02:00
parent 999caa65d9
commit b7df2ca436
4 changed files with 59 additions and 24 deletions

View file

@ -17,6 +17,9 @@ abstract class CachedTenantResolver implements TenantResolver
public function __construct(Application $app) public function __construct(Application $app)
{ {
// globalCache should generally not be injected, however in this case
// the class is always created from scratch when calling invalidateCache()
// meaning the global cache stores are also resolved from scratch.
$this->cache = $app->make('globalCache')->store(static::cacheStore()); $this->cache = $app->make('globalCache')->store(static::cacheStore());
} }

View file

@ -83,10 +83,6 @@ class TenancyServiceProvider extends ServiceProvider
return new Commands\Seed($app['db']); return new Commands\Seed($app['db']);
}); });
// todo0 check what happens if globalCache is injected - it may be
// problematic if it's injected before adjustCacheManagerUsing
// was used
$this->app->bind('globalCache', function ($app) { $this->app->bind('globalCache', function ($app) {
// We create a separate CacheManager to be used for "global" cache -- cache that // We create a separate CacheManager to be used for "global" cache -- cache that
// is always central, regardless of the current context. // is always central, regardless of the current context.

View file

@ -14,6 +14,8 @@ use Illuminate\Support\Facades\Route as RouteFacade;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper; use Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper;
use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\DatabaseCacheBootstrapper;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException; use Stancl\Tenancy\Contracts\TenantCouldNotBeIdentifiedException;
use Stancl\Tenancy\Events\TenancyEnded; use Stancl\Tenancy\Events\TenancyEnded;
use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Events\TenancyInitialized;
@ -23,6 +25,8 @@ use Stancl\Tenancy\Listeners\RevertToCentralContext;
use Stancl\Tenancy\Middleware\InitializeTenancyByPath; use Stancl\Tenancy\Middleware\InitializeTenancyByPath;
use Stancl\Tenancy\Resolvers\RequestDataTenantResolver; use Stancl\Tenancy\Resolvers\RequestDataTenantResolver;
use function Stancl\Tenancy\Tests\pest; use function Stancl\Tenancy\Tests\pest;
use function Stancl\Tenancy\Tests\withCacheTables;
use function Stancl\Tenancy\Tests\withTenantDatabases;
beforeEach($cleanup = function () { beforeEach($cleanup = function () {
Tenant::$extraCustomColumns = []; Tenant::$extraCustomColumns = [];
@ -112,11 +116,19 @@ test('cache is invalidated when the tenant is updated', function (string $resolv
// Only testing update here - presumably if this works, deletes (and other things we test here) // Only testing update here - presumably if this works, deletes (and other things we test here)
// will work as well. The main unique thing about this test is that it makes the change from // will work as well. The main unique thing about this test is that it makes the change from
// *within* the tenant context. // *within* the tenant context.
test('cache is invalidated when tenant is updated from within the tenant context', function (string $cacheBootstrapper) { test('cache is invalidated when tenant is updated from within the tenant context', function (string $cacheStore, array $bootstrappers) {
config(['tenancy.bootstrappers' => [$cacheBootstrapper]]); config([
'cache.default' => $cacheStore,
'tenancy.bootstrappers' => $bootstrappers,
]);
Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
Event::listen(TenancyEnded::class, RevertToCentralContext::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class);
if ($cacheStore === 'database') {
withCacheTables();
withTenantDatabases();
}
$resolver = PathTenantResolver::class; $resolver = PathTenantResolver::class;
$tenant = Tenant::create([$tenantModelColumn = tenantModelColumn(true) => 'acme']); $tenant = Tenant::create([$tenantModelColumn = tenantModelColumn(true) => 'acme']);
@ -150,9 +162,9 @@ test('cache is invalidated when tenant is updated from within the tenant context
expect(DB::getQueryLog())->not()->toBeEmpty(); // Cache was invalidated, so the tenant was retrieved from the DB expect(DB::getQueryLog())->not()->toBeEmpty(); // Cache was invalidated, so the tenant was retrieved from the DB
})->with([ })->with([
// todo0 test this with the database cache bootstrapper too? ['redis', [CacheTenancyBootstrapper::class]],
CacheTenancyBootstrapper::class, ['redis', [CacheTagsBootstrapper::class]],
CacheTagsBootstrapper::class, ['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]],
]); ]);
test('cache is invalidated when the tenant is deleted', function (string $resolver, bool $configureTenantModelColumn) { test('cache is invalidated when the tenant is deleted', function (string $resolver, bool $configureTenantModelColumn) {

View file

@ -29,8 +29,13 @@ beforeEach(function () {
withCacheTables(); withCacheTables();
}); });
test('global cache manager stores data in global cache', function (string $bootstrapper) { test('global cache manager stores data in global cache', function (string $store, array $bootstrappers) {
config(['tenancy.bootstrappers' => [$bootstrapper]]); config([
'cache.default' => $store,
'tenancy.bootstrappers' => $bootstrappers,
]);
if ($store === 'database') withTenantDatabases(true);
expect(cache('foo'))->toBe(null); expect(cache('foo'))->toBe(null);
GlobalCache::put('foo', 'bar'); GlobalCache::put('foo', 'bar');
@ -44,9 +49,16 @@ test('global cache manager stores data in global cache', function (string $boots
cache(['def' => 'ghi'], 10); cache(['def' => 'ghi'], 10);
expect(cache('def'))->toBe('ghi'); expect(cache('def'))->toBe('ghi');
// different stores, same underlying connection. the prefix is set ON THE STORE // different stores
expect(cache()->store()->getStore() !== GlobalCache::store()->getStore())->toBeTrue(); expect(cache()->store()->getStore() !== GlobalCache::store()->getStore())->toBeTrue();
expect(cache()->store()->getStore()->connection() === GlobalCache::store()->getStore()->connection())->toBeTrue(); if ($store === 'redis') {
// same underlying connection. the prefix is set ON THE STORE
expect(cache()->store()->getStore()->connection() === GlobalCache::store()->getStore()->connection())->toBeTrue();
} else {
// different connections
expect(cache()->store()->getStore()->getConnection()->getName())->toBe('tenant');
expect(GlobalCache::store()->getStore()->getConnection()->getName())->toBe('central');
}
tenancy()->end(); tenancy()->end();
expect(GlobalCache::get('abc'))->toBe('xyz'); expect(GlobalCache::get('abc'))->toBe('xyz');
@ -64,8 +76,9 @@ test('global cache manager stores data in global cache', function (string $boots
tenancy()->initialize($tenant1); tenancy()->initialize($tenant1);
expect(cache('def'))->toBe('ghi'); expect(cache('def'))->toBe('ghi');
})->with([ })->with([
CacheTagsBootstrapper::class, ['redis', [CacheTagsBootstrapper::class]],
CacheTenancyBootstrapper::class, ['redis', [CacheTenancyBootstrapper::class]],
['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]],
]); ]);
test('global cache facade is not persistent', function () { test('global cache facade is not persistent', function () {
@ -76,8 +89,6 @@ test('global cache facade is not persistent', function () {
expect(spl_object_id(GlobalCache::getFacadeRoot()))->not()->toBe($oldId); expect(spl_object_id(GlobalCache::getFacadeRoot()))->not()->toBe($oldId);
}); });
// todo0 add database cache bootstrapper to other tests
test('global cache is always central', function (string $store, array $bootstrappers, string $initialCentralCall) { test('global cache is always central', function (string $store, array $bootstrappers, string $initialCentralCall) {
config([ config([
'cache.default' => $store, 'cache.default' => $store,
@ -161,15 +172,27 @@ test('global cache is always central', function (string $store, array $bootstrap
'none', 'none',
]); ]);
test('the global_cache helper supports the same syntax as the cache helper', function (string $bootstrapper) { test('the global_cache helper supports the same syntax as the cache helper', function (string $store, array $bootstrappers) {
config(['tenancy.bootstrappers' => [$bootstrapper]]); config([
'cache.default' => $store,
'tenancy.bootstrappers' => $bootstrappers,
]);
if ($store === 'database') withTenantDatabases(true);
$tenant = Tenant::create(); $tenant = Tenant::create();
$tenant->enter(); $tenant->enter();
// different stores, same underlying connection. the prefix is set ON THE STORE // different stores
expect(cache()->store()->getStore() !== global_cache()->store()->getStore())->toBeTrue(); expect(cache()->store()->getStore() !== GlobalCache::store()->getStore())->toBeTrue();
expect(cache()->store()->getStore()->connection() === global_cache()->store()->getStore()->connection())->toBeTrue(); if ($store === 'redis') {
// same underlying connection. the prefix is set ON THE STORE
expect(cache()->store()->getStore()->connection() === global_cache()->store()->getStore()->connection())->toBeTrue();
} else {
// different connections
expect(cache()->store()->getStore()->getConnection()->getName())->toBe('tenant');
expect(global_cache()->store()->getStore()->getConnection()->getName())->toBe('central');
}
expect(cache('foo'))->toBe(null); // tenant cache is empty expect(cache('foo'))->toBe(null); // tenant cache is empty
@ -181,6 +204,7 @@ test('the global_cache helper supports the same syntax as the cache helper', fun
expect(cache('foo'))->toBe(null); // tenant cache is not affected expect(cache('foo'))->toBe(null); // tenant cache is not affected
})->with([ })->with([
CacheTagsBootstrapper::class, ['redis', [CacheTagsBootstrapper::class]],
CacheTenancyBootstrapper::class, ['redis', [CacheTenancyBootstrapper::class]],
['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]],
]); ]);