mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-12 08:24:04 +00:00
* Add readied tenants Add config for readied tenants Add `create` and `clear` command Add Readied scope and static functions Add tests * Fix initialize function name * Add readied events * Fix readied column cast * Laravel 6 compatible * Add readied scope tests * Rename config from include_in_scope to include_in_queries * Change terminology to pending * Update CreatePendingTenants.php * Laravel 6 compatible * Update CreatePendingTenants.php * runForMultiple can scope pending tenants * Fix issues * Code and comment style improvements * Change 'tenant' to 'tenants' in command signature * Fix code style (php-cs-fixer) * Rename variables in CreatePendingTenants * Remove withPending from runForMultiple * Update tenants option trait * Update command that use tenants * Fix code style (php-cs-fixer) * Improve getTenants condition * Update config comments * Minor config comment corrections * Grammar fix * Update comments and naming * Correct comments * Improve writing * Remove pending tenant clearing time constraints * Allow using only one time constraint for clearing the pending tenants * phpunit to pest * Fix code style (php-cs-fixer) * Fix code style (php-cs-fixer) * [4.x] Optionally delete storage after tenant deletion (#938) * Add test for deleting storage after tenant deletion * Save `storage_path()` in a variable after initializing tenant in test Co-authored-by: Samuel Štancl <samuel.stancl@gmail.com> * Add DeleteTenantStorage listener * Update test name * Remove storage deletion config key * Remove tenant storage deletion events * Move tenant storage deletion to the DeletingTenant event Co-authored-by: Samuel Štancl <samuel.stancl@gmail.com> * [4.x] Finish incomplete and missing tests (#947) * complete test sqlite manager customize path * complete test seed command works * complete uniqe exists test * Update SingleDatabaseTenancyTest.php * refactor the ternary into if condition * custom path * simplify if condition * random dir name * Update SingleDatabaseTenancyTest.php * Update CommandsTest.php * prefix random DB name with custom_ Co-authored-by: Samuel Štancl <samuel@archte.ch> * [4.x] Add batch tenancy queue bootstrapper (#874) * exclude master from CI * Add batch tenancy queue bootstrapper * add test case * skip tests for old versions * variable docblocks * use Laravel's connection getter and setter * convert test to pest * bottom space * singleton regis in TestCase * Update src/Bootstrappers/BatchTenancyBootstrapper.php Co-authored-by: Samuel Štancl <samuel@archte.ch> * convert batch class resolution to property level * enabled BatchTenancyBootstrapper by default * typehint DatabaseBatchRepository * refactore name * DI DB manager * typehint * Update config.php * use initialize() twice without end()ing tenancy to assert that previousConnection logic works correctly Co-authored-by: Samuel Štancl <samuel.stancl@gmail.com> Co-authored-by: Abrar Ahmad <abrar.dev99@gmail.com> Co-authored-by: Samuel Štancl <samuel@archte.ch> * [4.x] Storage::url() support (modified #689) (#909) * This adds support for tenancy aware Storage::url() method * Trigger CI build * Fixed Link command for Laravel v6, added StorageLink Events, more StorageLink tests, added RemoveStorageSymlinks Job, added Storage Jobs to TenancyServiceProvider stub, renamed misleading config example. * Fix typo * Fix code style (php-cs-fixer) * Update config comments * Format code in Link command, make writing more concise * Change "symLinks" to "symlinks" * Refactor Link command * Fix test name typo * Test fetching files using the public URL * Extract Link command logic into actions * Fix code style (php-cs-fixer) * Check if closure is null in CreateStorageSymlinksAction * Stop using command terminology in CreateStorageSymlinksAction * Separate the Storage::url() test cases * Update url_override comments * Remove afterLink closures, add types, move actions, add usage explanation to the symlink trait * Fix code style (php-cs-fixer) * Update public storage URL test * Fix issue with using str() * Improve url_override comment, add todos * add todo comment * fix docblock style * Add link command tests back * Add types to $tenants in the action handle() methods * Fix typo, update variable name formatting * Add tests for the symlink actions * Change possibleTenantSymlinks not to prefix the paths twice while tenancy is initialized * Fix code style (php-cs-fixer) * Stop testing storage directory existence in symlink test * Don't specify full namespace for Tenant model annotation * Don't specify full namespace in ActionTest * Remove "change to DI" todo * Remove possibleTenantSymlinks return annotation * Remove symlink-related jobs, instantiate and use actions * Revert "Remove symlink-related jobs, instantiate and use actions" This reverts commit547440c887. * Add a comment line about the possible tenant symlinks * Correct storagePath and publicPath variables * Revert "Correct storagePath and publicPath variables" This reverts commite3aa8e2086. * add a todo Co-authored-by: Martin Vlcek <martin@dontfreakout.eu> Co-authored-by: lukinovec <lukinovec@gmail.com> Co-authored-by: PHP CS Fixer <phpcsfixer@example.com> * Use HasTenantOptions in Link * Correct the tenant order in Run command * Fix code style (php-cs-fixer) * Fix formatting issue * Add missing imports * Fix code style (php-cs-fixer) * Use HasTenantOptions instead of the old trait name in Up/Down commands * Fix test name typo * Remove redundant passing of $withPending to runForMultiple in TenantCollection's runForEach * Make `with-pending` default to `config('tenancy.pending.include_in_queries')` in HasTenantOptions * Make `createPending()` return the created tenant * Fix code style (php-cs-fixer) * Remove tenant ordering * Fix code style (php-cs-fixer) * Remove duplicate tenancy bootstrappers config setting * Add and use getWithPendingOption method * Fix code style (php-cs-fixer) * Add optionNotPassedValue property * Test using --with-pending and the include_in_queries config value * Make with-pending VALUE_NONE * use plural in test names * fix test names * add pullPendingTenantFromPool * Add docblock type * Import commands * Fix code style (php-cs-fixer) * Move pending tenant tests to a more appropriate file * Delete queuetest from gitignore * Delete queuetest file * Add queuetest to gitignore * Rename pullPendingTenant to pullPending and don't pass bool to that method * Add a test that checks if pulling a pending tenant removes it from the pool * bump stancl/virtualcolumn to ^1.3 * Update pending tenant pulling test * Dynamically get columns for pending queries * Dynamically get virtual column name in ClearPendingTenants * Fix ClearPendingTenants bug * Make test name more accurate * Update test name * add a todo * Update include in queries test name * Remove `Tenant::query()->delete()` from pending tenant check test * Rename the pending tenant check test name * Update HasPending.php * fix all() call * code style * all() -> get() * Remove redundant `Tenant::all()` call Co-authored-by: j.stein <joristein@gmail.com> Co-authored-by: lukinovec <lukinovec@gmail.com> Co-authored-by: PHP CS Fixer <phpcsfixer@example.com> Co-authored-by: Abrar Ahmad <abrar.dev99@gmail.com> Co-authored-by: Riley19280 <rileyaven88@gmail.com> Co-authored-by: Martin Vlcek <martin@dontfreakout.eu>
209 lines
6.3 KiB
PHP
209 lines
6.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Illuminate\Support\Facades\Artisan;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Stancl\Tenancy\Commands\ClearPendingTenants;
|
|
use Stancl\Tenancy\Commands\CreatePendingTenants;
|
|
use Stancl\Tenancy\Events\CreatingPendingTenant;
|
|
use Stancl\Tenancy\Events\PendingTenantCreated;
|
|
use Stancl\Tenancy\Events\PendingTenantPulled;
|
|
use Stancl\Tenancy\Events\PullingPendingTenant;
|
|
use Stancl\Tenancy\Tests\Etc\Tenant;
|
|
|
|
test('tenants are correctly identified as pending', function (){
|
|
Tenant::createPending();
|
|
|
|
expect(Tenant::onlyPending()->count())->toBe(1);
|
|
|
|
Tenant::onlyPending()->first()->update([
|
|
'pending_since' => null
|
|
]);
|
|
|
|
expect(Tenant::onlyPending()->count())->toBe(0);
|
|
});
|
|
|
|
test('pending trait adds query scopes', function () {
|
|
Tenant::createPending();
|
|
Tenant::create();
|
|
Tenant::create();
|
|
|
|
expect(Tenant::onlyPending()->count())->toBe(1)
|
|
->and(Tenant::withPending(true)->count())->toBe(3)
|
|
->and(Tenant::withPending(false)->count())->toBe(2)
|
|
->and(Tenant::withoutPending()->count())->toBe(2);
|
|
|
|
});
|
|
|
|
test('pending tenants can be created and deleted using commands', function () {
|
|
config(['tenancy.pending.count' => 4]);
|
|
|
|
Artisan::call(CreatePendingTenants::class);
|
|
|
|
expect(Tenant::onlyPending()->count())->toBe(4);
|
|
|
|
Artisan::call(ClearPendingTenants::class);
|
|
|
|
expect(Tenant::onlyPending()->count())->toBe(0);
|
|
});
|
|
|
|
test('CreatePendingTenants command can have an older than constraint', function () {
|
|
config(['tenancy.pending.count' => 2]);
|
|
|
|
Artisan::call(CreatePendingTenants::class);
|
|
|
|
tenancy()->model()->query()->onlyPending()->first()->update([
|
|
'pending_since' => now()->subDays(5)->timestamp
|
|
]);
|
|
|
|
Artisan::call('tenants:pending-clear --older-than-days=2');
|
|
|
|
expect(Tenant::onlyPending()->count())->toBe(1);
|
|
});
|
|
|
|
test('CreatePendingTenants command cannot run with both time constraints', function () {
|
|
pest()->artisan('tenants:pending-clear --older-than-days=2 --older-than-hours=2')
|
|
->assertFailed();
|
|
});
|
|
|
|
test('CreatePendingTenants commands all option overrides any config constraints', function () {
|
|
Tenant::createPending();
|
|
Tenant::createPending();
|
|
|
|
tenancy()->model()->query()->onlyPending()->first()->update([
|
|
'pending_since' => now()->subDays(10)
|
|
]);
|
|
|
|
config(['tenancy.pending.older_than_days' => 4]);
|
|
|
|
Artisan::call(ClearPendingTenants::class, [
|
|
'--all' => true
|
|
]);
|
|
|
|
expect(Tenant::onlyPending()->count())->toBe(0);
|
|
});
|
|
|
|
test('tenancy can check if there are any pending tenants', function () {
|
|
expect(Tenant::onlyPending()->exists())->toBeFalse();
|
|
|
|
Tenant::createPending();
|
|
|
|
expect(Tenant::onlyPending()->exists())->toBeTrue();
|
|
});
|
|
|
|
test('tenancy can pull a pending tenant', function () {
|
|
Tenant::createPending();
|
|
|
|
expect(Tenant::pullPendingFromPool())->toBeInstanceOf(Tenant::class);
|
|
});
|
|
|
|
test('pulling a tenant from the pending tenant pool removes it from the pool', function () {
|
|
Tenant::createPending();
|
|
|
|
expect(Tenant::onlyPending()->count())->toEqual(1);
|
|
|
|
Tenant::pullPendingFromPool();
|
|
|
|
expect(Tenant::onlyPending()->count())->toEqual(0);
|
|
});
|
|
|
|
test('a new tenant gets created while pulling a pending tenant if the pending pool is empty', function () {
|
|
expect(Tenant::withPending()->get()->count())->toBe(0); // All tenants
|
|
|
|
Tenant::pullPending();
|
|
|
|
expect(Tenant::withPending()->get()->count())->toBe(1); // All tenants
|
|
});
|
|
|
|
test('pending tenants are included in all queries based on the include_in_queries config', function () {
|
|
Tenant::createPending();
|
|
|
|
config(['tenancy.pending.include_in_queries' => false]);
|
|
|
|
expect(Tenant::all()->count())->toBe(0);
|
|
|
|
config(['tenancy.pending.include_in_queries' => true]);
|
|
|
|
expect(Tenant::all()->count())->toBe(1);
|
|
});
|
|
|
|
test('pending events are dispatched', function () {
|
|
Event::fake([
|
|
CreatingPendingTenant::class,
|
|
PendingTenantCreated::class,
|
|
PullingPendingTenant::class,
|
|
PendingTenantPulled::class,
|
|
]);
|
|
|
|
Tenant::createPending();
|
|
|
|
Event::assertDispatched(CreatingPendingTenant::class);
|
|
Event::assertDispatched(PendingTenantCreated::class);
|
|
|
|
Tenant::pullPending();
|
|
|
|
Event::assertDispatched(PullingPendingTenant::class);
|
|
Event::assertDispatched(PendingTenantPulled::class);
|
|
});
|
|
|
|
test('commands do not run for pending tenants if tenancy.pending.include_in_queries is false and the with pending option does not get passed', function() {
|
|
config(['tenancy.pending.include_in_queries' => false]);
|
|
|
|
$tenants = collect([
|
|
Tenant::create(),
|
|
Tenant::create(),
|
|
Tenant::createPending(),
|
|
Tenant::createPending(),
|
|
]);
|
|
|
|
pest()->artisan('tenants:migrate --with-pending');
|
|
|
|
$artisan = pest()->artisan("tenants:run 'foo foo --b=bar --c=xyz'");
|
|
|
|
$pendingTenants = $tenants->filter->pending();
|
|
$readyTenants = $tenants->reject->pending();
|
|
|
|
$pendingTenants->each(fn ($tenant) => $artisan->doesntExpectOutputToContain("Tenant: {$tenant->getTenantKey()}"));
|
|
$readyTenants->each(fn ($tenant) => $artisan->expectsOutputToContain("Tenant: {$tenant->getTenantKey()}"));
|
|
|
|
$artisan->assertExitCode(0);
|
|
});
|
|
|
|
test('commands run for pending tenants too if tenancy.pending.include_in_queries is true', function() {
|
|
config(['tenancy.pending.include_in_queries' => true]);
|
|
|
|
$tenants = collect([
|
|
Tenant::create(),
|
|
Tenant::create(),
|
|
Tenant::createPending(),
|
|
Tenant::createPending(),
|
|
]);
|
|
|
|
pest()->artisan('tenants:migrate --with-pending');
|
|
|
|
$artisan = pest()->artisan("tenants:run 'foo foo --b=bar --c=xyz'");
|
|
|
|
$tenants->each(fn ($tenant) => $artisan->expectsOutputToContain("Tenant: {$tenant->getTenantKey()}"));
|
|
|
|
$artisan->assertExitCode(0);
|
|
});
|
|
|
|
test('commands run for pending tenants too if the with pending option is passed', function() {
|
|
config(['tenancy.pending.include_in_queries' => false]);
|
|
|
|
$tenants = collect([
|
|
Tenant::create(),
|
|
Tenant::create(),
|
|
Tenant::createPending(),
|
|
Tenant::createPending(),
|
|
]);
|
|
|
|
pest()->artisan('tenants:migrate --with-pending');
|
|
|
|
$artisan = pest()->artisan("tenants:run 'foo foo --b=bar --c=xyz' --with-pending");
|
|
|
|
$tenants->each(fn ($tenant) => $artisan->expectsOutputToContain("Tenant: {$tenant->getTenantKey()}"));
|
|
|
|
$artisan->assertExitCode(0);
|
|
});
|