1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-02-05 10:54:04 +00:00
This commit is contained in:
Samuel Štancl 2019-08-15 19:57:55 +02:00
commit 8c74cb4d76
21 changed files with 850 additions and 82 deletions

View file

@ -76,7 +76,7 @@ class CommandsTest extends TestCase
}
/** @test */
public function database_connection_is_switched_to_default_after_migrating_or_seeding_or_rolling_back()
public function database_connection_is_switched_to_default()
{
$originalDBName = DB::connection()->getDatabaseName();
@ -88,13 +88,209 @@ class CommandsTest extends TestCase
Artisan::call('tenants:rollback');
$this->assertSame($originalDBName, DB::connection()->getDatabaseName());
$this->run_commands_works();
$this->assertSame($originalDBName, DB::connection()->getDatabaseName());
}
/** @test */
public function database_connection_is_switched_to_default_after_migrating_or_seeding_or_rolling_back_when_tenancy_has_been_initialized()
public function database_connection_is_switched_to_default_when_tenancy_has_been_initialized()
{
tenancy()->init('localhost');
$this->database_connection_is_switched_to_default_after_migrating_or_seeding_or_rolling_back();
$this->database_connection_is_switched_to_default();
}
/** @test */
public function run_commands_works()
{
$uuid = tenant()->create('run.localhost')['uuid'];
Artisan::call('tenants:migrate', ['--tenants' => $uuid]);
$this->artisan("tenants:run foo --tenants=$uuid --argument='a=foo' --option='b=bar' --option='c=xyz'")
->expectsOutput("User's name is Test command")
->expectsOutput('foo')
->expectsOutput('xyz');
}
/** @test */
public function install_command_works()
{
if (! is_dir($dir = app_path('Http'))) {
mkdir($dir, 0777, true);
}
if (! is_dir($dir = base_path('routes'))) {
mkdir($dir, 0777, true);
}
file_put_contents(app_path('Http/Kernel.php'), "<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected \$middleware = [
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected \$middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected \$routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
/**
* The priority-sorted list of middleware.
*
* This forces non-global middleware to always be in the given order.
*
* @var array
*/
protected \$middlewarePriority = [
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\Authenticate::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];
}
");
$this->artisan('tenancy:install')
->expectsQuestion('Do you want to publish the default database migration?', 'yes');
$this->assertFileExists(base_path('routes/tenant.php'));
$this->assertFileExists(base_path('config/tenancy.php'));
$this->assertSame("<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected \$middleware = [
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected \$middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected \$routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::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,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\Authenticate::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Auth\Middleware\Authorize::class,
];
}
", \file_get_contents(app_path('Http/Kernel.php')));
}
}

View file

@ -0,0 +1,17 @@
<?php
namespace Stancl\Tenancy\Tests\Etc;
use Orchestra\Testbench\Console\Kernel;
class ConsoleKernel extends Kernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
ExampleCommand::class,
];
}

View file

@ -0,0 +1,39 @@
<?php
namespace Stancl\Tenancy\Tests\Etc;
use Illuminate\Console\Command;
class ExampleCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'foo {a} {--b=} {--c=}';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
User::create([
'id' => 999,
'name' => 'Test command',
'email' => 'test@command.com',
'password' => bcrypt('password'),
]);
$this->line("User's name is " . User::find(999)->name);
$this->line($this->argument('a'));
$this->line($this->option('c'));
}
}
class User extends \Illuminate\Database\Eloquent\Model
{
protected $guarded = [];
}

View file

@ -2,6 +2,7 @@
namespace Stancl\Tenancy\Tests;
use Tenant;
use Tenancy;
class FacadeTest extends TestCase
@ -15,4 +16,14 @@ class FacadeTest extends TestCase
$this->assertSame('bar', Tenancy::get('foo'));
$this->assertSame('xyz', Tenancy::get('abc'));
}
/** @test */
public function tenant_manager_can_be_accessed_using_the_Tenant_facade()
{
tenancy()->put('foo', 'bar');
Tenant::put('abc', 'xyz');
$this->assertSame('bar', Tenant::get('foo'));
$this->assertSame('xyz', Tenant::get('abc'));
}
}

View file

@ -0,0 +1,137 @@
<?php
namespace Stancl\Tenancy\Tests;
use Tenant;
use Tenancy;
class TenantManagerEventsTest extends TestCase
{
/** @test */
public function bootstrapping_event_works()
{
$uuid = tenant()->create('foo.localhost')['uuid'];
Tenancy::bootstrapping(function ($tenantManager) use ($uuid) {
if ($tenantManager->tenant['uuid'] === $uuid) {
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()
{
$uuid = tenant()->create('foo.localhost')['uuid'];
Tenancy::bootstrapped(function ($tenantManager) use ($uuid) {
if ($tenantManager->tenant['uuid'] === $uuid) {
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()
{
$uuid = tenant()->create('foo.localhost')['uuid'];
Tenancy::ending(function ($tenantManager) use ($uuid) {
if ($tenantManager->tenant['uuid'] === $uuid) {
config(['tenancy.foo' => 'bar']);
}
});
$this->assertSame(null, config('tenancy.foo'));
tenancy()->init('foo.localhost');
$this->assertSame(null, config('tenancy.foo'));
tenancy()->end();
$this->assertSame('bar', config('tenancy.foo'));
}
/** @test */
public function ended_event_works()
{
$uuid = tenant()->create('foo.localhost')['uuid'];
Tenancy::ended(function ($tenantManager) use ($uuid) {
if ($tenantManager->tenant['uuid'] === $uuid) {
config(['tenancy.foo' => 'bar']);
}
});
$this->assertSame(null, config('tenancy.foo'));
tenancy()->init('foo.localhost');
$this->assertSame(null, config('tenancy.foo'));
tenancy()->end();
$this->assertSame('bar', config('tenancy.foo'));
}
/** @test */
public function event_returns_a_collection()
{
// Note: The event() method should not be called by your code.
tenancy()->bootstrapping(function ($tenancy) {
return ['database'];
});
tenancy()->bootstrapping(function ($tenancy) {
return ['redis', 'cache'];
});
$prevents = tenancy()->event('bootstrapping');
$this->assertEquals(collect(['database', 'redis', 'cache']), $prevents);
}
/** @test */
public function database_can_be_reconnected_using_event_hooks()
{
config(['database.connections.tenantabc' => [
'driver' => 'sqlite',
'database' => database_path('some_special_database.sqlite'),
]]);
$uuid = Tenant::create('abc.localhost')['uuid'];
Tenancy::bootstrapping(function ($tenancy) use ($uuid) {
if ($tenancy->tenant['uuid'] === $uuid) {
$tenancy->database->useConnection('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'),
]]);
$uuid = Tenant::create('abc.localhost')['uuid'];
Tenancy::bootstrapping(function ($tenancy) use ($uuid) {
if ($tenancy->tenant['uuid'] === $uuid) {
$tenancy->database->useConnection('tenantabc');
// return ['database'];
}
});
$this->assertNotSame('tenantabc', \DB::connection()->getConfig()['name']);
tenancy()->init('abc.localhost');
$this->assertSame('tenant', \DB::connection()->getConfig()['name']);
}
}

View file

@ -4,6 +4,7 @@ namespace Stancl\Tenancy\Tests;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Stancl\Tenancy\Exceptions\CannotChangeUuidOrDomainException;
class TenantManagerTest extends TestCase
{
@ -194,4 +195,50 @@ class TenantManagerTest extends TestCase
$tenant2 = tenant()->create('bar.localhost');
$this->assertEqualsCanonicalizing([$tenant1, $tenant2], tenant()->all()->toArray());
}
/** @test */
public function properites_can_be_passed_in_the_create_method()
{
$data = ['plan' => 'free', 'subscribed_until' => '2020-01-01'];
$tenant = tenant()->create('foo.localhost', $data);
$tenant_data = $tenant;
unset($tenant_data['uuid']);
unset($tenant_data['domain']);
$this->assertSame($data, $tenant_data);
}
/** @test */
public function database_name_can_be_passed_in_the_create_method()
{
$database = 'abc';
config(['tenancy.database_name_key' => '_stancl_tenancy_database_name']);
$tenant = tenant()->create('foo.localhost', [
'_stancl_tenancy_database_name' => $database,
]);
$this->assertSame($database, tenant()->getDatabaseName($tenant));
}
/** @test */
public function uuid_and_domain_cannot_be_changed()
{
$tenant = tenant()->create('foo.localhost');
$this->expectException(CannotChangeUuidOrDomainException::class);
tenant()->put('uuid', 'foo', $tenant['uuid']);
$this->expectException(CannotChangeUuidOrDomainException::class);
tenant()->put(['uuid' => 'foo'], null, $tenant['uuid']);
tenancy()->init('foo.localhost');
$this->expectException(CannotChangeUuidOrDomainException::class);
tenant()->put('uuid', 'foo');
$this->expectException(CannotChangeUuidOrDomainException::class);
tenant()->put(['uuid' => 'foo']);
}
}

View file

@ -60,7 +60,6 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
}
$app['config']->set([
'database.redis.client' => 'phpredis',
'database.redis.cache.host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'),
'database.redis.default.host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'),
'database.redis.options.prefix' => 'foo',
@ -86,24 +85,11 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
'public',
's3',
],
'tenancy.redis.tenancy' => true,
'tenancy.redis.tenancy' => env('TENANCY_TEST_REDIS_TENANCY', true),
'database.redis.client' => env('TENANCY_TEST_REDIS_CLIENT', 'phpredis'),
'tenancy.redis.prefixed_connections' => ['default'],
'tenancy.migrations_directory' => database_path('../migrations'),
]);
switch ((string) env('STANCL_TENANCY_TEST_VARIANT', '1')) {
case '2':
$app['config']->set([
'tenancy.redis.tenancy' => false,
'database.redis.client' => 'predis',
]);
break;
default:
$app['config']->set([
'tenancy.redis.tenancy' => true,
'database.redis.client' => 'phpredis',
]);
}
}
protected function getPackageProviders($app)
@ -115,6 +101,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
{
return [
'Tenancy' => \Stancl\Tenancy\TenancyFacade::class,
'Tenant' => \Stancl\Tenancy\TenancyFacade::class,
'GlobalCache' => \Stancl\Tenancy\GlobalCacheFacade::class,
];
}
@ -130,6 +117,17 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
$app->singleton('Illuminate\Contracts\Http\Kernel', Etc\HttpKernel::class);
}
/**
* Resolve application Console Kernel implementation.
*
* @param \Illuminate\Foundation\Application $app
* @return void
*/
protected function resolveApplicationConsoleKernel($app)
{
$app->singleton('Illuminate\Contracts\Console\Kernel', Etc\ConsoleKernel::class);
}
public function randomString(int $length = 10)
{
return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);