From a0f4126318f0043b399d9d44556be5dcd9dc349b Mon Sep 17 00:00:00 2001 From: lukinovec Date: Tue, 7 Jan 2025 17:32:03 +0100 Subject: [PATCH] Add test for syncable models with global scopes --- tests/ResourceSyncingTest.php | 85 +++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/tests/ResourceSyncingTest.php b/tests/ResourceSyncingTest.php index 34a6ba14..399bf994 100644 --- a/tests/ResourceSyncingTest.php +++ b/tests/ResourceSyncingTest.php @@ -43,6 +43,9 @@ use Stancl\Tenancy\ResourceSyncing\Events\CentralResourceDetachedFromTenant; use Stancl\Tenancy\Tests\Etc\ResourceSyncing\CentralUser as BaseCentralUser; use Stancl\Tenancy\ResourceSyncing\CentralResourceNotAvailableInPivotException; use Stancl\Tenancy\ResourceSyncing\Events\SyncedResourceSavedInForeignDatabase; +use Illuminate\Database\Eloquent\Scope; +use Illuminate\Database\Eloquent\Attributes\ScopedBy; +use Illuminate\Database\QueryException; beforeEach(function () { config(['tenancy.bootstrappers' => [ @@ -107,6 +110,28 @@ afterEach(function () { UpdateOrCreateSyncedResource::$scopeGetModelQuery = null; }); +test('multiple tenants can have users synced to a central resource', function() { + $tenants = [Tenant::create(), Tenant::create(), Tenant::create()]; + migrateUsersTableForTenants(); + + tenancy()->runForMultiple($tenants, function () { + // Create a user in tenant DB + TenantUser::create([ + 'global_id' => 'acme', + 'name' => Str::random(), + 'email' => 'john@localhost', + 'password' => 'secret', + 'role' => 'commenter', + ]); + }); + + // Create the same user in tenant DB + $users = CentralUser::where(['global_id' => 'acme'])->get(); + + expect($users)->toHaveCount(1); + expect($users->first()->global_id)->toBe('acme'); +}); + test('SyncedResourceSaved event gets triggered when resource gets created or when its synced attributes get updated', function () { Event::fake(SyncedResourceSaved::class); @@ -1172,6 +1197,53 @@ test('resource creation works correctly when central resource provides defaults expect($centralUser->foo)->toBe('bar'); }); +test('resource syncing works correctly when using a global scope on a tenant model', function(bool $scopeGetModelQuery) { + if ($scopeGetModelQuery) { + UpdateOrCreateSyncedResource::$scopeGetModelQuery = function (Builder $query) { + if ($query->getModel()->hasGlobalScope(TestingScope::class)) { + $query->withoutGlobalScope(TestingScope::class); + } + }; + } + + $centralUser = CentralUser::firstOrCreate( + ['email' => 'user@test.cz'], + ['name' => 'User', 'password' => bcrypt('****'), 'role' => 'admin'] + ); + + [$tenant1, $tenant2] = createTenantsAndRunMigrations(); + + tenancy()->initialize($tenant1); + + TenantUserWithScope::create([ + 'global_id' => $centralUser->global_id, + 'name' => $centralUser->name, + 'email' => $centralUser->email, + 'password' => $centralUser->password, + 'role' => 'admin' + ]); + + tenancy()->end(); + + tenancy()->initialize($tenant2); + + if (! $scopeGetModelQuery) { + pest()->expectException(QueryException::class); + pest()->expectExceptionMessage('Duplicate entry'); + } + + TenantUserWithScope::create([ + 'global_id' => $centralUser->global_id, + 'name' => $centralUser->name, + 'email' => $centralUser->email, + 'password' => $centralUser->password, + 'role' => 'admin' + ]); +})->with([ + true, + false, +]); + /** * Create two tenants and run migrations for those tenants. * @@ -1243,6 +1315,11 @@ class TenantUser extends BaseTenantUser } } +#[ScopedBy([TestingScope::class])] +class TenantUserWithScope extends TenantUser +{ +} + class TenantPivot extends BasePivot { public $table = 'tenant_users'; @@ -1344,3 +1421,11 @@ class TenantCompany extends Model implements Syncable ]; } } + +class TestingScope implements Scope +{ + public function apply(Builder $builder, Model $model): void + { + $builder->whereNull('name'); + } +}