diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7d256f42..ee451d20 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,3 +43,9 @@ If you need to rebuild the container for any reason (e.g. a change in `Dockerfil ## PHPStan Use `composer phpstan` to run our phpstan suite. + +## PhpStorm + +Create `.env` with `PROJECT_PATH=/full/path/to/this/directory`. Configure a Docker-based interpreter for tests (with exec, not run). + +If you want to use XDebug, use `composer docker-rebuild-with-xdebug`. diff --git a/docker-compose.yml b/docker-compose.yml index 699504fe..2d7a6e9f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,8 +20,8 @@ services: dynamodb: condition: service_healthy volumes: - - .:$PWD:cached - working_dir: $PWD + - .:${PROJECT_PATH:-$PWD}:cached + working_dir: ${PROJECT_PATH:-$PWD} environment: DOCKER: 1 DB_PASSWORD: password diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index 72ba5ebd..7972bbb2 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -11,6 +11,11 @@ use Stancl\Tenancy\Listeners\BootstrapTenancy; use Stancl\Tenancy\Listeners\RevertToCentralContext; use Stancl\Tenancy\Bootstrappers\CacheTagsBootstrapper; use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper; +use Stancl\Tenancy\Bootstrappers\DatabaseCacheBootstrapper; +use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper; + +use function Stancl\Tenancy\Tests\withCacheTables; +use function Stancl\Tenancy\Tests\withTenantDatabases; beforeEach(function () { config([ @@ -20,25 +25,27 @@ beforeEach(function () { Event::listen(TenancyInitialized::class, BootstrapTenancy::class); Event::listen(TenancyEnded::class, RevertToCentralContext::class); + + withCacheTables(); }); test('global cache manager stores data in global cache', function (string $bootstrapper) { config(['tenancy.bootstrappers' => [$bootstrapper]]); expect(cache('foo'))->toBe(null); - GlobalCache::put(['foo' => 'bar'], 1); + GlobalCache::put('foo', 'bar'); expect(GlobalCache::get('foo'))->toBe('bar'); $tenant1 = Tenant::create(); tenancy()->initialize($tenant1); expect(GlobalCache::get('foo'))->toBe('bar'); - GlobalCache::put(['abc' => 'xyz'], 1); + GlobalCache::put('abc', 'xyz'); cache(['def' => 'ghi'], 10); expect(cache('def'))->toBe('ghi'); // different stores, same underlying connection. the prefix is set ON THE STORE - expect(cache()->store()->getStore() === GlobalCache::store()->getStore())->toBeFalse(); + expect(cache()->store()->getStore() !== GlobalCache::store()->getStore())->toBeTrue(); expect(cache()->store()->getStore()->connection() === GlobalCache::store()->getStore()->connection())->toBeTrue(); tenancy()->end(); @@ -61,6 +68,80 @@ test('global cache manager stores data in global cache', function (string $boots CacheTenancyBootstrapper::class, ]); +test('global cache is always central', function (string $store, array $bootstrappers, string $initialCentralCall) { + config([ + 'cache.default' => $store, + 'tenancy.bootstrappers' => $bootstrappers, + ]); + + if ($store === 'database') { + withTenantDatabases(true); + } + + // todo@samuel maybe add assertions about the DB connection used by: + // 1. global_cache()->store()->getStore()->getConnection()->getName() + // 2. cache()->store()->getStore()->getConnection()->getName() + // 3. GlobalCache::store()->getStore()->getConnection()->getName() + // and possibly Redis as well (after we integrate these data sets into the other tests here) + + if ($initialCentralCall === 'helper') { + global_cache()->put('central-helper', true); + } else if ($initialCentralCall === 'facade') { + GlobalCache::put('central-facade', true); + } else if ($initialCentralCall === 'both') { + global_cache()->put('central-helper', true); + GlobalCache::put('central-facade', true); + } + + $tenant = Tenant::create(); + $tenant->enter(); + + // Here we use both the helper and the facade to ensure the value is accessible via either one + if ($initialCentralCall === 'helper') { + expect(global_cache('central-helper'))->toBe(true); + expect(GlobalCache::get('central-helper'))->toBe(true); + } else if ($initialCentralCall === 'facade') { + expect(global_cache('central-facade'))->toBe(true); + expect(GlobalCache::get('central-facade'))->toBe(true); + } else if ($initialCentralCall === 'both') { + expect(global_cache('central-helper'))->toBe(true); + expect(GlobalCache::get('central-helper'))->toBe(true); + expect(global_cache('central-facade'))->toBe(true); + expect(GlobalCache::get('central-facade'))->toBe(true); + } + + global_cache()->put('tenant-helper', true); + GlobalCache::put('tenant-facade', true); + + tenancy()->end(); + + expect(global_cache('tenant-helper'))->toBe(true); + expect(GlobalCache::get('tenant-helper'))->toBe(true); + expect(global_cache('tenant-facade'))->toBe(true); + expect(GlobalCache::get('tenant-facade'))->toBe(true); + + if ($initialCentralCall === 'helper') { + expect(GlobalCache::get('central-helper'))->toBe(true); + } else if ($initialCentralCall === 'facade') { + expect(global_cache('central-facade'))->toBe(true); + } else if ($initialCentralCall === 'both') { + expect(global_cache('central-helper'))->toBe(true); + expect(GlobalCache::get('central-helper'))->toBe(true); + expect(global_cache('central-facade'))->toBe(true); + expect(GlobalCache::get('central-facade'))->toBe(true); + } + +})->with([ + ['redis', [CacheTagsBootstrapper::class]], + ['redis', [CacheTenancyBootstrapper::class]], + ['database', [DatabaseTenancyBootstrapper::class, DatabaseCacheBootstrapper::class]], +])->with([ + 'helper', + 'facade', + 'both', + 'none', +]); + test('the global_cache helper supports the same syntax as the cache helper', function (string $bootstrapper) { config(['tenancy.bootstrappers' => [$bootstrapper]]); @@ -68,7 +149,7 @@ test('the global_cache helper supports the same syntax as the cache helper', fun $tenant->enter(); // different stores, same underlying connection. the prefix is set ON THE STORE - expect(cache()->store()->getStore() === global_cache()->store()->getStore())->toBeFalse(); + expect(cache()->store()->getStore() !== global_cache()->store()->getStore())->toBeTrue(); expect(cache()->store()->getStore()->connection() === global_cache()->store()->getStore()->connection())->toBeTrue(); expect(cache('foo'))->toBe(null); // tenant cache is empty