mirror of
https://github.com/archtechx/tenancy.git
synced 2025-12-12 06:44:04 +00:00
Laravel 11 support + Docker improvements (#29)
* wip * bump jobpipeline dependency * bump pest dependency * fix composer.json syntax * minor changes to docker setup * more docker changes * compact pest output, remove unnecessary env vars from composer.json * minor pest tweaks * mssql fix * try enabling colors in CI * try setting --columns=max for pest in CI * try setting columns using env var instead of --columns in CI * Revert "try setting columns using env var instead of --columns in CI" This reverts commit eb3c177aefa97b0a3140d7f0e89c5012a854ff42. * replace --compact with --no-progress * try setting a hardcoded columns value in CI * remove --columns (doesn't work), add back --compact * try setting COLUMNS to a hardcoded value in CI * remove alternative env syntax from CI * fix PrefixCacheBootstrapperTest on L11, skip on L10 * add one more skip() call * fix validate.yml * Simplify schema dump, skip dump-related tests in L10 * Rename 'dump' table to 'example' * Bring schema dump-related tests together, add comments * Merge schema path-related tests into one, add comments * Rename dataset parameter --------- Co-authored-by: lukinovec <lukinovec@gmail.com>
This commit is contained in:
parent
d2ab2dacf2
commit
32a063b834
16 changed files with 135 additions and 178 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -18,6 +18,8 @@ jobs:
|
||||||
include:
|
include:
|
||||||
- laravel: "^10.0"
|
- laravel: "^10.0"
|
||||||
php: "8.2"
|
php: "8.2"
|
||||||
|
- laravel: "^11.0"
|
||||||
|
php: "8.3"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
@ -28,7 +30,7 @@ jobs:
|
||||||
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
|
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
|
||||||
composer update --prefer-dist --no-interaction
|
composer update --prefer-dist --no-interaction
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: ./vendor/bin/pest
|
run: COLUMNS=200 ./vendor/bin/pest --compact --colors=always
|
||||||
env:
|
env:
|
||||||
DB_PASSWORD: password
|
DB_PASSWORD: password
|
||||||
DB_USERNAME: root
|
DB_USERNAME: root
|
||||||
|
|
@ -41,7 +43,7 @@ jobs:
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v2
|
uses: codecov/codecov-action@v2
|
||||||
with:
|
with:
|
||||||
token: 24382d15-84e7-4a55-bea4-c4df96a24a9b
|
token: 24382d15-84e7-4a55-bea4-c4df96a24a9b # todo it's fine if this is here in plaintext, but move this to GH secrets eventually
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
|
|
|
||||||
4
.github/workflows/validate.yml
vendored
4
.github/workflows/validate.yml
vendored
|
|
@ -15,6 +15,6 @@ jobs:
|
||||||
- name: Check for todo2
|
- name: Check for todo2
|
||||||
run: '! grep -r "todo2" --exclude-dir=workflows .'
|
run: '! grep -r "todo2" --exclude-dir=workflows .'
|
||||||
if: always()
|
if: always()
|
||||||
- name: Check for skip() in tests
|
- name: Check for non-todo skip()s in tests
|
||||||
run: '! grep -r "skip(" --exclude-dir=workflows tests/'
|
run: '! grep -r "skip(" --exclude-dir=workflows tests/ | grep -v "todo"'
|
||||||
if: always()
|
if: always()
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,6 +5,7 @@ vendor/
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea
|
.idea
|
||||||
psysh
|
psysh
|
||||||
|
.phpunit.cache
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
phpunit_var_*.xml
|
phpunit_var_*.xml
|
||||||
coverage/
|
coverage/
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@
|
||||||
|
|
||||||
php-cs-fixer will fix code style violations in your pull requests.
|
php-cs-fixer will fix code style violations in your pull requests.
|
||||||
|
|
||||||
|
To run it locally, use `composer cs`.
|
||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
|
|
||||||
Run `composer docker-up` to start the containers. Then run `composer test` to run the tests.
|
Run `composer docker-up` to start the containers. Then run `composer test` to run the tests.
|
||||||
|
|
||||||
If you need to pass additional flags to phpunit, use `./test --foo` instead of `composer test --foo`. Composer scripts unfortunately don't pass CLI arguments.
|
If you need to pass additional flags to phpunit, use `composer test --`, e.g. `composer test -- --filter="foo"`. Alternatively, you can use `./test --filter="foo"`
|
||||||
|
|
||||||
If you want to run a specific test (or test file), you can also use `./t 'name of the test'`. This is equivalent to `./test --no-coverage --filter 'name of the test'` (`--no-coverage` speeds up the execution time).
|
If you want to run a specific test (or test file), you can also use `./t 'name of the test'`. This is equivalent to `./test --no-coverage --filter 'name of the test'` (`--no-coverage` speeds up the execution time).
|
||||||
|
|
||||||
|
|
|
||||||
17
Dockerfile
17
Dockerfile
|
|
@ -1,7 +1,7 @@
|
||||||
# add amd64 platform to support Mac M1
|
FROM shivammathur/node:latest
|
||||||
FROM --platform=linux/amd64 shivammathur/node:latest-amd64
|
SHELL ["/bin/bash", "-c"]
|
||||||
|
|
||||||
ARG PHP_VERSION=8.2
|
ARG PHP_VERSION=8.3
|
||||||
|
|
||||||
WORKDIR /var/www/html
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
|
@ -9,13 +9,18 @@ WORKDIR /var/www/html
|
||||||
ENV TZ=Europe/London
|
ENV TZ=Europe/London
|
||||||
ENV LANG=en_GB.UTF-8
|
ENV LANG=en_GB.UTF-8
|
||||||
|
|
||||||
# install MYSSQL ODBC Driver
|
# install MSSQL ODBC driver (1/2)
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y gnupg2 \
|
&& apt-get install -y gnupg2 \
|
||||||
&& curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \
|
&& curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \
|
||||||
&& curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list \
|
&& curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > /etc/apt/sources.list.d/mssql-release.list \
|
||||||
&& apt-get update \
|
&& apt-get update
|
||||||
&& ACCEPT_EULA=Y apt-get install -y unixodbc-dev=2.3.7 unixodbc=2.3.7 odbcinst1debian2=2.3.7 odbcinst=2.3.7 msodbcsql17
|
|
||||||
|
# install MSSQL ODBC driver (2/2)
|
||||||
|
RUN if [[ $(uname -m) == "arm64" || $(uname -m) == "aarch64" ]]; \
|
||||||
|
then ACCEPT_EULA=Y apt-get install -y unixodbc-dev msodbcsql18; \
|
||||||
|
else ACCEPT_EULA=Y apt-get install -y unixodbc-dev=2.3.7 unixodbc=2.3.7 odbcinst1debian2=2.3.7 odbcinst=2.3.7 msodbcsql17; \
|
||||||
|
fi
|
||||||
|
|
||||||
# set PHP version
|
# set PHP version
|
||||||
RUN update-alternatives --set php /usr/bin/php$PHP_VERSION \
|
RUN update-alternatives --set php /usr/bin/php$PHP_VERSION \
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
## Updating the docker image used by the GH action
|
## Updating the docker image used by the GH action
|
||||||
|
|
||||||
1. Login in to Docker Hub: `docker login -u archtechx -p`
|
1. Login in to Docker Hub: `docker login -u archtechx -p`
|
||||||
2. Build the image (probably shut down docker-compose containers first): `docker-compose build --no-cache`
|
1. Build the image (probably shut down docker-compose containers first): `DOCKER_DEFAULT_PLATFORM=linux/amd64 docker-compose build --no-cache`
|
||||||
3. Tag a new image: `docker tag tenancy_test archtechx/tenancy:latest`
|
1. Verify that tests pass on the new image: `composer test`
|
||||||
4. Push the image: `docker push archtechx/tenancy:latest`
|
1. Tag a new image: `docker tag tenancy-test archtechx/tenancy:latest`
|
||||||
|
1. Push the image: `docker push archtechx/tenancy:latest`
|
||||||
|
|
|
||||||
|
|
@ -17,21 +17,21 @@
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"illuminate/support": "^10.1",
|
"illuminate/support": "^10.1|^11.0",
|
||||||
"facade/ignition-contracts": "^1.0.2",
|
"facade/ignition-contracts": "^1.0.2",
|
||||||
"spatie/ignition": "^1.4",
|
"spatie/ignition": "^1.4",
|
||||||
"ramsey/uuid": "^4.7.3",
|
"ramsey/uuid": "^4.7.3",
|
||||||
"stancl/jobpipeline": "2.0.0-rc1",
|
"stancl/jobpipeline": "2.0.0-rc2",
|
||||||
"stancl/virtualcolumn": "dev-master",
|
"stancl/virtualcolumn": "dev-master",
|
||||||
"spatie/invade": "^1.1"
|
"spatie/invade": "^1.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"laravel/framework": "^10.1",
|
"laravel/framework": "^10.1|^11.0",
|
||||||
"orchestra/testbench": "^8.0",
|
"orchestra/testbench": "^8.0|^9.0",
|
||||||
"league/flysystem-aws-s3-v3": "^3.12.2",
|
"league/flysystem-aws-s3-v3": "^3.12.2",
|
||||||
"doctrine/dbal": "^3.6.0",
|
"doctrine/dbal": "^3.6.0",
|
||||||
"spatie/valuestore": "^1.2.5",
|
"spatie/valuestore": "^1.2.5",
|
||||||
"pestphp/pest": "^1.21",
|
"pestphp/pest": "^2.0",
|
||||||
"larastan/larastan": "^2.4",
|
"larastan/larastan": "^2.4",
|
||||||
"spatie/invade": "^1.1"
|
"spatie/invade": "^1.1"
|
||||||
},
|
},
|
||||||
|
|
@ -60,16 +60,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"docker-up": "PHP_VERSION=8.2 docker-compose up -d",
|
"docker-up": "docker-compose up -d",
|
||||||
"docker-down": "PHP_VERSION=8.2 docker-compose down",
|
"docker-down": "docker-compose down",
|
||||||
"docker-rebuild": "PHP_VERSION=8.2 docker-compose up -d --no-deps --build",
|
"docker-rebuild": "PHP_VERSION=8.3 docker-compose up -d --no-deps --build",
|
||||||
"docker-m1": "ln -s docker-compose-m1.override.yml docker-compose.override.yml",
|
"docker-m1": "ln -s docker-compose-m1.override.yml docker-compose.override.yml",
|
||||||
"coverage": "open coverage/phpunit/html/index.html",
|
"coverage": "open coverage/phpunit/html/index.html",
|
||||||
"phpstan": "vendor/bin/phpstan",
|
"phpstan": "vendor/bin/phpstan",
|
||||||
"phpstan-pro": "vendor/bin/phpstan --pro",
|
"phpstan-pro": "vendor/bin/phpstan --pro",
|
||||||
"cs": "php-cs-fixer fix --config=.php-cs-fixer.php",
|
"cs": "php-cs-fixer fix --config=.php-cs-fixer.php",
|
||||||
"test": "PHP_VERSION=8.2 ./test --no-coverage",
|
"test": "./test --no-coverage --color=always",
|
||||||
"test-full": "PHP_VERSION=8.2 ./test"
|
"test-full": "./test --color=always"
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
platform: linux/amd64
|
# platform: linux/amd64 # either one works
|
||||||
|
image: arm64v8/mysql
|
||||||
mysql2:
|
mysql2:
|
||||||
platform: linux/amd64
|
# platform: linux/amd64 # either one works
|
||||||
|
image: arm64v8/mysql
|
||||||
mssql:
|
mssql:
|
||||||
image: mcr.microsoft.com/azure-sql-edge
|
image: mcr.microsoft.com/azure-sql-edge
|
||||||
|
|
|
||||||
69
phpunit.xml
69
phpunit.xml
|
|
@ -1,39 +1,34 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<phpunit backupGlobals="false"
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||||
backupStaticAttributes="false"
|
<coverage>
|
||||||
bootstrap="vendor/autoload.php"
|
<report>
|
||||||
colors="true"
|
<clover outputFile="coverage/phpunit/clover.xml"/>
|
||||||
convertErrorsToExceptions="true"
|
<html outputDirectory="coverage/phpunit/html" lowUpperBound="35" highLowerBound="70"/>
|
||||||
convertNoticesToExceptions="true"
|
</report>
|
||||||
convertWarningsToExceptions="true"
|
</coverage>
|
||||||
processIsolation="false"
|
<testsuites>
|
||||||
stopOnFailure="false">
|
<testsuite name="Unit">
|
||||||
<testsuites>
|
<directory suffix="Test.php">./tests</directory>
|
||||||
<testsuite name="Unit">
|
</testsuite>
|
||||||
<directory suffix="Test.php">./tests</directory>
|
</testsuites>
|
||||||
</testsuite>
|
<php>
|
||||||
</testsuites>
|
<env name="APP_ENV" value="testing"/>
|
||||||
<filter>
|
<env name="APP_KEY" value="base64:uYVmTs9lrQbXWfHgSSiG0VZMjc2KG/fBbjV1i1JDVos="/>
|
||||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||||
<directory suffix=".php">./src</directory>
|
<env name="CACHE_DRIVER" value="redis"/>
|
||||||
<exclude>
|
<env name="MAIL_DRIVER" value="array"/>
|
||||||
<file>./src/routes.php</file>
|
<env name="QUEUE_CONNECTION" value="sync"/>
|
||||||
</exclude>
|
<env name="SESSION_DRIVER" value="array"/>
|
||||||
</whitelist>
|
<env name="DB_CONNECTION" value="central"/>
|
||||||
</filter>
|
<env name="AWS_DEFAULT_REGION" value="us-west-2"/>
|
||||||
<php>
|
</php>
|
||||||
<env name="APP_ENV" value="testing"/>
|
<logging/>
|
||||||
<env name="APP_KEY" value="base64:uYVmTs9lrQbXWfHgSSiG0VZMjc2KG/fBbjV1i1JDVos="/>
|
<source>
|
||||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
<include>
|
||||||
<env name="CACHE_DRIVER" value="redis"/>
|
<directory suffix=".php">./src</directory>
|
||||||
<env name="MAIL_DRIVER" value="array"/>
|
</include>
|
||||||
<env name="QUEUE_CONNECTION" value="sync"/>
|
<exclude>
|
||||||
<env name="SESSION_DRIVER" value="array"/>
|
<file>./src/routes.php</file>
|
||||||
<env name="DB_CONNECTION" value="central"/>
|
</exclude>
|
||||||
<env name="AWS_DEFAULT_REGION" value="us-west-2"/>
|
</source>
|
||||||
</php>
|
|
||||||
<logging>
|
|
||||||
<log type="coverage-clover" target="coverage/phpunit/clover.xml" showUncoveredFiles="true"/>
|
|
||||||
<log type="coverage-html" target="coverage/phpunit/html" lowUpperBound="35" highLowerBound="70"/>
|
|
||||||
</logging>
|
|
||||||
</phpunit>
|
</phpunit>
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
trait TenantAwareCommand
|
trait TenantAwareCommand
|
||||||
{
|
{
|
||||||
/** @return int */
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
{
|
||||||
$tenants = $this->getTenants();
|
$tenants = $this->getTenants();
|
||||||
$exitCode = 0;
|
$exitCode = 0;
|
||||||
|
|
|
||||||
2
t
2
t
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
docker-compose exec -T test vendor/bin/pest --no-coverage --filter "$@"
|
docker-compose exec -e COLUMNS=$(tput cols) -T test vendor/bin/pest --color=always --no-coverage --filter "$@"
|
||||||
|
|
|
||||||
3
test
3
test
|
|
@ -1,3 +1,4 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
docker-compose exec -T test vendor/bin/pest "$@"
|
# --columns doesn't seem to work at the moment, so we're setting it using an environment variable
|
||||||
|
docker-compose exec -e COLUMNS=$(tput cols) -T test vendor/bin/pest "$@"
|
||||||
|
|
|
||||||
|
|
@ -93,24 +93,6 @@ test('migrate command works with tenants option', function () {
|
||||||
expect(Schema::hasTable('users'))->toBeTrue();
|
expect(Schema::hasTable('users'))->toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('migrate command loads schema state', function () {
|
|
||||||
$tenant = Tenant::create();
|
|
||||||
|
|
||||||
expect(Schema::hasTable('schema_users'))->toBeFalse();
|
|
||||||
expect(Schema::hasTable('users'))->toBeFalse();
|
|
||||||
|
|
||||||
Artisan::call('tenants:migrate --schema-path="tests/Etc/tenant-schema.dump"');
|
|
||||||
|
|
||||||
expect(Schema::hasTable('schema_users'))->toBeFalse();
|
|
||||||
expect(Schema::hasTable('users'))->toBeFalse();
|
|
||||||
|
|
||||||
tenancy()->initialize($tenant);
|
|
||||||
|
|
||||||
// Check for both tables to see if missing migrations also get executed
|
|
||||||
expect(Schema::hasTable('schema_users'))->toBeTrue();
|
|
||||||
expect(Schema::hasTable('users'))->toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('migrate command only throws exceptions if skip-failing is not passed', function() {
|
test('migrate command only throws exceptions if skip-failing is not passed', function() {
|
||||||
Tenant::create();
|
Tenant::create();
|
||||||
|
|
||||||
|
|
@ -151,6 +133,37 @@ test('migrate command does not stop after the first failure if skip-failing is p
|
||||||
expect($migratedTenants)->toBe(2);
|
expect($migratedTenants)->toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('the tenants migrate command uses the schema dump correctly', function (bool $schemaPathAsConfig) {
|
||||||
|
$artisanCommand = 'tenants:migrate';
|
||||||
|
|
||||||
|
if ($schemaPathAsConfig) {
|
||||||
|
// The schema dump path can be configured in 'tenancy.migration_parameters.--schema-path'
|
||||||
|
// The tenants:migrate command will use the schema dump located at that path by default
|
||||||
|
config(['tenancy.migration_parameters.--schema-path' => 'tests/Etc/tenant-schema.dump']);
|
||||||
|
} else {
|
||||||
|
// The schema dump path can be passed as an option to the tenants:migrate command
|
||||||
|
$artisanCommand .= ' --schema-path="tests/Etc/tenant-schema.dump"';
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant = Tenant::create();
|
||||||
|
|
||||||
|
Artisan::call($artisanCommand);
|
||||||
|
|
||||||
|
// 'example' is a table included in the tests/Etc/tenant-schema dump
|
||||||
|
// 'users' is a table created by the migrations
|
||||||
|
// The tables weren't created in the central database
|
||||||
|
expect(Schema::hasTable('example'))->toBeFalse();
|
||||||
|
expect(Schema::hasTable('users'))->toBeFalse();
|
||||||
|
|
||||||
|
tenancy()->initialize($tenant);
|
||||||
|
|
||||||
|
// Both the table from the schema dump and the table from actual migrations
|
||||||
|
// Were created in the tenant database
|
||||||
|
expect(Schema::hasTable('example'))->toBeTrue();
|
||||||
|
expect(Schema::hasTable('users'))->toBeTrue();
|
||||||
|
})->with([true, false])
|
||||||
|
->skip(fn () => str(app()->version())->startsWith('10.'), 'todo@l10 drop laravel 10 support before release');
|
||||||
|
|
||||||
test('dump command works', function () {
|
test('dump command works', function () {
|
||||||
$tenant = Tenant::create();
|
$tenant = Tenant::create();
|
||||||
$schemaPath = 'tests/Etc/tenant-schema-test.dump';
|
$schemaPath = 'tests/Etc/tenant-schema-test.dump';
|
||||||
|
|
@ -190,26 +203,6 @@ test('dump command generates dump at the path specified in the tenancy migration
|
||||||
expect($schemaPath)->toBeFile();
|
expect($schemaPath)->toBeFile();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('migrate command correctly uses the schema dump located at the configured schema path by default', function () {
|
|
||||||
config(['tenancy.migration_parameters.--schema-path' => 'tests/Etc/tenant-schema.dump']);
|
|
||||||
$tenant = Tenant::create();
|
|
||||||
|
|
||||||
expect(Schema::hasTable('schema_users'))->toBeFalse();
|
|
||||||
expect(Schema::hasTable('users'))->toBeFalse();
|
|
||||||
|
|
||||||
Artisan::call('tenants:migrate');
|
|
||||||
|
|
||||||
expect(Schema::hasTable('schema_users'))->toBeFalse();
|
|
||||||
expect(Schema::hasTable('users'))->toBeFalse();
|
|
||||||
|
|
||||||
tenancy()->initialize($tenant);
|
|
||||||
|
|
||||||
// schema_users is a table included in the tests/Etc/tenant-schema dump
|
|
||||||
// Check for both tables to see if missing migrations also get executed
|
|
||||||
expect(Schema::hasTable('schema_users'))->toBeTrue();
|
|
||||||
expect(Schema::hasTable('users'))->toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('rollback command works', function () {
|
test('rollback command works', function () {
|
||||||
$tenant = Tenant::create();
|
$tenant = Tenant::create();
|
||||||
Artisan::call('tenants:migrate');
|
Artisan::call('tenants:migrate');
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,17 @@
|
||||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
|
||||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
|
||||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
|
||||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
|
||||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
|
||||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
|
||||||
DROP TABLE IF EXISTS `failed_jobs`;
|
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
|
||||||
/*!40101 SET character_set_client = utf8 */;
|
|
||||||
CREATE TABLE `failed_jobs` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`connection` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`queue` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
|
||||||
DROP TABLE IF EXISTS `migrations`;
|
DROP TABLE IF EXISTS `migrations`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
|
||||||
/*!40101 SET character_set_client = utf8 */;
|
|
||||||
CREATE TABLE `migrations` (
|
CREATE TABLE `migrations` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`batch` int(11) NOT NULL,
|
`batch` int(11) NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
);
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
|
||||||
DROP TABLE IF EXISTS `password_resets`;
|
DROP TABLE IF EXISTS `example`;
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
|
||||||
/*!40101 SET character_set_client = utf8 */;
|
CREATE TABLE `example` (
|
||||||
CREATE TABLE `password_resets` (
|
|
||||||
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
|
||||||
KEY `password_resets_email_index` (`email`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
|
||||||
DROP TABLE IF EXISTS `users`;
|
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
|
||||||
/*!40101 SET character_set_client = utf8 */;
|
|
||||||
CREATE TABLE `schema_users` (
|
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`email_verified_at` timestamp NULL DEFAULT NULL,
|
|
||||||
`password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
|
||||||
`remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
|
||||||
`created_at` timestamp NULL DEFAULT NULL,
|
`created_at` timestamp NULL DEFAULT NULL,
|
||||||
`updated_at` timestamp NULL DEFAULT NULL,
|
`updated_at` timestamp NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`)
|
||||||
UNIQUE KEY `users_email_unique` (`email`)
|
);
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
|
||||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
|
||||||
|
|
||||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
|
||||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
|
||||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
|
||||||
|
|
||||||
INSERT INTO `migrations` VALUES (2,'2014_10_12_100000_testbench_create_password_resets_table',1);
|
|
||||||
INSERT INTO `migrations` VALUES (3,'2019_08_19_000000_testbench_create_failed_jobs_table',1);
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ test('correct cache prefix is used in all contexts', function () {
|
||||||
$bootstrapper = app(PrefixCacheTenancyBootstrapper::class);
|
$bootstrapper = app(PrefixCacheTenancyBootstrapper::class);
|
||||||
|
|
||||||
$expectCachePrefixToBe = function (string $prefix) {
|
$expectCachePrefixToBe = function (string $prefix) {
|
||||||
expect($prefix . ':') // RedisStore suffixes prefix with ':'
|
expect($prefix)
|
||||||
->toBe(app('cache')->getPrefix())
|
->toBe(app('cache')->getPrefix())
|
||||||
->toBe(app('cache.store')->getPrefix())
|
->toBe(app('cache.store')->getPrefix())
|
||||||
->toBe(cache()->getPrefix())
|
->toBe(cache()->getPrefix())
|
||||||
|
|
@ -72,9 +72,9 @@ test('correct cache prefix is used in all contexts', function () {
|
||||||
config(['cache.prefix' => null]); // stop prefixing cache keys in central so we can provide prefix manually
|
config(['cache.prefix' => null]); // stop prefixing cache keys in central so we can provide prefix manually
|
||||||
app('cache')->forgetDriver(config('cache.default'));
|
app('cache')->forgetDriver(config('cache.default'));
|
||||||
|
|
||||||
expect(cache($tenantOnePrefix . ':key'))->toBe('tenantone-value');
|
expect(cache($tenantOnePrefix . 'key'))->toBe('tenantone-value');
|
||||||
expect(cache($tenantTwoPrefix . ':key'))->toBe('tenanttwo-value');
|
expect(cache($tenantTwoPrefix . 'key'))->toBe('tenanttwo-value');
|
||||||
});
|
})->skip(fn () => str(app()->version())->startsWith('10.'), 'todo@l10 drop laravel 10 support before release');
|
||||||
|
|
||||||
test('cache is persisted when reidentification is used', function () {
|
test('cache is persisted when reidentification is used', function () {
|
||||||
$tenant1 = Tenant::create();
|
$tenant1 = Tenant::create();
|
||||||
|
|
@ -143,12 +143,12 @@ test('cache base prefix is customizable', function () {
|
||||||
|
|
||||||
tenancy()->initialize($tenant1);
|
tenancy()->initialize($tenant1);
|
||||||
|
|
||||||
expect($originalPrefix . $prefixBase . $tenant1->getTenantKey() . ':')
|
expect($originalPrefix . $prefixBase . $tenant1->getTenantKey())
|
||||||
->toBe(cache()->getPrefix())
|
->toBe(cache()->getPrefix())
|
||||||
->toBe(cache()->store('redis2')->getPrefix()) // Non-default store gets prefixed correctly too
|
->toBe(cache()->store('redis2')->getPrefix()) // Non-default store gets prefixed correctly too
|
||||||
->toBe(app('cache')->getPrefix())
|
->toBe(app('cache')->getPrefix())
|
||||||
->toBe(app('cache.store')->getPrefix());
|
->toBe(app('cache.store')->getPrefix());
|
||||||
});
|
})->skip(fn () => str(app()->version())->startsWith('10.'), 'todo@l10 drop laravel 10 support before release');
|
||||||
|
|
||||||
test('cache is prefixed correctly when using a repository injected in a singleton', function () {
|
test('cache is prefixed correctly when using a repository injected in a singleton', function () {
|
||||||
$this->app->singleton(CacheService::class);
|
$this->app->singleton(CacheService::class);
|
||||||
|
|
@ -275,12 +275,12 @@ test('non default stores get prefixed too when specified in tenantCacheStores',
|
||||||
tenancy()->initialize($tenant);
|
tenancy()->initialize($tenant);
|
||||||
|
|
||||||
// We didn't add a prefix generator for our 'redis2' driver, so we expect the prefix to be generated using the 'default' generator
|
// We didn't add a prefix generator for our 'redis2' driver, so we expect the prefix to be generated using the 'default' generator
|
||||||
expect($bootstrapper->generatePrefix($tenant) . ':')
|
expect($bootstrapper->generatePrefix($tenant))
|
||||||
->toBe(cache()->getPrefix())
|
->toBe(cache()->getPrefix())
|
||||||
->toBe(cache()->store('redis2')->getPrefix()); // Non-default store
|
->toBe(cache()->store('redis2')->getPrefix()); // Non-default store
|
||||||
|
|
||||||
tenancy()->end();
|
tenancy()->end();
|
||||||
});
|
})->skip(fn () => str(app()->version())->startsWith('10.'), 'todo@l10 drop laravel 10 support before release');
|
||||||
|
|
||||||
test('cache store prefix generation can be customized', function() {
|
test('cache store prefix generation can be customized', function() {
|
||||||
// Use custom prefix generator
|
// Use custom prefix generator
|
||||||
|
|
@ -295,14 +295,14 @@ test('cache store prefix generation can be customized', function() {
|
||||||
tenancy()->initialize($tenant = Tenant::create());
|
tenancy()->initialize($tenant = Tenant::create());
|
||||||
|
|
||||||
// Expect the 'redis' store to use the prefix generated by the custom generator
|
// Expect the 'redis' store to use the prefix generated by the custom generator
|
||||||
expect($customPrefixGenerator($tenant) . ':')
|
expect($customPrefixGenerator($tenant))
|
||||||
->toBe(cache()->getPrefix())
|
->toBe(cache()->getPrefix())
|
||||||
->toBe(cache()->store('redis2')->getPrefix()) // Non-default cache stores specified in $tenantCacheStores are prefixed too
|
->toBe(cache()->store('redis2')->getPrefix()) // Non-default cache stores specified in $tenantCacheStores are prefixed too
|
||||||
->toBe(app('cache')->getPrefix())
|
->toBe(app('cache')->getPrefix())
|
||||||
->toBe(app('cache.store')->getPrefix());
|
->toBe(app('cache.store')->getPrefix());
|
||||||
|
|
||||||
tenancy()->end();
|
tenancy()->end();
|
||||||
});
|
})->skip(fn () => str(app()->version())->startsWith('10.'), 'todo@l10 drop laravel 10 support before release');
|
||||||
|
|
||||||
test('stores get prefixed using the default way if no prefix generator is specified', function() {
|
test('stores get prefixed using the default way if no prefix generator is specified', function() {
|
||||||
$originalPrefix = config('cache.prefix');
|
$originalPrefix = config('cache.prefix');
|
||||||
|
|
@ -315,10 +315,10 @@ test('stores get prefixed using the default way if no prefix generator is specif
|
||||||
tenancy()->initialize($tenant);
|
tenancy()->initialize($tenant);
|
||||||
|
|
||||||
// All stores use the default way of generating the prefix when the prefix generator isn't specified
|
// All stores use the default way of generating the prefix when the prefix generator isn't specified
|
||||||
expect($defaultPrefix . ':')
|
expect($defaultPrefix)
|
||||||
->toBe(app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant) . ':')
|
->toBe(app(PrefixCacheTenancyBootstrapper::class)->generatePrefix($tenant))
|
||||||
->toBe(cache()->getPrefix()) // Get prefix of the default store ('redis')
|
->toBe(cache()->getPrefix()) // Get prefix of the default store ('redis')
|
||||||
->toBe(cache()->store('redis2')->getPrefix());
|
->toBe(cache()->store('redis2')->getPrefix());
|
||||||
|
|
||||||
tenancy()->end();
|
tenancy()->end();
|
||||||
});
|
})->skip(fn () => str(app()->version())->startsWith('10.'), 'todo@l10 drop laravel 10 support before release');
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
'--realpath' => true,
|
'--realpath' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Laravel 6.x support
|
// Laravel 6.x support todo clean up
|
||||||
$testResponse = class_exists('Illuminate\Testing\TestResponse') ? 'Illuminate\Testing\TestResponse' : 'Illuminate\Foundation\Testing\TestResponse';
|
$testResponse = class_exists('Illuminate\Testing\TestResponse') ? 'Illuminate\Testing\TestResponse' : 'Illuminate\Foundation\Testing\TestResponse';
|
||||||
$testResponse::macro('assertContent', function ($content) {
|
$testResponse::macro('assertContent', function ($content) {
|
||||||
$assertClass = class_exists('Illuminate\Testing\Assert') ? 'Illuminate\Testing\Assert' : 'Illuminate\Foundation\Testing\Assert';
|
$assertClass = class_exists('Illuminate\Testing\Assert') ? 'Illuminate\Testing\Assert' : 'Illuminate\Foundation\Testing\Assert';
|
||||||
|
|
@ -68,9 +68,11 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
|
|
||||||
$app['config']->set([
|
$app['config']->set([
|
||||||
'database.default' => 'central',
|
'database.default' => 'central',
|
||||||
|
'cache.default' => 'redis',
|
||||||
'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.options.prefix' => 'foo',
|
||||||
|
'database.redis.client' => 'predis',
|
||||||
'database.connections.central' => [
|
'database.connections.central' => [
|
||||||
'driver' => 'mysql',
|
'driver' => 'mysql',
|
||||||
'url' => env('DATABASE_URL'),
|
'url' => env('DATABASE_URL'),
|
||||||
|
|
@ -91,11 +93,14 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||||
]) : [],
|
]) : [],
|
||||||
],
|
],
|
||||||
'database.connections.sqlite.database' => ':memory:',
|
'database.connections.sqlite.database' => ':memory:',
|
||||||
|
'database.connections.mysql.charset' => 'utf8mb4',
|
||||||
|
'database.connections.mysql.collation' => 'utf8mb4_unicode_ci',
|
||||||
'database.connections.mysql.host' => env('TENANCY_TEST_MYSQL_HOST', '127.0.0.1'),
|
'database.connections.mysql.host' => env('TENANCY_TEST_MYSQL_HOST', '127.0.0.1'),
|
||||||
'database.connections.sqlsrv.username' => env('TENANCY_TEST_SQLSRV_USERNAME', 'sa'),
|
'database.connections.sqlsrv.username' => env('TENANCY_TEST_SQLSRV_USERNAME', 'sa'),
|
||||||
'database.connections.sqlsrv.password' => env('TENANCY_TEST_SQLSRV_PASSWORD', 'P@ssword'),
|
'database.connections.sqlsrv.password' => env('TENANCY_TEST_SQLSRV_PASSWORD', 'P@ssword'),
|
||||||
'database.connections.sqlsrv.host' => env('TENANCY_TEST_SQLSRV_HOST', '127.0.0.1'),
|
'database.connections.sqlsrv.host' => env('TENANCY_TEST_SQLSRV_HOST', '127.0.0.1'),
|
||||||
'database.connections.sqlsrv.database' => null,
|
'database.connections.sqlsrv.database' => null,
|
||||||
|
'database.connections.sqlsrv.trust_server_certificate' => true,
|
||||||
'database.connections.pgsql.host' => env('TENANCY_TEST_PGSQL_HOST', '127.0.0.1'),
|
'database.connections.pgsql.host' => env('TENANCY_TEST_PGSQL_HOST', '127.0.0.1'),
|
||||||
'tenancy.filesystem.disks' => [
|
'tenancy.filesystem.disks' => [
|
||||||
'local',
|
'local',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue