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

Merge branch 'master' into 3.x

This commit is contained in:
Samuel Štancl 2022-06-01 16:19:15 +02:00 committed by GitHub
commit 2695162879
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 352 additions and 102 deletions

View file

@ -4,23 +4,27 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
use Illuminate\Support\Facades\Cache;
use Illuminate\Filesystem\FilesystemAdapter;
use ReflectionObject;
use ReflectionProperty;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
use Stancl\JobPipeline\JobPipeline;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use Stancl\JobPipeline\JobPipeline;
use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper;
use Stancl\Tenancy\Events\TenancyEnded;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Jobs\CreateDatabase;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Listeners\BootstrapTenancy;
use Stancl\Tenancy\Listeners\RevertToCentralContext;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Stancl\Tenancy\Bootstrappers\CacheTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\RedisTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Bootstrappers\FilesystemTenancyBootstrapper;
class BootstrapperTest extends TestCase
{
@ -165,6 +169,7 @@ class BootstrapperTest extends TestCase
$tenant2 = Tenant::create();
tenancy()->initialize($tenant1);
Storage::disk('public')->put('foo', 'bar');
$this->assertSame('bar', Storage::disk('public')->get('foo'));
@ -184,30 +189,38 @@ class BootstrapperTest extends TestCase
$this->assertFalse(Storage::disk('public')->exists('foo'));
$this->assertFalse(Storage::disk('public')->exists('abc'));
$expected_storage_path = $old_storage_path . '/tenant' . tenant('id'); // /tenant = suffix base
// Check that disk prefixes respect the root_override logic
$this->assertSame($expected_storage_path . '/app/', $this->getDiskPrefix('local'));
$this->assertSame($expected_storage_path . '/app/public/', $this->getDiskPrefix('public'));
$this->assertSame('tenant' . tenant('id') . '/', $this->getDiskPrefix('s3'), '/');
// Check suffixing logic
$new_storage_path = storage_path();
$this->assertEquals($old_storage_path . '/' . config('tenancy.filesystem.suffix_base') . tenant('id'), $new_storage_path);
$this->assertEquals($expected_storage_path, $new_storage_path);
}
foreach (config('tenancy.filesystem.disks') as $disk) {
$suffix = config('tenancy.filesystem.suffix_base') . tenant('id');
protected function getDiskPrefix(string $disk): string
{
/** @var FilesystemAdapter $disk */
$disk = Storage::disk($disk);
$adapter = $disk->getAdapter();
/** @var FilesystemAdapter $filesystemDisk */
$filesystemDisk = Storage::disk($disk);
$current_path_prefix = $filesystemDisk->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);
if (! Str::startsWith(app()->version(), '9.')) {
return $adapter->getPathPrefix();
}
$prefixer = (new ReflectionObject($adapter))->getProperty('prefixer');
$prefixer->setAccessible(true);
// reflection -> instance
$prefixer = $prefixer->getValue($adapter);
$prefix = (new ReflectionProperty($prefixer, 'prefix'));
$prefix->setAccessible(true);
return $prefix->getValue($prefixer);
}
// for queues see QueueTest

View file

@ -91,6 +91,38 @@ class CommandsTest extends TestCase
$this->assertTrue(Schema::hasTable('users'));
}
/** @test */
public function migrate_command_loads_schema_state()
{
$tenant = Tenant::create();
$this->assertFalse(Schema::hasTable('schema_users'));
$this->assertFalse(Schema::hasTable('users'));
Artisan::call('tenants:migrate --schema-path="tests/Etc/tenant-schema.dump"');
$this->assertFalse(Schema::hasTable('schema_users'));
$this->assertFalse(Schema::hasTable('users'));
tenancy()->initialize($tenant);
// Check for both tables to see if missing migrations also get executed
$this->assertTrue(Schema::hasTable('schema_users'));
$this->assertTrue(Schema::hasTable('users'));
}
/** @test */
public function dump_command_works()
{
$tenant = Tenant::create();
Artisan::call('tenants:migrate');
tenancy()->initialize($tenant);
Artisan::call('tenants:dump --path="tests/Etc/tenant-schema-test.dump"');
$this->assertFileExists('tests/Etc/tenant-schema-test.dump');
}
/** @test */
public function rollback_command_works()
{

View file

@ -10,6 +10,7 @@ use Illuminate\Support\Str;
use Stancl\JobPipeline\JobPipeline;
use Stancl\Tenancy\Bootstrappers\DatabaseTenancyBootstrapper;
use Stancl\Tenancy\Contracts\ManagesDatabaseUsers;
use Stancl\Tenancy\Events\DatabaseCreated;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Events\TenantCreated;
use Stancl\Tenancy\Exceptions\TenantDatabaseUserAlreadyExistsException;
@ -67,14 +68,18 @@ class DatabaseUsersTest extends TestCase
$this->assertTrue($manager->databaseExists($tenant->database()->getName()));
$this->expectException(TenantDatabaseUserAlreadyExistsException::class);
Event::fake([DatabaseCreated::class]);
$tenant2 = Tenant::create([
'tenancy_db_username' => $username,
]);
/** @var ManagesDatabaseUsers $manager */
$manager = $tenant2->database()->manager();
$manager2 = $tenant2->database()->manager();
// database was not created because of DB transaction
$this->assertFalse($manager->databaseExists($tenant2->database()->getName()));
$this->assertFalse($manager2->databaseExists($tenant2->database()->getName()));
Event::assertNotDispatched(DatabaseCreated::class);
}
/** @test */

View file

@ -4,15 +4,10 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests\Etc;
use Orchestra\Testbench\Console\Kernel;
use Orchestra\Testbench\Foundation\Console\Kernel;
class ConsoleKernel extends Kernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
ExampleCommand::class,
AddUserCommand::class,

View file

@ -0,0 +1,66 @@
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
DROP TABLE IF EXISTS `failed_jobs`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `failed_jobs` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`connection` text COLLATE utf8mb4_unicode_ci NOT NULL,
`queue` text COLLATE utf8mb4_unicode_ci NOT NULL,
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
`exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
`failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `migrations`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `migrations` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`batch` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `password_resets`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `password_resets` (
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
KEY `password_resets_email_index` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `schema_users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`email_verified_at` timestamp NULL DEFAULT NULL,
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
INSERT INTO `migrations` VALUES (2,'2014_10_12_100000_testbench_create_password_resets_table',1);
INSERT INTO `migrations` VALUES (3,'2019_08_19_000000_testbench_create_failed_jobs_table',1);

View file

@ -4,12 +4,14 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Http\Exceptions\MaintenanceModeException;
use Illuminate\Support\Facades\Route;
use Stancl\Tenancy\Database\Concerns\MaintenanceMode;
use Stancl\Tenancy\Middleware\CheckTenantForMaintenanceMode;
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
use Stancl\Tenancy\Tests\Etc\Tenant;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
class MaintenanceModeTest extends TestCase
{
@ -32,7 +34,7 @@ class MaintenanceModeTest extends TestCase
$tenant->putDownForMaintenance();
$this->expectException(MaintenanceModeException::class);
$this->expectException(HttpException::class);
$this->withoutExceptionHandling()
->get('http://acme.localhost/foo');
}

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Tests;
use Closure;
use Exception;
use Illuminate\Support\Str;
use Illuminate\Bus\Queueable;
@ -24,6 +25,7 @@ use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobProcessing;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use PDO;
use Stancl\Tenancy\Events\TenancyInitialized;
use Stancl\Tenancy\Listeners\BootstrapTenancy;
use Stancl\Tenancy\Listeners\RevertToCentralContext;
@ -52,7 +54,7 @@ class QueueTest extends TestCase
Event::listen(TenancyInitialized::class, BootstrapTenancy::class);
Event::listen(TenancyEnded::class, RevertToCentralContext::class);
$this->valuestore = Valuestore::make(__DIR__ . '/Etc/tmp/queuetest.json')->flush();
$this->createValueStore();
}
public function tearDown(): void
@ -60,6 +62,22 @@ class QueueTest extends TestCase
$this->valuestore->flush();
}
protected function createValueStore(): void
{
$valueStorePath = __DIR__ . '/Etc/tmp/queuetest.json';
if (! file_exists($valueStorePath)) {
// The directory sometimes goes missing as well when the file is deleted in git
if (! is_dir(__DIR__ . '/Etc/tmp')) {
mkdir(__DIR__ . '/Etc/tmp');
}
file_put_contents($valueStorePath, '');
}
$this->valuestore = Valuestore::make($valueStorePath)->flush();
}
protected function withFailedJobs()
{
Schema::connection('central')->create('failed_jobs', function (Blueprint $table) {

View file

@ -196,7 +196,11 @@ class TenantDatabaseManagerTest extends TestCase
]);
tenancy()->initialize($tenant);
$this->assertSame($tenant->database()->getName(), config('database.connections.' . config('database.default') . '.schema'));
$schemaConfig = version_compare(app()->version(), '9.0', '>=') ?
config('database.connections.' . config('database.default') . '.search_path') :
config('database.connections.' . config('database.default') . '.schema');
$this->assertSame($tenant->database()->getName(), $schemaConfig);
$this->assertSame($originalDatabaseName, config(['database.connections.pgsql.database']));
}

View file

@ -87,6 +87,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
'public',
's3',
],
'filesystems.disks.s3.bucket' => 'foo',
'tenancy.redis.tenancy' => env('TENANCY_TEST_REDIS_TENANCY', true),
'database.redis.client' => env('TENANCY_TEST_REDIS_CLIENT', 'phpredis'),
'tenancy.redis.prefixed_connections' => ['default'],