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

Bootstrapper tests

This commit is contained in:
Samuel Štancl 2020-05-11 03:37:47 +02:00
parent 73fc525126
commit 6f4b9f486c
20 changed files with 266 additions and 79 deletions

View file

@ -8,7 +8,7 @@ use Stancl\Tenancy\Database\Models\Tenant;
return [ return [
'tenant_model' => Tenant::class, 'tenant_model' => Tenant::class,
'domain_model' => Domain::class, 'domain_model' => Domain::class,
'internal_prefix' => 'tenancy_', 'internal_column_prefix' => 'tenancy_',
'central_connection' => 'central', 'central_connection' => 'central',
'template_tenant_connection' => null, 'template_tenant_connection' => null,

View file

@ -16,6 +16,9 @@ services:
DB_PASSWORD: password DB_PASSWORD: password
DB_USERNAME: root DB_USERNAME: root
DB_DATABASE: main DB_DATABASE: main
TENANCY_TEST_REDIS_HOST: redis
TENANCY_TEST_MYSQL_HOST: mysql
TENANCY_TEST_PGSQL_HOST: postgres
stdin_open: true stdin_open: true
tty: true tty: true
mysql: mysql:

View file

@ -7,6 +7,7 @@ namespace Stancl\Tenancy\Commands;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Database\Console\Migrations\MigrateCommand; use Illuminate\Database\Console\Migrations\MigrateCommand;
use Illuminate\Database\Migrations\Migrator; use Illuminate\Database\Migrations\Migrator;
use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\DatabaseManager; use Stancl\Tenancy\DatabaseManager;
use Stancl\Tenancy\Events\DatabaseMigrated; use Stancl\Tenancy\Events\DatabaseMigrated;
use Stancl\Tenancy\Traits\DealsWithMigrations; use Stancl\Tenancy\Traits\DealsWithMigrations;
@ -56,15 +57,20 @@ class Migrate extends MigrateCommand
return; return;
} }
tenancy()->all($this->option('tenants'))->each(function ($tenant) { tenancy()
$this->line("Tenant: {$tenant['id']}"); ->query()
->when($this->option('tenants'), function ($query) {
$query->whereIn(tenancy()->model()->getTenantKeyName(), $this->option('tenants'));
})
->each(function (TenantWithDatabase $tenant) {
$this->line("Tenant: {$tenant['id']}");
$tenant->run(function () { $tenant->run(function () {
// Migrate // Migrate
parent::handle(); parent::handle();
});
event(new DatabaseMigrated($tenant));
}); });
event(new DatabaseMigrated($tenant));
});
} }
} }

View file

@ -2,8 +2,12 @@
namespace Stancl\Tenancy\Contracts; namespace Stancl\Tenancy\Contracts;
/**
* @see \Stancl\Tenancy\Database\Models\Tenant
*/
interface Tenant interface Tenant
{ {
public function getTenantKeyName(): string; public function getTenantKeyName(): string;
public function getTenantKey(): string; public function getTenantKey(): string;
public function run(callable $callback);
} }

View file

@ -4,8 +4,6 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Contracts; namespace Stancl\Tenancy\Contracts;
use Stancl\Tenancy\Tenant;
interface TenantDatabaseManager interface TenantDatabaseManager
{ {
/** /**
@ -18,12 +16,12 @@ interface TenantDatabaseManager
/** /**
* Create a database. * Create a database.
*/ */
public function createDatabase(Tenant $tenant): bool; public function createDatabase(TenantWithDatabase $tenant): bool;
/** /**
* Delete a database. * Delete a database.
*/ */
public function deleteDatabase(Tenant $tenant): bool; public function deleteDatabase(TenantWithDatabase $tenant): bool;
/** /**
* Does a database exist. * Does a database exist.

View file

@ -8,7 +8,7 @@ use Stancl\Tenancy\Events;
use Stancl\Tenancy\Contracts; use Stancl\Tenancy\Contracts;
// todo @property // todo @property
class Tenant extends Model implements Contracts\Tenant class Tenant extends Model implements Contracts\TenantWithDatabase
{ {
use Concerns\CentralConnection, Concerns\HasADataColumn, Concerns\GeneratesIds, Concerns\HasADataColumn { use Concerns\CentralConnection, Concerns\HasADataColumn, Concerns\GeneratesIds, Concerns\HasADataColumn {
Concerns\HasADataColumn::getCasts as dataColumnCasts; Concerns\HasADataColumn::getCasts as dataColumnCasts;
@ -41,7 +41,7 @@ class Tenant extends Model implements Contracts\Tenant
public static function internalPrefix(): string public static function internalPrefix(): string
{ {
return config('tenancy.database_prefix'); return config('tenancy.internal_column_prefix');
} }
/** /**
@ -76,15 +76,15 @@ class Tenant extends Model implements Contracts\Tenant
public function run(callable $callback) public function run(callable $callback)
{ {
// todo new logic with the manager $originalTenant = tenant();
$originalTenant = $this->manager->getTenant();
$this->manager->initializeTenancy($this); tenancy()->initialize($this);
$result = $callback($this); $result = $callback($this);
$this->manager->endTenancy($this);
if ($originalTenant) { if ($originalTenant) {
$this->manager->initializeTenancy($originalTenant); tenancy()->initialize($originalTenant);
} else {
tenancy()->end();
} }
return $result; return $result;

View file

@ -93,7 +93,7 @@ class DatabaseConfig
{ {
return $this->tenant->getInternal('db_connection') return $this->tenant->getInternal('db_connection')
?? config('tenancy.template_tenant_connection') ?? config('tenancy.template_tenant_connection')
?? DatabaseManager::$originalDefaultConnectionName; ?? config('tenancy.central_connection');
} }
/** /**
@ -105,6 +105,7 @@ class DatabaseConfig
$templateConnection = config("database.connections.{$template}"); $templateConnection = config("database.connections.{$template}");
// todo move a lot of this logic to the tenant DB manager so that we dont have to deal with the separators & modifying DB names here
$databaseName = $this->getName(); $databaseName = $this->getName();
if (($manager = $this->manager()) instanceof ModifiesDatabaseNameForConnection) { if (($manager = $this->manager()) instanceof ModifiesDatabaseNameForConnection) {
/** @var ModifiesDatabaseNameForConnection $manager */ /** @var ModifiesDatabaseNameForConnection $manager */

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy; namespace Stancl\Tenancy;
use Closure; use Closure;
use Illuminate\Config\Repository;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\DatabaseManager as BaseDatabaseManager; use Illuminate\Database\DatabaseManager as BaseDatabaseManager;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
@ -18,58 +19,43 @@ use Stancl\Tenancy\Jobs\QueuedTenantDatabaseDeleter;
/** /**
* @internal Class is subject to breaking changes in minor and patch versions. * @internal Class is subject to breaking changes in minor and patch versions.
*/ */
// todo rewrite everything
class DatabaseManager class DatabaseManager
{ {
/** @var string */
public static $originalDefaultConnectionName;
/** @var Application */ /** @var Application */
protected $app; protected $app;
/** @var BaseDatabaseManager */ /** @var BaseDatabaseManager */
protected $database; protected $database;
/** @var TenantManager */ /** @var Repository */
protected $tenancy; protected $config;
public function __construct(Application $app, BaseDatabaseManager $database) public function __construct(Application $app, BaseDatabaseManager $database, Repository $config)
{ {
$this->app = $app; $this->app = $app;
$this->database = $database; $this->database = $database;
static::$originalDefaultConnectionName = $app['config']['database.default']; $this->config = $config;
}
/**
* Set the TenantManager instance, used to dispatch tenancy events.
*/
public function withTenantManager(Tenancy $tenantManager): self
{
$this->tenancy = $tenantManager;
return $this;
} }
/** /**
* Connect to a tenant's database. * Connect to a tenant's database.
*/ */
public function connect(TenantWithDatabase $tenant) public function connectToTenant(TenantWithDatabase $tenant)
{ {
$this->createTenantConnection($tenant); $this->createTenantConnection($tenant);
$this->setDefaultConnection('tenant'); $this->setDefaultConnection('tenant');
$this->switchConnection('tenant'); $this->database->purge('tenant');
} }
/** /**
* Reconnect to the default non-tenant connection. * Reconnect to the default non-tenant connection.
*/ */
public function reconnect() public function reconnectToCentral()
{ {
if ($this->tenancy->initialized) { if (tenancy()->initialized) {
$this->database->purge('tenant'); $this->database->purge('tenant');
} }
$this->setDefaultConnection(static::$originalDefaultConnectionName); $this->setDefaultConnection($this->config->get('tenancy.central_connection'));
$this->switchConnection(static::$originalDefaultConnectionName);
} }
/** /**
@ -78,25 +64,17 @@ class DatabaseManager
public function setDefaultConnection(string $connection) public function setDefaultConnection(string $connection)
{ {
$this->app['config']['database.default'] = $connection; $this->app['config']['database.default'] = $connection;
$this->database->setDefaultConnection($connection);
} }
/** /**
* Create the tenant database connection. * Create the tenant database connection.
*/ */
public function createTenantConnection(Tenant $tenant) public function createTenantConnection(TenantWithDatabase $tenant)
{ {
$this->app['config']['database.connections.tenant'] = $tenant->database()->connection(); $this->app['config']['database.connections.tenant'] = $tenant->database()->connection();
} }
/**
* Switch the application's connection.
*/
public function switchConnection(string $connection)
{
$this->database->reconnect($connection);
$this->database->setDefaultConnection($connection);
}
/** /**
* Check if a tenant can be created. * Check if a tenant can be created.
* *
@ -104,7 +82,7 @@ class DatabaseManager
* @throws DatabaseManagerNotRegisteredException * @throws DatabaseManagerNotRegisteredException
* @throws TenantDatabaseAlreadyExistsException * @throws TenantDatabaseAlreadyExistsException
*/ */
public function ensureTenantCanBeCreated(Tenant $tenant): void public function ensureTenantCanBeCreated(TenantWithDatabase $tenant): void
{ {
if ($tenant->database()->manager()->databaseExists($database = $tenant->database()->getName())) { if ($tenant->database()->manager()->databaseExists($database = $tenant->database()->getName())) {
throw new TenantDatabaseAlreadyExistsException($database); throw new TenantDatabaseAlreadyExistsException($database);
@ -119,8 +97,9 @@ class DatabaseManager
* @return void * @return void
* @throws DatabaseManagerNotRegisteredException * @throws DatabaseManagerNotRegisteredException
*/ */
public function createDatabase(Tenant $tenant, array $afterCreating = []) public function createDatabase(TenantWithDatabase $tenant, array $afterCreating = [])
{ {
// todo get rid of aftercreating logic
$afterCreating = array_merge( $afterCreating = array_merge(
$afterCreating, $afterCreating,
$this->tenancy->event('database.creating', $tenant->database()->getName(), $tenant) $this->tenancy->event('database.creating', $tenant->database()->getName(), $tenant)
@ -168,7 +147,7 @@ class DatabaseManager
* *
* @throws DatabaseManagerNotRegisteredException * @throws DatabaseManagerNotRegisteredException
*/ */
public function deleteDatabase(Tenant $tenant) public function deleteDatabase(TenantWithDatabase $tenant)
{ {
$database = $tenant->database()->getName(); $database = $tenant->database()->getName();
$manager = $tenant->database()->manager(); $manager = $tenant->database()->manager();

View file

@ -3,7 +3,7 @@
namespace Stancl\Tenancy\Events\Contracts; namespace Stancl\Tenancy\Events\Contracts;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Stancl\Tenancy\Database\Models\Domain; use Stancl\Tenancy\Contracts\Domain;
abstract class DomainEvent abstract class DomainEvent
{ {

View file

@ -3,7 +3,7 @@
namespace Stancl\Tenancy\Events\Contracts; namespace Stancl\Tenancy\Events\Contracts;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Stancl\Tenancy\Database\Models\Tenant; use Stancl\Tenancy\Contracts\Tenant;
abstract class TenantEvent abstract class TenantEvent
{ {

View file

@ -61,7 +61,7 @@ class JobPipeline implements ShouldQueue
public function handle(): void public function handle(): void
{ {
foreach ($this->jobs as $job) { foreach ($this->jobs as $job) {
app($job)->handle($this->passable); app()->call([new $job(...$this->passable), 'handle']);
} }
} }
@ -82,7 +82,10 @@ class JobPipeline implements ShouldQueue
{ {
$clone = clone $this; $clone = clone $this;
$clone->passable = ($clone->send)(...$listenerArgs); $passable = ($clone->send)(...$listenerArgs);
$passable = is_array($passable) ? $passable : [$passable];
$clone->passable = $passable;
unset($clone->send); unset($clone->send);
return $clone; return $clone;

View file

@ -6,16 +6,18 @@ namespace Stancl\Tenancy\Jobs;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Stancl\Tenancy\Database\Models\Tenant; use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Contracts\Tenant;
class CreateDatabase implements ShouldQueue class CreateDatabase implements ShouldQueue
{ {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** @var Tenant */ /** @var TenantWithDatabase|Model */
protected $tenant; protected $tenant;
public function __construct(Tenant $tenant) public function __construct(Tenant $tenant)

View file

@ -2,12 +2,14 @@
namespace Stancl\Tenancy; namespace Stancl\Tenancy;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\TenancyBootstrapper;
use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\Tenant;
class Tenancy class Tenancy
{ {
/** @var Tenant|null */ /** @var Tenant|Model|null */
public $tenant; public $tenant;
/** @var callable|null */ /** @var callable|null */
@ -48,4 +50,17 @@ class Tenancy
return $resolve($this->tenant); return $resolve($this->tenant);
} }
public function query(): Builder
{
return $this->model()->query();
}
/** @return Tenant|Model */
public function model()
{
$class = config('tenancy.tenant_model');
return new $class;
}
} }

View file

@ -6,6 +6,7 @@ namespace Stancl\Tenancy\TenancyBootstrappers;
use Illuminate\Cache\CacheManager; use Illuminate\Cache\CacheManager;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Cache;
use Stancl\Tenancy\CacheManager as TenantCacheManager; use Stancl\Tenancy\CacheManager as TenantCacheManager;
use Stancl\Tenancy\Contracts\TenancyBootstrapper; use Stancl\Tenancy\Contracts\TenancyBootstrapper;
use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Contracts\Tenant;
@ -25,6 +26,8 @@ class CacheTenancyBootstrapper implements TenancyBootstrapper
public function start(Tenant $tenant) public function start(Tenant $tenant)
{ {
$this->resetFacadeCache();
$this->originalCache = $this->originalCache ?? $this->app['cache']; $this->originalCache = $this->originalCache ?? $this->app['cache'];
$this->app->extend('cache', function () { $this->app->extend('cache', function () {
return new TenantCacheManager($this->app); return new TenantCacheManager($this->app);
@ -33,10 +36,22 @@ class CacheTenancyBootstrapper implements TenancyBootstrapper
public function end() public function end()
{ {
$this->resetFacadeCache();
$this->app->extend('cache', function () { $this->app->extend('cache', function () {
return $this->originalCache; return $this->originalCache;
}); });
$this->originalCache = null; $this->originalCache = null;
} }
/**
* This wouldn't be necessary, but is needed when a call to the
* facade has been made prior to bootstrapping tenancy. The
* facade has its own cache, separate from the container.
*/
public function resetFacadeCache()
{
Cache::clearResolvedInstances();
}
} }

View file

@ -8,6 +8,7 @@ use Stancl\Tenancy\Contracts\TenancyBootstrapper;
use Stancl\Tenancy\DatabaseManager; use Stancl\Tenancy\DatabaseManager;
use Stancl\Tenancy\Exceptions\TenantDatabaseDoesNotExistException; use Stancl\Tenancy\Exceptions\TenantDatabaseDoesNotExistException;
use Stancl\Tenancy\Contracts\TenantWithDatabase; use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Contracts\Tenant;
class DatabaseTenancyBootstrapper implements TenancyBootstrapper class DatabaseTenancyBootstrapper implements TenancyBootstrapper
{ {
@ -19,8 +20,10 @@ class DatabaseTenancyBootstrapper implements TenancyBootstrapper
$this->database = $database; $this->database = $database;
} }
public function start(TenantWithDatabase $tenant) public function start(Tenant $tenant)
{ {
/** @var TenantWithDatabase $tenant */
$database = $tenant->database()->getName(); $database = $tenant->database()->getName();
if (! $tenant->database()->manager()->databaseExists($database)) { if (! $tenant->database()->manager()->databaseExists($database)) {
throw new TenantDatabaseDoesNotExistException($database); throw new TenantDatabaseDoesNotExistException($database);
@ -31,6 +34,6 @@ class DatabaseTenancyBootstrapper implements TenancyBootstrapper
public function end() public function end()
{ {
$this->database->revertToCentral(); $this->database->reconnectToCentral();
} }
} }

View file

@ -8,10 +8,9 @@ use Illuminate\Cache\CacheManager;
use Illuminate\Contracts\Http\Kernel; use Illuminate\Contracts\Http\Kernel;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Stancl\Tenancy\Database\Models\Tenant;
use Stancl\Tenancy\Database\TenantObserver;
use Stancl\Tenancy\StorageDrivers\Database\DatabaseStorageDriver; use Stancl\Tenancy\StorageDrivers\Database\DatabaseStorageDriver;
use Stancl\Tenancy\TenancyBootstrappers\FilesystemTenancyBootstrapper; use Stancl\Tenancy\TenancyBootstrappers\FilesystemTenancyBootstrapper;
use Stancl\Tenancy\Contracts\Tenant;
class TenancyServiceProvider extends ServiceProvider class TenancyServiceProvider extends ServiceProvider
{ {

View file

@ -6,7 +6,7 @@ namespace Stancl\Tenancy\TenantDatabaseManagers;
use Stancl\Tenancy\Contracts\ModifiesDatabaseNameForConnection; use Stancl\Tenancy\Contracts\ModifiesDatabaseNameForConnection;
use Stancl\Tenancy\Contracts\TenantDatabaseManager; use Stancl\Tenancy\Contracts\TenantDatabaseManager;
use Stancl\Tenancy\Tenant; use Stancl\Tenancy\Contracts\TenantWithDatabase;
class SQLiteDatabaseManager implements TenantDatabaseManager, ModifiesDatabaseNameForConnection class SQLiteDatabaseManager implements TenantDatabaseManager, ModifiesDatabaseNameForConnection
{ {
@ -15,7 +15,7 @@ class SQLiteDatabaseManager implements TenantDatabaseManager, ModifiesDatabaseNa
return 'database'; return 'database';
} }
public function createDatabase(Tenant $tenant): bool public function createDatabase(TenantWithDatabase $tenant): bool
{ {
try { try {
return fclose(fopen(database_path($tenant->database()->getName()), 'w')); return fclose(fopen(database_path($tenant->database()->getName()), 'w'));
@ -24,7 +24,7 @@ class SQLiteDatabaseManager implements TenantDatabaseManager, ModifiesDatabaseNa
} }
} }
public function deleteDatabase(Tenant $tenant): bool public function deleteDatabase(TenantWithDatabase $tenant): bool
{ {
try { try {
return unlink(database_path($tenant->database()->getName())); return unlink(database_path($tenant->database()->getName()));

View file

@ -2,8 +2,8 @@
declare(strict_types=1); declare(strict_types=1);
use Stancl\Tenancy\Database\Models\Tenant;
use Stancl\Tenancy\Tenancy; use Stancl\Tenancy\Tenancy;
use Stancl\Tenancy\Contracts\Tenant;
if (! function_exists('tenancy')) { if (! function_exists('tenancy')) {
/** @return Tenancy */ /** @return Tenancy */
@ -18,10 +18,14 @@ if (! function_exists('tenant')) {
* Get a key from the current tenant's storage. * Get a key from the current tenant's storage.
* *
* @param string|null $key * @param string|null $key
* @return Tenant|mixed * @return Tenant|null|mixed
*/ */
function tenant($key = null) function tenant($key = null)
{ {
if (! app()->bound(Tenant::class)) {
return null;
}
if (is_null($key)) { if (is_null($key)) {
return app(Tenant::class); return app(Tenant::class);
} }

View file

@ -2,37 +2,185 @@
namespace Stancl\Tenancy\Tests\v3; namespace Stancl\Tenancy\Tests\v3;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use Stancl\Tenancy\Database\Models\Tenant;
use Stancl\Tenancy\Events\Listeners\BootstrapTenancy;
use Stancl\Tenancy\Events\Listeners\JobPipeline;
use Stancl\Tenancy\Events\Listeners\RevertToCentralContext;
use Stancl\Tenancy\Events\TenancyEnded;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Jobs\CreateDatabase;
use Stancl\Tenancy\TenancyBootstrappers\CacheTenancyBootstrapper;
use Stancl\Tenancy\TenancyBootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\TenancyBootstrappers\FilesystemTenancyBootstrapper;
use Stancl\Tenancy\TenancyBootstrappers\RedisTenancyBootstrapper;
use Stancl\Tenancy\Tests\TestCase; use Stancl\Tenancy\Tests\TestCase;
class BootstrapperTest extends TestCase class BootstrapperTest extends TestCase
{ {
public $mockConsoleOutput = false;
public function setUp(): void
{
parent::setUp();
Event::listen(
TenantCreated::class,
JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
return $event->tenant;
})->toListener()
);
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
}
/** @test */ /** @test */
public function database_data_is_separated() public function database_data_is_separated()
{ {
config(['tenancy.bootstrappers' => [
DatabaseTenancyBootstrapper::class
]]);
$tenant1 = Tenant::create();
$tenant2 = Tenant::create();
$this->artisan('tenants:migrate');
tenancy()->initialize($tenant1);
// Create Foo user
DB::table('users')->insert(['name' => 'Foo', 'email' => 'foo@bar.com', 'password' => 'secret']);
$this->assertCount(1, DB::table('users')->get());
tenancy()->initialize($tenant2);
// Assert Foo user is not in this DB
$this->assertCount(0, DB::table('users')->get());
// Create Bar user
DB::table('users')->insert(['name' => 'Bar', 'email' => 'bar@bar.com', 'password' => 'secret']);
$this->assertCount(1, DB::table('users')->get());
tenancy()->initialize($tenant1);
// Assert Bar user is not in this DB
$this->assertCount(1, DB::table('users')->get());
$this->assertSame('Foo', DB::table('users')->first()->name);
} }
/** @test */ /** @test */
public function cache_data_is_separated() public function cache_data_is_separated()
{ {
config([
'tenancy.bootstrappers' => [
CacheTenancyBootstrapper::class
],
'cache.default' => 'redis',
]);
$tenant1 = Tenant::create();
$tenant2 = Tenant::create();
cache()->set('foo', 'central');
$this->assertSame('central', Cache::get('foo'));
tenancy()->initialize($tenant1);
// Assert central cache doesn't leak to tenant context
$this->assertFalse(Cache::has('foo'));
cache()->set('foo', 'bar');
$this->assertSame('bar', Cache::get('foo'));
tenancy()->initialize($tenant2);
// Assert one tenant's data doesn't leak to another tenant
$this->assertFalse(Cache::has('foo'));
cache()->set('foo', 'xyz');
$this->assertSame('xyz', Cache::get('foo'));
tenancy()->initialize($tenant1);
// Asset data didn't leak to original tenant
$this->assertSame('bar', Cache::get('foo'));
tenancy()->end();
// Asset central is still the same
$this->assertSame('central', Cache::get('foo'));
} }
/** @test */ /** @test */
public function redis_data_is_separated() public function redis_data_is_separated()
{ {
config(['tenancy.bootstrappers' => [
RedisTenancyBootstrapper::class
]]);
$tenant1 = Tenant::create();
$tenant2 = Tenant::create();
tenancy()->initialize($tenant1);
Redis::set('foo', 'bar');
$this->assertSame('bar', Redis::get('foo'));
tenancy()->initialize($tenant2);
$this->assertSame(null, Redis::get('foo'));
Redis::set('foo', 'xyz');
Redis::set('abc', 'def');
$this->assertSame('xyz', Redis::get('foo'));
$this->assertSame('def', Redis::get('abc'));
tenancy()->initialize($tenant1);
$this->assertSame('bar', Redis::get('foo'));
$this->assertSame(null, Redis::get('abc'));
$tenant3 = Tenant::create();
tenancy()->initialize($tenant3);
$this->assertSame(null, Redis::get('foo'));
$this->assertSame(null, Redis::get('abc'));
} }
/** @test */ /** @test */
public function filesystem_data_is_separated() public function filesystem_data_is_separated()
{ {
config(['tenancy.bootstrappers' => [
FilesystemTenancyBootstrapper::class
]]);
$tenant1 = Tenant::create();
$tenant2 = Tenant::create();
tenancy()->initialize($tenant1);
Storage::disk('public')->put('foo', 'bar');
$this->assertSame('bar', Storage::disk('public')->get('foo'));
tenancy()->initialize($tenant2);
$this->assertFalse(Storage::disk('public')->exists('foo'));
Storage::disk('public')->put('foo', 'xyz');
Storage::disk('public')->put('abc', 'def');
$this->assertSame('xyz', Storage::disk('public')->get('foo'));
$this->assertSame('def', Storage::disk('public')->get('abc'));
tenancy()->initialize($tenant1);
$this->assertSame('bar', Storage::disk('public')->get('foo'));
$this->assertFalse(Storage::disk('public')->exists('abc'));
$tenant3 = Tenant::create();
tenancy()->initialize($tenant3);
$this->assertFalse(Storage::disk('public')->exists('foo'));
$this->assertFalse(Storage::disk('public')->exists('abc'));
} }
/** @test */ /** @test */
public function queue_data_is_separated() public function queue_data_is_separated()
{ {
// todo
} }
} }

View file

@ -9,6 +9,7 @@ use Stancl\Tenancy\Events\Listeners\JobPipeline;
use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Tests\TestCase; use Stancl\Tenancy\Tests\TestCase;
// todo the shouldQueue() doesnt make sense? test if it really works or if its just because of sync queue driver
class JobPipelineTest extends TestCase class JobPipelineTest extends TestCase
{ {
/** @test */ /** @test */
@ -19,7 +20,7 @@ class JobPipelineTest extends TestCase
])->toListener()); ])->toListener());
$this->assertFalse(app()->bound('foo')); $this->assertFalse(app()->bound('foo'));
Tenant::create(); Tenant::create();
$this->assertSame('bar', app('foo')); $this->assertSame('bar', app('foo'));
@ -60,6 +61,12 @@ class JobPipelineTest extends TestCase
$this->assertSame('first job changed property', app('foo')); $this->assertSame('first job changed property', app('foo'));
} }
/** @test */
public function send_can_return_multiple_arguments()
{
// todo
}
} }
class FooJob class FooJob