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

[4.x] Migrate tests to Pest (#884)

* Add Pest dependencies

* Add base Pest file

* Convert test cases

* Remove non-compound imports

* Adopt expectation API

* Optimize uses

* Shift cleanup

* phpunit -> pest

* Fix tests in PR #884 PHPUnit to Pest Converter  (#885)

* fixed tests, remove method duplications, restore necessary inner classes

* Update CommandsTest.php

* temporary checks run on `shift-64622` on branch.

* fixed `TestSeeder` class not resolved

* fixed messed up names

* removed `uses` from individual files and add it in `Pest`

* extract tests to helpers

* use pest dataset

* Update AutomaticModeTest.php

* newline

* todo convention

* resolve reviews

* added `// todo@tests`

* remove shift branch from CI workflow

Co-authored-by: Samuel Štancl <samuel@archte.ch>

* check if I have write permission

* Convert newly added tests to Pest

Co-authored-by: Shift <shift@laravelshift.com>
Co-authored-by: Abrar Ahmad <abrar.dev99@gmail.com>
This commit is contained in:
Samuel Štancl 2022-07-22 19:26:59 +02:00 committed by GitHub
parent 69de181b7d
commit b47c5549ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 3010 additions and 3478 deletions

View file

@ -2,264 +2,229 @@
declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobProcessing;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
use Spatie\Valuestore\Valuestore;
use Illuminate\Support\Facades\DB;
use Stancl\Tenancy\Tests\Etc\User;
use Stancl\JobPipeline\JobPipeline;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\QueueTenancyBootstrapper;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Schema;
use Stancl\Tenancy\Events\TenancyEnded;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Jobs\CreateDatabase;
use Stancl\Tenancy\Events\TenantCreated;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobProcessing;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Listeners\BootstrapTenancy;
use Stancl\Tenancy\Listeners\RevertToCentralContext;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Stancl\Tenancy\Tests\Etc\User;
use Stancl\Tenancy\Bootstrappers\QueueTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
class QueueTest extends TestCase
beforeEach(function () {
config([
'tenancy.bootstrappers' => [
QueueTenancyBootstrapper::class,
DatabaseTenancyBootstrapper::class,
],
'queue.default' => 'redis',
]);
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
createValueStore();
});
afterEach(function () {
$this->valuestore->flush();
});
test('tenant id is passed to tenant queues', function () {
config(['queue.default' => 'sync']);
$tenant = Tenant::create();
tenancy()->initialize($tenant);
Event::fake([JobProcessing::class, JobProcessed::class]);
dispatch(new TestJob($this->valuestore));
Event::assertDispatched(JobProcessing::class, function ($event) {
return $event->job->payload()['tenant_id'] === tenant('id');
});
});
test('tenant id is not passed to central queues', function () {
$tenant = Tenant::create();
tenancy()->initialize($tenant);
Event::fake();
config(['queue.connections.central' => [
'driver' => 'sync',
'central' => true,
]]);
dispatch(new TestJob($this->valuestore))->onConnection('central');
Event::assertDispatched(JobProcessing::class, function ($event) {
return ! isset($event->job->payload()['tenant_id']);
});
});
test('tenancy is initialized inside queues', function (bool $shouldEndTenancy) {
withTenantDatabases();
withFailedJobs();
$tenant = Tenant::create();
tenancy()->initialize($tenant);
withUsers();
$user = User::create(['name' => 'Foo', 'email' => 'foo@bar.com', 'password' => 'secret']);
$this->valuestore->put('userName', 'Bar');
dispatch(new TestJob($this->valuestore, $user));
expect($this->valuestore->has('tenant_id'))->toBeFalse();
if ($shouldEndTenancy) {
tenancy()->end();
}
$this->artisan('queue:work --once');
expect(DB::connection('central')->table('failed_jobs')->count())->toBe(0);
expect($this->valuestore->get('tenant_id'))->toBe('The current tenant id is: ' . $tenant->id);
$tenant->run(function () use ($user) {
expect($user->fresh()->name)->toBe('Bar');
});
})->with([true, false]);;
test('tenancy is initialized when retrying jobs', function (bool $shouldEndTenancy) {
if (! Str::startsWith(app()->version(), '8')) {
$this->markTestSkipped('queue:retry tenancy is only supported in Laravel 8');
}
withFailedJobs();
withTenantDatabases();
$tenant = Tenant::create();
tenancy()->initialize($tenant);
withUsers();
$user = User::create(['name' => 'Foo', 'email' => 'foo@bar.com', 'password' => 'secret']);
$this->valuestore->put('userName', 'Bar');
$this->valuestore->put('shouldFail', true);
dispatch(new TestJob($this->valuestore, $user));
expect($this->valuestore->has('tenant_id'))->toBeFalse();
if ($shouldEndTenancy) {
tenancy()->end();
}
$this->artisan('queue:work --once');
expect(DB::connection('central')->table('failed_jobs')->count())->toBe(1);
expect($this->valuestore->get('tenant_id'))->toBeNull(); // job failed
$this->artisan('queue:retry all');
$this->artisan('queue:work --once');
expect(DB::connection('central')->table('failed_jobs')->count())->toBe(0);
expect($this->valuestore->get('tenant_id'))->toBe('The current tenant id is: ' . $tenant->id); // job succeeded
$tenant->run(function () use ($user) {
expect($user->fresh()->name)->toBe('Bar');
});
})->with([true, false]);
test('the tenant used by the job doesnt change when the current tenant changes', function () {
$tenant1 = Tenant::create([
'id' => 'acme',
]);
tenancy()->initialize($tenant1);
dispatch(new TestJob($this->valuestore));
$tenant2 = Tenant::create([
'id' => 'foobar',
]);
tenancy()->initialize($tenant2);
expect($this->valuestore->has('tenant_id'))->toBeFalse();
$this->artisan('queue:work --once');
expect($this->valuestore->get('tenant_id'))->toBe('The current tenant id is: acme');
});
function createValueStore(): void
{
public $mockConsoleOutput = false;
$valueStorePath = __DIR__ . '/Etc/tmp/queuetest.json';
/** @var Valuestore */
protected $valuestore;
public function setUp(): void
{
parent::setUp();
config([
'tenancy.bootstrappers' => [
QueueTenancyBootstrapper::class,
DatabaseTenancyBootstrapper::class,
],
'queue.default' => 'redis',
]);
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
$this->createValueStore();
}
public function tearDown(): void
{
$this->valuestore->flush();
}
protected function createValueStore(): void
{
$valueStorePath = __DIR__ . '/Etc/tmp/queuetest.json';
if (! file_exists($valueStorePath)) {
// The directory sometimes goes missing as well when the file is deleted in git
if (! is_dir(__DIR__ . '/Etc/tmp')) {
mkdir(__DIR__ . '/Etc/tmp');
}
file_put_contents($valueStorePath, '');
if (! file_exists($valueStorePath)) {
// The directory sometimes goes missing as well when the file is deleted in git
if (! is_dir(__DIR__ . '/Etc/tmp')) {
mkdir(__DIR__ . '/Etc/tmp');
}
$this->valuestore = Valuestore::make($valueStorePath)->flush();
file_put_contents($valueStorePath, '');
}
protected function withFailedJobs()
{
Schema::connection('central')->create('failed_jobs', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid')->unique();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
test()->valuestore = Valuestore::make($valueStorePath)->flush();
}
protected function withUsers()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
function withFailedJobs()
{
Schema::connection('central')->create('failed_jobs', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid')->unique();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
protected function withTenantDatabases()
{
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
return $event->tenant;
})->toListener());
}
function withUsers()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
/** @test */
public function tenant_id_is_passed_to_tenant_queues()
{
config(['queue.default' => 'sync']);
$tenant = Tenant::create();
tenancy()->initialize($tenant);
Event::fake([JobProcessing::class, JobProcessed::class]);
dispatch(new TestJob($this->valuestore));
Event::assertDispatched(JobProcessing::class, function ($event) {
return $event->job->payload()['tenant_id'] === tenant('id');
});
}
/** @test */
public function tenant_id_is_not_passed_to_central_queues()
{
$tenant = Tenant::create();
tenancy()->initialize($tenant);
Event::fake();
config(['queue.connections.central' => [
'driver' => 'sync',
'central' => true,
]]);
dispatch(new TestJob($this->valuestore))->onConnection('central');
Event::assertDispatched(JobProcessing::class, function ($event) {
return ! isset($event->job->payload()['tenant_id']);
});
}
/**
* @test
*
* @testWith [true]
* [false]
*/
public function tenancy_is_initialized_inside_queues(bool $shouldEndTenancy)
{
$this->withTenantDatabases();
$this->withFailedJobs();
$tenant = Tenant::create();
tenancy()->initialize($tenant);
$this->withUsers();
$user = User::create(['name' => 'Foo', 'email' => 'foo@bar.com', 'password' => 'secret']);
$this->valuestore->put('userName', 'Bar');
dispatch(new TestJob($this->valuestore, $user));
$this->assertFalse($this->valuestore->has('tenant_id'));
if ($shouldEndTenancy) {
tenancy()->end();
}
$this->artisan('queue:work --once');
$this->assertSame(0, DB::connection('central')->table('failed_jobs')->count());
$this->assertSame('The current tenant id is: ' . $tenant->id, $this->valuestore->get('tenant_id'));
$tenant->run(function () use ($user) {
$this->assertSame('Bar', $user->fresh()->name);
});
}
/**
* @test
*
* @testWith [true]
* [false]
*/
public function tenancy_is_initialized_when_retrying_jobs(bool $shouldEndTenancy)
{
if (! Str::startsWith(app()->version(), '8')) {
$this->markTestSkipped('queue:retry tenancy is only supported in Laravel 8');
}
$this->withFailedJobs();
$this->withTenantDatabases();
$tenant = Tenant::create();
tenancy()->initialize($tenant);
$this->withUsers();
$user = User::create(['name' => 'Foo', 'email' => 'foo@bar.com', 'password' => 'secret']);
$this->valuestore->put('userName', 'Bar');
$this->valuestore->put('shouldFail', true);
dispatch(new TestJob($this->valuestore, $user));
$this->assertFalse($this->valuestore->has('tenant_id'));
if ($shouldEndTenancy) {
tenancy()->end();
}
$this->artisan('queue:work --once');
$this->assertSame(1, DB::connection('central')->table('failed_jobs')->count());
$this->assertNull($this->valuestore->get('tenant_id')); // job failed
$this->artisan('queue:retry all');
$this->artisan('queue:work --once');
$this->assertSame(0, DB::connection('central')->table('failed_jobs')->count());
$this->assertSame('The current tenant id is: ' . $tenant->id, $this->valuestore->get('tenant_id')); // job succeeded
$tenant->run(function () use ($user) {
$this->assertSame('Bar', $user->fresh()->name);
});
}
/** @test */
public function the_tenant_used_by_the_job_doesnt_change_when_the_current_tenant_changes()
{
$tenant1 = Tenant::create([
'id' => 'acme',
]);
tenancy()->initialize($tenant1);
dispatch(new TestJob($this->valuestore));
$tenant2 = Tenant::create([
'id' => 'foobar',
]);
tenancy()->initialize($tenant2);
$this->assertFalse($this->valuestore->has('tenant_id'));
$this->artisan('queue:work --once');
$this->assertSame('The current tenant id is: acme', $this->valuestore->get('tenant_id'));
}
function withTenantDatabases()
{
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
return $event->tenant;
})->toListener());
}
class TestJob implements ShouldQueue
@ -297,3 +262,4 @@ class TestJob implements ShouldQueue
}
}
}