1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-02-04 19:24:02 +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/
psysh
.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:
- 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)

View file

@ -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

View file

@ -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 \

View file

@ -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

View file

@ -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": {

View file

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

View file

@ -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.");
}

View file

@ -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']}");
});

View file

@ -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]);
}
}

View file

@ -10,4 +10,4 @@ class GlobalCacheFacade extends Facade
{
return 'globalCache';
}
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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];
}
}

View file

@ -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}");
}
}

View file

@ -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());
}
}

29
test
View file

@ -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 "$@"
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/")

View file

@ -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/";

View file

@ -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'));
}

View file

@ -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();
}
}

View file

@ -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 = [];
}
}

View file

@ -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);
}

View file

@ -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'));
}
}
}

View file

@ -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());
}

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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));
}
}

View file

@ -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',
]);
}
}