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

merge 1.x into .

This commit is contained in:
Samuel Štancl 2019-08-08 22:27:49 +02:00
commit 545c2330d4
33 changed files with 214 additions and 103 deletions

3
.gitignore vendored
View file

@ -4,3 +4,6 @@ vendor/
.vscode/ .vscode/
psysh psysh
.phpunit.result.cache .phpunit.result.cache
phpunit_var_*.xml
coverage/
clover.xml

4
.styleci.yml Normal file
View file

@ -0,0 +1,4 @@
preset: laravel
disabled:
- concat_without_spaces
- ternary_operator_spaces

View file

@ -1,5 +1,4 @@
env: env:
- LARAVEL_VERSION="5.7.*" TESTBENCH_VERSION="~3.7" REDIS_DRIVER=phpredis
- LARAVEL_VERSION="5.8.*" TESTBENCH_VERSION="~3.8" REDIS_DRIVER=phpredis - LARAVEL_VERSION="5.8.*" TESTBENCH_VERSION="~3.8" REDIS_DRIVER=phpredis
language: php language: php
@ -19,10 +18,7 @@ before_script:
- export DB_USERNAME=root DB_PASSWORD="" DB_DATABASE=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' - 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 script: ./test
after_script:
- docker-compose down
after_success: after_success:
- bash <(curl -s https://codecov.io/bash) - bash <(curl -s https://codecov.io/bash)

View file

@ -1,5 +1,17 @@
# Release Notes for 1.x # 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) ## [v1.6.0 (2019-07-30)](https://github.com/stancl/tenancy/compare/v1.5.1...v1.6.0)
### Added ### Added

View file

@ -16,7 +16,15 @@ RUN apt-get update \
&& php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \ && php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
&& mkdir /run/php && 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 \ RUN apt-get -y autoremove \
&& apt-get clean \ && apt-get clean \

View file

@ -1,6 +1,6 @@
# [stancl/tenancy](https://stancl.github.io/tenancy/) # [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) [![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) [![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) [![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:list`](#-tenants-list-)
- [`tenants:migrate`, `tenants:rollback`, `tenants:seed`](#-tenants-migrate----tenants-rollback----tenants-seed-) - [`tenants:migrate`, `tenants:rollback`, `tenants:seed`](#-tenants-migrate----tenants-rollback----tenants-seed-)
+ [Tenant migrations](#tenant-migrations) + [Tenant migrations](#tenant-migrations)
* [Testing](#testing)
- [Tips](#tips) - [Tips](#tips)
* [HTTPS certificates](#https-certificates) * [HTTPS certificates](#https-certificates)
+ [1. Use nginx with the lua module](#1-use-nginx-with-the-lua-module) + [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) + [2. Add a simple server block for each tenant](#2-add-a-simple-server-block-for-each-tenant)
+ [Generating certificates](#generating-certificates) + [Generating certificates](#generating-certificates)
- [Testing](#testing) - [Development](#development)
* [Running tests](#running-tests)
+ [With Docker](#with-docker) + [With Docker](#with-docker)
+ [Without Docker](#without-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 ### Requirements
- Laravel 5.7 or 5.8 - Laravel 5.8
### Installing the package ### 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 ### 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 ```php
tenancy()->init(); 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. 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 # 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. - 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. 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 ### 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 ### Without Docker

View file

@ -10,17 +10,18 @@
} }
], ],
"require": { "require": {
"illuminate/support": "5.8.*||5.7.*", "illuminate/support": "5.8.*",
"webpatser/laravel-uuid": "^3.0", "webpatser/laravel-uuid": "^3.0",
"predis/predis": "^1.1" "predis/predis": "^1.1"
}, },
"require-dev": { "require-dev": {
"vlucas/phpdotenv": "^2.2||^3.3", "vlucas/phpdotenv": "^3.3",
"psy/psysh": "@stable", "psy/psysh": "@stable",
"laravel/framework": "5.8.*||5.7.*",
"orchestra/testbench": "~3.7||~3.8",
"league/flysystem-aws-s3-v3": "~1.0", "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": { "autoload": {
"psr-4": { "psr-4": {

View file

@ -30,5 +30,6 @@
<env name="SESSION_DRIVER" value="array"/> <env name="SESSION_DRIVER" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/> <env name="DB_CONNECTION" value="sqlite"/>
<env name="AWS_DEFAULT_REGION" value="us-west-2"/> <env name="AWS_DEFAULT_REGION" value="us-west-2"/>
<env name="STANCL_TENANCY_TEST_VARIANT" value="1"/>
</php> </php>
</phpunit> </phpunit>

View file

@ -10,7 +10,7 @@ class CacheManager extends BaseCacheManager
{ {
$tags = [config('tenancy.cache.tag_base') . tenant('uuid')]; $tags = [config('tenancy.cache.tag_base') . tenant('uuid')];
if ($method === "tags") { if ($method === 'tags') {
if (\count($parameters) !== 1) { if (\count($parameters) !== 1) {
throw new \Exception("Method tags() takes exactly 1 argument. {count($parameters)} passed."); throw new \Exception("Method tags() takes exactly 1 argument. {count($parameters)} passed.");
} }

View file

@ -37,7 +37,7 @@ class TenantList extends Command
*/ */
public function handle() public function handle()
{ {
$this->info("Listing all tenants."); $this->info('Listing all tenants.');
tenancy()->all()->each(function ($tenant) { tenancy()->all()->each(function ($tenant) {
$this->line("[Tenant] uuid: {$tenant['uuid']} @ {$tenant['domain']}"); $this->line("[Tenant] uuid: {$tenant['uuid']} @ {$tenant['domain']}");
}); });

View file

@ -90,7 +90,7 @@ class DatabaseManager
public function getDriver(): ?string public function getDriver(): ?string
{ {
return config("database.connections.tenant.driver"); return config('database.connections.tenant.driver');
} }
public function createTenantConnection(string $database_name) public function createTenantConnection(string $database_name)
@ -98,11 +98,11 @@ class DatabaseManager
// Create the `tenancy` database connection. // Create the `tenancy` database connection.
$based_on = config('tenancy.database.based_on') ?: config('database.default'); $based_on = config('tenancy.database.based_on') ?: config('database.default');
config()->set([ config()->set([
'database.connections.tenant' => config('database.connections.' . $based_on) 'database.connections.tenant' => config('database.connections.' . $based_on),
]); ]);
// Change DB name // 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]); config()->set(['database.connections.tenant.database' => $database_name]);
} }
} }

View file

@ -5,13 +5,22 @@ namespace Stancl\Tenancy\Interfaces;
interface StorageDriver interface StorageDriver
{ {
public function identifyTenant(string $domain): array; public function identifyTenant(string $domain): array;
public function getAllTenants(array $uuids = []): array; public function getAllTenants(array $uuids = []): array;
public function getTenantById(string $uuid, array $fields = []): array; public function getTenantById(string $uuid, array $fields = []): array;
public function getTenantIdByDomain(string $domain): ?string; public function getTenantIdByDomain(string $domain): ?string;
public function createTenant(string $domain, string $uuid): array; public function createTenant(string $domain, string $uuid): array;
public function deleteTenant(string $uuid): bool; public function deleteTenant(string $uuid): bool;
public function get(string $uuid, string $key); public function get(string $uuid, string $key);
public function getMany(string $uuid, array $keys): array; public function getMany(string $uuid, array $keys): array;
public function put(string $uuid, string $key, $value); public function put(string $uuid, string $key, $value);
public function putMany(string $uuid, array $values): array; public function putMany(string $uuid, array $values): array;
} }

View file

@ -8,7 +8,7 @@ interface TenantDatabaseManager
* Create a database. * Create a database.
* *
* @param string $name Name of the database. * @param string $name Name of the database.
* @return boolean * @return bool
*/ */
public function createDatabase(string $name): bool; public function createDatabase(string $name): bool;
@ -16,7 +16,7 @@ interface TenantDatabaseManager
* Delete a database. * Delete a database.
* *
* @param string $name Name of the database. * @param string $name Name of the database.
* @return boolean * @return bool
*/ */
public function deleteDatabase(string $name): bool; public function deleteDatabase(string $name): bool;
} }

View file

@ -5,8 +5,8 @@ namespace Stancl\Tenancy\Jobs;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Stancl\Tenancy\Interfaces\TenantDatabaseManager; use Stancl\Tenancy\Interfaces\TenantDatabaseManager;
class QueuedTenantDatabaseCreator implements ShouldQueue class QueuedTenantDatabaseCreator implements ShouldQueue

View file

@ -5,8 +5,8 @@ namespace Stancl\Tenancy\Jobs;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Stancl\Tenancy\Interfaces\TenantDatabaseManager; use Stancl\Tenancy\Interfaces\TenantDatabaseManager;
class QueuedTenantDatabaseDeleter implements ShouldQueue class QueuedTenantDatabaseDeleter implements ShouldQueue

View file

@ -20,6 +20,7 @@ class RedisStorageDriver implements StorageDriver
if (! $id) { if (! $id) {
throw new \Exception("Tenant could not be identified on domain {$domain}"); throw new \Exception("Tenant could not be identified on domain {$domain}");
} }
return $this->getTenantById($id); return $this->getTenantById($id);
} }
@ -50,14 +51,15 @@ class RedisStorageDriver implements StorageDriver
{ {
$this->redis->hmset("domains:$domain", 'tenant_id', $uuid); $this->redis->hmset("domains:$domain", 'tenant_id', $uuid);
$this->redis->hmset("tenants:$uuid", 'uuid', json_encode($uuid), 'domain', json_encode($domain)); $this->redis->hmset("tenants:$uuid", 'uuid', json_encode($uuid), 'domain', json_encode($domain));
return $this->redis->hgetall("tenants:$uuid"); return $this->redis->hgetall("tenants:$uuid");
} }
/** /**
* @inheritDoc * {@inheritdoc}
* *
* @param string $id * @param string $id
* @return boolean * @return bool
* @todo Make tenant & domain deletion atomic. * @todo Make tenant & domain deletion atomic.
*/ */
public function deleteTenant(string $id): bool public function deleteTenant(string $id): bool
@ -69,6 +71,7 @@ class RedisStorageDriver implements StorageDriver
} }
$this->redis->del("domains:$domain"); $this->redis->del("domains:$domain");
return (bool) $this->redis->del("tenants:$id"); return (bool) $this->redis->del("tenants:$id");
} }
@ -79,17 +82,21 @@ class RedisStorageDriver implements StorageDriver
}, $uuids); }, $uuids);
if (! $hashes) { if (! $hashes) {
// Apparently, the PREFIX is applied to all functions except scan(). // Prefix is applied to all functions except scan().
// Therefore, if the `tenancy` Redis connection has a prefix set // This code applies the correct prefix manually.
// (and PhpRedis is used), prepend the prefix to the search. $redis_prefix = config('database.redis.options.prefix');
$redis_prefix = '';
if (config('database.redis.client') === 'phpredis') { 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 $hashes = array_map(function ($key) use ($redis_prefix) {
return substr($hash, strlen($redis_prefix)); // Left strip $redis_prefix from $key
}, $this->redis->scan(null, $redis_prefix.'tenants:*')); return substr($key, strlen($redis_prefix));
}, $all_keys);
} }
return array_map(function ($tenant) { return array_map(function ($tenant) {
@ -110,12 +117,14 @@ class RedisStorageDriver implements StorageDriver
public function put(string $uuid, string $key, $value) public function put(string $uuid, string $key, $value)
{ {
$this->redis->hset("tenants:$uuid", $key, $value); $this->redis->hset("tenants:$uuid", $key, $value);
return $value; return $value;
} }
public function putMany(string $uuid, array $values): array public function putMany(string $uuid, array $values): array
{ {
$this->redis->hmset("tenants:$uuid", $values); $this->redis->hmset("tenants:$uuid", $values);
return $values; return $values;
} }
} }

View file

@ -49,6 +49,7 @@ class TenantManager
{ {
$this->setTenant($this->identify($domain)); $this->setTenant($this->identify($domain));
$this->bootstrap(); $this->bootstrap();
return $this->tenant; return $this->tenant;
} }
@ -57,7 +58,7 @@ class TenantManager
$domain = $domain ?: $this->currentDomain(); $domain = $domain ?: $this->currentDomain();
if (! $domain) { if (! $domain) {
throw new \Exception("No domain supplied nor detected."); throw new \Exception('No domain supplied nor detected.');
} }
$tenant = $this->storage->identifyTenant($domain); $tenant = $this->storage->identifyTenant($domain);
@ -98,6 +99,7 @@ class TenantManager
public function getTenantById(string $uuid, $fields = []) public function getTenantById(string $uuid, $fields = [])
{ {
$fields = (array) $fields; $fields = (array) $fields;
return $this->jsonDecodeArrayValues($this->storage->getTenantById($uuid, $fields)); return $this->jsonDecodeArrayValues($this->storage->getTenantById($uuid, $fields));
} }
@ -165,6 +167,7 @@ class TenantManager
public function getDatabaseName($tenant = []): string public function getDatabaseName($tenant = []): string
{ {
$tenant = $tenant ?: $this->tenant; $tenant = $tenant ?: $this->tenant;
return $this->app['config']['tenancy.database.prefix'] . $tenant['uuid'] . $this->app['config']['tenancy.database.suffix']; return $this->app['config']['tenancy.database.prefix'] . $tenant['uuid'] . $this->app['config']['tenancy.database.suffix'];
} }
@ -219,6 +222,7 @@ class TenantManager
{ {
$this->setTenant($this->storage->getTenantById($uuid)); $this->setTenant($this->storage->getTenantById($uuid));
$this->bootstrap(); $this->bootstrap();
return $this->tenant; return $this->tenant;
} }
@ -252,7 +256,7 @@ class TenantManager
{ {
if (\is_null($uuid)) { if (\is_null($uuid)) {
if (! isset($this->tenant['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']; $uuid = $this->tenant['uuid'];

View file

@ -13,7 +13,7 @@ trait BootstrapsTenancy
/** /**
* Was tenancy initialized/bootstrapped? * Was tenancy initialized/bootstrapped?
* *
* @var boolean * @var bool
*/ */
public $initialized = false; public $initialized = false;

View file

@ -9,7 +9,7 @@ trait HasATenantsOption
protected function getOptions() protected function getOptions()
{ {
return array_merge([ 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()); ], parent::getOptions());
} }
} }

29
test
View file

@ -1,5 +1,26 @@
#!/bin/bash #!/usr/bin/env python3
from os import system
import argparse
# for development system('docker-compose up -d')
docker-compose up -d
docker-compose exec test vendor/bin/phpunit "$@" 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/")

View file

@ -24,6 +24,10 @@ class BootstrapsTenancyTest extends TestCase
/** @test */ /** @test */
public function redis_is_prefixed() public function redis_is_prefixed()
{ {
if (! config('tenancy.redis.tenancy')) {
$this->markTestSkipped('Redis tenancy disabled.');
}
$this->initTenancy(); $this->initTenancy();
foreach (config('tenancy.redis.prefixed_connections', ['default']) as $connection) { foreach (config('tenancy.redis.prefixed_connections', ['default']) as $connection) {
$prefix = config('tenancy.redis.prefix_base') . tenant('uuid'); $prefix = config('tenancy.redis.prefix_base') . tenant('uuid');
@ -35,6 +39,7 @@ class BootstrapsTenancyTest extends TestCase
/** @test */ /** @test */
public function predis_is_supported() public function predis_is_supported()
{ {
// No setDriver() before that version.
if (app()->version() < 'v5.8.27') { if (app()->version() < 'v5.8.27') {
$this->markTestSkipped(); $this->markTestSkipped();
} }
@ -74,14 +79,14 @@ class BootstrapsTenancyTest extends TestCase
$this->initTenancy(); $this->initTenancy();
$new_storage_path = storage_path(); $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) { foreach (config('tenancy.filesystem.disks') as $disk) {
$suffix = config('tenancy.filesystem.suffix_base') . tenant('uuid'); $suffix = config('tenancy.filesystem.suffix_base') . tenant('uuid');
$current_path_prefix = \Storage::disk($disk)->getAdapter()->getPathPrefix(); $current_path_prefix = \Storage::disk($disk)->getAdapter()->getPathPrefix();
if ($override = config("tenancy.filesystem.root_override.{$disk}")) { 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 { } else {
if ($base = $old_storage_facade_roots[$disk]) { if ($base = $old_storage_facade_roots[$disk]) {
$correct_path_prefix = $base . "/$suffix/"; $correct_path_prefix = $base . "/$suffix/";

View file

@ -2,9 +2,9 @@
namespace Stancl\Tenancy\Tests; namespace Stancl\Tenancy\Tests;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Artisan;
use Stancl\Tenancy\Tests\Etc\ExampleSeeder; use Stancl\Tenancy\Tests\Etc\ExampleSeeder;
class CommandsTest extends TestCase class CommandsTest extends TestCase
@ -47,7 +47,7 @@ class CommandsTest extends TestCase
{ {
$tenant = tenant()->create('test.localhost'); $tenant = tenant()->create('test.localhost');
Artisan::call('tenants:migrate', [ Artisan::call('tenants:migrate', [
'--tenants' => [$tenant['uuid']] '--tenants' => [$tenant['uuid']],
]); ]);
$this->assertFalse(Schema::hasTable('users')); $this->assertFalse(Schema::hasTable('users'));

View file

@ -2,11 +2,11 @@
namespace Stancl\Tenancy\Tests; 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\Str;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
class DataSeparationTest extends TestCase class DataSeparationTest extends TestCase
{ {
@ -19,7 +19,7 @@ class DataSeparationTest extends TestCase
$tenant1 = tenancy()->create('tenant1.localhost'); $tenant1 = tenancy()->create('tenant1.localhost');
$tenant2 = tenancy()->create('tenant2.localhost'); $tenant2 = tenancy()->create('tenant2.localhost');
\Artisan::call('tenants:migrate', [ \Artisan::call('tenants:migrate', [
'--tenants' => [$tenant1['uuid'], $tenant2['uuid']] '--tenants' => [$tenant1['uuid'], $tenant2['uuid']],
]); ]);
tenancy()->init('tenant1.localhost'); tenancy()->init('tenant1.localhost');
@ -52,7 +52,7 @@ class DataSeparationTest extends TestCase
$tenant3 = tenancy()->create('tenant3.localhost'); $tenant3 = tenancy()->create('tenant3.localhost');
\Artisan::call('tenants:migrate', [ \Artisan::call('tenants:migrate', [
'--tenants' => [$tenant1['uuid'], $tenant3['uuid']] '--tenants' => [$tenant1['uuid'], $tenant3['uuid']],
]); ]);
tenancy()->init('tenant3.localhost'); tenancy()->init('tenant3.localhost');
@ -66,6 +66,10 @@ class DataSeparationTest extends TestCase
/** @test */ /** @test */
public function redis_is_separated() public function redis_is_separated()
{ {
if (! config('tenancy.redis.tenancy')) {
$this->markTestSkipped('Redis tenancy disabled.');
}
tenancy()->create('tenant1.localhost'); tenancy()->create('tenant1.localhost');
tenancy()->create('tenant2.localhost'); tenancy()->create('tenant2.localhost');

View file

@ -27,7 +27,7 @@ class ReidentificationTest extends TestCase
$current_path_prefix = \Storage::disk($disk)->getAdapter()->getPathPrefix(); $current_path_prefix = \Storage::disk($disk)->getAdapter()->getPathPrefix();
if ($override = config("tenancy.filesystem.root_override.{$disk}")) { 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 { } else {
if ($base = $originals[$disk]) { if ($base = $originals[$disk]) {
$correct_path_prefix = $base . "/$suffix/"; $correct_path_prefix = $base . "/$suffix/";
@ -49,7 +49,6 @@ class ReidentificationTest extends TestCase
tenant()->create('second.localhost'); tenant()->create('second.localhost');
tenancy()->init('second.localhost'); tenancy()->init('second.localhost');
$suffix = config('tenancy.filesystem.suffix_base') . tenant('uuid'); $suffix = config('tenancy.filesystem.suffix_base') . tenant('uuid');
$this->assertSame($original . "/$suffix", storage_path()); $this->assertSame($original . "/$suffix", storage_path());
} }

View file

@ -186,4 +186,12 @@ class TenantManagerTest extends TestCase
$tenant = tenant()->create('foo.localhost'); $tenant = tenant()->create('foo.localhost');
$this->assertSame([$tenant], tenancy()->all()->toArray()); $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());
}
} }

View file

@ -2,8 +2,6 @@
namespace Stancl\Tenancy\Tests; namespace Stancl\Tenancy\Tests;
use Stancl\Tenancy\Interfaces\StorageDriver;
class TenantStorageTest extends TestCase class TenantStorageTest extends TestCase
{ {
/** @test */ /** @test */

View file

@ -9,8 +9,15 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
public $autoCreateTenant = true; public $autoCreateTenant = true;
public $autoInitTenancy = true; public $autoInitTenancy = true;
private function checkRequirements(): void
{
parent::checkRequirements();
dd($this->getAnnotations());
}
/** /**
* Setup the test environment * Setup the test environment.
* *
* @return void * @return void
*/ */
@ -49,13 +56,14 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
protected function getEnvironmentSetUp($app) protected function getEnvironmentSetUp($app)
{ {
if (file_exists(__DIR__ . '/../.env')) { if (file_exists(__DIR__ . '/../.env')) {
$this->loadDotEnv(); \Dotenv\Dotenv::create(__DIR__ . '/..')->load();
} }
$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.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.default.host' => env('TENANCY_TEST_REDIS_HOST', '127.0.0.1'),
'database.redis.options.prefix' => 'foo',
'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),
@ -63,6 +71,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
// Use the #14 Redis database unless specified otherwise. // Use the #14 Redis database unless specified otherwise.
// Make sure you don't store anything in this db! // Make sure you don't store anything in this db!
'database' => env('TENANCY_TEST_REDIS_DB', 14), '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' => [ 'tenancy.database' => [
'based_on' => 'sqlite', 'based_on' => 'sqlite',
@ -81,14 +90,19 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
'tenancy.redis.prefixed_connections' => ['default'], 'tenancy.redis.prefixed_connections' => ['default'],
'tenancy.migrations_directory' => database_path('../migrations'), 'tenancy.migrations_directory' => database_path('../migrations'),
]); ]);
}
protected function loadDotEnv() switch ((string) env('STANCL_TENANCY_TEST_VARIANT', '1')) {
{ case '2':
if (app()::VERSION > '5.8.0') { $app['config']->set([
\Dotenv\Dotenv::create(__DIR__ . '/..')->load(); 'tenancy.redis.tenancy' => false,
} else { 'database.redis.client' => 'predis',
(new \Dotenv\Dotenv(__DIR__ . '/..'))->load(); ]);
break;
default:
$app['config']->set([
'tenancy.redis.tenancy' => true,
'database.redis.client' => 'phpredis',
]);
} }
} }