1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-02-05 22:04:04 +00:00

Merge branch 'master' into bugfix/batch-bootstrapper

This commit is contained in:
Abrar Ahmad 2022-09-05 11:40:24 +05:00 committed by GitHub
commit d1a8b741d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 268 additions and 31 deletions

View file

@ -16,6 +16,7 @@ use Stancl\Tenancy\Listeners\BootstrapTenancy;
use Stancl\Tenancy\Listeners\RevertToCentralContext;
use Stancl\Tenancy\Tests\Etc\ExampleSeeder;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Stancl\Tenancy\Tests\Etc\User;
beforeEach(function () {
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
@ -179,6 +180,29 @@ test('run command with array of tenants works', function () {
->expectsOutput('Tenant: ' . $tenantId2);
});
test('run command works when sub command asks questions and accepts arguments', function () {
$tenant = Tenant::create();
$id = $tenant->getTenantKey();
Artisan::call('tenants:migrate');
pest()->artisan("tenants:run --tenants=$id 'user:addwithname Abrar' ")
->expectsQuestion('What is your email?', 'email@localhost')
->expectsOutput("Tenant: $id")
->expectsOutput("User created: Abrar(email@localhost)");
// Assert we are in central context
expect(tenancy()->initialized)->toBeFalse();
// Assert user was created in tenant context
tenancy()->initialize($tenant);
$user = User::first();
// Assert user is same as provided using the command
expect($user->name)->toBe('Abrar');
expect($user->email)->toBe('email@localhost');
});
// todo@tests
function runCommandWorks(): void
{

View file

@ -2,12 +2,13 @@
declare(strict_types=1);
namespace Stancl\Tenancy\Tests\Etc;
namespace Stancl\Tenancy\Tests\Etc\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Stancl\Tenancy\Concerns\HasATenantsOption;
use Stancl\Tenancy\Concerns\TenantAwareCommand;
use Stancl\Tenancy\Tests\Etc\User;
class AddUserCommand extends Command
{

View file

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Stancl\Tenancy\Tests\Etc;
namespace Stancl\Tenancy\Tests\Etc\Console;
use Orchestra\Testbench\Foundation\Console\Kernel;
@ -10,6 +10,7 @@ class ConsoleKernel extends Kernel
{
protected $commands = [
ExampleCommand::class,
ExampleQuestionCommand::class,
AddUserCommand::class,
];
}

View file

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Stancl\Tenancy\Tests\Etc;
namespace Stancl\Tenancy\Tests\Etc\Console;
use Illuminate\Console\Command;

View file

@ -0,0 +1,46 @@
<?php
namespace Stancl\Tenancy\Tests\Etc\Console;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Stancl\Tenancy\Tests\Etc\User;
class ExampleQuestionCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'user:addwithname {name}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$email = $this->ask('What is your email?');
User::create([
'name' => $this->argument('name'),
'email' => $email,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
]);
$this->line("User created: ". $this->argument('name') . "($email)");
return 0;
}
}

View file

@ -18,7 +18,11 @@ beforeEach(function () {
], function () {
Route::get('/foo/{a}/{b}', function ($a, $b) {
return "$a + $b";
});
})->name('foo');
Route::get('/baz/{a}/{b}', function ($a, $b) {
return "$a - $b";
})->name('baz');
});
});
@ -123,3 +127,23 @@ test('tenant parameter name can be customized', function () {
->withoutExceptionHandling()
->get('/acme/foo/abc/xyz');
});
test('tenant parameter is set for all routes as the default parameter once the tenancy initialized', function () {
Tenant::create([
'id' => 'acme',
]);
expect(tenancy()->initialized)->toBeFalse();
// make a request that will initialize tenancy
pest()->get(route('foo', ['tenant' => 'acme', 'a' => 1, 'b' => 2]));
expect(tenancy()->initialized)->toBeTrue();
expect(tenant('id'))->toBe('acme');
// assert that the route WITHOUT the tenant parameter matches the route WITH the tenant parameter
expect(route('baz', ['a' => 1, 'b' => 2]))->toBe(route('baz', ['tenant' => 'acme', 'a' => 1, 'b' => 2]));
expect(route('baz', ['a' => 1, 'b' => 2]))->toBe('http://localhost/acme/baz/1/2'); // assert the full route string
pest()->get(route('baz', ['a' => 1, 'b' => 2]))->assertOk(); // Assert route don't need tenant parameter
});

View file

@ -4,25 +4,27 @@ declare(strict_types=1);
use Carbon\Carbon;
use Carbon\CarbonInterval;
use Illuminate\Support\Str;
use Illuminate\Auth\TokenGuard;
use Illuminate\Auth\SessionGuard;
use Stancl\JobPipeline\JobPipeline;
use Illuminate\Support\Facades\Auth;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
use Stancl\JobPipeline\JobPipeline;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Database\Models\ImpersonationToken;
use Stancl\Tenancy\Events\TenancyEnded;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Features\UserImpersonation;
use Stancl\Tenancy\Jobs\CreateDatabase;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Features\UserImpersonation;
use Stancl\Tenancy\Listeners\BootstrapTenancy;
use Stancl\Tenancy\Listeners\RevertToCentralContext;
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
use Stancl\Tenancy\Middleware\InitializeTenancyByPath;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Illuminate\Foundation\Auth\User as Authenticable;
use Stancl\Tenancy\Database\Models\ImpersonationToken;
use Stancl\Tenancy\Middleware\InitializeTenancyByPath;
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Exceptions\StatefulGuardRequiredException;
beforeEach(function () {
pest()->artisan('migrate', [
@ -223,6 +225,46 @@ test('impersonation works with multiple models and guards', function () {
});
});
test('impersonation tokens can be created only with stateful guards', function () {
config([
'auth.guards' => [
'nonstateful' => [
'driver' => 'nonstateful',
'provider' => 'provider',
],
'stateful' => [
'driver' => 'session',
'provider' => 'provider',
],
],
'auth.providers.provider' => [
'driver' => 'eloquent',
'model' => ImpersonationUser::class,
],
]);
$tenant = Tenant::create();
migrateTenants();
$user = $tenant->run(function () {
return ImpersonationUser::create([
'name' => 'Joe',
'email' => 'joe@local',
'password' => bcrypt('secret'),
]);
});
Auth::extend('nonstateful', fn($app, $name, array $config) => new TokenGuard(Auth::createUserProvider($config['provider']), request()));
expect(fn() => tenancy()->impersonate($tenant, $user->id, '/dashboard', 'nonstateful'))
->toThrow(StatefulGuardRequiredException::class);
Auth::extend('stateful', fn ($app, $name, array $config) => new SessionGuard($name, Auth::createUserProvider($config['provider']), session()));
expect(tenancy()->impersonate($tenant, $user->id, '/dashboard', 'stateful'))
->toBeInstanceOf(ImpersonationToken::class);
});
function migrateTenants()
{
pest()->artisan('tenants:migrate')->assertExitCode(0);

View file

@ -103,7 +103,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
'--realpath' => true,
'--force' => true,
],
'tenancy.bootstrappers.redis' => RedisTenancyBootstrapper::class,
'tenancy.bootstrappers.redis' => RedisTenancyBootstrapper::class, // todo0 change this to []? two tests in TenantDatabaseManagerTest are failing with that
'queue.connections.central' => [
'driver' => 'sync',
'central' => true,
@ -150,7 +150,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
*/
protected function resolveApplicationConsoleKernel($app)
{
$app->singleton('Illuminate\Contracts\Console\Kernel', Etc\ConsoleKernel::class);
$app->singleton('Illuminate\Contracts\Console\Kernel', Etc\Console\ConsoleKernel::class);
}
public function randomString(int $length = 10)