diff --git a/.gitignore b/.gitignore index 53129d62..9df52aa7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ vendor/ .vscode/ psysh .phpunit.result.cache +phpunit_var_*.xml +coverage/ +clover.xml diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 00000000..2a6c92f2 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,4 @@ +preset: laravel +disabled: +- concat_without_spaces +- ternary_operator_spaces diff --git a/.travis.yml b/.travis.yml index ff31db18..ae2f21fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ env: - - LARAVEL_VERSION="5.7.*" TESTBENCH_VERSION="~3.7" REDIS_DRIVER=phpredis - LARAVEL_VERSION="5.8.*" TESTBENCH_VERSION="~3.8" REDIS_DRIVER=phpredis language: php @@ -19,10 +18,7 @@ before_script: - export DB_USERNAME=root DB_PASSWORD="" DB_DATABASE=tenancy CODECOV_TOKEN="24382d15-84e7-4a55-bea4-c4df96a24a9b" - cat vendor/laravel/framework/src/Illuminate/Foundation/Application.php| grep 'const VERSION' -script: docker-compose exec test vendor/bin/phpunit -v --coverage-clover=coverage.xml - -after_script: - - docker-compose down +script: ./test after_success: - bash <(curl -s https://codecov.io/bash) diff --git a/CHANGELOG-1.x.md b/CHANGELOG-1.x.md index eefa74eb..fe5caaca 100644 --- a/CHANGELOG-1.x.md +++ b/CHANGELOG-1.x.md @@ -1,5 +1,17 @@ # Release Notes for 1.x +## [v1.6.1 (2019-08-04)](https://github.com/stancl/tenancy/compare/v1.6.0...v1.6.1) + +Multiple phpunit.xml configs are now generated to run the tests with different configurations, such as different Redis drivers. + +### Fixed + +- `tenancy()->all()` with predis [`0dc8c80`](https://github.com/stancl/tenancy/commit/0dc8c80a02efbee5676cc72e648e108037ca5268) + +### Dropped + +- Laravel 5.7 support [`65b3882`](https://github.com/stancl/tenancy/commit/65b38827d5a2fa183838a9dce9fb6a157fd7e859) + ## [v1.6.0 (2019-07-30)](https://github.com/stancl/tenancy/compare/v1.5.1...v1.6.0) ### Added diff --git a/Dockerfile b/Dockerfile index a6727e03..a6512668 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,15 @@ RUN apt-get update \ && php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \ && mkdir /run/php -RUN apt-get install php7.2-redis +RUN apt-get install -y php7.2-redis + +RUN apt-get install -y python3 + +RUN apt-get install -y php7.2-dev php-pear +RUN pecl install xdebug +# RUN echo '' > /etc/php/7.2/cli/conf.d/20-xdebug.ini +# RUN echo 'zend_extension=/usr/lib/php/20170718/xdebug.so' >> /etc/php/7.2/cli/php.ini +RUN echo 'zend_extension=/usr/lib/php/20170718/xdebug.so' > /etc/php/7.2/cli/conf.d/20-xdebug.ini RUN apt-get -y autoremove \ && apt-get clean \ diff --git a/README.md b/README.md index 3f0fa9bb..31f03153 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [stancl/tenancy](https://stancl.github.io/tenancy/) -[![Laravel 5.7+](https://img.shields.io/badge/laravel-5.7+-red.svg)](https://laravel.com) +[![Laravel 5.8](https://img.shields.io/badge/laravel-5.8-red.svg)](https://laravel.com) [![Latest Stable Version](https://poser.pugx.org/stancl/tenancy/version)](https://packagist.org/packages/stancl/tenancy) [![Travis CI build](https://travis-ci.com/stancl/tenancy.svg?branch=master)](https://travis-ci.com/stancl/tenancy) [![codecov](https://codecov.io/gh/stancl/tenancy/branch/master/graph/badge.svg)](https://codecov.io/gh/stancl/tenancy) @@ -54,12 +54,14 @@ You won't have to change a thing in your application's code.\* - [`tenants:list`](#-tenants-list-) - [`tenants:migrate`, `tenants:rollback`, `tenants:seed`](#-tenants-migrate----tenants-rollback----tenants-seed-) + [Tenant migrations](#tenant-migrations) + * [Testing](#testing) - [Tips](#tips) * [HTTPS certificates](#https-certificates) + [1. Use nginx with the lua module](#1-use-nginx-with-the-lua-module) + [2. Add a simple server block for each tenant](#2-add-a-simple-server-block-for-each-tenant) + [Generating certificates](#generating-certificates) -- [Testing](#testing) +- [Development](#development) + * [Running tests](#running-tests) + [With Docker](#with-docker) + [Without Docker](#without-docker) @@ -76,7 +78,7 @@ If you'd like to be notified about new versions and related stuff, [sign up for ### Requirements -- Laravel 5.7 or 5.8 +- Laravel 5.8 ### Installing the package @@ -226,7 +228,7 @@ You can also seed the database in the same way. The only difference is the comma ### Starting a session as a tenant -This runs `TenantManager::bootstrap()` which switches the DB connection, prefixes Redis, changes filesystem root paths, etc. +This switches the DB connection, prefixes Redis, changes filesystem root paths and tags cache. ```php tenancy()->init(); @@ -511,6 +513,17 @@ Database seeding completed successfully. Tenant migrations are located in `database/migrations/tenant`, so you should move your tenant migrations there. +## Testing + +To test your multi-tenant application, simply run the following at the beginning of every test: + +```php +tenant()->create('test.localhost') +tenancy()->init('test.localhost') +``` + +To do this automatically, you can make this part of your `TestCase::setUp()` method. [Here](https://github.com/stancl/tenancy/blob/13048002ef687c3c85207df1fbf8b09ce89fb430/tests/TestCase.php#L31-L37)'s how this package handles it. + # Tips - If you create a tenant using the interactive console (`artisan tinker`) and use sqlite, you might need to change the database's permissions and/or ownership (`chmod`/`chown`) so that the web application can access it. @@ -549,11 +562,13 @@ Creating this config dynamically from PHP is not easy, but is probably feasible. However, you still need to reload nginx configuration to apply the changes to configuration. This is problematic and I'm not sure if there is a simple and secure way to do this from PHP. -# Testing +# Development + +## Running tests ### With Docker -If you have Docker installed, simply run `docker-compose exec test vendor/bin/phpunit -v`. If you need to run the tests multiple times during development, run `./test` to run the tests. This script runs `docker-compose up -d` and phpunit via the `test` container. When you're done testing, run `docker-compose down` to shut down the containers. +If you have Docker installed, simply run `./test`. When you're done testing, run `docker-compose down` to shut down the containers. ### Without Docker diff --git a/composer.json b/composer.json index a8d93299..7712229c 100644 --- a/composer.json +++ b/composer.json @@ -10,17 +10,18 @@ } ], "require": { - "illuminate/support": "5.8.*||5.7.*", + "illuminate/support": "5.8.*", "webpatser/laravel-uuid": "^3.0", "predis/predis": "^1.1" }, "require-dev": { - "vlucas/phpdotenv": "^2.2||^3.3", + "vlucas/phpdotenv": "^3.3", "psy/psysh": "@stable", - "laravel/framework": "5.8.*||5.7.*", - "orchestra/testbench": "~3.7||~3.8", "league/flysystem-aws-s3-v3": "~1.0", - "laravel/telescope": "^2.0" + "laravel/telescope": "^2.0", + "laravel/framework": "5.8.*", + "orchestra/testbench": "~3.8", + "phpunit/phpcov": "^6.0" }, "autoload": { "psr-4": { diff --git a/phpunit.xml b/phpunit.xml index 26f7e0b2..d4f07804 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -30,5 +30,6 @@ + \ No newline at end of file diff --git a/src/CacheManager.php b/src/CacheManager.php index 6e37f417..d3b31ea2 100644 --- a/src/CacheManager.php +++ b/src/CacheManager.php @@ -10,7 +10,7 @@ class CacheManager extends BaseCacheManager { $tags = [config('tenancy.cache.tag_base') . tenant('uuid')]; - if ($method === "tags") { + if ($method === 'tags') { if (\count($parameters) !== 1) { throw new \Exception("Method tags() takes exactly 1 argument. {count($parameters)} passed."); } diff --git a/src/Commands/TenantList.php b/src/Commands/TenantList.php index 94eae4c6..6a8fc400 100644 --- a/src/Commands/TenantList.php +++ b/src/Commands/TenantList.php @@ -37,7 +37,7 @@ class TenantList extends Command */ public function handle() { - $this->info("Listing all tenants."); + $this->info('Listing all tenants.'); tenancy()->all()->each(function ($tenant) { $this->line("[Tenant] uuid: {$tenant['uuid']} @ {$tenant['domain']}"); }); diff --git a/src/DatabaseManager.php b/src/DatabaseManager.php index a5bae6bd..47bee9fc 100644 --- a/src/DatabaseManager.php +++ b/src/DatabaseManager.php @@ -90,7 +90,7 @@ class DatabaseManager public function getDriver(): ?string { - return config("database.connections.tenant.driver"); + return config('database.connections.tenant.driver'); } public function createTenantConnection(string $database_name) @@ -98,11 +98,11 @@ class DatabaseManager // Create the `tenancy` database connection. $based_on = config('tenancy.database.based_on') ?: config('database.default'); config()->set([ - 'database.connections.tenant' => config('database.connections.' . $based_on) + 'database.connections.tenant' => config('database.connections.' . $based_on), ]); // Change DB name - $database_name = $this->getDriver() === "sqlite" ? database_path($database_name) : $database_name; + $database_name = $this->getDriver() === 'sqlite' ? database_path($database_name) : $database_name; config()->set(['database.connections.tenant.database' => $database_name]); } } diff --git a/src/GlobalCacheFacade.php b/src/GlobalCacheFacade.php index ba2f8fad..bc4d9317 100644 --- a/src/GlobalCacheFacade.php +++ b/src/GlobalCacheFacade.php @@ -10,4 +10,4 @@ class GlobalCacheFacade extends Facade { return 'globalCache'; } -} \ No newline at end of file +} diff --git a/src/Interfaces/StorageDriver.php b/src/Interfaces/StorageDriver.php index 8dbcf91e..83dcae4a 100644 --- a/src/Interfaces/StorageDriver.php +++ b/src/Interfaces/StorageDriver.php @@ -5,13 +5,22 @@ namespace Stancl\Tenancy\Interfaces; interface StorageDriver { public function identifyTenant(string $domain): array; + public function getAllTenants(array $uuids = []): array; + public function getTenantById(string $uuid, array $fields = []): array; + public function getTenantIdByDomain(string $domain): ?string; + public function createTenant(string $domain, string $uuid): array; + public function deleteTenant(string $uuid): bool; + public function get(string $uuid, string $key); + public function getMany(string $uuid, array $keys): array; + public function put(string $uuid, string $key, $value); + public function putMany(string $uuid, array $values): array; } diff --git a/src/Interfaces/TenantDatabaseManager.php b/src/Interfaces/TenantDatabaseManager.php index 89bb330e..3abc8698 100644 --- a/src/Interfaces/TenantDatabaseManager.php +++ b/src/Interfaces/TenantDatabaseManager.php @@ -8,7 +8,7 @@ interface TenantDatabaseManager * Create a database. * * @param string $name Name of the database. - * @return boolean + * @return bool */ public function createDatabase(string $name): bool; @@ -16,7 +16,7 @@ interface TenantDatabaseManager * Delete a database. * * @param string $name Name of the database. - * @return boolean + * @return bool */ public function deleteDatabase(string $name): bool; } diff --git a/src/Jobs/QueuedTenantDatabaseCreator.php b/src/Jobs/QueuedTenantDatabaseCreator.php index f23f6442..d8eb90d1 100644 --- a/src/Jobs/QueuedTenantDatabaseCreator.php +++ b/src/Jobs/QueuedTenantDatabaseCreator.php @@ -5,8 +5,8 @@ namespace Stancl\Tenancy\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Foundation\Bus\Dispatchable; use Stancl\Tenancy\Interfaces\TenantDatabaseManager; class QueuedTenantDatabaseCreator implements ShouldQueue diff --git a/src/Jobs/QueuedTenantDatabaseDeleter.php b/src/Jobs/QueuedTenantDatabaseDeleter.php index ba3e5bc7..cf3a964e 100644 --- a/src/Jobs/QueuedTenantDatabaseDeleter.php +++ b/src/Jobs/QueuedTenantDatabaseDeleter.php @@ -5,8 +5,8 @@ namespace Stancl\Tenancy\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Foundation\Bus\Dispatchable; use Stancl\Tenancy\Interfaces\TenantDatabaseManager; class QueuedTenantDatabaseDeleter implements ShouldQueue diff --git a/src/StorageDrivers/RedisStorageDriver.php b/src/StorageDrivers/RedisStorageDriver.php index b604c9b8..82faebdb 100644 --- a/src/StorageDrivers/RedisStorageDriver.php +++ b/src/StorageDrivers/RedisStorageDriver.php @@ -20,6 +20,7 @@ class RedisStorageDriver implements StorageDriver if (! $id) { throw new \Exception("Tenant could not be identified on domain {$domain}"); } + return $this->getTenantById($id); } @@ -33,7 +34,7 @@ class RedisStorageDriver implements StorageDriver public function getTenantById(string $uuid, array $fields = []): array { $fields = (array) $fields; - + if (! $fields) { return $this->redis->hgetall("tenants:$uuid"); } @@ -50,14 +51,15 @@ class RedisStorageDriver implements StorageDriver { $this->redis->hmset("domains:$domain", 'tenant_id', $uuid); $this->redis->hmset("tenants:$uuid", 'uuid', json_encode($uuid), 'domain', json_encode($domain)); + return $this->redis->hgetall("tenants:$uuid"); } /** - * @inheritDoc + * {@inheritdoc} * * @param string $id - * @return boolean + * @return bool * @todo Make tenant & domain deletion atomic. */ public function deleteTenant(string $id): bool @@ -69,6 +71,7 @@ class RedisStorageDriver implements StorageDriver } $this->redis->del("domains:$domain"); + return (bool) $this->redis->del("tenants:$id"); } @@ -79,19 +82,23 @@ class RedisStorageDriver implements StorageDriver }, $uuids); if (! $hashes) { - // Apparently, the PREFIX is applied to all functions except scan(). - // Therefore, if the `tenancy` Redis connection has a prefix set - // (and PhpRedis is used), prepend the prefix to the search. - $redis_prefix = ''; + // Prefix is applied to all functions except scan(). + // This code applies the correct prefix manually. + $redis_prefix = config('database.redis.options.prefix'); + if (config('database.redis.client') === 'phpredis') { - $redis_prefix = $this->redis->getOption($this->redis->client()::OPT_PREFIX); + $redis_prefix = $this->redis->getOption($this->redis->client()::OPT_PREFIX) ?? $redis_prefix; + $all_keys = $this->redis->scan(null, $redis_prefix . 'tenants:*'); + } else { + $all_keys = $this->redis->scan(null, 'MATCH', $redis_prefix . 'tenants:*')[1]; } - $hashes = array_map(function ($hash) use ($redis_prefix) { - // Left strip $redis_prefix from $hash - return substr($hash, strlen($redis_prefix)); - }, $this->redis->scan(null, $redis_prefix.'tenants:*')); + + $hashes = array_map(function ($key) use ($redis_prefix) { + // Left strip $redis_prefix from $key + return substr($key, strlen($redis_prefix)); + }, $all_keys); } - + return array_map(function ($tenant) { return $this->redis->hgetall($tenant); }, $hashes); @@ -110,12 +117,14 @@ class RedisStorageDriver implements StorageDriver public function put(string $uuid, string $key, $value) { $this->redis->hset("tenants:$uuid", $key, $value); + return $value; } public function putMany(string $uuid, array $values): array { $this->redis->hmset("tenants:$uuid", $values); + return $values; } } diff --git a/src/TenantManager.php b/src/TenantManager.php index 8299ee15..b76a84a8 100644 --- a/src/TenantManager.php +++ b/src/TenantManager.php @@ -23,7 +23,7 @@ class TenantManager * @var StorageDriver */ protected $storage; - + /** * Database manager. * @@ -49,6 +49,7 @@ class TenantManager { $this->setTenant($this->identify($domain)); $this->bootstrap(); + return $this->tenant; } @@ -57,7 +58,7 @@ class TenantManager $domain = $domain ?: $this->currentDomain(); if (! $domain) { - throw new \Exception("No domain supplied nor detected."); + throw new \Exception('No domain supplied nor detected.'); } $tenant = $this->storage->identifyTenant($domain); @@ -79,7 +80,7 @@ class TenantManager $tenant = $this->jsonDecodeArrayValues($this->storage->createTenant($domain, (string) \Webpatser\Uuid\Uuid::generate(1, $domain))); $this->database->create($this->getDatabaseName($tenant)); - + return $tenant; } @@ -98,6 +99,7 @@ class TenantManager public function getTenantById(string $uuid, $fields = []) { $fields = (array) $fields; + return $this->jsonDecodeArrayValues($this->storage->getTenantById($uuid, $fields)); } @@ -165,6 +167,7 @@ class TenantManager public function getDatabaseName($tenant = []): string { $tenant = $tenant ?: $this->tenant; + return $this->app['config']['tenancy.database.prefix'] . $tenant['uuid'] . $this->app['config']['tenancy.database.suffix']; } @@ -179,7 +182,7 @@ class TenantManager $tenant = $this->jsonDecodeArrayValues($tenant); $this->tenant = $tenant; - + return $tenant; } @@ -219,6 +222,7 @@ class TenantManager { $this->setTenant($this->storage->getTenantById($uuid)); $this->bootstrap(); + return $this->tenant; } @@ -252,9 +256,9 @@ class TenantManager { if (\is_null($uuid)) { if (! isset($this->tenant['uuid'])) { - throw new \Exception("No UUID supplied (and no tenant is currently identified)."); + throw new \Exception('No UUID supplied (and no tenant is currently identified).'); } - + $uuid = $this->tenant['uuid']; // If $uuid is the uuid of the current tenant, put @@ -313,7 +317,7 @@ class TenantManager if (\is_null($attribute)) { return $this->tenant; } - + return $this->tenant[(string) $attribute]; } } diff --git a/src/Traits/BootstrapsTenancy.php b/src/Traits/BootstrapsTenancy.php index b53ce25f..5f2b74d3 100644 --- a/src/Traits/BootstrapsTenancy.php +++ b/src/Traits/BootstrapsTenancy.php @@ -13,7 +13,7 @@ trait BootstrapsTenancy /** * Was tenancy initialized/bootstrapped? * - * @var boolean + * @var bool */ public $initialized = false; @@ -53,7 +53,7 @@ trait BootstrapsTenancy foreach ($connections as $connection) { $prefix = $this->app['config']['tenancy.redis.prefix_base'] . $this->tenant['uuid']; $client = Redis::connection($connection)->client(); - + try { $this->originalSettings['redis'][$connection] = $client->getOption($client::OPT_PREFIX); $client->setOption($client::OPT_PREFIX, $prefix); @@ -67,7 +67,7 @@ trait BootstrapsTenancy { foreach ($connections as $connection) { $client = Redis::connection($connection)->client(); - + try { $client->setOption($client::OPT_PREFIX, $this->originalSettings['redis'][$connection]); } catch (\Throwable $t) { @@ -106,12 +106,12 @@ trait BootstrapsTenancy // Storage facade foreach ($this->app['config']['tenancy.filesystem.disks'] as $disk) { $old['disks'][$disk] = Storage::disk($disk)->getAdapter()->getPathPrefix(); - + if ($root = str_replace('%storage_path%', storage_path(), $this->app['config']["tenancy.filesystem.root_override.{$disk}"])) { Storage::disk($disk)->getAdapter()->setPathPrefix($root); } else { $root = $this->app['config']["filesystems.disks.{$disk}.root"]; - + Storage::disk($disk)->getAdapter()->setPathPrefix($root . "/{$suffix}"); } } diff --git a/src/Traits/HasATenantsOption.php b/src/Traits/HasATenantsOption.php index 5eadc3d4..1dc055af 100644 --- a/src/Traits/HasATenantsOption.php +++ b/src/Traits/HasATenantsOption.php @@ -9,7 +9,7 @@ trait HasATenantsOption protected function getOptions() { return array_merge([ - ['tenants', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, '', null] + ['tenants', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, '', null], ], parent::getOptions()); } } diff --git a/test b/test index b22f03b1..0d11eef3 100755 --- a/test +++ b/test @@ -1,5 +1,26 @@ -#!/bin/bash +#!/usr/bin/env python3 +from os import system +import argparse -# for development -docker-compose up -d -docker-compose exec test vendor/bin/phpunit "$@" \ No newline at end of file +system('docker-compose up -d') + +parser = argparse.ArgumentParser() +parser.add_argument("--variants", default='1,2', + help="Comma-separated values. Which test variants should be run.") +args, other = parser.parse_known_args() + +variants = args.variants.split(',') + +for variant in variants: + filename_base = "phpunit_var_" + variant + with open('phpunit.xml', 'r') as inp, open(filename_base + '.xml', 'w') as out: + out.write(inp.read().replace('"STANCL_TENANCY_TEST_VARIANT" value="1"', + '"STANCL_TENANCY_TEST_VARIANT" value="%s"' % variant)) + + print("Test variant: %s\n" % variant) + + system('docker-compose exec test vendor/bin/phpunit --configuration "%s" --coverage-php %s %s' + % (filename_base + '.xml', 'coverage/' + filename_base + '.cov', ' '.join(other))) + +# todo delete folder contents first? +system("docker-compose exec test vendor/bin/phpcov merge --clover clover.xml coverage/") diff --git a/tests/BootstrapsTenancyTest.php b/tests/BootstrapsTenancyTest.php index a3751a1c..fc0d761f 100644 --- a/tests/BootstrapsTenancyTest.php +++ b/tests/BootstrapsTenancyTest.php @@ -24,6 +24,10 @@ class BootstrapsTenancyTest extends TestCase /** @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('uuid'); @@ -35,6 +39,7 @@ class BootstrapsTenancyTest extends TestCase /** @test */ public function predis_is_supported() { + // No setDriver() before that version. if (app()->version() < 'v5.8.27') { $this->markTestSkipped(); } @@ -57,7 +62,7 @@ class BootstrapsTenancyTest extends TestCase Config::set('database.redis.client', 'predis'); Redis::setDriver('predis'); Config::set('tenancy.redis.tenancy', true); - + $this->expectException(PhpRedisNotInstalledException::class); $this->initTenancy(); } @@ -72,16 +77,16 @@ class BootstrapsTenancyTest extends TestCase } $this->initTenancy(); - + $new_storage_path = storage_path(); - $this->assertEquals($old_storage_path . "/" . config('tenancy.filesystem.suffix_base') . tenant('uuid'), $new_storage_path); + $this->assertEquals($old_storage_path . '/' . config('tenancy.filesystem.suffix_base') . tenant('uuid'), $new_storage_path); foreach (config('tenancy.filesystem.disks') as $disk) { $suffix = config('tenancy.filesystem.suffix_base') . tenant('uuid'); $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); + $correct_path_prefix = str_replace('%storage_path%', storage_path(), $override); } else { if ($base = $old_storage_facade_roots[$disk]) { $correct_path_prefix = $base . "/$suffix/"; diff --git a/tests/CacheManagerTest.php b/tests/CacheManagerTest.php index b8ce09f9..fe884182 100644 --- a/tests/CacheManagerTest.php +++ b/tests/CacheManagerTest.php @@ -51,7 +51,7 @@ class CacheManagerTest extends TestCase tenancy()->init('bar.localhost'); $this->assertNotSame('bar', cache()->get('foo')); - + cache()->put('foo', 'xyz', 1); $this->assertSame('xyz', cache()->get('foo')); } diff --git a/tests/CommandsTest.php b/tests/CommandsTest.php index 046c2998..3998719d 100644 --- a/tests/CommandsTest.php +++ b/tests/CommandsTest.php @@ -2,9 +2,9 @@ namespace Stancl\Tenancy\Tests; -use Illuminate\Support\Facades\Artisan; -use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\Artisan; use Stancl\Tenancy\Tests\Etc\ExampleSeeder; class CommandsTest extends TestCase @@ -47,7 +47,7 @@ class CommandsTest extends TestCase { $tenant = tenant()->create('test.localhost'); Artisan::call('tenants:migrate', [ - '--tenants' => [$tenant['uuid']] + '--tenants' => [$tenant['uuid']], ]); $this->assertFalse(Schema::hasTable('users')); @@ -79,7 +79,7 @@ class CommandsTest extends TestCase public function database_connection_is_switched_to_default_after_migrating_or_seeding_or_rolling_back() { $originalDBName = DB::connection()->getDatabaseName(); - + Artisan::call('tenants:migrate'); $this->assertSame($originalDBName, DB::connection()->getDatabaseName()); @@ -94,7 +94,7 @@ class CommandsTest extends TestCase public function database_connection_is_switched_to_default_after_migrating_or_seeding_or_rolling_back_when_tenancy_has_been_initialized() { tenancy()->init('localhost'); - + $this->database_connection_is_switched_to_default_after_migrating_or_seeding_or_rolling_back(); } } diff --git a/tests/DataSeparationTest.php b/tests/DataSeparationTest.php index 14deb808..89790df0 100644 --- a/tests/DataSeparationTest.php +++ b/tests/DataSeparationTest.php @@ -2,11 +2,11 @@ namespace Stancl\Tenancy\Tests; -use Illuminate\Support\Facades\Redis; -use Illuminate\Support\Facades\Cache; -use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\Redis; +use Illuminate\Support\Facades\Storage; class DataSeparationTest extends TestCase { @@ -19,7 +19,7 @@ class DataSeparationTest extends TestCase $tenant1 = tenancy()->create('tenant1.localhost'); $tenant2 = tenancy()->create('tenant2.localhost'); \Artisan::call('tenants:migrate', [ - '--tenants' => [$tenant1['uuid'], $tenant2['uuid']] + '--tenants' => [$tenant1['uuid'], $tenant2['uuid']], ]); tenancy()->init('tenant1.localhost'); @@ -31,7 +31,7 @@ class DataSeparationTest extends TestCase 'remember_token' => Str::random(10), ]); $this->assertSame('foo', User::first()->name); - + tenancy()->init('tenant2.localhost'); $this->assertSame(null, User::first()); @@ -52,7 +52,7 @@ class DataSeparationTest extends TestCase $tenant3 = tenancy()->create('tenant3.localhost'); \Artisan::call('tenants:migrate', [ - '--tenants' => [$tenant1['uuid'], $tenant3['uuid']] + '--tenants' => [$tenant1['uuid'], $tenant3['uuid']], ]); tenancy()->init('tenant3.localhost'); @@ -66,13 +66,17 @@ class DataSeparationTest extends TestCase /** @test */ public function redis_is_separated() { + if (! config('tenancy.redis.tenancy')) { + $this->markTestSkipped('Redis tenancy disabled.'); + } + tenancy()->create('tenant1.localhost'); tenancy()->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'); @@ -99,7 +103,7 @@ class DataSeparationTest extends TestCase 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); @@ -126,7 +130,7 @@ class DataSeparationTest extends TestCase 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'); @@ -148,4 +152,4 @@ class DataSeparationTest extends TestCase class User extends \Illuminate\Database\Eloquent\Model { protected $guarded = []; -} \ No newline at end of file +} diff --git a/tests/DatabaseManagerTest.php b/tests/DatabaseManagerTest.php index c96161fd..e6d7c2cf 100644 --- a/tests/DatabaseManagerTest.php +++ b/tests/DatabaseManagerTest.php @@ -13,7 +13,7 @@ class DatabaseManagerTest extends TestCase tenancy()->init(); tenancy()->disconnectDatabase(); $new_connection_name = app(\Illuminate\Database\DatabaseManager::class)->connection()->getName(); - + $this->assertSame($old_connection_name, $new_connection_name); $this->assertNotEquals('tenant', $new_connection_name); } diff --git a/tests/GlobalCacheTest.php b/tests/GlobalCacheTest.php index bdbcedfe..8d517a17 100644 --- a/tests/GlobalCacheTest.php +++ b/tests/GlobalCacheTest.php @@ -19,16 +19,16 @@ class GlobalCacheTest extends TestCase tenant()->create('foo.localhost'); tenancy()->init('foo.localhost'); $this->assertSame('bar', GlobalCache::get('foo')); - + GlobalCache::put(['abc' => 'xyz'], 1); cache(['def' => 'ghi'], 10); $this->assertSame('ghi', cache('def')); - + tenancy()->end(); $this->assertSame('xyz', GlobalCache::get('abc')); $this->assertSame('bar', GlobalCache::get('foo')); $this->assertSame(null, cache('def')); - + tenant()->create('bar.localhost'); tenancy()->init('bar.localhost'); $this->assertSame('xyz', GlobalCache::get('abc')); @@ -40,4 +40,4 @@ class GlobalCacheTest extends TestCase tenancy()->init('foo.localhost'); $this->assertSame('ghi', cache('def')); } -} \ No newline at end of file +} diff --git a/tests/ReidentificationTest.php b/tests/ReidentificationTest.php index eeba2e52..d372af98 100644 --- a/tests/ReidentificationTest.php +++ b/tests/ReidentificationTest.php @@ -27,7 +27,7 @@ class ReidentificationTest extends TestCase $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); + $correct_path_prefix = str_replace('%storage_path%', storage_path(), $override); } else { if ($base = $originals[$disk]) { $correct_path_prefix = $base . "/$suffix/"; @@ -49,7 +49,6 @@ class ReidentificationTest extends TestCase tenant()->create('second.localhost'); tenancy()->init('second.localhost'); - $suffix = config('tenancy.filesystem.suffix_base') . tenant('uuid'); $this->assertSame($original . "/$suffix", storage_path()); } diff --git a/tests/TenantAssetTest.php b/tests/TenantAssetTest.php index 985a782e..01f1fd28 100644 --- a/tests/TenantAssetTest.php +++ b/tests/TenantAssetTest.php @@ -10,7 +10,7 @@ class TenantAssetTest extends TestCase $filename = 'testfile' . $this->randomString(10); \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->get(tenant_asset($filename))->assertSuccessful(); diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php index dc68ac03..9f6e911b 100644 --- a/tests/TenantDatabaseManagerTest.php +++ b/tests/TenantDatabaseManagerTest.php @@ -139,7 +139,7 @@ class TenantDatabaseManagerTest extends TestCase config()->set('tenancy.queue_database_deletion', true); $db_name = 'testdatabase' . $this->randomString(10) . '.sqlite'; app(DatabaseManager::class)->delete($db_name, 'sqlite'); - + Queue::assertPushed(QueuedTenantDatabaseDeleter::class); } } diff --git a/tests/TenantManagerTest.php b/tests/TenantManagerTest.php index ea24ff0e..050c729a 100644 --- a/tests/TenantManagerTest.php +++ b/tests/TenantManagerTest.php @@ -66,7 +66,7 @@ class TenantManagerTest extends TestCase public function getTenantById_works() { $tenant = tenant()->create('foo.localhost'); - + $this->assertSame($tenant, tenancy()->getTenantById($tenant['uuid'])); } @@ -120,7 +120,7 @@ class TenantManagerTest extends TestCase tenant()->create('foo.localhost'); 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()); @@ -146,7 +146,7 @@ class TenantManagerTest extends TestCase tenant()->create('foo.localhost'); 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()); @@ -182,8 +182,16 @@ class TenantManagerTest extends TestCase $tenant = tenant()->create('foo.localhost'); tenant()->delete($tenant['uuid']); $this->assertSame([], tenancy()->all()->toArray()); - + $tenant = tenant()->create('foo.localhost'); $this->assertSame([$tenant], tenancy()->all()->toArray()); } + + /** @test */ + public function all_returns_a_list_of_all_tenants() + { + $tenant1 = tenant()->create('foo.localhost'); + $tenant2 = tenant()->create('bar.localhost'); + $this->assertEqualsCanonicalizing([$tenant1, $tenant2], tenant()->all()->toArray()); + } } diff --git a/tests/TenantStorageTest.php b/tests/TenantStorageTest.php index bfbfa368..aaa4209b 100644 --- a/tests/TenantStorageTest.php +++ b/tests/TenantStorageTest.php @@ -2,15 +2,13 @@ namespace Stancl\Tenancy\Tests; -use Stancl\Tenancy\Interfaces\StorageDriver; - class TenantStorageTest extends TestCase { /** @test */ public function deleting_a_tenant_works() { $abc = tenant()->create('abc.localhost'); - + $this->assertTrue(tenant()->all()->contains($abc)); tenant()->delete($abc['uuid']); @@ -110,7 +108,7 @@ class TenantStorageTest extends TestCase public function put_returns_the_key_value_pairs_when_a_single_argument_is_used() { $value = ['foo' => 'bar', 'abc' => 'xyz']; - + $this->assertSame($value, tenancy()->put($value)); } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 200c70b0..7cc55500 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -9,8 +9,15 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase public $autoCreateTenant = true; public $autoInitTenancy = true; + private function checkRequirements(): void + { + parent::checkRequirements(); + + dd($this->getAnnotations()); + } + /** - * Setup the test environment + * Setup the test environment. * * @return void */ @@ -49,13 +56,14 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase protected function getEnvironmentSetUp($app) { if (file_exists(__DIR__ . '/../.env')) { - $this->loadDotEnv(); + \Dotenv\Dotenv::create(__DIR__ . '/..')->load(); } $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', 'database.redis.tenancy' => [ 'host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'), 'password' => env('TENANCY_TEST_REDIS_PASSWORD', null), @@ -63,6 +71,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase // Use the #14 Redis database unless specified otherwise. // Make sure you don't store anything in this db! 'database' => env('TENANCY_TEST_REDIS_DB', 14), + 'prefix' => 'abc', // todo unrelated to tenancy, but this doesn't seem to have an effect? try to replicate in a fresh laravel installation ], 'tenancy.database' => [ 'based_on' => 'sqlite', @@ -81,14 +90,19 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase 'tenancy.redis.prefixed_connections' => ['default'], 'tenancy.migrations_directory' => database_path('../migrations'), ]); - } - protected function loadDotEnv() - { - if (app()::VERSION > '5.8.0') { - \Dotenv\Dotenv::create(__DIR__ . '/..')->load(); - } else { - (new \Dotenv\Dotenv(__DIR__ . '/..'))->load(); + 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', + ]); } }