From f950265f585cd2879ceee0acfe4ad612263d741b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Sun, 30 Jun 2019 15:28:05 +0200 Subject: [PATCH 01/10] Add link to the tutorial --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 40f2cede..6ecd0fba 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ You won't have to change a thing in your application's code.\* ## Installation +> If you find this documentation hard to follow, **try reading the [tutorial](https://stancl.github.io/blog/how-to-make-any-laravel-app-multi-tenant-in-5-minutes/) first.** + ### Requirements - Laravel 5.7 or 5.8 From e7b5a77a6b77f571651478e57dd2d2073a364810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Mon, 1 Jul 2019 12:28:22 +0200 Subject: [PATCH 02/10] Data separation tests (#58) * Add purge() * Add DataSeparationTest --- src/DatabaseManager.php | 1 + tests/DataSeparationTest.php | 151 +++++++++++++++++++++++++++++++++++ tests/TestCase.php | 1 + 3 files changed, 153 insertions(+) create mode 100644 tests/DataSeparationTest.php diff --git a/src/DatabaseManager.php b/src/DatabaseManager.php index 1064aa5e..feeeac2f 100644 --- a/src/DatabaseManager.php +++ b/src/DatabaseManager.php @@ -31,6 +31,7 @@ class DatabaseManager public function disconnect() { $default_connection = $this->originalDefaultConnection; + $this->database->purge(); $this->database->reconnect($default_connection); $this->database->setDefaultConnection($default_connection); } diff --git a/tests/DataSeparationTest.php b/tests/DataSeparationTest.php new file mode 100644 index 00000000..14deb808 --- /dev/null +++ b/tests/DataSeparationTest.php @@ -0,0 +1,151 @@ +create('tenant1.localhost'); + $tenant2 = tenancy()->create('tenant2.localhost'); + \Artisan::call('tenants:migrate', [ + '--tenants' => [$tenant1['uuid'], $tenant2['uuid']] + ]); + + 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 = tenancy()->create('tenant3.localhost'); + \Artisan::call('tenants:migrate', [ + '--tenants' => [$tenant1['uuid'], $tenant3['uuid']] + ]); + + 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() + { + 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'); + 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')); + + tenancy()->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() + { + tenancy()->create('tenant1.localhost'); + tenancy()->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')); + + tenancy()->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() + { + tenancy()->create('tenant1.localhost'); + tenancy()->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')); + + tenancy()->create('tenant3.localhost'); + tenancy()->init('tenant3.localhost'); + $this->assertFalse(Storage::disk('public')->exists('foo')); + $this->assertFalse(Storage::disk('public')->exists('abc')); + } +} + +class User extends \Illuminate\Database\Eloquent\Model +{ + protected $guarded = []; +} \ No newline at end of file diff --git a/tests/TestCase.php b/tests/TestCase.php index a802367c..180600d9 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -72,6 +72,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase 'public', 's3', ], + 'tenancy.migrations_directory' => database_path('../migrations'), ]); } From 1b6759084ffca0cf26f37ca87fa90c2c6587b482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Wed, 3 Jul 2019 14:48:55 +0200 Subject: [PATCH 03/10] Add Predis support (#59) * wip * Add Predis support * Enable phpredis extension only for some builds * Add note about phpredis * Fix if command * Revert travis changes & add a version check to predis tests --- .travis.yml | 6 ++-- README.md | 5 +-- composer.json | 3 +- .../PhpRedisNotInstalledException.php | 8 +++++ src/StorageDrivers/RedisStorageDriver.php | 23 +++++++------ src/Traits/BootstrapsTenancy.php | 12 +++++-- src/config/tenancy.php | 1 + tests/BootstrapsTenancyTest.php | 32 +++++++++++++++++++ tests/TestCase.php | 3 +- 9 files changed, 75 insertions(+), 18 deletions(-) create mode 100644 src/Exceptions/PhpRedisNotInstalledException.php diff --git a/.travis.yml b/.travis.yml index f92d5e2c..94a09dd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ env: - - LARAVEL_VERSION="5.7.*" TESTBENCH_VERSION="~3.7" - - LARAVEL_VERSION="5.8.*" TESTBENCH_VERSION="~3.8" + - LARAVEL_VERSION="5.7.*" TESTBENCH_VERSION="~3.7" REDIS_DRIVER=phpredis + - LARAVEL_VERSION="5.8.*" TESTBENCH_VERSION="~3.8" REDIS_DRIVER=phpredis language: php php: @@ -14,7 +14,7 @@ before_install: - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini install: - - composer require "laravel/framework:$LARAVEL_VERSION" "orchestra/testbench:$TESTBENCH_VERSION" + - travis_retry composer require "laravel/framework:$LARAVEL_VERSION" "orchestra/testbench:$TESTBENCH_VERSION" - travis_retry composer install --no-interaction before_script: diff --git a/README.md b/README.md index 6ecd0fba..152b9e46 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ You won't have to change a thing in your application's code.\* ### Requirements - Laravel 5.7 or 5.8 -- phpredis (predis is not supported) ### Installing the package @@ -99,6 +98,8 @@ config('tenancy.redis.prefix_base') . $uuid These changes will only apply for connections listed in `prefixed_connections`. +> **Note: *If you want Redis to be multi-tenant, you must use phpredis. Predis does not support prefixes.*** + #### `cache` Cache keys will be tagged with a tag: @@ -328,7 +329,7 @@ The entire application will use a new database connection. The connection will b Connections listed in the `tenancy.redis.prefixed_connections` config array use a prefix based on the `tenancy.redis.prefix_base` and the tenant UUID. -**Note: You *must* use phpredis. Predis doesn't support prefixes.** +**Note: You *must* use phpredis if you want mutli-tenant Redis. Predis doesn't support prefixes.** ## Cache diff --git a/composer.json b/composer.json index 3dedc135..0d77a1de 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ ], "require": { "illuminate/support": "5.7.*||5.8.*", - "webpatser/laravel-uuid": "^3.0" + "webpatser/laravel-uuid": "^3.0", + "predis/predis": "^1.1" }, "require-dev": { "vlucas/phpdotenv": "^2.2||^3.3", diff --git a/src/Exceptions/PhpRedisNotInstalledException.php b/src/Exceptions/PhpRedisNotInstalledException.php new file mode 100644 index 00000000..6c9da3e7 --- /dev/null +++ b/src/Exceptions/PhpRedisNotInstalledException.php @@ -0,0 +1,8 @@ +redis->getOption($this->redis->client()::OPT_PREFIX); - $hashes = $hashes ?: $this->redis->scan(null, $redis_prefix.'tenants:*'); - - return array_map(function ($tenant) use ($redis_prefix) { - // Left strip $redis_prefix from $tenant - if (substr($tenant, 0, strlen($redis_prefix)) == $redis_prefix) { - $tenant = substr($tenant, strlen($redis_prefix)); + 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 = ''; + if (config('database.redis.client') === 'phpredis') { + $redis_prefix = $this->redis->getOption($this->redis->client()::OPT_PREFIX); } - + $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:*')); + } + + return array_map(function ($tenant) { return $this->redis->hgetall($tenant); }, $hashes); } diff --git a/src/Traits/BootstrapsTenancy.php b/src/Traits/BootstrapsTenancy.php index d09be0ff..f8441b66 100644 --- a/src/Traits/BootstrapsTenancy.php +++ b/src/Traits/BootstrapsTenancy.php @@ -5,6 +5,8 @@ namespace Stancl\Tenancy\Traits; use Stancl\Tenancy\CacheManager; use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Storage; +use Symfony\Component\Debug\Exception\FatalThrowableError; +use Stancl\Tenancy\Exceptions\PhpRedisNotInstalledException; trait BootstrapsTenancy { @@ -13,7 +15,9 @@ trait BootstrapsTenancy public function bootstrap() { $this->switchDatabaseConnection(); - $this->setPhpRedisPrefix($this->app['config']['tenancy.redis.prefixed_connections']); + if ($this->app['config']['tenancy.redis.tenancy']) { + $this->setPhpRedisPrefix($this->app['config']['tenancy.redis.prefixed_connections']); + } $this->tagCache(); $this->suffixFilesystemRootPaths(); } @@ -28,7 +32,11 @@ trait BootstrapsTenancy foreach ($connections as $connection) { $prefix = $this->app['config']['tenancy.redis.prefix_base'] . $this->tenant['uuid']; $client = Redis::connection($connection)->client(); - $client->setOption($client::OPT_PREFIX, $prefix); + try { + $client->setOption($client::OPT_PREFIX, $prefix); + } catch (\Throwable $t) { + throw new PhpRedisNotInstalledException(); + } } } diff --git a/src/config/tenancy.php b/src/config/tenancy.php index f1d9207f..c414a688 100644 --- a/src/config/tenancy.php +++ b/src/config/tenancy.php @@ -12,6 +12,7 @@ return [ 'suffix' => '', ], 'redis' => [ + 'tenancy' => false, 'prefix_base' => 'tenant', 'prefixed_connections' => [ 'default', diff --git a/tests/BootstrapsTenancyTest.php b/tests/BootstrapsTenancyTest.php index 6fdab20c..a3751a1c 100644 --- a/tests/BootstrapsTenancyTest.php +++ b/tests/BootstrapsTenancyTest.php @@ -3,6 +3,8 @@ namespace Stancl\Tenancy\Tests; use Illuminate\Support\Facades\Redis; +use Illuminate\Support\Facades\Config; +use Stancl\Tenancy\Exceptions\PhpRedisNotInstalledException; class BootstrapsTenancyTest extends TestCase { @@ -30,6 +32,36 @@ class BootstrapsTenancyTest extends TestCase } } + /** @test */ + public function predis_is_supported() + { + if (app()->version() < 'v5.8.27') { + $this->markTestSkipped(); + } + + Config::set('database.redis.client', 'predis'); + Redis::setDriver('predis'); + Config::set('tenancy.redis.tenancy', false); + + // assert no exception is thrown from initializing tenancy + $this->assertNotNull($this->initTenancy()); + } + + /** @test */ + public function predis_is_not_supported_without_disabling_redis_multitenancy() + { + if (app()->version() < 'v5.8.27') { + $this->markTestSkipped(); + } + + Config::set('database.redis.client', 'predis'); + Redis::setDriver('predis'); + Config::set('tenancy.redis.tenancy', true); + + $this->expectException(PhpRedisNotInstalledException::class); + $this->initTenancy(); + } + /** @test */ public function filesystem_is_suffixed() { diff --git a/tests/TestCase.php b/tests/TestCase.php index 180600d9..8a81121c 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -36,7 +36,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase public function initTenancy($domain = 'localhost') { - tenancy()->init($domain); + return tenancy()->init($domain); } /** @@ -72,6 +72,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase 'public', 's3', ], + 'tenancy.redis.tenancy' => true, 'tenancy.migrations_directory' => database_path('../migrations'), ]); } From a2ac7a25c35bfbabbf9dda55b0d43a025ba0f0c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Wed, 3 Jul 2019 15:41:15 +0200 Subject: [PATCH 04/10] Update note about predis --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 152b9e46..4191d9e4 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,11 @@ config('tenancy.redis.prefix_base') . $uuid These changes will only apply for connections listed in `prefixed_connections`. -> **Note: *If you want Redis to be multi-tenant, you must use phpredis. Predis does not support prefixes.*** +You can enable Redis tenancy by changing the `tenancy.redis.tenancy` config to `true`. + +**Note: If you want Redis to be multi-tenant, you *must* use phpredis. Predis does not support prefixes.** + +If you're using Laravel 5.7, predis is not supported even if Redis tenancy is disabled. #### `cache` From 4c03402601895d49fd3521485b42c4a2c01d8f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Wed, 3 Jul 2019 15:42:57 +0200 Subject: [PATCH 05/10] update changelog --- CHANGELOG-1.x.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG-1.x.md b/CHANGELOG-1.x.md index 77963d92..d7bae2c0 100644 --- a/CHANGELOG-1.x.md +++ b/CHANGELOG-1.x.md @@ -1,5 +1,11 @@ # Release Notes for 1.x +## [v1.4.0 (2019-07-03)](https://github.com/stancl/tenancy/compare/v1.3.1...v1.4.0) + +### Added + +- Predis support [#59](https://github.com/stancl/tenancy/pull/59) + ## [v1.3.1 (2019-05-06)](https://github.com/stancl/tenancy/compare/v1.3.0...v1.3.1) ### Fixed From 83f8d15a890fa9f78b3e4fe353466f1292d2f15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Wed, 3 Jul 2019 18:39:58 +0200 Subject: [PATCH 06/10] Change note about tutorial --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4191d9e4..ca9418f1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ You won't have to change a thing in your application's code.\* ## Installation -> If you find this documentation hard to follow, **try reading the [tutorial](https://stancl.github.io/blog/how-to-make-any-laravel-app-multi-tenant-in-5-minutes/) first.** +> If you're installing this package for the first time, **there's also a [tutorial](https://stancl.github.io/blog/how-to-make-any-laravel-app-multi-tenant-in-5-minutes/).** ### Requirements From 7c7ba2839193a352c49433850afbcb3511659dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Wed, 3 Jul 2019 19:19:19 +0200 Subject: [PATCH 07/10] implementation -> package --- README.md | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4191d9e4..1c48709c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![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) -### *A Laravel multi-database tenancy implementation that respects your code.* +### *A Laravel multi-database tenancy package that respects your code.* You won't have to change a thing in your application's code.\* diff --git a/composer.json b/composer.json index 0d77a1de..8d3aec87 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "stancl/tenancy", - "description": "A Laravel multi-database tenancy implementation that respects your code.", + "description": "A Laravel multi-database tenancy package that respects your code.", "keywords": ["laravel", "multi-tenancy", "multi-database", "tenancy"], "license": "MIT", "authors": [ From 73c818f9758869708b270419b853ed42e1399a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Fri, 5 Jul 2019 15:02:20 +0200 Subject: [PATCH 08/10] wip --- .env.example | 3 -- .travis.yml | 16 +++++------ Dockerfile | 25 +++++++++++++++++ docker-compose.yml | 43 +++++++++++++++++++++++++++++ test | 5 ++++ tests/TenantDatabaseManagerTest.php | 4 +-- tests/TestCase.php | 9 +++--- 7 files changed, 88 insertions(+), 17 deletions(-) delete mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100755 test diff --git a/.env.example b/.env.example deleted file mode 100644 index 775d99e8..00000000 --- a/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -DB_DATABASE=travis_tenancy -DB_USERNAME=foo -DB_PASSWORD=bar \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 94a09dd4..9f992754 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,22 +7,22 @@ php: - '7.2' services: - - mysql - - redis-server + - docker before_install: - - echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + - docker-compose up -d install: - - travis_retry composer require "laravel/framework:$LARAVEL_VERSION" "orchestra/testbench:$TESTBENCH_VERSION" - - travis_retry composer install --no-interaction + - travis_retry docker-compose exec app composer require --no-interaction "laravel/framework:$LARAVEL_VERSION" "orchestra/testbench:$TESTBENCH_VERSION" before_script: - - mysql -e 'CREATE DATABASE travis_tenancy;' - - export DB_USERNAME=root DB_PASSWORD="" DB_DATABASE=travis_tenancy CODECOV_TOKEN="24382d15-84e7-4a55-bea4-c4df96a24a9b" + - 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: vendor/bin/phpunit -v --coverage-clover=coverage.xml +script: docker-compose exec app vendor/bin/phpunit -v --coverage-clover=coverage.xml + +after_script: + - docker-compose down after_success: - bash <(curl -s https://codecov.io/bash) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a6727e03 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM ubuntu:18.04 + +LABEL maintainer="Samuel Ć tancl" + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update \ + && apt-get install -y curl zip unzip git sqlite3 \ + php7.2-fpm php7.2-cli \ + php7.2-pgsql php7.2-sqlite3 php7.2-gd \ + php7.2-curl php7.2-memcached \ + php7.2-imap php7.2-mysql php7.2-mbstring \ + php7.2-xml php7.2-zip php7.2-bcmath php7.2-soap \ + php7.2-intl php7.2-readline php7.2-xdebug \ + php-msgpack php-igbinary \ + && 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 -y autoremove \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +WORKDIR /var/www/html \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..afa91367 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,43 @@ +version: '3' +services: + test: + build: + context: . + networks: + - testnet + depends_on: + - mysql + - postgres + - redis + volumes: + - .:/var/www/html + environment: + DOCKER: 1 + DB_PASSWORD: "password" + TENANCY_TEST_REDIS_HOST: "redis" + TENANCY_TEST_MYSQL_HOST: "mysql" + TENANCY_TEST_PGSQL_HOST: "postgres" + stdin_open: true + tty: true + mysql: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: main + MYSQL_USER: user + MYSQL_PASSWORD: password + networks: + - testnet + postgres: + image: postgres:11 + environment: + POSTGRES_PASSWORD: "" + POSTGRES_USER: user + POSTGRES_DB: main + redis: + image: redis:alpine + networks: + - testnet +networks: + testnet: + driver: bridge \ No newline at end of file diff --git a/test b/test new file mode 100755 index 00000000..b22f03b1 --- /dev/null +++ b/test @@ -0,0 +1,5 @@ +#!/bin/bash + +# for development +docker-compose up -d +docker-compose exec test vendor/bin/phpunit "$@" \ No newline at end of file diff --git a/tests/TenantDatabaseManagerTest.php b/tests/TenantDatabaseManagerTest.php index 8d25913a..150db99c 100644 --- a/tests/TenantDatabaseManagerTest.php +++ b/tests/TenantDatabaseManagerTest.php @@ -40,7 +40,7 @@ class TenantDatabaseManagerTest extends TestCase /** @test */ public function mysql_database_can_be_created_and_deleted() { - if (! $this->isTravis()) { + if (! $this->isContainerized()) { $this->markTestSkipped('As to not bloat your MySQL instance with test databases, this test is not run by default.'); } @@ -57,7 +57,7 @@ class TenantDatabaseManagerTest extends TestCase /** @test */ public function mysql_database_can_be_created_and_deleted_using_queued_commands() { - if (! $this->isTravis()) { + if (! $this->isContainerized()) { $this->markTestSkipped('As to not bloat your MySQL instance with test databases, this test is not run by default.'); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 8a81121c..5d0998e4 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -53,6 +53,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase $app['config']->set([ 'database.redis.client' => 'phpredis', + 'database.redis.default.host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'), 'database.redis.tenancy' => [ 'host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'), 'password' => env('TENANCY_TEST_REDIS_PASSWORD', null), @@ -67,6 +68,8 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase 'suffix' => '.sqlite', ], 'database.connections.sqlite.database' => ':memory:', + 'database.connections.mysql.host' => env('TENANCY_TESTING_MYSQL_HOST', '127.0.0.1'), + 'database.connections.pgsql.host' => env('TENANCY_TESTING_PGSQL_HOST', '127.0.0.1'), 'tenancy.filesystem.disks' => [ 'local', 'public', @@ -114,11 +117,9 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length); } - public function isTravis() + public function isContainerized() { - // Multiple, just to make sure. Someone might accidentally - // set one of these environment vars on their computer. - return env('CI') && env('TRAVIS') && env('CONTINUOUS_INTEGRATION'); + return env('CONTINUOUS_INTEGRATION') || env('DOCKER'); } public function assertArrayIsSubset($subset, $array, string $message = ''): void From 87a207b70cf0811651b7e74f065c4312b7efa307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Fri, 12 Jul 2019 21:35:36 +0200 Subject: [PATCH 09/10] Add docker --- composer.json | 4 ++-- docker-compose.yml | 12 +++++++----- src/Traits/BootstrapsTenancy.php | 1 - tests/TestCase.php | 5 +++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 8d3aec87..e6fc6818 100644 --- a/composer.json +++ b/composer.json @@ -10,14 +10,14 @@ } ], "require": { - "illuminate/support": "5.7.*||5.8.*", + "illuminate/support": "5.8.*||5.7.*", "webpatser/laravel-uuid": "^3.0", "predis/predis": "^1.1" }, "require-dev": { "vlucas/phpdotenv": "^2.2||^3.3", "psy/psysh": "@stable", - "laravel/framework": "5.7.*||5.8.*", + "laravel/framework": "5.8.*||5.7.*", "orchestra/testbench": "~3.7||~3.8", "league/flysystem-aws-s3-v3": "~1.0" }, diff --git a/docker-compose.yml b/docker-compose.yml index afa91367..3f1575c6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,10 +13,12 @@ services: - .:/var/www/html environment: DOCKER: 1 - DB_PASSWORD: "password" - TENANCY_TEST_REDIS_HOST: "redis" - TENANCY_TEST_MYSQL_HOST: "mysql" - TENANCY_TEST_PGSQL_HOST: "postgres" + DB_PASSWORD: password + DB_USERNAME: root + DB_DATABASE: main + TENANCY_TEST_REDIS_HOST: redis + TENANCY_TEST_MYSQL_HOST: mysql + TENANCY_TEST_PGSQL_HOST: postgres stdin_open: true tty: true mysql: @@ -31,7 +33,7 @@ services: postgres: image: postgres:11 environment: - POSTGRES_PASSWORD: "" + POSTGRES_PASSWORD: password POSTGRES_USER: user POSTGRES_DB: main redis: diff --git a/src/Traits/BootstrapsTenancy.php b/src/Traits/BootstrapsTenancy.php index f8441b66..1121cc73 100644 --- a/src/Traits/BootstrapsTenancy.php +++ b/src/Traits/BootstrapsTenancy.php @@ -5,7 +5,6 @@ namespace Stancl\Tenancy\Traits; use Stancl\Tenancy\CacheManager; use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Storage; -use Symfony\Component\Debug\Exception\FatalThrowableError; use Stancl\Tenancy\Exceptions\PhpRedisNotInstalledException; trait BootstrapsTenancy diff --git a/tests/TestCase.php b/tests/TestCase.php index 5d0998e4..fc250f6d 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -53,6 +53,7 @@ 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.tenancy' => [ 'host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'), @@ -68,8 +69,8 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase 'suffix' => '.sqlite', ], 'database.connections.sqlite.database' => ':memory:', - 'database.connections.mysql.host' => env('TENANCY_TESTING_MYSQL_HOST', '127.0.0.1'), - 'database.connections.pgsql.host' => env('TENANCY_TESTING_PGSQL_HOST', '127.0.0.1'), + 'database.connections.mysql.host' => env('TENANCY_TEST_MYSQL_HOST', '127.0.0.1'), + 'database.connections.pgsql.host' => env('TENANCY_TEST_PGSQL_HOST', '127.0.0.1'), 'tenancy.filesystem.disks' => [ 'local', 'public', From 43c9b02d307dc17c08fc807c50c1fd7df213b911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=A0tancl?= Date: Fri, 12 Jul 2019 21:39:04 +0200 Subject: [PATCH 10/10] fix travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f992754..ff31db18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,13 +13,13 @@ before_install: - docker-compose up -d install: - - travis_retry docker-compose exec app composer require --no-interaction "laravel/framework:$LARAVEL_VERSION" "orchestra/testbench:$TESTBENCH_VERSION" + - travis_retry docker-compose exec test composer require --no-interaction "laravel/framework:$LARAVEL_VERSION" "orchestra/testbench:$TESTBENCH_VERSION" 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 app vendor/bin/phpunit -v --coverage-clover=coverage.xml +script: docker-compose exec test vendor/bin/phpunit -v --coverage-clover=coverage.xml after_script: - docker-compose down