mirror of
https://github.com/archtechx/tenancy.git
synced 2026-02-05 04:54:03 +00:00
add docker [wip]
This commit is contained in:
commit
acdf39d15b
17 changed files with 358 additions and 47 deletions
|
|
@ -1,3 +0,0 @@
|
||||||
DB_DATABASE=travis_tenancy
|
|
||||||
DB_USERNAME=foo
|
|
||||||
DB_PASSWORD=bar
|
|
||||||
22
.travis.yml
22
.travis.yml
|
|
@ -1,30 +1,28 @@
|
||||||
env:
|
env:
|
||||||
- LARAVEL_VERSION="5.7.*" TESTBENCH_VERSION="~3.7"
|
- LARAVEL_VERSION="5.7.*" TESTBENCH_VERSION="~3.7" REDIS_DRIVER=phpredis
|
||||||
- LARAVEL_VERSION="5.8.*" TESTBENCH_VERSION="~3.8"
|
- LARAVEL_VERSION="5.8.*" TESTBENCH_VERSION="~3.8" REDIS_DRIVER=phpredis
|
||||||
|
|
||||||
language: php
|
language: php
|
||||||
php:
|
php:
|
||||||
- '7.2'
|
- '7.2'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- mysql
|
- docker
|
||||||
- postgresql
|
|
||||||
- redis-server
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
|
- docker-compose up -d
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- composer require "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"
|
||||||
- travis_retry composer install --no-interaction
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- mysql -e 'CREATE DATABASE travis_tenancy;'
|
- export DB_USERNAME=root DB_PASSWORD="" DB_DATABASE=tenancy CODECOV_TOKEN="24382d15-84e7-4a55-bea4-c4df96a24a9b"
|
||||||
- psql -c 'create database travis_tenancy;' -U postgres
|
|
||||||
- export DB_USERNAME=root DB_PASSWORD="" DB_DATABASE=travis_tenancy CODECOV_TOKEN="24382d15-84e7-4a55-bea4-c4df96a24a9b"
|
|
||||||
- cat vendor/laravel/framework/src/Illuminate/Foundation/Application.php| grep 'const VERSION'
|
- 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 test vendor/bin/phpunit -v --coverage-clover=coverage.xml
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
- docker-compose down
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- bash <(curl -s https://codecov.io/bash)
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
# Release Notes for 1.x
|
# 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)
|
## [v1.3.1 (2019-05-06)](https://github.com/stancl/tenancy/compare/v1.3.0...v1.3.1)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
||||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
|
|
@ -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
|
||||||
13
README.md
13
README.md
|
|
@ -5,7 +5,7 @@
|
||||||
[](https://travis-ci.com/stancl/tenancy)
|
[](https://travis-ci.com/stancl/tenancy)
|
||||||
[](https://codecov.io/gh/stancl/tenancy)
|
[](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.\*
|
You won't have to change a thing in your application's code.\*
|
||||||
|
|
||||||
|
|
@ -17,10 +17,11 @@ You won't have to change a thing in your application's code.\*
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
> 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
|
### Requirements
|
||||||
|
|
||||||
- Laravel 5.7 or 5.8
|
- Laravel 5.7 or 5.8
|
||||||
- phpredis (predis is not supported)
|
|
||||||
|
|
||||||
### Installing the package
|
### Installing the package
|
||||||
|
|
||||||
|
|
@ -97,6 +98,12 @@ config('tenancy.redis.prefix_base') . $uuid
|
||||||
|
|
||||||
These changes will only apply for connections listed in `prefixed_connections`.
|
These changes will only apply for connections listed in `prefixed_connections`.
|
||||||
|
|
||||||
|
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`
|
#### `cache`
|
||||||
|
|
||||||
Cache keys will be tagged with a tag:
|
Cache keys will be tagged with a tag:
|
||||||
|
|
@ -326,7 +333,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.
|
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
|
## Cache
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "stancl/tenancy",
|
"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"],
|
"keywords": ["laravel", "multi-tenancy", "multi-database", "tenancy"],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|
@ -10,13 +10,14 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"illuminate/support": "5.7.*||5.8.*",
|
"illuminate/support": "5.8.*||5.7.*",
|
||||||
"webpatser/laravel-uuid": "^3.0"
|
"webpatser/laravel-uuid": "^3.0",
|
||||||
|
"predis/predis": "^1.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"vlucas/phpdotenv": "^2.2||^3.3",
|
"vlucas/phpdotenv": "^2.2||^3.3",
|
||||||
"psy/psysh": "@stable",
|
"psy/psysh": "@stable",
|
||||||
"laravel/framework": "5.7.*||5.8.*",
|
"laravel/framework": "5.8.*||5.7.*",
|
||||||
"orchestra/testbench": "~3.7||~3.8",
|
"orchestra/testbench": "~3.7||~3.8",
|
||||||
"league/flysystem-aws-s3-v3": "~1.0"
|
"league/flysystem-aws-s3-v3": "~1.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
47
docker-compose.yml
Normal file
47
docker-compose.yml
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
test:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
networks:
|
||||||
|
- testnet
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
- postgres
|
||||||
|
- redis
|
||||||
|
volumes:
|
||||||
|
- .:/var/www/html
|
||||||
|
environment:
|
||||||
|
DOCKER: 1
|
||||||
|
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:
|
||||||
|
image: mysql:5.7
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: password
|
||||||
|
MYSQL_DATABASE: main
|
||||||
|
MYSQL_USER: user # redundant
|
||||||
|
MYSQL_PASSWORD: password
|
||||||
|
networks:
|
||||||
|
- testnet
|
||||||
|
postgres:
|
||||||
|
image: postgres:11
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: password
|
||||||
|
POSTGRES_USER: root # superuser name
|
||||||
|
POSTGRES_DB: main
|
||||||
|
networks:
|
||||||
|
- testnet
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
networks:
|
||||||
|
- testnet
|
||||||
|
networks:
|
||||||
|
testnet:
|
||||||
|
driver: bridge
|
||||||
|
|
@ -31,10 +31,19 @@ class DatabaseManager
|
||||||
public function disconnect()
|
public function disconnect()
|
||||||
{
|
{
|
||||||
$default_connection = $this->originalDefaultConnection;
|
$default_connection = $this->originalDefaultConnection;
|
||||||
|
$this->database->purge();
|
||||||
$this->database->reconnect($default_connection);
|
$this->database->reconnect($default_connection);
|
||||||
$this->database->setDefaultConnection($default_connection);
|
$this->database->setDefaultConnection($default_connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a database.
|
||||||
|
* @todo Should this handle prefixes?
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string $driver
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function create(string $name, string $driver = null)
|
public function create(string $name, string $driver = null)
|
||||||
{
|
{
|
||||||
$this->createTenantConnection($name);
|
$this->createTenantConnection($name);
|
||||||
|
|
@ -49,10 +58,18 @@ class DatabaseManager
|
||||||
if (config('tenancy.queue_database_creation', false)) {
|
if (config('tenancy.queue_database_creation', false)) {
|
||||||
QueuedTenantDatabaseCreator::dispatch(app($databaseManagers[$driver]), $name, 'create');
|
QueuedTenantDatabaseCreator::dispatch(app($databaseManagers[$driver]), $name, 'create');
|
||||||
} else {
|
} else {
|
||||||
app($databaseManagers[$driver])->createDatabase($name);
|
return app($databaseManagers[$driver])->createDatabase($name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a database.
|
||||||
|
* @todo Should this handle prefixes?
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param string $driver
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function delete(string $name, string $driver = null)
|
public function delete(string $name, string $driver = null)
|
||||||
{
|
{
|
||||||
$this->createTenantConnection($name);
|
$this->createTenantConnection($name);
|
||||||
|
|
@ -67,7 +84,7 @@ class DatabaseManager
|
||||||
if (config('tenancy.queue_database_deletion', false)) {
|
if (config('tenancy.queue_database_deletion', false)) {
|
||||||
QueuedTenantDatabaseDeleter::dispatch(app($databaseManagers[$driver]), $name, 'delete');
|
QueuedTenantDatabaseDeleter::dispatch(app($databaseManagers[$driver]), $name, 'delete');
|
||||||
} else {
|
} else {
|
||||||
app($databaseManagers[$driver])->deleteDatabase($name);
|
return app($databaseManagers[$driver])->deleteDatabase($name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
8
src/Exceptions/PhpRedisNotInstalledException.php
Normal file
8
src/Exceptions/PhpRedisNotInstalledException.php
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Stancl\Tenancy\Exceptions;
|
||||||
|
|
||||||
|
class PhpRedisNotInstalledException extends \Exception
|
||||||
|
{
|
||||||
|
protected $message = 'PhpRedis is not installed. PhpRedis is required for Redis multi-tenancy because Predis does not support prefixes.';
|
||||||
|
}
|
||||||
|
|
@ -71,16 +71,21 @@ class RedisStorageDriver implements StorageDriver
|
||||||
return "tenants:{$hash}";
|
return "tenants:{$hash}";
|
||||||
}, $uuids);
|
}, $uuids);
|
||||||
|
|
||||||
// Apparently, the PREFIX is applied to all functions except scan()
|
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);
|
$redis_prefix = $this->redis->getOption($this->redis->client()::OPT_PREFIX);
|
||||||
$hashes = $hashes ?: $this->redis->scan(null, $redis_prefix.'tenants:*');
|
}
|
||||||
|
$hashes = array_map(function ($hash) use ($redis_prefix) {
|
||||||
return array_map(function ($tenant) use ($redis_prefix) {
|
// Left strip $redis_prefix from $hash
|
||||||
// Left strip $redis_prefix from $tenant
|
return substr($hash, strlen($redis_prefix));
|
||||||
if (substr($tenant, 0, strlen($redis_prefix)) == $redis_prefix) {
|
}, $this->redis->scan(null, $redis_prefix.'tenants:*'));
|
||||||
$tenant = substr($tenant, strlen($redis_prefix));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return array_map(function ($tenant) {
|
||||||
return $this->redis->hgetall($tenant);
|
return $this->redis->hgetall($tenant);
|
||||||
}, $hashes);
|
}, $hashes);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ namespace Stancl\Tenancy\Traits;
|
||||||
use Stancl\Tenancy\CacheManager;
|
use Stancl\Tenancy\CacheManager;
|
||||||
use Illuminate\Support\Facades\Redis;
|
use Illuminate\Support\Facades\Redis;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Stancl\Tenancy\Exceptions\PhpRedisNotInstalledException;
|
||||||
|
|
||||||
trait BootstrapsTenancy
|
trait BootstrapsTenancy
|
||||||
{
|
{
|
||||||
|
|
@ -13,7 +14,9 @@ trait BootstrapsTenancy
|
||||||
public function bootstrap()
|
public function bootstrap()
|
||||||
{
|
{
|
||||||
$this->switchDatabaseConnection();
|
$this->switchDatabaseConnection();
|
||||||
|
if ($this->app['config']['tenancy.redis.tenancy']) {
|
||||||
$this->setPhpRedisPrefix($this->app['config']['tenancy.redis.prefixed_connections']);
|
$this->setPhpRedisPrefix($this->app['config']['tenancy.redis.prefixed_connections']);
|
||||||
|
}
|
||||||
$this->tagCache();
|
$this->tagCache();
|
||||||
$this->suffixFilesystemRootPaths();
|
$this->suffixFilesystemRootPaths();
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +31,11 @@ trait BootstrapsTenancy
|
||||||
foreach ($connections as $connection) {
|
foreach ($connections as $connection) {
|
||||||
$prefix = $this->app['config']['tenancy.redis.prefix_base'] . $this->tenant['uuid'];
|
$prefix = $this->app['config']['tenancy.redis.prefix_base'] . $this->tenant['uuid'];
|
||||||
$client = Redis::connection($connection)->client();
|
$client = Redis::connection($connection)->client();
|
||||||
|
try {
|
||||||
$client->setOption($client::OPT_PREFIX, $prefix);
|
$client->setOption($client::OPT_PREFIX, $prefix);
|
||||||
|
} catch (\Throwable $t) {
|
||||||
|
throw new PhpRedisNotInstalledException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ return [
|
||||||
'suffix' => '',
|
'suffix' => '',
|
||||||
],
|
],
|
||||||
'redis' => [
|
'redis' => [
|
||||||
|
'tenancy' => false,
|
||||||
'prefix_base' => 'tenant',
|
'prefix_base' => 'tenant',
|
||||||
'prefixed_connections' => [
|
'prefixed_connections' => [
|
||||||
'default',
|
'default',
|
||||||
|
|
|
||||||
5
test
Executable file
5
test
Executable file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# for development
|
||||||
|
docker-compose up -d
|
||||||
|
docker-compose exec test vendor/bin/phpunit "$@"
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
namespace Stancl\Tenancy\Tests;
|
namespace Stancl\Tenancy\Tests;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Redis;
|
use Illuminate\Support\Facades\Redis;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
use Stancl\Tenancy\Exceptions\PhpRedisNotInstalledException;
|
||||||
|
|
||||||
class BootstrapsTenancyTest extends TestCase
|
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 */
|
/** @test */
|
||||||
public function filesystem_is_suffixed()
|
public function filesystem_is_suffixed()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
151
tests/DataSeparationTest.php
Normal file
151
tests/DataSeparationTest.php
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
class DataSeparationTest extends TestCase
|
||||||
|
{
|
||||||
|
public $autoCreateTenant = false;
|
||||||
|
public $autoInitTenancy = false;
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function databases_are_separated()
|
||||||
|
{
|
||||||
|
$tenant1 = tenancy()->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 = [];
|
||||||
|
}
|
||||||
|
|
@ -40,7 +40,7 @@ class TenantDatabaseManagerTest extends TestCase
|
||||||
/** @test */
|
/** @test */
|
||||||
public function mysql_database_can_be_created_and_deleted()
|
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.');
|
$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 */
|
/** @test */
|
||||||
public function mysql_database_can_be_created_and_deleted_using_queued_commands()
|
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.');
|
$this->markTestSkipped('As to not bloat your MySQL instance with test databases, this test is not run by default.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ class TenantDatabaseManagerTest extends TestCase
|
||||||
/** @test */
|
/** @test */
|
||||||
public function pgsql_database_can_be_created_and_deleted()
|
public function pgsql_database_can_be_created_and_deleted()
|
||||||
{
|
{
|
||||||
if (! $this->isTravis()) {
|
if (! $this->isContainerized()) {
|
||||||
$this->markTestSkipped('As to not bloat your PostgreSQL instance with test databases, this test is not run by default.');
|
$this->markTestSkipped('As to not bloat your PostgreSQL instance with test databases, this test is not run by default.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +98,7 @@ class TenantDatabaseManagerTest extends TestCase
|
||||||
/** @test */
|
/** @test */
|
||||||
public function pgsql_database_can_be_created_and_deleted_using_queued_commands()
|
public function pgsql_database_can_be_created_and_deleted_using_queued_commands()
|
||||||
{
|
{
|
||||||
if (! $this->isTravis()) {
|
if (! $this->isContainerized()) {
|
||||||
$this->markTestSkipped('As to not bloat your PostgreSQL instance with test databases, this test is not run by default.');
|
$this->markTestSkipped('As to not bloat your PostgreSQL instance with test databases, this test is not run by default.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,7 +126,7 @@ class TenantDatabaseManagerTest extends TestCase
|
||||||
|
|
||||||
config()->set('tenancy.queue_database_creation', true);
|
config()->set('tenancy.queue_database_creation', true);
|
||||||
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
|
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
|
||||||
$this->assertTrue(app(DatabaseManager::class)->create($db_name, 'sqlite'));
|
app(DatabaseManager::class)->create($db_name, 'sqlite');
|
||||||
|
|
||||||
Queue::assertPushed(QueuedTenantDatabaseCreator::class);
|
Queue::assertPushed(QueuedTenantDatabaseCreator::class);
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +138,7 @@ class TenantDatabaseManagerTest extends TestCase
|
||||||
|
|
||||||
config()->set('tenancy.queue_database_deletion', true);
|
config()->set('tenancy.queue_database_deletion', true);
|
||||||
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
|
$db_name = 'testdatabase' . $this->randomString(10) . '.sqlite';
|
||||||
$this->assertTrue(app(DatabaseManager::class)->delete($db_name, 'sqlite'));
|
app(DatabaseManager::class)->delete($db_name, 'sqlite');
|
||||||
|
|
||||||
Queue::assertPushed(QueuedTenantDatabaseDeleter::class);
|
Queue::assertPushed(QueuedTenantDatabaseDeleter::class);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
|
|
||||||
public function initTenancy($domain = 'localhost')
|
public function initTenancy($domain = 'localhost')
|
||||||
{
|
{
|
||||||
tenancy()->init($domain);
|
return tenancy()->init($domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -53,6 +53,8 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
|
|
||||||
$app['config']->set([
|
$app['config']->set([
|
||||||
'database.redis.client' => 'phpredis',
|
'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' => [
|
'database.redis.tenancy' => [
|
||||||
'host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'),
|
'host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'),
|
||||||
'password' => env('TENANCY_TEST_REDIS_PASSWORD', null),
|
'password' => env('TENANCY_TEST_REDIS_PASSWORD', null),
|
||||||
|
|
@ -67,12 +69,16 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
'suffix' => '.sqlite',
|
'suffix' => '.sqlite',
|
||||||
],
|
],
|
||||||
'database.connections.sqlite.database' => ':memory:',
|
'database.connections.sqlite.database' => ':memory:',
|
||||||
'database.connections.pgsql.username' => 'postgres',
|
'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'),
|
||||||
|
// 'database.connections.pgsql.username' => 'pgsqluser',
|
||||||
'tenancy.filesystem.disks' => [
|
'tenancy.filesystem.disks' => [
|
||||||
'local',
|
'local',
|
||||||
'public',
|
'public',
|
||||||
's3',
|
's3',
|
||||||
],
|
],
|
||||||
|
'tenancy.redis.tenancy' => true,
|
||||||
|
'tenancy.migrations_directory' => database_path('../migrations'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,11 +119,9 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
|
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
|
return env('CONTINUOUS_INTEGRATION') || env('DOCKER');
|
||||||
// set one of these environment vars on their computer.
|
|
||||||
return env('CI') && env('TRAVIS') && env('CONTINUOUS_INTEGRATION');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function assertArrayIsSubset($subset, $array, string $message = ''): void
|
public function assertArrayIsSubset($subset, $array, string $message = ''): void
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue