mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-12 12:54:05 +00:00
Merge branch 'master' into shared-users
This commit is contained in:
commit
8915297c30
85 changed files with 880 additions and 3280 deletions
|
|
@ -154,6 +154,12 @@ class BootstrapperTest extends TestCase
|
|||
FilesystemTenancyBootstrapper::class
|
||||
]]);
|
||||
|
||||
$old_storage_path = storage_path();
|
||||
$old_storage_facade_roots = [];
|
||||
foreach (config('tenancy.filesystem.disks') as $disk) {
|
||||
$old_storage_facade_roots[$disk] = config("filesystems.disks.{$disk}.root");
|
||||
}
|
||||
|
||||
$tenant1 = Tenant::create();
|
||||
$tenant2 = Tenant::create();
|
||||
|
||||
|
|
@ -176,6 +182,27 @@ class BootstrapperTest extends TestCase
|
|||
tenancy()->initialize($tenant3);
|
||||
$this->assertFalse(Storage::disk('public')->exists('foo'));
|
||||
$this->assertFalse(Storage::disk('public')->exists('abc'));
|
||||
|
||||
// Check suffixing logic
|
||||
$new_storage_path = storage_path();
|
||||
$this->assertEquals($old_storage_path . '/' . config('tenancy.filesystem.suffix_base') . tenant('id'), $new_storage_path);
|
||||
|
||||
foreach (config('tenancy.filesystem.disks') as $disk) {
|
||||
$suffix = config('tenancy.filesystem.suffix_base') . tenant('id');
|
||||
$current_path_prefix = Storage::disk($disk)->getAdapter()->getPathPrefix();
|
||||
|
||||
if ($override = config("tenancy.filesystem.root_override.{$disk}")) {
|
||||
$correct_path_prefix = str_replace('%storage_path%', storage_path(), $override);
|
||||
} else {
|
||||
if ($base = $old_storage_facade_roots[$disk]) {
|
||||
$correct_path_prefix = $base . "/$suffix/";
|
||||
} else {
|
||||
$correct_path_prefix = "$suffix/";
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertSame($correct_path_prefix, $current_path_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
// for queues see QueueTest
|
||||
|
|
@ -2,25 +2,41 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Events\Listeners\BootstrapTenancy;
|
||||
use Stancl\Tenancy\Events\TenancyInitialized;
|
||||
use Stancl\Tenancy\TenancyBootstrappers\CacheTenancyBootstrapper;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class CacheManagerTest extends TestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config(['tenancy.bootstrappers' => [
|
||||
CacheTenancyBootstrapper::class,
|
||||
]]);
|
||||
|
||||
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function default_tag_is_automatically_applied()
|
||||
{
|
||||
$this->createTenant();
|
||||
$this->initTenancy();
|
||||
tenancy()->initialize(Tenant::create());
|
||||
|
||||
$this->assertArrayIsSubset([config('tenancy.cache.tag_base') . tenant('id')], cache()->tags('foo')->getTags()->getNames());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tags_are_merged_when_array_is_passed()
|
||||
{
|
||||
$this->createTenant();
|
||||
$this->initTenancy();
|
||||
tenancy()->initialize(Tenant::create());
|
||||
|
||||
$expected = [config('tenancy.cache.tag_base') . tenant('id'), 'foo', 'bar'];
|
||||
$this->assertEquals($expected, cache()->tags(['foo', 'bar'])->getTags()->getNames());
|
||||
}
|
||||
|
|
@ -28,8 +44,8 @@ class CacheManagerTest extends TestCase
|
|||
/** @test */
|
||||
public function tags_are_merged_when_string_is_passed()
|
||||
{
|
||||
$this->createTenant();
|
||||
$this->initTenancy();
|
||||
tenancy()->initialize(Tenant::create());
|
||||
|
||||
$expected = [config('tenancy.cache.tag_base') . tenant('id'), 'foo'];
|
||||
$this->assertEquals($expected, cache()->tags('foo')->getTags()->getNames());
|
||||
}
|
||||
|
|
@ -37,8 +53,8 @@ class CacheManagerTest extends TestCase
|
|||
/** @test */
|
||||
public function exception_is_thrown_when_zero_arguments_are_passed_to_tags_method()
|
||||
{
|
||||
$this->createTenant();
|
||||
$this->initTenancy();
|
||||
tenancy()->initialize(Tenant::create());
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
cache()->tags();
|
||||
}
|
||||
|
|
@ -46,8 +62,8 @@ class CacheManagerTest extends TestCase
|
|||
/** @test */
|
||||
public function exception_is_thrown_when_more_than_one_argument_is_passed_to_tags_method()
|
||||
{
|
||||
$this->createTenant();
|
||||
$this->initTenancy();
|
||||
tenancy()->initialize(Tenant::create());
|
||||
|
||||
$this->expectException(\Exception::class);
|
||||
cache()->tags(1, 2);
|
||||
}
|
||||
|
|
@ -55,14 +71,14 @@ class CacheManagerTest extends TestCase
|
|||
/** @test */
|
||||
public function tags_separate_cache_well_enough()
|
||||
{
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant1 = Tenant::create();
|
||||
tenancy()->initialize($tenant1);
|
||||
|
||||
cache()->put('foo', 'bar', 1);
|
||||
$this->assertSame('bar', cache()->get('foo'));
|
||||
|
||||
Tenant::new()->withDomains(['bar.localhost'])->save();
|
||||
tenancy()->init('bar.localhost');
|
||||
$tenant2 = Tenant::create();
|
||||
tenancy()->initialize($tenant2);
|
||||
|
||||
$this->assertNotSame('bar', cache()->get('foo'));
|
||||
|
||||
|
|
@ -73,14 +89,14 @@ class CacheManagerTest extends TestCase
|
|||
/** @test */
|
||||
public function invoking_the_cache_helper_works()
|
||||
{
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant1 = Tenant::create();
|
||||
tenancy()->initialize($tenant1);
|
||||
|
||||
cache(['foo' => 'bar'], 1);
|
||||
$this->assertSame('bar', cache('foo'));
|
||||
|
||||
Tenant::new()->withDomains(['bar.localhost'])->save();
|
||||
tenancy()->init('bar.localhost');
|
||||
$tenant2 = Tenant::create();
|
||||
tenancy()->initialize($tenant2);
|
||||
|
||||
$this->assertNotSame('bar', cache('foo'));
|
||||
|
||||
|
|
@ -91,32 +107,32 @@ class CacheManagerTest extends TestCase
|
|||
/** @test */
|
||||
public function cache_is_persisted()
|
||||
{
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant1 = Tenant::create();
|
||||
tenancy()->initialize($tenant1);
|
||||
|
||||
cache(['foo' => 'bar'], 10);
|
||||
$this->assertSame('bar', cache('foo'));
|
||||
|
||||
tenancy()->endTenancy();
|
||||
tenancy()->end();
|
||||
|
||||
tenancy()->init('foo.localhost');
|
||||
tenancy()->initialize($tenant1);
|
||||
$this->assertSame('bar', cache('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function cache_is_persisted_when_reidentification_is_used()
|
||||
{
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
Tenant::new()->withDomains(['bar.localhost'])->save();
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant1 = Tenant::create();
|
||||
$tenant2 = Tenant::create();
|
||||
tenancy()->initialize($tenant1);
|
||||
|
||||
cache(['foo' => 'bar'], 10);
|
||||
$this->assertSame('bar', cache('foo'));
|
||||
|
||||
tenancy()->init('bar.localhost');
|
||||
tenancy()->endTenancy();
|
||||
tenancy()->initialize($tenant2);
|
||||
tenancy()->end();
|
||||
|
||||
tenancy()->init('foo.localhost');
|
||||
tenancy()->initialize($tenant1);
|
||||
$this->assertSame('bar', cache('foo'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,164 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Stancl\Tenancy\StorageDrivers\Database\DatabaseStorageDriver;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
|
||||
class CachedResolverTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (config('tenancy.storage_driver') !== 'db') {
|
||||
$this->markTestSkipped('This test is only relevant for the DB storage driver.');
|
||||
}
|
||||
|
||||
config(['tenancy.storage_drivers.db.cache_store' => config('cache.default')]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_query_is_not_made_for_tenant_id_once_domain_is_cached()
|
||||
{
|
||||
$tenant = Tenant::new()
|
||||
->withData(['foo' => 'bar'])
|
||||
->withDomains(['foo.localhost'])
|
||||
->save();
|
||||
|
||||
// query is made
|
||||
$queried = tenancy()->findByDomain('foo.localhost');
|
||||
$this->assertEquals($tenant->data, $queried->data);
|
||||
$this->assertSame($tenant->domains, $queried->domains);
|
||||
|
||||
// cache is set
|
||||
$this->assertEquals($tenant->id, Cache::get('_tenancy_domain_to_id:foo.localhost'));
|
||||
$this->assertEquals($tenant->data, Cache::get('_tenancy_id_to_data:' . $tenant->id));
|
||||
$this->assertSame($tenant->domains, Cache::get('_tenancy_id_to_domains:' . $tenant->id));
|
||||
|
||||
// query is not made
|
||||
DatabaseStorageDriver::getCentralConnection()->enableQueryLog();
|
||||
$cached = tenancy()->findByDomain('foo.localhost');
|
||||
$this->assertEquals($tenant->data, $cached->data);
|
||||
$this->assertSame($tenant->domains, $cached->domains);
|
||||
$this->assertSame([], DatabaseStorageDriver::getCentralConnection()->getQueryLog());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_query_is_not_made_for_tenant_once_id_is_cached()
|
||||
{
|
||||
$tenant = Tenant::new()
|
||||
->withData(['foo' => 'bar'])
|
||||
->withDomains(['foo.localhost'])
|
||||
->save();
|
||||
|
||||
// query is made
|
||||
$queried = tenancy()->find($tenant->id);
|
||||
$this->assertEquals($tenant->data, $queried->data);
|
||||
$this->assertSame($tenant->domains, $queried->domains);
|
||||
|
||||
// cache is set
|
||||
$this->assertEquals($tenant->data, Cache::get('_tenancy_id_to_data:' . $tenant->id));
|
||||
$this->assertSame($tenant->domains, Cache::get('_tenancy_id_to_domains:' . $tenant->id));
|
||||
|
||||
// query is not made
|
||||
DatabaseStorageDriver::getCentralConnection()->enableQueryLog();
|
||||
$cached = tenancy()->find($tenant->id);
|
||||
$this->assertEquals($tenant->data, $cached->data);
|
||||
$this->assertSame($tenant->domains, $cached->domains);
|
||||
$this->assertSame([], DatabaseStorageDriver::getCentralConnection()->getQueryLog());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function modifying_tenant_domains_invalidates_the_cached_domain_to_id_mapping()
|
||||
{
|
||||
$tenant = Tenant::new()
|
||||
->withDomains(['foo.localhost', 'bar.localhost'])
|
||||
->save();
|
||||
|
||||
// queried
|
||||
$this->assertSame($tenant->id, tenancy()->findByDomain('foo.localhost')->id);
|
||||
$this->assertSame($tenant->id, tenancy()->findByDomain('bar.localhost')->id);
|
||||
|
||||
// assert cache set
|
||||
$this->assertSame($tenant->id, Cache::get('_tenancy_domain_to_id:foo.localhost'));
|
||||
$this->assertSame($tenant->id, Cache::get('_tenancy_domain_to_id:bar.localhost'));
|
||||
|
||||
$tenant
|
||||
->removeDomains(['foo.localhost', 'bar.localhost'])
|
||||
->addDomains(['xyz.localhost'])
|
||||
->save();
|
||||
|
||||
// assert neither domain is cached
|
||||
$this->assertSame(null, Cache::get('_tenancy_domain_to_id:foo.localhost'));
|
||||
$this->assertSame(null, Cache::get('_tenancy_domain_to_id:bar.localhost'));
|
||||
$this->assertSame(null, Cache::get('_tenancy_domain_to_id:xyz.localhost'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function modifying_tenants_data_invalidates_tenant_data_cache()
|
||||
{
|
||||
$tenant = Tenant::new()->withData(['foo' => 'bar'])->save();
|
||||
|
||||
// cache record is set
|
||||
$this->assertSame('bar', tenancy()->find($tenant->id)->get('foo'));
|
||||
$this->assertSame('bar', Cache::get('_tenancy_id_to_data:' . $tenant->id)['foo']);
|
||||
|
||||
// cache record is invalidated
|
||||
$tenant->set('foo', 'xyz');
|
||||
$this->assertSame(null, Cache::get('_tenancy_id_to_data:' . $tenant->id));
|
||||
|
||||
// cache record is set
|
||||
$this->assertSame('xyz', tenancy()->find($tenant->id)->get('foo'));
|
||||
$this->assertSame('xyz', Cache::get('_tenancy_id_to_data:' . $tenant->id)['foo']);
|
||||
|
||||
// cache record is invalidated
|
||||
$tenant->foo = 'abc';
|
||||
$tenant->save();
|
||||
$this->assertSame(null, Cache::get('_tenancy_id_to_data:' . $tenant->id));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function modifying_tenants_domains_invalidates_tenant_domain_cache()
|
||||
{
|
||||
$tenant = Tenant::new()
|
||||
->withData(['foo' => 'bar'])
|
||||
->withDomains(['foo.localhost'])
|
||||
->save();
|
||||
|
||||
// cache record is set
|
||||
$this->assertSame(['foo.localhost'], tenancy()->find($tenant->id)->domains);
|
||||
$this->assertSame(['foo.localhost'], Cache::get('_tenancy_id_to_domains:' . $tenant->id));
|
||||
|
||||
// cache record is invalidated
|
||||
$tenant->addDomains(['bar.localhost'])->save();
|
||||
$this->assertEquals(null, Cache::get('_tenancy_id_to_domains:' . $tenant->id));
|
||||
|
||||
$this->assertEquals(['foo.localhost', 'bar.localhost'], tenancy()->find($tenant->id)->domains);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function deleting_a_tenant_invalidates_all_caches()
|
||||
{
|
||||
$tenant = Tenant::new()
|
||||
->withData(['foo' => 'bar'])
|
||||
->withDomains(['foo.localhost'])
|
||||
->save();
|
||||
|
||||
tenancy()->findByDomain('foo.localhost');
|
||||
$this->assertEquals($tenant->id, Cache::get('_tenancy_domain_to_id:foo.localhost'));
|
||||
$this->assertEquals($tenant->data, Cache::get('_tenancy_id_to_data:' . $tenant->id));
|
||||
$this->assertEquals(['foo.localhost'], Cache::get('_tenancy_id_to_domains:' . $tenant->id));
|
||||
|
||||
$tenant->delete();
|
||||
$this->assertEquals(null, Cache::get('_tenancy_domain_to_id:foo.localhost'));
|
||||
$this->assertEquals(null, Cache::get('_tenancy_id_to_data:' . $tenant->id));
|
||||
$this->assertEquals(null, Cache::get('_tenancy_id_to_domains:' . $tenant->id));
|
||||
}
|
||||
}
|
||||
|
|
@ -2,18 +2,41 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Stancl\Tenancy\Tests\Etc\ExampleSeeder;
|
||||
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\DatabaseTenancyBootstrapper;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class CommandsTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = true;
|
||||
public $autoInitTenancy = false;
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
config(['tenancy.bootstrappers' => [
|
||||
DatabaseTenancyBootstrapper::class
|
||||
]]);
|
||||
|
||||
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
|
||||
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function migrate_command_doesnt_change_the_db_connection()
|
||||
|
|
@ -32,35 +55,42 @@ class CommandsTest extends TestCase
|
|||
/** @test */
|
||||
public function migrate_command_works_without_options()
|
||||
{
|
||||
$tenant = Tenant::create();
|
||||
|
||||
$this->assertFalse(Schema::hasTable('users'));
|
||||
Artisan::call('tenants:migrate');
|
||||
$this->assertFalse(Schema::hasTable('users'));
|
||||
tenancy()->init('test.localhost');
|
||||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertTrue(Schema::hasTable('users'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function migrate_command_works_with_tenants_option()
|
||||
{
|
||||
$tenant = Tenant::new()->withDomains(['test2.localhost'])->save();
|
||||
$tenant = Tenant::create();
|
||||
Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant['id']],
|
||||
]);
|
||||
|
||||
$this->assertFalse(Schema::hasTable('users'));
|
||||
tenancy()->init('test.localhost');
|
||||
tenancy()->initialize(Tenant::create());
|
||||
$this->assertFalse(Schema::hasTable('users'));
|
||||
|
||||
tenancy()->init('test2.localhost');
|
||||
tenancy()->initialize($tenant);
|
||||
$this->assertTrue(Schema::hasTable('users'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function rollback_command_works()
|
||||
{
|
||||
$tenant = Tenant::create();
|
||||
Artisan::call('tenants:migrate');
|
||||
$this->assertFalse(Schema::hasTable('users'));
|
||||
tenancy()->init('test.localhost');
|
||||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertTrue(Schema::hasTable('users'));
|
||||
Artisan::call('tenants:rollback');
|
||||
$this->assertFalse(Schema::hasTable('users'));
|
||||
|
|
@ -93,7 +123,7 @@ class CommandsTest extends TestCase
|
|||
/** @test */
|
||||
public function database_connection_is_switched_to_default_when_tenancy_has_been_initialized()
|
||||
{
|
||||
tenancy()->init('test.localhost');
|
||||
tenancy()->initialize(Tenant::create());
|
||||
|
||||
$this->database_connection_is_switched_to_default();
|
||||
}
|
||||
|
|
@ -101,7 +131,7 @@ class CommandsTest extends TestCase
|
|||
/** @test */
|
||||
public function run_commands_works()
|
||||
{
|
||||
$id = Tenant::new()->withDomains(['run.localhost'])->save()['id'];
|
||||
$id = Tenant::create()->id;
|
||||
|
||||
Artisan::call('tenants:migrate', ['--tenants' => [$id]]);
|
||||
|
||||
|
|
@ -121,34 +151,25 @@ class CommandsTest extends TestCase
|
|||
mkdir($dir, 0777, true);
|
||||
}
|
||||
|
||||
if (app()->version()[0] === '6') {
|
||||
file_put_contents(app_path('Http/Kernel.php'), file_get_contents(__DIR__ . '/Etc/defaultHttpKernelv6.stub'));
|
||||
} else {
|
||||
file_put_contents(app_path('Http/Kernel.php'), file_get_contents(__DIR__ . '/Etc/defaultHttpKernelv7.stub'));
|
||||
}
|
||||
|
||||
$this->artisan('tenancy:install')
|
||||
->expectsQuestion('Do you wish to publish the migrations that create these tables?', 'yes');
|
||||
$this->artisan('tenancy:install');
|
||||
$this->assertFileExists(base_path('routes/tenant.php'));
|
||||
$this->assertFileExists(base_path('config/tenancy.php'));
|
||||
$this->assertFileExists(database_path('migrations/2019_09_15_000010_create_tenants_table.php'));
|
||||
$this->assertFileExists(database_path('migrations/2019_09_15_000020_create_domains_table.php'));
|
||||
$this->assertDirectoryExists(database_path('migrations/tenant'));
|
||||
|
||||
if (app()->version()[0] === '6') {
|
||||
$this->assertSame(file_get_contents(__DIR__ . '/Etc/modifiedHttpKernelv6.stub'), file_get_contents(app_path('Http/Kernel.php')));
|
||||
} else {
|
||||
$this->assertSame(file_get_contents(__DIR__ . '/Etc/modifiedHttpKernelv7.stub'), file_get_contents(app_path('Http/Kernel.php')));
|
||||
}
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function migrate_fresh_command_works()
|
||||
{
|
||||
$tenant = Tenant::create();
|
||||
|
||||
$this->assertFalse(Schema::hasTable('users'));
|
||||
Artisan::call('tenants:migrate-fresh');
|
||||
$this->assertFalse(Schema::hasTable('users'));
|
||||
tenancy()->init('test.localhost');
|
||||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertTrue(Schema::hasTable('users'));
|
||||
|
||||
$this->assertFalse(DB::table('users')->exists());
|
||||
|
|
@ -159,17 +180,4 @@ class CommandsTest extends TestCase
|
|||
Artisan::call('tenants:migrate-fresh');
|
||||
$this->assertFalse(DB::table('users')->exists());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function create_command_works()
|
||||
{
|
||||
Artisan::call('tenants:create -d aaa.localhost -d bbb.localhost plan=free email=foo@test.local');
|
||||
$tenant = tenancy()->all()[1]; // a tenant is autocreated prior to this
|
||||
$data = $tenant->data;
|
||||
unset($data['id']);
|
||||
unset($data['_tenancy_db_name']);
|
||||
|
||||
$this->assertSame(['plan' => 'free', 'email' => 'foo@test.local'], $data);
|
||||
$this->assertSame(['aaa.localhost', 'bbb.localhost'], $tenant->domains);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,154 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Stancl\Tenancy\Tests\Etc\User;
|
||||
|
||||
class DataSeparationTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/** @test */
|
||||
public function databases_are_separated()
|
||||
{
|
||||
$tenant1 = Tenant::create('tenant1.localhost');
|
||||
$tenant2 = Tenant::create('tenant2.localhost');
|
||||
\Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant1['id'], $tenant2['id']],
|
||||
]);
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
User::create([
|
||||
'name' => 'foo',
|
||||
'email' => 'foo@bar.com',
|
||||
'email_verified_at' => now(),
|
||||
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
||||
'remember_token' => Str::random(10),
|
||||
]);
|
||||
$this->assertSame('foo', User::first()->name);
|
||||
|
||||
tenancy()->init('tenant2.localhost');
|
||||
$this->assertSame(null, User::first());
|
||||
|
||||
User::create([
|
||||
'name' => 'xyz',
|
||||
'email' => 'xyz@bar.com',
|
||||
'email_verified_at' => now(),
|
||||
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
||||
'remember_token' => Str::random(10),
|
||||
]);
|
||||
|
||||
$this->assertSame('xyz', User::first()->name);
|
||||
$this->assertSame('xyz@bar.com', User::first()->email);
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
$this->assertSame('foo', User::first()->name);
|
||||
$this->assertSame('foo@bar.com', User::first()->email);
|
||||
|
||||
$tenant3 = Tenant::create('tenant3.localhost');
|
||||
\Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant1['id'], $tenant3['id']],
|
||||
]);
|
||||
|
||||
tenancy()->init('tenant3.localhost');
|
||||
$this->assertSame(null, User::first());
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
DB::table('users')->where('id', 1)->update(['name' => 'xxx']);
|
||||
$this->assertSame('xxx', User::first()->name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function redis_is_separated()
|
||||
{
|
||||
if (! config('tenancy.redis.tenancy')) {
|
||||
$this->markTestSkipped('Redis tenancy disabled.');
|
||||
}
|
||||
|
||||
Tenant::create('tenant1.localhost');
|
||||
Tenant::create('tenant2.localhost');
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
Redis::set('foo', 'bar');
|
||||
$this->assertSame('bar', Redis::get('foo'));
|
||||
|
||||
tenancy()->init('tenant2.localhost');
|
||||
$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()->init('tenant1.localhost');
|
||||
$this->assertSame('bar', Redis::get('foo'));
|
||||
$this->assertSame(null, Redis::get('abc'));
|
||||
|
||||
Tenant::create('tenant3.localhost');
|
||||
tenancy()->init('tenant3.localhost');
|
||||
$this->assertSame(null, Redis::get('foo'));
|
||||
$this->assertSame(null, Redis::get('abc'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function cache_is_separated()
|
||||
{
|
||||
Tenant::create('tenant1.localhost');
|
||||
Tenant::create('tenant2.localhost');
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
Cache::put('foo', 'bar', 60);
|
||||
$this->assertSame('bar', Cache::get('foo'));
|
||||
|
||||
tenancy()->init('tenant2.localhost');
|
||||
$this->assertSame(null, Cache::get('foo'));
|
||||
Cache::put('foo', 'xyz', 60);
|
||||
Cache::put('abc', 'def', 60);
|
||||
$this->assertSame('xyz', Cache::get('foo'));
|
||||
$this->assertSame('def', Cache::get('abc'));
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
$this->assertSame('bar', Cache::get('foo'));
|
||||
$this->assertSame(null, Cache::get('abc'));
|
||||
|
||||
Tenant::create('tenant3.localhost');
|
||||
tenancy()->init('tenant3.localhost');
|
||||
$this->assertSame(null, Cache::get('foo'));
|
||||
$this->assertSame(null, Cache::get('abc'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function filesystem_is_separated()
|
||||
{
|
||||
Tenant::create('tenant1.localhost');
|
||||
Tenant::create('tenant2.localhost');
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
Storage::disk('public')->put('foo', 'bar');
|
||||
$this->assertSame('bar', Storage::disk('public')->get('foo'));
|
||||
|
||||
tenancy()->init('tenant2.localhost');
|
||||
$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()->init('tenant1.localhost');
|
||||
$this->assertSame('bar', Storage::disk('public')->get('foo'));
|
||||
$this->assertFalse(Storage::disk('public')->exists('abc'));
|
||||
|
||||
Tenant::create('tenant3.localhost');
|
||||
tenancy()->init('tenant3.localhost');
|
||||
$this->assertFalse(Storage::disk('public')->exists('foo'));
|
||||
$this->assertFalse(Storage::disk('public')->exists('abc'));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Stancl\Tenancy\DatabaseManager;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
|
||||
class DatabaseManagerTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function reconnect_method_works()
|
||||
{
|
||||
$old_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName();
|
||||
$this->createTenant();
|
||||
$this->initTenancy();
|
||||
app(\Stancl\Tenancy\DatabaseManager::class)->reconnect();
|
||||
$new_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName();
|
||||
|
||||
$this->assertSame($old_connection_name, $new_connection_name);
|
||||
$this->assertNotEquals('tenant', $new_connection_name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function db_name_is_prefixed_with_db_path_when_sqlite_is_used()
|
||||
{
|
||||
if (file_exists(database_path('foodb'))) {
|
||||
unlink(database_path('foodb')); // cleanup
|
||||
}
|
||||
config(['database.connections.fooconn.driver' => 'sqlite']);
|
||||
$tenant = Tenant::new()->withData([
|
||||
'_tenancy_db_name' => 'foodb',
|
||||
'_tenancy_db_connection' => 'fooconn',
|
||||
])->save();
|
||||
app(DatabaseManager::class)->createTenantConnection($tenant);
|
||||
|
||||
$this->assertSame(config('database.connections.tenant.database'), database_path('foodb'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_default_db_is_used_when_template_connection_is_null()
|
||||
{
|
||||
$this->assertSame('central', config('database.default'));
|
||||
config([
|
||||
'database.connections.central.foo' => 'bar',
|
||||
'tenancy.database.template_connection' => null,
|
||||
]);
|
||||
|
||||
$this->createTenant();
|
||||
$this->initTenancy();
|
||||
|
||||
$this->assertSame('tenant', config('database.default'));
|
||||
$this->assertSame('bar', config('database.connections.' . config('database.default') . '.foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ending_tenancy_doesnt_purge_the_central_connection()
|
||||
{
|
||||
$this->markTestIncomplete('Seems like this only happens on MySQL?');
|
||||
|
||||
// regression test for https://github.com/stancl/tenancy/pull/189
|
||||
// config(['tenancy.migrate_after_creation' => true]);
|
||||
|
||||
tenancy()->create(['foo.localhost']);
|
||||
tenancy()->init('foo.localhost');
|
||||
tenancy()->end();
|
||||
|
||||
$this->assertNotEmpty(tenancy()->all());
|
||||
|
||||
tenancy()->all()->each->delete();
|
||||
}
|
||||
}
|
||||
135
tests/DatabasePreparationTest.php
Normal file
135
tests/DatabasePreparationTest.php
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Foundation\Auth\User as Authenticable;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Events\Listeners\JobPipeline;
|
||||
use Stancl\Tenancy\Events\TenantCreated;
|
||||
use Stancl\Tenancy\Jobs\CreateDatabase;
|
||||
use Stancl\Tenancy\Jobs\MigrateDatabase;
|
||||
use Stancl\Tenancy\Jobs\SeedDatabase;
|
||||
use Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class DatabasePreparationTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function database_can_be_created_after_tenant_creation()
|
||||
{
|
||||
config(['tenancy.template_tenant_connection' => 'mysql']);
|
||||
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
$tenant = Tenant::create();
|
||||
|
||||
$this->assertTrue(app(MySQLDatabaseManager::class)->databaseExists($tenant->database()->getName()));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function database_can_be_migrated_after_tenant_creation()
|
||||
{
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([
|
||||
CreateDatabase::class,
|
||||
MigrateDatabase::class,
|
||||
])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
$tenant = Tenant::create();
|
||||
|
||||
$tenant->run(function () {
|
||||
$this->assertTrue(Schema::hasTable('users'));
|
||||
});
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function database_can_be_seeded_after_tenant_creation()
|
||||
{
|
||||
config(['tenancy.seeder_parameters' => [
|
||||
'--class' => TestSeeder::class,
|
||||
]]);
|
||||
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([
|
||||
CreateDatabase::class,
|
||||
MigrateDatabase::class,
|
||||
SeedDatabase::class,
|
||||
])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
$tenant = Tenant::create();
|
||||
|
||||
$tenant->run(function () {
|
||||
$this->assertSame('Seeded User', User::first()->name);
|
||||
});
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function custom_job_can_be_added_to_the_pipeline()
|
||||
{
|
||||
config(['tenancy.seeder_parameters' => [
|
||||
'--class' => TestSeeder::class,
|
||||
]]);
|
||||
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([
|
||||
CreateDatabase::class,
|
||||
MigrateDatabase::class,
|
||||
SeedDatabase::class,
|
||||
CreateSuperuser::class,
|
||||
])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
$tenant = Tenant::create();
|
||||
|
||||
$tenant->run(function () {
|
||||
$this->assertSame('Foo', User::all()[1]->name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class User extends Authenticable
|
||||
{
|
||||
protected $guarded = [];
|
||||
}
|
||||
|
||||
class TestSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
DB::table('users')->insert([
|
||||
'name' => 'Seeded User',
|
||||
'email' => 'seeded@user',
|
||||
'password' => bcrypt('password'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class CreateSuperuser
|
||||
{
|
||||
protected $tenant;
|
||||
|
||||
public function __construct(Tenant $tenant)
|
||||
{
|
||||
$this->tenant = $tenant;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->tenant->run(function () {
|
||||
User::create(['name' => 'Foo', 'email' => 'foo@bar.com', 'password' => 'secret']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Stancl\Tenancy\Tests\Etc\User;
|
||||
|
||||
class DatabaseSchemaManagerTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = true;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
protected function getEnvironmentSetUp($app)
|
||||
{
|
||||
parent::getEnvironmentSetUp($app);
|
||||
|
||||
$app['config']->set([
|
||||
'database.default' => 'pgsql',
|
||||
'tenancy.storage_drivers.db.connection' => 'pgsql',
|
||||
'database.connections.pgsql.database' => 'main',
|
||||
'database.connections.pgsql.schema' => 'public',
|
||||
'tenancy.database.template_connection' => null,
|
||||
'tenancy.database.suffix' => '',
|
||||
'tenancy.database_managers.pgsql' => \Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager::class,
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function reconnect_method_works()
|
||||
{
|
||||
$old_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName();
|
||||
|
||||
tenancy()->init('test.localhost');
|
||||
|
||||
app(\Stancl\Tenancy\DatabaseManager::class)->reconnect();
|
||||
|
||||
$new_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName();
|
||||
|
||||
$this->assertSame($old_connection_name, $new_connection_name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_default_db_is_used_when_template_connection_is_null()
|
||||
{
|
||||
$this->assertSame('pgsql', config('database.default'));
|
||||
config([
|
||||
'database.connections.pgsql.foo' => 'bar',
|
||||
'tenancy.database.template_connection' => null,
|
||||
]);
|
||||
|
||||
tenancy()->init('test.localhost');
|
||||
|
||||
$this->assertSame('tenant', config('database.default'));
|
||||
$this->assertSame('bar', config('database.connections.tenant.foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function make_sure_using_schema_connection()
|
||||
{
|
||||
$tenant = tenancy()->create(['schema.localhost']);
|
||||
tenancy()->init('schema.localhost');
|
||||
|
||||
$this->assertSame($tenant->database()->getName(), config('database.connections.' . config('database.default') . '.schema'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function databases_are_separated_using_schema_and_not_database()
|
||||
{
|
||||
tenancy()->create('foo.localhost');
|
||||
tenancy()->init('foo.localhost');
|
||||
$this->assertSame('tenant', config('database.default'));
|
||||
$this->assertSame('main', config('database.connections.tenant.database'));
|
||||
|
||||
$schema1 = config('database.connections.' . config('database.default') . '.schema');
|
||||
$database1 = config('database.connections.' . config('database.default') . '.database');
|
||||
|
||||
tenancy()->create('bar.localhost');
|
||||
tenancy()->init('bar.localhost');
|
||||
$this->assertSame('tenant', config('database.default'));
|
||||
$this->assertSame('main', config('database.connections.tenant.database'));
|
||||
|
||||
$schema2 = config('database.connections.' . config('database.default') . '.schema');
|
||||
$database2 = config('database.connections.' . config('database.default') . '.database');
|
||||
|
||||
$this->assertSame($database1, $database2);
|
||||
$this->assertNotSame($schema1, $schema2);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function schemas_are_separated()
|
||||
{
|
||||
// copied from DataSeparationTest
|
||||
|
||||
$tenant1 = Tenant::create('tenant1.localhost');
|
||||
$tenant2 = Tenant::create('tenant2.localhost');
|
||||
|
||||
\Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant1['id'], $tenant2['id']],
|
||||
]);
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
User::create([
|
||||
'name' => 'foo',
|
||||
'email' => 'foo@bar.com',
|
||||
'email_verified_at' => now(),
|
||||
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
||||
'remember_token' => Str::random(10),
|
||||
]);
|
||||
$this->assertSame('foo', User::first()->name);
|
||||
|
||||
tenancy()->init('tenant2.localhost');
|
||||
$this->assertSame(null, User::first());
|
||||
|
||||
User::create([
|
||||
'name' => 'xyz',
|
||||
'email' => 'xyz@bar.com',
|
||||
'email_verified_at' => now(),
|
||||
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
||||
'remember_token' => Str::random(10),
|
||||
]);
|
||||
|
||||
$this->assertSame('xyz', User::first()->name);
|
||||
$this->assertSame('xyz@bar.com', User::first()->email);
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
$this->assertSame('foo', User::first()->name);
|
||||
$this->assertSame('foo@bar.com', User::first()->email);
|
||||
|
||||
$tenant3 = Tenant::create('tenant3.localhost');
|
||||
\Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant1['id'], $tenant3['id']],
|
||||
]);
|
||||
|
||||
tenancy()->init('tenant3.localhost');
|
||||
$this->assertSame(null, User::first());
|
||||
|
||||
tenancy()->init('tenant1.localhost');
|
||||
\DB::table('users')->where('id', 1)->update(['name' => 'xxx']);
|
||||
$this->assertSame('xxx', User::first()->name);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,20 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Str;
|
||||
use Stancl\Tenancy\Contracts\ManagesDatabaseUsers;
|
||||
use Stancl\Tenancy\Exceptions\TenantDatabaseUserAlreadyExistsException;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager;
|
||||
use Stancl\Tenancy\TenantDatabaseManagers\PermissionControlledMySQLDatabaseManager;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Events\Listeners\JobPipeline;
|
||||
use Stancl\Tenancy\Events\TenantCreated;
|
||||
use Stancl\Tenancy\Jobs\CreateDatabase;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class DatabaseUsersTest extends TestCase
|
||||
{
|
||||
|
|
@ -21,14 +26,18 @@ class DatabaseUsersTest extends TestCase
|
|||
config([
|
||||
'tenancy.database_managers.mysql' => PermissionControlledMySQLDatabaseManager::class,
|
||||
'tenancy.database.suffix' => '',
|
||||
'tenancy.database.template_connection' => 'mysql',
|
||||
'tenancy.template_tenant_connection' => 'mysql',
|
||||
]);
|
||||
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_are_created_when_permission_controlled_mysql_manager_is_used()
|
||||
{
|
||||
$tenant = Tenant::new()->withData([
|
||||
$tenant = new Tenant([
|
||||
'id' => 'foo' . Str::random(10),
|
||||
]);
|
||||
$tenant->database()->makeCredentials();
|
||||
|
|
@ -46,9 +55,9 @@ class DatabaseUsersTest extends TestCase
|
|||
public function a_tenants_database_cannot_be_created_when_the_user_already_exists()
|
||||
{
|
||||
$username = 'foo' . Str::random(8);
|
||||
$tenant = Tenant::new()->withData([
|
||||
'_tenancy_db_username' => $username,
|
||||
])->save();
|
||||
$tenant = Tenant::create([
|
||||
'tenancy_db_username' => $username,
|
||||
]);
|
||||
|
||||
/** @var ManagesDatabaseUsers $manager */
|
||||
$manager = $tenant->database()->manager();
|
||||
|
|
@ -56,9 +65,9 @@ class DatabaseUsersTest extends TestCase
|
|||
$this->assertTrue($manager->databaseExists($tenant->database()->getName()));
|
||||
|
||||
$this->expectException(TenantDatabaseUserAlreadyExistsException::class);
|
||||
$tenant2 = Tenant::new()->withData([
|
||||
'_tenancy_db_username' => $username,
|
||||
])->save();
|
||||
$tenant2 = Tenant::create([
|
||||
'tenancy_db_username' => $username,
|
||||
]);
|
||||
|
||||
/** @var ManagesDatabaseUsers $manager */
|
||||
$manager = $tenant2->database()->manager();
|
||||
|
|
@ -73,9 +82,9 @@ class DatabaseUsersTest extends TestCase
|
|||
'ALTER', 'ALTER ROUTINE', 'CREATE',
|
||||
];
|
||||
|
||||
$tenant = Tenant::new()->withData([
|
||||
'_tenancy_db_username' => $user = 'user' . Str::random(8),
|
||||
])->save();
|
||||
$tenant = Tenant::create([
|
||||
'tenancy_db_username' => $user = 'user' . Str::random(8),
|
||||
]);
|
||||
|
||||
$query = DB::connection('mysql')->select("SHOW GRANTS FOR `{$tenant->database()->getUsername()}`@`{$tenant->database()->connection()['host']}`")[1];
|
||||
$this->assertStringStartsWith('GRANT CREATE, ALTER, ALTER ROUTINE ON', $query->{"Grants for {$user}@mysql"}); // @mysql because that's the hostname within the docker network
|
||||
|
|
@ -90,15 +99,15 @@ class DatabaseUsersTest extends TestCase
|
|||
'tenancy.database.template_connection' => 'mysql',
|
||||
]);
|
||||
|
||||
$tenant = Tenant::new()->withData([
|
||||
$tenant = Tenant::create([
|
||||
'id' => 'foo' . Str::random(10),
|
||||
])->save();
|
||||
]);
|
||||
|
||||
$this->assertTrue($tenant->database()->manager() instanceof MySQLDatabaseManager);
|
||||
|
||||
$tenant = Tenant::new()->withData([
|
||||
$tenant = Tenant::create([
|
||||
'id' => 'foo' . Str::random(10),
|
||||
])->save();
|
||||
]);
|
||||
|
||||
tenancy()->initialize($tenant); // check if everything works
|
||||
tenancy()->end();
|
||||
|
|
|
|||
|
|
@ -39,10 +39,6 @@ class HttpKernel extends Kernel
|
|||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
|
||||
'tenancy' => [
|
||||
\Stancl\Tenancy\Middleware\InitializeTenancy::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
'throttle:60,1',
|
||||
'bindings',
|
||||
|
|
@ -66,18 +62,5 @@ class HttpKernel extends Kernel
|
|||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
|
||||
'tenancy' => \Stancl\Tenancy\Middleware\InitializeTenancy::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The priority-sorted list of middleware.
|
||||
*
|
||||
* This forces non-global middleware to always be in the given order.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middlewarePriority = [
|
||||
\Stancl\Tenancy\Middleware\InitializeTenancy::class,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Tenancy;
|
||||
use Tenant;
|
||||
|
||||
class FacadeTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = true;
|
||||
public $autoInitTenancy = true;
|
||||
|
||||
/** @test */
|
||||
public function tenant_manager_can_be_accessed_using_the_Tenancy_facade()
|
||||
{
|
||||
$this->assertSame(tenancy()->getTenant(), Tenancy::getTenant());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_storage_can_be_accessed_using_the_Tenant_facade()
|
||||
{
|
||||
tenant()->put('foo', 'bar');
|
||||
Tenant::put('abc', 'xyz');
|
||||
|
||||
$this->assertSame('bar', Tenant::get('foo'));
|
||||
$this->assertSame('xyz', Tenant::get('abc'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_can_be_created_using_the_Tenant_facade()
|
||||
{
|
||||
$this->assertSame('bar', Tenant::create(['foo.localhost'], ['foo' => 'bar'])->foo);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,17 +2,15 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\Features;
|
||||
|
||||
use Route;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Stancl\Tenancy\Features\CrossDomainRedirect;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class RedirectTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/** @test */
|
||||
public function tenant_redirect_macro_replaces_only_the_hostname()
|
||||
{
|
||||
|
|
@ -28,8 +26,8 @@ class RedirectTest extends TestCase
|
|||
return redirect()->route('home')->domain('abcd');
|
||||
});
|
||||
|
||||
Tenant::create('foo.localhost');
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant = Tenant::create();
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->get('/redirect')
|
||||
->assertRedirect('http://abcd/foobar');
|
||||
|
|
@ -42,9 +40,7 @@ class RedirectTest extends TestCase
|
|||
return 'Foo';
|
||||
})->name('foo');
|
||||
|
||||
$this->assertSame('http://foo.localhost/abcdef/as/df', tenant_route('foo', ['a' => 'as', 'b' => 'df'], 'foo.localhost'));
|
||||
$this->assertSame('http://foo.localhost/abcdef', tenant_route('foo', [], 'foo.localhost'));
|
||||
|
||||
$this->assertSame('http://' . request()->getHost() . '/abcdef/x/y', tenant_route('foo', ['a' => 'x', 'b' => 'y']));
|
||||
$this->assertSame('http://foo.localhost/abcdef/as/df', tenant_route('foo.localhost', 'foo', ['a' => 'as', 'b' => 'df']));
|
||||
$this->assertSame('http://foo.localhost/abcdef', tenant_route('foo.localhost', 'foo', []));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Stancl\Tenancy\Contracts\Future\CanFindByAnyKey;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
|
||||
class FutureTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/** @test */
|
||||
public function keys_can_be_deleted_from_tenant_storage()
|
||||
{
|
||||
$tenant = Tenant::new()->withData(['email' => 'foo@example.com', 'role' => 'admin'])->save();
|
||||
|
||||
$this->assertArrayHasKey('email', $tenant->data);
|
||||
$tenant->deleteKey('email');
|
||||
$this->assertArrayNotHasKey('email', $tenant->data);
|
||||
$this->assertArrayNotHasKey('email', tenancy()->all()->first()->data);
|
||||
|
||||
$tenant->put(['foo' => 'bar', 'abc' => 'xyz']);
|
||||
$this->assertArrayHasKey('foo', $tenant->data);
|
||||
$this->assertArrayHasKey('abc', $tenant->data);
|
||||
|
||||
$tenant->deleteKeys(['foo', 'abc']);
|
||||
$this->assertArrayNotHasKey('foo', $tenant->data);
|
||||
$this->assertArrayNotHasKey('abc', $tenant->data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_can_be_identified_using_an_arbitrary_string()
|
||||
{
|
||||
if (! tenancy()->storage instanceof CanFindByAnyKey) {
|
||||
$this->markTestSkipped(get_class(tenancy()->storage) . ' does not implement the CanFindByAnyKey interface.');
|
||||
}
|
||||
|
||||
$tenant = Tenant::new()->withData(['email' => 'foo@example.com'])->save();
|
||||
|
||||
$this->assertSame($tenant->id, tenancy()->findByEmail('foo@example.com')->id);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,28 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use GlobalCache;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Stancl\Tenancy\Facades\GlobalCache;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Events\Listeners\BootstrapTenancy;
|
||||
use Stancl\Tenancy\Events\TenancyInitialized;
|
||||
use Stancl\Tenancy\TenancyBootstrappers\CacheTenancyBootstrapper;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class GlobalCacheTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config(['tenancy.bootstrappers' => [
|
||||
CacheTenancyBootstrapper::class,
|
||||
]]);
|
||||
|
||||
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function global_cache_manager_stores_data_in_global_cache()
|
||||
|
|
@ -19,28 +32,28 @@ class GlobalCacheTest extends TestCase
|
|||
GlobalCache::put(['foo' => 'bar'], 1);
|
||||
$this->assertSame('bar', GlobalCache::get('foo'));
|
||||
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant1 = Tenant::create();
|
||||
tenancy()->initialize($tenant1);
|
||||
$this->assertSame('bar', GlobalCache::get('foo'));
|
||||
|
||||
GlobalCache::put(['abc' => 'xyz'], 1);
|
||||
cache(['def' => 'ghi'], 10);
|
||||
$this->assertSame('ghi', cache('def'));
|
||||
|
||||
tenancy()->endTenancy();
|
||||
tenancy()->end();
|
||||
$this->assertSame('xyz', GlobalCache::get('abc'));
|
||||
$this->assertSame('bar', GlobalCache::get('foo'));
|
||||
$this->assertSame(null, cache('def'));
|
||||
|
||||
Tenant::new()->withDomains(['bar.localhost'])->save();
|
||||
tenancy()->init('bar.localhost');
|
||||
$tenant2 = Tenant::create();
|
||||
tenancy()->initialize($tenant2);
|
||||
$this->assertSame('xyz', GlobalCache::get('abc'));
|
||||
$this->assertSame('bar', GlobalCache::get('foo'));
|
||||
$this->assertSame(null, cache('def'));
|
||||
cache(['def' => 'xxx'], 1);
|
||||
$this->assertSame('xxx', cache('def'));
|
||||
|
||||
tenancy()->init('foo.localhost');
|
||||
tenancy()->initialize($tenant1);
|
||||
$this->assertSame('ghi', cache('def'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
|
|
@ -11,26 +9,46 @@ use Illuminate\Queue\Events\JobProcessing;
|
|||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Spatie\Valuestore\Valuestore;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Events\Listeners\BootstrapTenancy;
|
||||
use Stancl\Tenancy\Events\TenancyInitialized;
|
||||
use Stancl\Tenancy\TenancyBootstrappers\QueueTenancyBootstrapper;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class QueueTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = true;
|
||||
public $autoInitTenancy = true;
|
||||
public $mockConsoleOutput = false;
|
||||
|
||||
/** @test */
|
||||
public function queues_use_non_tenant_db_connection()
|
||||
/** @var Valuestore */
|
||||
protected $valuestore;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
// requires using the db driver
|
||||
$this->markTestIncomplete();
|
||||
parent::setUp();
|
||||
|
||||
config([
|
||||
'tenancy.bootstrappers' => [
|
||||
QueueTenancyBootstrapper::class,
|
||||
],
|
||||
'queue.default' => 'redis',
|
||||
]);
|
||||
|
||||
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
|
||||
|
||||
$this->valuestore = Valuestore::make(__DIR__ . '/../Etc/tmp/queuetest.json')->flush();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenancy_is_initialized_inside_queues()
|
||||
public function tenant_id_is_passed_to_tenant_queues()
|
||||
{
|
||||
$this->loadLaravelMigrations(['--database' => 'tenant']);
|
||||
$tenant = Tenant::create();
|
||||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
Event::fake();
|
||||
|
||||
dispatch(new TestJob());
|
||||
dispatch(new TestJob($this->valuestore));
|
||||
|
||||
Event::assertDispatched(JobProcessing::class, function ($event) {
|
||||
return $event->job->payload()['tenant_id'] === tenant('id');
|
||||
|
|
@ -38,40 +56,81 @@ class QueueTest extends TestCase
|
|||
}
|
||||
|
||||
/** @test */
|
||||
public function tenancy_is_not_initialized_in_non_tenant_queues()
|
||||
public function tenant_id_is_not_passed_to_central_queues()
|
||||
{
|
||||
$this->loadLaravelMigrations(['--database' => 'tenant']);
|
||||
$tenant = Tenant::create();
|
||||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
Event::fake();
|
||||
|
||||
dispatch(new TestJob())->onConnection('central');
|
||||
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 */
|
||||
public function tenancy_is_initialized_inside_queues()
|
||||
{
|
||||
$tenant = Tenant::create([
|
||||
'id' => 'acme',
|
||||
]);
|
||||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
dispatch(new TestJob($this->valuestore));
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
/** @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'));
|
||||
}
|
||||
}
|
||||
|
||||
class TestJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
/** @var Valuestore */
|
||||
protected $valuestore;
|
||||
|
||||
public function __construct(Valuestore $valuestore)
|
||||
{
|
||||
//
|
||||
$this->valuestore = $valuestore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
logger(json_encode(\DB::table('users')->get()));
|
||||
$this->valuestore->put('tenant_id', "The current tenant id is: " . tenant('id'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Stancl\Tenancy\Tenant;
|
||||
|
||||
class ReidentificationTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = true;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/**
|
||||
* These tests are run when a tenant is identified after another tenant has already been identified.
|
||||
*/
|
||||
|
||||
/** @test */
|
||||
public function storage_facade_roots_are_correct()
|
||||
{
|
||||
$originals = [];
|
||||
|
||||
foreach (config('tenancy.filesystem.disks') as $disk) {
|
||||
$originals[$disk] = config("filesystems.disks.{$disk}.root");
|
||||
}
|
||||
|
||||
tenancy()->init('test.localhost');
|
||||
Tenant::new()->withDomains(['second.localhost'])->save();
|
||||
tenancy()->init('second.localhost');
|
||||
|
||||
foreach (config('tenancy.filesystem.disks') as $disk) {
|
||||
$suffix = config('tenancy.filesystem.suffix_base') . tenant('id');
|
||||
$current_path_prefix = \Storage::disk($disk)->getAdapter()->getPathPrefix();
|
||||
|
||||
if ($override = config("tenancy.filesystem.root_override.{$disk}")) {
|
||||
$correct_path_prefix = str_replace('%storage_path%', storage_path(), $override);
|
||||
} else {
|
||||
if ($base = $originals[$disk]) {
|
||||
$correct_path_prefix = $base . "/$suffix/";
|
||||
} else {
|
||||
$correct_path_prefix = "$suffix/";
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertSame($correct_path_prefix, $current_path_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function storage_path_is_correct()
|
||||
{
|
||||
$original = storage_path();
|
||||
|
||||
tenancy()->init('test.localhost');
|
||||
Tenant::new()->withDomains(['second.localhost'])->save();
|
||||
tenancy()->init('second.localhost');
|
||||
|
||||
$suffix = config('tenancy.filesystem.suffix_base') . tenant('id');
|
||||
$this->assertSame($original . "/$suffix", storage_path());
|
||||
}
|
||||
}
|
||||
|
|
@ -2,27 +2,28 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class RequestDataIdentificationTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config([
|
||||
'tenancy.exempt_domains' => [
|
||||
'tenancy.central_domains' => [
|
||||
'localhost',
|
||||
],
|
||||
]);
|
||||
|
||||
InitializeTenancyByRequestData::$header = 'X-Tenant';
|
||||
InitializeTenancyByRequestData::$queryParameter = 'tenant';
|
||||
|
||||
Route::middleware(InitializeTenancyByRequestData::class)->get('/test', function () {
|
||||
return 'Tenant id: ' . tenant('id');
|
||||
});
|
||||
|
|
@ -31,11 +32,9 @@ class RequestDataIdentificationTest extends TestCase
|
|||
/** @test */
|
||||
public function header_identification_works()
|
||||
{
|
||||
$this->app->bind(InitializeTenancyByRequestData::class, function () {
|
||||
return new InitializeTenancyByRequestData('X-Tenant');
|
||||
});
|
||||
$tenant = Tenant::new()->save();
|
||||
$tenant2 = Tenant::new()->save();
|
||||
InitializeTenancyByRequestData::$header = 'X-Tenant';
|
||||
$tenant = Tenant::create();
|
||||
$tenant2 = Tenant::create();
|
||||
|
||||
$this
|
||||
->withoutExceptionHandling()
|
||||
|
|
@ -48,11 +47,11 @@ class RequestDataIdentificationTest extends TestCase
|
|||
/** @test */
|
||||
public function query_parameter_identification_works()
|
||||
{
|
||||
$this->app->bind(InitializeTenancyByRequestData::class, function () {
|
||||
return new InitializeTenancyByRequestData(null, 'tenant');
|
||||
});
|
||||
$tenant = Tenant::new()->save();
|
||||
$tenant2 = Tenant::new()->save();
|
||||
InitializeTenancyByRequestData::$header = null;
|
||||
InitializeTenancyByRequestData::$queryParameter = 'tenant';
|
||||
|
||||
$tenant = Tenant::create();
|
||||
$tenant2 = Tenant::create();
|
||||
|
||||
$this
|
||||
->withoutExceptionHandling()
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class TenancyBootstrappersTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = true;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/** @test */
|
||||
public function database_connection_is_switched()
|
||||
{
|
||||
$old_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName();
|
||||
$this->initTenancy();
|
||||
$new_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName();
|
||||
|
||||
$this->assertNotEquals($old_connection_name, $new_connection_name);
|
||||
$this->assertEquals('tenant', $new_connection_name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function redis_is_prefixed()
|
||||
{
|
||||
if (! config('tenancy.redis.tenancy')) {
|
||||
$this->markTestSkipped('Redis tenancy disabled.');
|
||||
}
|
||||
|
||||
$this->initTenancy();
|
||||
foreach (config('tenancy.redis.prefixed_connections', ['default']) as $connection) {
|
||||
$prefix = config('tenancy.redis.prefix_base') . tenant('id');
|
||||
$client = Redis::connection($connection)->client();
|
||||
$this->assertEquals($prefix, $client->getOption($client::OPT_PREFIX));
|
||||
}
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function filesystem_is_suffixed()
|
||||
{
|
||||
$old_storage_path = storage_path();
|
||||
$old_storage_facade_roots = [];
|
||||
foreach (config('tenancy.filesystem.disks') as $disk) {
|
||||
$old_storage_facade_roots[$disk] = config("filesystems.disks.{$disk}.root");
|
||||
}
|
||||
|
||||
$this->initTenancy();
|
||||
|
||||
$new_storage_path = storage_path();
|
||||
$this->assertEquals($old_storage_path . '/' . config('tenancy.filesystem.suffix_base') . tenant('id'), $new_storage_path);
|
||||
|
||||
foreach (config('tenancy.filesystem.disks') as $disk) {
|
||||
$suffix = config('tenancy.filesystem.suffix_base') . tenant('id');
|
||||
$current_path_prefix = \Storage::disk($disk)->getAdapter()->getPathPrefix();
|
||||
|
||||
if ($override = config("tenancy.filesystem.root_override.{$disk}")) {
|
||||
$correct_path_prefix = str_replace('%storage_path%', storage_path(), $override);
|
||||
} else {
|
||||
if ($base = $old_storage_facade_roots[$disk]) {
|
||||
$correct_path_prefix = $base . "/$suffix/";
|
||||
} else {
|
||||
$correct_path_prefix = "$suffix/";
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertSame($correct_path_prefix, $current_path_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function cache_is_tagged()
|
||||
{
|
||||
$this->assertSame(['foo'], cache()->tags('foo')->getTags()->getNames());
|
||||
$this->initTenancy();
|
||||
|
||||
$expected = [config('tenancy.cache.tag_base') . tenant('id'), 'foo', 'bar'];
|
||||
$this->assertEquals($expected, cache()->tags(['foo', 'bar'])->getTags()->getNames());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_default_db_connection_is_used_when_the_config_value_is_null()
|
||||
{
|
||||
$original = config('database.default');
|
||||
tenancy()->create(['foo.localhost']);
|
||||
tenancy()->init('foo.localhost');
|
||||
|
||||
$this->assertSame(null, config("database.connections.$original.foo"));
|
||||
|
||||
config(["database.connections.$original.foo" => 'bar']);
|
||||
tenancy()->create(['bar.localhost']);
|
||||
tenancy()->init('bar.localhost');
|
||||
|
||||
$this->assertSame('bar', config("database.connections.$original.foo"));
|
||||
}
|
||||
}
|
||||
|
|
@ -2,29 +2,58 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Stancl\Tenancy\Controllers\TenantAssetsController;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Events\Listeners\BootstrapTenancy;
|
||||
use Stancl\Tenancy\Events\TenancyInitialized;
|
||||
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
|
||||
use Stancl\Tenancy\Middleware\InitializeTenancyByRequestData;
|
||||
use Stancl\Tenancy\TenancyBootstrappers\FilesystemTenancyBootstrapper;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class TenantAssetTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config(['tenancy.bootstrappers' => [
|
||||
FilesystemTenancyBootstrapper::class
|
||||
]]);
|
||||
|
||||
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
// Cleanup
|
||||
TenantAssetsController::$tenancyMiddleware = InitializeTenancyByDomain::class;
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function asset_can_be_accessed_using_the_url_returned_by_the_tenant_asset_helper()
|
||||
{
|
||||
Tenant::create('localhost');
|
||||
tenancy()->init('localhost');
|
||||
TenantAssetsController::$tenancyMiddleware = InitializeTenancyByRequestData::class;
|
||||
|
||||
$tenant = Tenant::create();
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$filename = 'testfile' . $this->randomString(10);
|
||||
\Storage::disk('public')->put($filename, 'bar');
|
||||
Storage::disk('public')->put($filename, 'bar');
|
||||
$path = storage_path("app/public/$filename");
|
||||
|
||||
// response()->file() returns BinaryFileResponse whose content is
|
||||
// inaccessible via getContent, so ->assertSee() can't be used
|
||||
$this->assertFileExists($path);
|
||||
$response = $this->get(tenant_asset($filename));
|
||||
$response = $this->get(tenant_asset($filename), [
|
||||
'X-Tenant' => $tenant->id,
|
||||
]);
|
||||
|
||||
$response->assertSuccessful();
|
||||
|
||||
|
|
@ -40,8 +69,8 @@ class TenantAssetTest extends TestCase
|
|||
{
|
||||
config(['app.asset_url' => null]);
|
||||
|
||||
Tenant::create('foo.localhost');
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant = Tenant::create();
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertSame(route('stancl.tenancy.asset', ['path' => 'foo']), asset('foo'));
|
||||
}
|
||||
|
|
@ -51,8 +80,8 @@ class TenantAssetTest extends TestCase
|
|||
{
|
||||
config(['app.asset_url' => 'https://an-s3-bucket']);
|
||||
|
||||
$tenant = Tenant::create(['foo.localhost']);
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant = Tenant::create();
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertSame("https://an-s3-bucket/tenant{$tenant->id}/foo", asset('foo'));
|
||||
}
|
||||
|
|
@ -63,8 +92,8 @@ class TenantAssetTest extends TestCase
|
|||
$original = global_asset('foobar');
|
||||
$this->assertSame(asset('foobar'), global_asset('foobar'));
|
||||
|
||||
Tenant::create(['foo.localhost']);
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant = Tenant::create();
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertSame($original, global_asset('foobar'));
|
||||
}
|
||||
|
|
@ -79,8 +108,8 @@ class TenantAssetTest extends TestCase
|
|||
'tenancy.filesystem.asset_helper_tenancy' => false,
|
||||
]);
|
||||
|
||||
Tenant::create('foo.localhost');
|
||||
tenancy()->init('foo.localhost');
|
||||
$tenant = Tenant::create();
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertSame($original, asset('foo'));
|
||||
}
|
||||
|
|
|
|||
34
tests/TenantAwareCommandTest.php
Normal file
34
tests/TenantAwareCommandTest.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class TenantAwareCommandTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function commands_run_globally_are_tenant_aware_and_return_valid_exit_code()
|
||||
{
|
||||
$tenant1 = Tenant::create();
|
||||
$tenant2 = Tenant::create();
|
||||
Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant1['id'], $tenant2['id']],
|
||||
]);
|
||||
|
||||
$this->artisan('user:add')
|
||||
->assertExitCode(0);
|
||||
|
||||
tenancy()->initialize($tenant1);
|
||||
$this->assertNotEmpty(DB::table('users')->get());
|
||||
tenancy()->end();
|
||||
|
||||
tenancy()->initialize($tenant2);
|
||||
$this->assertNotEmpty(DB::table('users')->get());
|
||||
tenancy()->end();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Mockery;
|
||||
use Stancl\Tenancy\Contracts\StorageDriver;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Tenancy;
|
||||
|
||||
class TenantClassTest extends TestCase
|
||||
{
|
||||
public $autoInitTenancy = false;
|
||||
public $autoCreateTenant = false;
|
||||
|
||||
/** @test */
|
||||
public function data_cache_works_properly()
|
||||
{
|
||||
// $spy = Mockery::spy(config('tenancy.storage_driver'))->makePartial();
|
||||
// $this->instance(StorageDriver::class, $spy);
|
||||
|
||||
$tenant = Tenant::create(['foo.localhost'], ['foo' => 'bar']);
|
||||
$this->assertSame('bar', $tenant->data['foo']);
|
||||
|
||||
$tenant->put('abc', 'xyz');
|
||||
$this->assertSame('xyz', $tenant->data['abc']);
|
||||
|
||||
$tenant->put(['aaa' => 'bbb', 'ccc' => 'ddd']);
|
||||
$this->assertSame('bbb', $tenant->data['aaa']);
|
||||
$this->assertSame('ddd', $tenant->data['ccc']);
|
||||
|
||||
// $spy->shouldNotHaveReceived('get');
|
||||
|
||||
$this->assertSame(null, $tenant->dfuighdfuigfhdui);
|
||||
// $spy->shouldHaveReceived('get')->once();
|
||||
|
||||
Mockery::close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_can_have_multiple_domains()
|
||||
{
|
||||
$tenant = Tenant::create(['foo.localhost', 'bar.localhost']);
|
||||
$this->assertSame(['foo.localhost', 'bar.localhost'], $tenant->domains);
|
||||
$this->assertSame($tenant->id, Tenancy::findByDomain('foo.localhost')->id);
|
||||
$this->assertSame($tenant->id, Tenancy::findByDomain('bar.localhost')->id);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function updating_a_tenant_works()
|
||||
{
|
||||
$id = 'abc' . $this->randomString();
|
||||
$tenant = Tenant::create(['foo.localhost'], ['id' => $id]);
|
||||
$tenant->foo = 'bar';
|
||||
$tenant->save();
|
||||
$this->assertEquals(['id' => $id, 'foo' => 'bar', '_tenancy_db_name' => $tenant->database()->getName()], $tenant->data);
|
||||
$this->assertEquals(['id' => $id, 'foo' => 'bar', '_tenancy_db_name' => $tenant->database()->getName()], tenancy()->find($id)->data);
|
||||
|
||||
$tenant->addDomains('abc.localhost');
|
||||
$tenant->save();
|
||||
$this->assertEqualsCanonicalizing(['foo.localhost', 'abc.localhost'], $tenant->domains);
|
||||
$this->assertEqualsCanonicalizing(['foo.localhost', 'abc.localhost'], tenancy()->find($id)->domains);
|
||||
|
||||
$tenant->removeDomains(['foo.localhost']);
|
||||
$tenant->save();
|
||||
$this->assertEqualsCanonicalizing(['abc.localhost'], $tenant->domains);
|
||||
$this->assertEqualsCanonicalizing(['abc.localhost'], tenancy()->find($id)->domains);
|
||||
|
||||
$tenant->withDomains(['completely.localhost', 'different.localhost', 'domains.localhost']);
|
||||
$tenant->save();
|
||||
$this->assertEqualsCanonicalizing(['completely.localhost', 'different.localhost', 'domains.localhost'], $tenant->domains);
|
||||
$this->assertEqualsCanonicalizing(['completely.localhost', 'different.localhost', 'domains.localhost'], tenancy()->find($id)->domains);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function with_methods_work()
|
||||
{
|
||||
$id = 'foo' . $this->randomString();
|
||||
$tenant = Tenant::new()->withDomains(['foo.localhost'])->with('id', $id);
|
||||
$this->assertSame($id, $tenant->id);
|
||||
|
||||
$id2 = 'bar' . $this->randomString();
|
||||
$tenant2 = Tenant::new()->withDomains(['bar.localhost'])->withId($id2)->withFooBar('xyz');
|
||||
$this->assertSame($id2, $tenant2->data['id']);
|
||||
$this->assertSame('xyz', $tenant2->foo_bar);
|
||||
$this->assertArrayHasKey('foo_bar', $tenant2->data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function an_exception_is_thrown_when_an_unknown_method_is_called()
|
||||
{
|
||||
$tenant = Tenant::new();
|
||||
$this->expectException(\BadMethodCallException::class);
|
||||
$tenant->sdjigndfgnjdfgj();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_data_can_be_set_during_creation()
|
||||
{
|
||||
Tenant::new()->withData(['foo' => 'bar'])->save();
|
||||
|
||||
$data = tenancy()->all()->first()->data;
|
||||
unset($data['id']);
|
||||
unset($data['_tenancy_db_name']);
|
||||
|
||||
$this->assertSame(['foo' => 'bar'], $data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function run_method_works()
|
||||
{
|
||||
$this->assertSame(null, tenancy()->getTenant());
|
||||
|
||||
$users_table_empty = function () {
|
||||
return count(\DB::table('users')->get()) === 0;
|
||||
};
|
||||
|
||||
$tenant = Tenant::new()->save();
|
||||
\Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant->id],
|
||||
]);
|
||||
tenancy()->initialize($tenant);
|
||||
$this->assertTrue($users_table_empty());
|
||||
tenancy()->end();
|
||||
|
||||
$foo = $tenant->run(function () {
|
||||
\DB::table('users')->insert([
|
||||
'name' => 'foo',
|
||||
'email' => 'foo@bar.xy',
|
||||
'password' => bcrypt('secret'),
|
||||
]);
|
||||
|
||||
return 'foo';
|
||||
});
|
||||
|
||||
// test return value
|
||||
$this->assertSame('foo', $foo);
|
||||
|
||||
// test that tenancy was ended
|
||||
$this->assertSame(false, tenancy()->initialized);
|
||||
$this->assertSame(null, tenancy()->getTenant());
|
||||
|
||||
// test closure
|
||||
tenancy()->initialize($tenant);
|
||||
$this->assertFalse($users_table_empty());
|
||||
|
||||
// test returning to original tenant
|
||||
$tenant2 = Tenant::new()->save();
|
||||
\Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant2->id],
|
||||
]);
|
||||
|
||||
tenancy()->initialize($tenant2);
|
||||
$this->assertSame($tenant2, tenancy()->getTenant());
|
||||
$this->assertTrue($users_table_empty());
|
||||
|
||||
$tenant->run(function () {
|
||||
\DB::table('users')->insert([
|
||||
'name' => 'bar',
|
||||
'email' => 'bar@bar.xy',
|
||||
'password' => bcrypt('secret'),
|
||||
]);
|
||||
});
|
||||
|
||||
$this->assertSame($tenant2, tenancy()->getTenant());
|
||||
|
||||
$this->assertSame(2, $tenant->run(function () {
|
||||
return \DB::table('users')->count();
|
||||
}));
|
||||
|
||||
// test that the tenant variable can be accessed
|
||||
$this->assertSame($tenant->id, $tenant->run(function ($tenant) {
|
||||
return $tenant->id;
|
||||
}));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function extra_config_is_merged_into_the_connection_config_array()
|
||||
{
|
||||
$tenant = Tenant::new()->withData([
|
||||
'_tenancy_db_link' => 'foo',
|
||||
'_tenancy_db_name' => 'dbname',
|
||||
'_tenancy_db_username' => 'usernamefoo',
|
||||
'_tenancy_db_password' => 'passwordfoo',
|
||||
'_tenancy_db_connection' => 'mysql',
|
||||
]);
|
||||
|
||||
config(['database.connections.mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => null,
|
||||
'host' => 'mysql',
|
||||
'port' => '3306',
|
||||
'database' => 'main',
|
||||
'username' => 'root',
|
||||
'password' => 'password',
|
||||
'unix_socket' => '',
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => [],
|
||||
]]);
|
||||
|
||||
$this->assertEquals([
|
||||
'database' => 'dbname',
|
||||
'username' => 'usernamefoo',
|
||||
'password' => 'passwordfoo',
|
||||
'link' => 'foo',
|
||||
|
||||
'driver' => 'mysql',
|
||||
'url' => null,
|
||||
'host' => 'mysql',
|
||||
'port' => '3306',
|
||||
'unix_socket' => '',
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => [],
|
||||
], $tenant->database()->connection());
|
||||
}
|
||||
}
|
||||
|
|
@ -2,44 +2,50 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseCreator;
|
||||
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseDeleter;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\DatabaseManager;
|
||||
use Stancl\Tenancy\Events\Listeners\BootstrapTenancy;
|
||||
use Stancl\Tenancy\Events\Listeners\JobPipeline;
|
||||
use Stancl\Tenancy\Events\TenancyInitialized;
|
||||
use Stancl\Tenancy\Events\TenantCreated;
|
||||
use Stancl\Tenancy\Jobs\CreateDatabase;
|
||||
use Stancl\Tenancy\TenancyBootstrappers\DatabaseTenancyBootstrapper;
|
||||
use Stancl\Tenancy\TenantDatabaseManagers\MySQLDatabaseManager;
|
||||
use Stancl\Tenancy\TenantDatabaseManagers\PermissionControlledMySQLDatabaseManager;
|
||||
use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLDatabaseManager;
|
||||
use Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager;
|
||||
use Stancl\Tenancy\TenantDatabaseManagers\SQLiteDatabaseManager;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class TenantDatabaseManagerTest extends TestCase
|
||||
{
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider database_manager_provider
|
||||
*/
|
||||
public function databases_can_be_created_and_deleted($driver, $databaseManager)
|
||||
{
|
||||
if (! $this->isContainerized()) {
|
||||
$this->markTestSkipped('As to not bloat your computer with test databases, this test is not run by default.');
|
||||
}
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
config()->set([
|
||||
"tenancy.database_managers.$driver" => $databaseManager,
|
||||
'tenancy.internal_prefix' => 'tenancy_',
|
||||
]);
|
||||
|
||||
$name = 'db' . $this->randomString();
|
||||
$tenant = Tenant::new()->withData([
|
||||
'_tenancy_db_name' => $name,
|
||||
'_tenancy_db_connection' => $driver,
|
||||
]);
|
||||
|
||||
$this->assertFalse(app($databaseManager)->databaseExists($name));
|
||||
$tenant->save(); // generate credentials & create DB
|
||||
|
||||
$tenant = Tenant::create([
|
||||
'tenancy_db_name' => $name,
|
||||
'tenancy_db_connection' => $driver,
|
||||
]);
|
||||
|
||||
$this->assertTrue(app($databaseManager)->databaseExists($name));
|
||||
app($databaseManager)->deleteDatabase($tenant);
|
||||
$this->assertFalse(app($databaseManager)->databaseExists($name));
|
||||
|
|
@ -50,60 +56,34 @@ class TenantDatabaseManagerTest extends TestCase
|
|||
{
|
||||
$this->assertSame('central', config('database.default'));
|
||||
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
// todo if the prefix is _tenancy_, this blows up. write a tenantmodel test that the prefix can be _tenancy_
|
||||
config(['tenancy.internal_prefix' => 'tenancy_',]);
|
||||
|
||||
$database = 'db' . $this->randomString();
|
||||
$tenant = Tenant::new()->withData([
|
||||
'_tenancy_db_name' => $database,
|
||||
'_tenancy_db_connection' => 'mysql',
|
||||
]);
|
||||
|
||||
$this->assertFalse(app(MySQLDatabaseManager::class)->databaseExists($database));
|
||||
$tenant->save(); // create DB
|
||||
Tenant::create([
|
||||
'tenancy_db_name' => $database,
|
||||
'tenancy_db_connection' => 'mysql',
|
||||
]);
|
||||
|
||||
$this->assertTrue(app(MySQLDatabaseManager::class)->databaseExists($database));
|
||||
|
||||
$database = 'db' . $this->randomString();
|
||||
$tenant = Tenant::new()->withData([
|
||||
'_tenancy_db_name' => $database,
|
||||
'_tenancy_db_connection' => 'pgsql',
|
||||
]);
|
||||
|
||||
$this->assertFalse(app(PostgreSQLDatabaseManager::class)->databaseExists($database));
|
||||
$tenant->save(); // create DB
|
||||
|
||||
Tenant::create([
|
||||
'tenancy_db_name' => $database,
|
||||
'tenancy_db_connection' => 'pgsql',
|
||||
]);
|
||||
|
||||
$this->assertTrue(app(PostgreSQLDatabaseManager::class)->databaseExists($database));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider database_manager_provider
|
||||
*/
|
||||
public function databases_can_be_created_and_deleted_using_queued_commands($driver, $databaseManager)
|
||||
{
|
||||
if (! $this->isContainerized()) {
|
||||
$this->markTestSkipped('As to not bloat your computer with test databases, this test is not run by default.');
|
||||
}
|
||||
|
||||
config()->set([
|
||||
'database.default' => $driver,
|
||||
"tenancy.database_managers.$driver" => $databaseManager,
|
||||
]);
|
||||
|
||||
$name = 'db' . $this->randomString();
|
||||
$tenant = Tenant::new()->withData([
|
||||
'_tenancy_db_name' => $name,
|
||||
'_tenancy_db_connection' => $driver,
|
||||
]);
|
||||
$tenant->database()->makeCredentials();
|
||||
|
||||
$this->assertFalse(app($databaseManager)->databaseExists($name));
|
||||
$job = new QueuedTenantDatabaseCreator(app($databaseManager), $tenant);
|
||||
|
||||
$job->handle();
|
||||
$this->assertTrue(app($databaseManager)->databaseExists($name));
|
||||
|
||||
$job = new QueuedTenantDatabaseDeleter(app($databaseManager), $tenant);
|
||||
$job->handle();
|
||||
$this->assertFalse(app($databaseManager)->databaseExists($name));
|
||||
}
|
||||
|
||||
public function database_manager_provider()
|
||||
{
|
||||
return [
|
||||
|
|
@ -116,30 +96,49 @@ class TenantDatabaseManagerTest extends TestCase
|
|||
}
|
||||
|
||||
/** @test */
|
||||
public function database_creation_can_be_queued()
|
||||
public function db_name_is_prefixed_with_db_path_when_sqlite_is_used()
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
config()->set([
|
||||
'tenancy.queue_database_creation' => true,
|
||||
if (file_exists(database_path('foodb'))) {
|
||||
unlink(database_path('foodb')); // cleanup
|
||||
}
|
||||
config([
|
||||
'database.connections.fooconn.driver' => 'sqlite',
|
||||
'tenancy.internal_prefix' => 'tenancy_',
|
||||
]);
|
||||
Tenant::create(['test2.localhost']);
|
||||
|
||||
Queue::assertPushed(QueuedTenantDatabaseCreator::class);
|
||||
$tenant = Tenant::create([
|
||||
'tenancy_db_name' => 'foodb',
|
||||
'tenancy_db_connection' => 'fooconn',
|
||||
]);
|
||||
app(DatabaseManager::class)->createTenantConnection($tenant);
|
||||
|
||||
$this->assertSame(config('database.connections.tenant.database'), database_path('foodb'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function database_deletion_can_be_queued()
|
||||
public function schema_manager_uses_schema_to_separate_tenant_dbs()
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
$tenant = Tenant::create(['test2.localhost']);
|
||||
config()->set([
|
||||
'tenancy.queue_database_deletion' => true,
|
||||
'tenancy.delete_database_after_tenant_deletion' => true,
|
||||
config([
|
||||
'tenancy.database_managers.pgsql' => \Stancl\Tenancy\TenantDatabaseManagers\PostgreSQLSchemaManager::class,
|
||||
'tenancy.boostrappers' => [
|
||||
DatabaseTenancyBootstrapper::class,
|
||||
],
|
||||
]);
|
||||
$tenant->delete();
|
||||
|
||||
Queue::assertPushed(QueuedTenantDatabaseDeleter::class);
|
||||
Event::listen(TenantCreated::class, JobPipeline::make([CreateDatabase::class])->send(function (TenantCreated $event) {
|
||||
return $event->tenant;
|
||||
})->toListener());
|
||||
|
||||
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
|
||||
|
||||
$originalDatabaseName = config(['database.connections.pgsql.database']);
|
||||
|
||||
$tenant = Tenant::create([
|
||||
'tenancy_db_connection' => 'pgsql',
|
||||
]);
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertSame($tenant->database()->getName(), config('database.connections.' . config('database.default') . '.schema'));
|
||||
$this->assertSame($originalDatabaseName, config(['database.connections.pgsql.database']));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,138 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Tenancy;
|
||||
|
||||
class TenantManagerEventsTest extends TestCase
|
||||
{
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/** @test */
|
||||
public function bootstrapping_event_works()
|
||||
{
|
||||
$id = Tenant::new()->withDomains(['foo.localhost'])->save()['id'];
|
||||
|
||||
Tenancy::eventListener('bootstrapping', function ($tenantManager) use ($id) {
|
||||
if ($tenantManager->getTenant('id') === $id) {
|
||||
config(['tenancy.foo' => 'bar']);
|
||||
}
|
||||
});
|
||||
|
||||
$this->assertSame(null, config('tenancy.foo'));
|
||||
tenancy()->init('foo.localhost');
|
||||
$this->assertSame('bar', config('tenancy.foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function bootstrapped_event_works()
|
||||
{
|
||||
$id = Tenant::new()->withDomains(['foo.localhost'])->save()['id'];
|
||||
|
||||
Tenancy::eventListener('bootstrapped', function ($tenantManager) use ($id) {
|
||||
if ($tenantManager->getTenant('id') === $id) {
|
||||
config(['tenancy.foo' => 'bar']);
|
||||
}
|
||||
});
|
||||
|
||||
$this->assertSame(null, config('tenancy.foo'));
|
||||
tenancy()->init('foo.localhost');
|
||||
$this->assertSame('bar', config('tenancy.foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ending_event_works()
|
||||
{
|
||||
$id = Tenant::new()->withDomains(['foo.localhost'])->save()['id'];
|
||||
|
||||
Tenancy::eventListener('ending', function ($tenantManager) use ($id) {
|
||||
if ($tenantManager->getTenant('id') === $id) {
|
||||
config(['tenancy.foo' => 'bar']);
|
||||
}
|
||||
});
|
||||
|
||||
$this->assertSame(null, config('tenancy.foo'));
|
||||
tenancy()->init('foo.localhost');
|
||||
$this->assertSame(null, config('tenancy.foo'));
|
||||
tenancy()->endTenancy();
|
||||
$this->assertSame('bar', config('tenancy.foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ended_event_works()
|
||||
{
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save()['id'];
|
||||
|
||||
Tenancy::eventListener('ended', function ($tenantManager) {
|
||||
config(['tenancy.foo' => 'bar']);
|
||||
});
|
||||
|
||||
$this->assertSame(null, config('tenancy.foo'));
|
||||
tenancy()->init('foo.localhost');
|
||||
$this->assertSame(null, config('tenancy.foo'));
|
||||
tenancy()->endTenancy();
|
||||
$this->assertSame('bar', config('tenancy.foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function database_can_be_reconnected_using_event_hooks()
|
||||
{
|
||||
config(['database.connections.tenantabc' => [
|
||||
'driver' => 'sqlite',
|
||||
'database' => database_path('some_special_database.sqlite'),
|
||||
]]);
|
||||
|
||||
$id = Tenant::create('abc.localhost')['id'];
|
||||
|
||||
Tenancy::eventListener('bootstrapping', function ($tenancy) use ($id) {
|
||||
if ($tenancy->getTenant()['id'] === $id) {
|
||||
$tenancy->database->switchConnection('tenantabc');
|
||||
|
||||
return ['database'];
|
||||
}
|
||||
});
|
||||
|
||||
$this->assertNotSame('tenantabc', \DB::connection()->getConfig()['name']);
|
||||
tenancy()->init('abc.localhost');
|
||||
$this->assertSame('tenantabc', \DB::connection()->getConfig()['name']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function database_cannot_be_reconnected_without_using_prevents()
|
||||
{
|
||||
config(['database.connections.tenantabc' => [
|
||||
'driver' => 'sqlite',
|
||||
'database' => database_path('some_special_database.sqlite'),
|
||||
]]);
|
||||
|
||||
$id = Tenant::create('abc.localhost')['id'];
|
||||
|
||||
Tenancy::eventListener('bootstrapping', function ($tenancy) use ($id) {
|
||||
if ($tenancy->getTenant()['id'] === $id) {
|
||||
$tenancy->database->switchConnection('tenantabc');
|
||||
// return ['database'];
|
||||
}
|
||||
});
|
||||
|
||||
$this->assertNotSame('tenantabc', \DB::connection()->getConfig()['name']);
|
||||
tenancy()->init('abc.localhost');
|
||||
$this->assertSame('tenant', \DB::connection()->getConfig()['name']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_is_persisted_before_the_created_hook_is_called()
|
||||
{
|
||||
$was_persisted = false;
|
||||
|
||||
Tenancy::eventListener('tenant.created', function ($tenancy, $tenant) use (&$was_persisted) {
|
||||
$was_persisted = $tenant->persisted;
|
||||
});
|
||||
|
||||
Tenant::new()->save();
|
||||
|
||||
$this->assertTrue($was_persisted);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,383 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Stancl\Tenancy\Exceptions\DomainsOccupiedByOtherTenantException;
|
||||
use Stancl\Tenancy\Exceptions\TenantDoesNotExistException;
|
||||
use Stancl\Tenancy\Exceptions\TenantWithThisIdAlreadyExistsException;
|
||||
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseCreator;
|
||||
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseMigrator;
|
||||
use Stancl\Tenancy\Jobs\QueuedTenantDatabaseSeeder;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Stancl\Tenancy\TenantManager;
|
||||
use Stancl\Tenancy\Tests\Etc\ExampleSeeder;
|
||||
|
||||
class TenantManagerTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/** @test */
|
||||
public function current_tenant_can_be_retrieved_using_getTenant()
|
||||
{
|
||||
$tenant = Tenant::new()->withDomains(['test2.localhost'])->save();
|
||||
|
||||
tenancy()->init('test2.localhost');
|
||||
|
||||
$this->assertEquals($tenant, tenancy()->getTenant());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function initById_works()
|
||||
{
|
||||
$tenant = Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
|
||||
$this->assertNotEquals($tenant, tenancy()->getTenant());
|
||||
|
||||
tenancy()->initById($tenant['id']);
|
||||
|
||||
$this->assertEquals($tenant, tenancy()->getTenant());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function findByDomain_works()
|
||||
{
|
||||
$tenant = Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
|
||||
$this->assertEquals($tenant, tenancy()->findByDomain('foo.localhost'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function find_works()
|
||||
{
|
||||
Tenant::new()->withDomains(['dev.localhost'])->save();
|
||||
tenancy()->init('dev.localhost');
|
||||
|
||||
$this->assertEquals(tenant(), tenancy()->find(tenant('id')));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function findByDomain_throws_an_exception_when_an_unused_domain_is_supplied()
|
||||
{
|
||||
$this->expectException(\Exception::class);
|
||||
tenancy()->findByDomain('nonexistent.domain');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenancy_can_be_ended()
|
||||
{
|
||||
$originals = [
|
||||
'databaseName' => DB::connection()->getDatabaseName(),
|
||||
'storage_path' => storage_path(),
|
||||
'storage_root' => Storage::disk('local')->getAdapter()->getPathPrefix(),
|
||||
'cache' => app('cache'),
|
||||
];
|
||||
|
||||
// Verify that these assertions are the right way for testing this
|
||||
$this->assertSame($originals['databaseName'], DB::connection()->getDatabaseName());
|
||||
$this->assertSame($originals['storage_path'], storage_path());
|
||||
$this->assertSame($originals['storage_root'], Storage::disk('local')->getAdapter()->getPathPrefix());
|
||||
$this->assertSame($originals['cache'], app('cache'));
|
||||
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
tenancy()->init('foo.localhost');
|
||||
|
||||
$this->assertNotSame($originals['databaseName'], DB::connection()->getDatabaseName());
|
||||
$this->assertNotSame($originals['storage_path'], storage_path());
|
||||
$this->assertNotSame($originals['storage_root'], Storage::disk('local')->getAdapter()->getPathPrefix());
|
||||
$this->assertNotSame($originals['cache'], app('cache'));
|
||||
|
||||
tenancy()->endTenancy();
|
||||
|
||||
$this->assertSame($originals['databaseName'], DB::connection()->getDatabaseName());
|
||||
$this->assertSame($originals['storage_path'], storage_path());
|
||||
$this->assertSame($originals['storage_root'], Storage::disk('local')->getAdapter()->getPathPrefix());
|
||||
$this->assertSame($originals['cache'], app('cache'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenancy_can_be_ended_after_reidentification()
|
||||
{
|
||||
$originals = [
|
||||
'databaseName' => DB::connection()->getDatabaseName(),
|
||||
'storage_path' => storage_path(),
|
||||
'storage_root' => Storage::disk('local')->getAdapter()->getPathPrefix(),
|
||||
'cache' => app('cache'),
|
||||
];
|
||||
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
tenancy()->init('foo.localhost');
|
||||
|
||||
$this->assertNotSame($originals['databaseName'], DB::connection()->getDatabaseName());
|
||||
$this->assertNotSame($originals['storage_path'], storage_path());
|
||||
$this->assertNotSame($originals['storage_root'], Storage::disk('local')->getAdapter()->getPathPrefix());
|
||||
$this->assertNotSame($originals['cache'], app('cache'));
|
||||
|
||||
tenancy()->endTenancy();
|
||||
|
||||
$this->assertSame($originals['databaseName'], DB::connection()->getDatabaseName());
|
||||
$this->assertSame($originals['storage_path'], storage_path());
|
||||
$this->assertSame($originals['storage_root'], Storage::disk('local')->getAdapter()->getPathPrefix());
|
||||
$this->assertSame($originals['cache'], app('cache'));
|
||||
|
||||
// Reidentify tenant
|
||||
Tenant::new()->withDomains(['bar.localhost'])->save();
|
||||
tenancy()->init('bar.localhost');
|
||||
|
||||
$this->assertNotSame($originals['databaseName'], DB::connection()->getDatabaseName());
|
||||
$this->assertNotSame($originals['storage_path'], storage_path());
|
||||
$this->assertNotSame($originals['storage_root'], Storage::disk('local')->getAdapter()->getPathPrefix());
|
||||
$this->assertNotSame($originals['cache'], app('cache'));
|
||||
|
||||
tenancy()->endTenancy();
|
||||
|
||||
$this->assertSame($originals['databaseName'], DB::connection()->getDatabaseName());
|
||||
$this->assertSame($originals['storage_path'], storage_path());
|
||||
$this->assertSame($originals['storage_root'], Storage::disk('local')->getAdapter()->getPathPrefix());
|
||||
$this->assertSame($originals['cache'], app('cache'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_can_be_deleted()
|
||||
{
|
||||
$tenant = Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
$this->assertEquals([$tenant], tenancy()->all()->toArray());
|
||||
$tenant->delete();
|
||||
$this->assertEquals([], tenancy()->all()->toArray());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function all_returns_a_list_of_all_tenants()
|
||||
{
|
||||
$tenant1 = Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
$tenant2 = Tenant::new()->withDomains(['bar.localhost'])->save();
|
||||
$this->assertEqualsCanonicalizing([$tenant1, $tenant2], tenancy()->all()->toArray());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function data_can_be_passed_in_the_create_method()
|
||||
{
|
||||
$data = ['plan' => 'free', 'subscribed_until' => '2020-01-01'];
|
||||
$tenant = Tenant::create(['foo.localhost'], $data);
|
||||
|
||||
$tenant_data = $tenant->data;
|
||||
unset($tenant_data['id']);
|
||||
unset($tenant_data['_tenancy_db_name']);
|
||||
|
||||
$this->assertSame($data, $tenant_data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function database_name_can_be_passed_in_the_create_method()
|
||||
{
|
||||
$database = 'abc' . $this->randomString();
|
||||
|
||||
$tenant = tenancy()->create(['foo.localhost'], [
|
||||
'_tenancy_db_name' => $database,
|
||||
]);
|
||||
|
||||
$this->assertSame($database, $tenant->database()->getName());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function id_cannot_be_changed()
|
||||
{
|
||||
$tenant = Tenant::create(['test2.localhost']);
|
||||
|
||||
$this->expectException(\Stancl\Tenancy\Exceptions\TenantStorageException::class);
|
||||
$tenant->id = 'bar';
|
||||
|
||||
$tenant2 = Tenant::create(['test3.localhost']);
|
||||
|
||||
$this->expectException(\Stancl\Tenancy\Exceptions\TenantStorageException::class);
|
||||
$tenant2->put('id', 'foo');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function all_returns_a_collection_of_tenant_objects()
|
||||
{
|
||||
Tenant::create('foo.localhost');
|
||||
$this->assertSame('Tenant', class_basename(tenancy()->all()[0]));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function Tenant_is_bound_correctly_to_the_service_container()
|
||||
{
|
||||
$this->assertSame(null, app(Tenant::class));
|
||||
$tenant = Tenant::create(['foo.localhost']);
|
||||
app(TenantManager::class)->initializeTenancy($tenant);
|
||||
$this->assertSame($tenant->id, app(Tenant::class)->id);
|
||||
$this->assertSame(app(Tenant::class), app(TenantManager::class)->getTenant());
|
||||
app(TenantManager::class)->endTenancy();
|
||||
$this->assertSame(app(Tenant::class), app(TenantManager::class)->getTenant());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function id_can_be_supplied_during_creation()
|
||||
{
|
||||
$id = 'abc' . $this->randomString();
|
||||
$this->assertSame($id, Tenant::create(['foo.localhost'], ['id' => $id])->id);
|
||||
$this->assertTrue(tenancy()->all()->contains(function ($tenant) use ($id) {
|
||||
return $tenant->id === $id;
|
||||
}));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function automatic_migrations_work()
|
||||
{
|
||||
$tenant = Tenant::create(['foo.localhost']);
|
||||
tenancy()->initialize($tenant);
|
||||
$this->assertFalse(\Schema::hasTable('users'));
|
||||
|
||||
config(['tenancy.migrate_after_creation' => true]);
|
||||
$tenant2 = Tenant::create(['bar.localhost']);
|
||||
tenancy()->initialize($tenant2);
|
||||
$this->assertTrue(\Schema::hasTable('users'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function automatic_seeding_works()
|
||||
{
|
||||
config(['tenancy.migrate_after_creation' => true]);
|
||||
|
||||
$tenant = Tenant::create(['foo.localhost']);
|
||||
tenancy()->initialize($tenant);
|
||||
$this->assertSame(0, \DB::table('users')->count());
|
||||
|
||||
config([
|
||||
'tenancy.seed_after_migration' => true,
|
||||
'tenancy.seeder_parameters' => [
|
||||
'--class' => ExampleSeeder::class,
|
||||
],
|
||||
]);
|
||||
|
||||
$tenant2 = Tenant::create(['bar.localhost']);
|
||||
tenancy()->initialize($tenant2);
|
||||
$this->assertSame(1, \DB::table('users')->count());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function ensureTenantCanBeCreated_works()
|
||||
{
|
||||
$id = 'foo' . $this->randomString();
|
||||
Tenant::create(['foo.localhost'], ['id' => $id]);
|
||||
$this->expectException(DomainsOccupiedByOtherTenantException::class);
|
||||
Tenant::create(['foo.localhost']);
|
||||
|
||||
$this->expectException(TenantWithThisIdAlreadyExistsException::class);
|
||||
Tenant::create(['bar.localhost'], ['id' => $id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function automigration_is_queued_when_db_creation_is_queued()
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
config([
|
||||
'tenancy.queue_database_creation' => true,
|
||||
'tenancy.migrate_after_creation' => true,
|
||||
]);
|
||||
|
||||
$tenant = Tenant::new()->save();
|
||||
|
||||
Queue::assertPushedWithChain(QueuedTenantDatabaseCreator::class, [
|
||||
QueuedTenantDatabaseMigrator::class,
|
||||
]);
|
||||
|
||||
// foreach (Queue::pushedJobs() as $job) {
|
||||
// $job[0]['job']->handle(); // this doesn't execute the chained job
|
||||
// }
|
||||
// tenancy()->initialize($tenant);
|
||||
// $this->assertTrue(\Schema::hasTable('users'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function autoseeding_is_queued_when_db_creation_is_queued()
|
||||
{
|
||||
Queue::fake();
|
||||
|
||||
config([
|
||||
'tenancy.queue_database_creation' => true,
|
||||
'tenancy.migrate_after_creation' => true,
|
||||
'tenancy.seed_after_migration' => true,
|
||||
]);
|
||||
|
||||
Tenant::new()->save();
|
||||
|
||||
Queue::assertPushedWithChain(QueuedTenantDatabaseCreator::class, [
|
||||
QueuedTenantDatabaseMigrator::class,
|
||||
QueuedTenantDatabaseSeeder::class,
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function TenantDoesNotExistException_is_thrown_when_find_is_called_on_an_id_that_does_not_belong_to_any_tenant()
|
||||
{
|
||||
$this->expectException(TenantDoesNotExistException::class);
|
||||
tenancy()->find('gjnfdgf');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function event_listeners_can_accept_arguments()
|
||||
{
|
||||
tenancy()->hook('tenant.creating', function ($tenantManager, $tenant) {
|
||||
$this->assertSame('bar', $tenant->foo);
|
||||
});
|
||||
|
||||
Tenant::new()->withData(['foo' => 'bar'])->save();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_creating_hook_can_be_used_to_modify_tenants_data()
|
||||
{
|
||||
tenancy()->hook('tenant.creating', function ($tm, Tenant $tenant) {
|
||||
$tenant->put([
|
||||
'foo' => 'bar',
|
||||
'abc123' => 'def456',
|
||||
]);
|
||||
});
|
||||
$tenant = Tenant::new()->save();
|
||||
|
||||
$this->assertArrayHasKey('foo', $tenant->data);
|
||||
$this->assertArrayHasKey('abc123', $tenant->data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function database_creation_can_be_disabled()
|
||||
{
|
||||
config(['tenancy.create_database' => false]);
|
||||
|
||||
tenancy()->hook('database.creating', function () {
|
||||
$this->fail();
|
||||
});
|
||||
|
||||
$tenant = Tenant::new()->save();
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function database_creation_can_be_disabled_for_specific_tenants()
|
||||
{
|
||||
config(['tenancy.create_database' => true]);
|
||||
|
||||
tenancy()->hook('database.creating', function () {
|
||||
$this->assertTrue(true);
|
||||
});
|
||||
|
||||
$tenant = Tenant::new()->save();
|
||||
|
||||
tenancy()->hook('database.creating', function () {
|
||||
$this->fail();
|
||||
});
|
||||
|
||||
$tenant2 = Tenant::new()->withData([
|
||||
'_tenancy_create_database' => false,
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ use Stancl\Tenancy\Events\TenantCreated;
|
|||
use Stancl\Tenancy\Tests\TestCase;
|
||||
use Stancl\Tenancy\UniqueIDGenerators\UUIDGenerator;
|
||||
use Stancl\Tenancy\Contracts;
|
||||
use Stancl\Tenancy\Contracts\UniqueIdentifierGenerator;
|
||||
|
||||
class TenantModelTest extends TestCase
|
||||
{
|
||||
|
|
@ -34,7 +35,7 @@ class TenantModelTest extends TestCase
|
|||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
$this->assertSame($tenant->id, app(Tenant::class)->id);
|
||||
$this->assertSame($tenant->id, app(Contracts\Tenant::class)->id);
|
||||
|
||||
tenancy()->end();
|
||||
|
||||
|
|
@ -100,10 +101,10 @@ class TenantModelTest extends TestCase
|
|||
$table->bigIncrements('id')->change();
|
||||
});
|
||||
|
||||
config(['tenancy.id_generator' => null]);
|
||||
unset(app()[UniqueIdentifierGenerator::class]);
|
||||
|
||||
$tenant1 = Tenant::create();
|
||||
$tenant2 = Tenant::create();
|
||||
$tenant1 = MyTenant::create();
|
||||
$tenant2 = MyTenant::create();
|
||||
|
||||
$this->assertSame(1, $tenant1->id);
|
||||
$this->assertSame(2, $tenant2->id);
|
||||
|
|
@ -137,6 +138,7 @@ class TenantModelTest extends TestCase
|
|||
class MyTenant extends Tenant
|
||||
{
|
||||
protected $table = 'tenants';
|
||||
public $increments = true;
|
||||
}
|
||||
|
||||
class AnotherTenant extends Model implements Contracts\Tenant
|
||||
|
|
@ -153,4 +155,9 @@ class AnotherTenant extends Model implements Contracts\Tenant
|
|||
{
|
||||
return $this->getAttribute('id');
|
||||
}
|
||||
|
||||
public function run(callable $callback)
|
||||
{
|
||||
$callback();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests;
|
||||
|
||||
use Stancl\Tenancy\StorageDrivers\Database\TenantRepository;
|
||||
use Stancl\Tenancy\Tenant;
|
||||
|
||||
class TenantStorageTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = true;
|
||||
public $autoInitTenancy = true;
|
||||
|
||||
/** @test */
|
||||
public function deleting_a_tenant_works()
|
||||
{
|
||||
$abc = Tenant::new()->withDomains(['abc.localhost'])->save();
|
||||
$exists = function () use ($abc) {
|
||||
return tenancy()->all()->contains(function ($tenant) use ($abc) {
|
||||
return $tenant->id === $abc->id;
|
||||
});
|
||||
};
|
||||
|
||||
$this->assertTrue($exists());
|
||||
|
||||
$abc->delete();
|
||||
|
||||
$this->assertFalse($exists());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function set_is_a_working_alias_for_put()
|
||||
{
|
||||
tenant()->set('foo', 'bar');
|
||||
|
||||
$this->assertSame('bar', tenant()->get('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function put_works_with_key_and_value_as_separate_args()
|
||||
{
|
||||
tenant()->put('foo', 'bar');
|
||||
|
||||
$this->assertSame('bar', tenant()->get('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function put_works_with_key_and_value_as_a_single_arg()
|
||||
{
|
||||
$keys = ['foo', 'abc'];
|
||||
$vals = ['bar', 'xyz'];
|
||||
$data = array_combine($keys, $vals);
|
||||
|
||||
tenant()->put($data);
|
||||
|
||||
$this->assertSame($data, tenant()->get($keys));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function put_on_the_current_tenant_pushes_the_value_into_the_tenant_property_array()
|
||||
{
|
||||
tenant()->put('foo', 'bar');
|
||||
|
||||
$this->assertSame('bar', tenancy()->getTenant('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function arrays_can_be_stored()
|
||||
{
|
||||
tenant()->put('foo', [1, 2]);
|
||||
|
||||
$this->assertSame([1, 2], tenant()->get('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function associative_arrays_can_be_stored()
|
||||
{
|
||||
$data = ['a' => 'b', 'c' => 'd'];
|
||||
tenant()->put('foo', $data);
|
||||
|
||||
$this->assertSame($data, tenant()->get('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function correct_storage_driver_is_used()
|
||||
{
|
||||
if (config('tenancy.storage_driver') == 'db') {
|
||||
$this->assertSame('DatabaseStorageDriver', class_basename(tenancy()->storage));
|
||||
} elseif (config('tenancy.storage_driver') == 'redis') {
|
||||
$this->assertSame('RedisStorageDriver', class_basename(tenancy()->storage));
|
||||
} else {
|
||||
dd(class_basename(config('tenancy.storage_driver')));
|
||||
}
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function data_is_stored_with_correct_data_types()
|
||||
{
|
||||
tenant()->put('someBool', false);
|
||||
$this->assertSame('boolean', gettype(tenant()->get('someBool')));
|
||||
$this->assertSame('boolean', gettype(tenant()->get(['someBool'])['someBool']));
|
||||
|
||||
tenant()->put('someInt', 5);
|
||||
$this->assertSame('integer', gettype(tenant()->get('someInt')));
|
||||
$this->assertSame('integer', gettype(tenant()->get(['someInt'])['someInt']));
|
||||
|
||||
tenant()->put('someDouble', 11.40);
|
||||
$this->assertSame('double', gettype(tenant()->get('someDouble')));
|
||||
$this->assertSame('double', gettype(tenant()->get(['someDouble'])['someDouble']));
|
||||
|
||||
tenant()->put('string', 'foo');
|
||||
$this->assertSame('string', gettype(tenant()->get('string')));
|
||||
$this->assertSame('string', gettype(tenant()->get(['string'])['string']));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_repository_uses_correct_connection()
|
||||
{
|
||||
config(['database.connections.foo' => config('database.connections.sqlite')]);
|
||||
config(['tenancy.storage_drivers.db.connection' => 'foo']);
|
||||
$this->assertSame('foo', app(TenantRepository::class)->database->getName());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function retrieving_data_without_cache_works()
|
||||
{
|
||||
Tenant::new()->withDomains(['foo.localhost'])->save();
|
||||
tenancy()->init('foo.localhost');
|
||||
|
||||
tenant()->put('foo', 'bar');
|
||||
$this->assertSame('bar', tenant()->get('foo'));
|
||||
$this->assertSame(['foo' => 'bar'], tenant()->get(['foo']));
|
||||
|
||||
tenancy()->endTenancy();
|
||||
tenancy()->init('foo.localhost');
|
||||
$this->assertSame('bar', tenant()->get('foo'));
|
||||
$this->assertSame(['foo' => 'bar'], tenant()->get(['foo']));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function custom_columns_work_with_db_storage_driver()
|
||||
{
|
||||
if (config('tenancy.storage_driver') != 'db') {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
tenancy()->endTenancy();
|
||||
|
||||
$this->loadMigrationsFrom([
|
||||
'--path' => __DIR__ . '/Etc',
|
||||
'--database' => 'central',
|
||||
]);
|
||||
config(['database.default' => 'sqlite']); // fix issue caused by loadMigrationsFrom
|
||||
|
||||
config(['tenancy.storage_drivers.db.custom_columns' => [
|
||||
'foo',
|
||||
]]);
|
||||
|
||||
tenancy()->create(['foo.localhost']);
|
||||
tenancy()->init('foo.localhost');
|
||||
|
||||
tenant()->put('foo', '111');
|
||||
$this->assertSame('111', tenant()->get('foo'));
|
||||
|
||||
tenant()->put(['foo' => 'bar', 'abc' => 'xyz']);
|
||||
$this->assertSame(['foo' => 'bar', 'abc' => 'xyz'], tenant()->get(['foo', 'abc']));
|
||||
|
||||
$this->assertSame('bar', \DB::connection('central')->table('tenants')->where('id', tenant('id'))->first()->foo);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function custom_columns_can_be_used_on_tenant_create()
|
||||
{
|
||||
if (config('tenancy.storage_driver') != 'db') {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
tenancy()->endTenancy();
|
||||
|
||||
$this->loadMigrationsFrom([
|
||||
'--path' => __DIR__ . '/Etc',
|
||||
'--database' => 'central',
|
||||
]);
|
||||
config(['database.default' => 'sqlite']); // fix issue caused by loadMigrationsFrom
|
||||
|
||||
config(['tenancy.storage_drivers.db.custom_columns' => [
|
||||
'foo',
|
||||
]]);
|
||||
|
||||
tenancy()->create(['foo.localhost'], ['foo' => 'bar', 'abc' => 'xyz']);
|
||||
tenancy()->init('foo.localhost');
|
||||
|
||||
$this->assertSame(['foo' => 'bar', 'abc' => 'xyz'], tenant()->get(['foo', 'abc']));
|
||||
$this->assertSame('bar', \DB::connection('central')->table('tenants')->where('id', tenant('id'))->first()->foo);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Stancl\Tenancy\Tests\Traits;
|
||||
|
||||
use Stancl\Tenancy\Tenant;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class TenantAwareCommandTest extends TestCase
|
||||
{
|
||||
public $autoCreateTenant = false;
|
||||
public $autoInitTenancy = false;
|
||||
|
||||
/** @test */
|
||||
public function commands_run_globally_are_tenant_aware_and_return_valid_exit_code()
|
||||
{
|
||||
$tenant1 = Tenant::new()->save();
|
||||
$tenant2 = Tenant::new()->save();
|
||||
\Artisan::call('tenants:migrate', [
|
||||
'--tenants' => [$tenant1['id'], $tenant2['id']],
|
||||
]);
|
||||
|
||||
$this->artisan('user:add')
|
||||
->assertExitCode(0);
|
||||
|
||||
tenancy()->initializeTenancy($tenant1);
|
||||
$this->assertNotEmpty(\DB::table('users')->get());
|
||||
tenancy()->end();
|
||||
|
||||
tenancy()->initializeTenancy($tenant2);
|
||||
$this->assertNotEmpty(\DB::table('users')->get());
|
||||
tenancy()->end();
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
// test DB creation, migration, seeding
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Stancl\Tenancy\Tests\v3;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\Events\JobProcessing;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Spatie\Valuestore\Valuestore;
|
||||
use Stancl\Tenancy\Database\Models\Tenant;
|
||||
use Stancl\Tenancy\Events\Listeners\BootstrapTenancy;
|
||||
use Stancl\Tenancy\Events\TenancyInitialized;
|
||||
use Stancl\Tenancy\TenancyBootstrappers\QueueTenancyBootstrapper;
|
||||
use Stancl\Tenancy\Tests\TestCase;
|
||||
|
||||
class QueueTest extends TestCase
|
||||
{
|
||||
public $mockConsoleOutput = false;
|
||||
|
||||
/** @var Valuestore */
|
||||
protected $valuestore;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config([
|
||||
'tenancy.bootstrappers' => [
|
||||
QueueTenancyBootstrapper::class,
|
||||
],
|
||||
'queue.default' => 'redis',
|
||||
]);
|
||||
|
||||
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
|
||||
|
||||
$this->valuestore = Valuestore::make(__DIR__ . '/../Etc/tmp/queuetest.json')->flush();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function tenant_id_is_passed_to_tenant_queues()
|
||||
{
|
||||
$tenant = Tenant::create();
|
||||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
Event::fake();
|
||||
|
||||
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 */
|
||||
public function tenancy_is_initialized_inside_queues()
|
||||
{
|
||||
$tenant = Tenant::create([
|
||||
'id' => 'acme',
|
||||
]);
|
||||
|
||||
tenancy()->initialize($tenant);
|
||||
|
||||
dispatch(new TestJob($this->valuestore));
|
||||
|
||||
$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'));
|
||||
}
|
||||
|
||||
/** @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'));
|
||||
}
|
||||
}
|
||||
|
||||
class TestJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/** @var Valuestore */
|
||||
protected $valuestore;
|
||||
|
||||
public function __construct(Valuestore $valuestore)
|
||||
{
|
||||
$this->valuestore = $valuestore;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->valuestore->put('tenant_id', "The current tenant id is: " . tenant('id'));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue