From 009748a3edabc91ff7d5ab2230977dcfe2b7126a Mon Sep 17 00:00:00 2001 From: xKairu Date: Thu, 12 Mar 2020 21:15:01 +1300 Subject: [PATCH 1/2] Add testing documentation --- docs/hyn/5.4/testing.md | 231 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 docs/hyn/5.4/testing.md diff --git a/docs/hyn/5.4/testing.md b/docs/hyn/5.4/testing.md new file mode 100644 index 00000000..5b800e41 --- /dev/null +++ b/docs/hyn/5.4/testing.md @@ -0,0 +1,231 @@ +--- +title: Testing +icon: fal fa-vial +--- + +## Introduction + +To run tests on your multi-tenant codebase, you will require a new tenant to be created every test. The best way to do this is via an in-memory SQLite database. + +## Considerations + +There are pros and cons to testing with MySQL vs. SQLite. As SQLite is the faster option, it's the one we'll be using here, but for reference, pros and cons for both are here too: + +MySQL: +- Pros: + - Fully featured migrations with no compromises + - Accessible via a SQL editor for debugging +- Cons: + - Extremely slow tests due to the sheer amount of queries generated + - If using the `prefix` division driver, you may run into duplicate foreign key errors. + - If using the `database` division driver, you will have to manually clean up databases if a test fails with an error. + - CI servers will require MySQL installed + +In-memory SQLite: +- Pros: + - Extremely fast, sub-1000ms tests + - If a test fails with an error, there's no leftover databases to manually clean up + - CI does not require a MySQL server running +- Cons: + - Migrations will require some rewriting and careful consideration in the future + +## Migration Caveats + +Make yourself familiar with the already documented caveats in the [Laravel documentation](https://laravel.com/docs/migrations). + +You can drop multiple columns in a single migration file, but not a single migration closure. + +```php +// incorrect +Schema::table('users', function (Blueprint $table) { + $table->dropColumn('location'); + $table->dropColumn('biography'); +}); + +// correct +Schema::table('users', function (Blueprint $table) { + $table->dropColumn('location'); +}); +Schema::table('users', function (Blueprint $table) { + $table->dropColumn('biography'); +}); +``` + +You cannot drop a column at the beginning of a migration closure, or else the rest of the migration will silently fail. + +```php +// incorrect +Schema::table('users', function (Blueprint $table) { + $table->dropColumn('location'); // migrates successfully + $table->integer('age')->nullable(); // will not migrate +}); + +// correct +Schema::table('users', function (Blueprint $table) { + $table->integer('age')->nullable(); + $table->dropColumn('location'); +}); + +// also correct +Schema::table('users', function (Blueprint $table) { + $table->dropColumn('location'); +}); +Schema::table('users', function (Blueprint $table) { + $table->integer('age')->nullable(); +}); +``` + +## Boilerplate + +### SQLiteDriver.php + +```php +app->make('tenancy.db.drivers')->put('sqlite', SqliteDriver::class); + + // bypass tenant connection settings modifications + config(['tenancy.db.tenant-division-mode' => 'bypass']); + + // create a website + $this->website = new Website; + $this->app->make(WebsiteRepository::class)->create($this->website); + + // create a hostname + $hostname = new Hostname; + $hostname->fqdn = $this->hostname; + $hostname = $this->app->make(HostnameRepository::class)->create($hostname); + $this->app->make(HostnameRepository::class)->attach($hostname, $this->website); + + // set current hostname + $this->app->singleton(CurrentHostname::class, function () use ($hostname) { + return $hostname; + }); + + // register tenant routes, by default web/tenants.php + (new RouteProvider($this->app))->boot(); + } +} +``` + +### config/database.php + +```php +'system' => [ + 'driver' => env('TENANCY_DRIVER', 'mysql'), + 'host' => env('TENANCY_HOST', '127.0.0.1'), + 'port' => env('TENANCY_PORT', '3306'), + 'database' => env('TENANCY_DATABASE', 'tenancy'), + 'username' => env('TENANCY_USERNAME', 'tenancy'), + 'password' => env('TENANCY_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => '', + 'strict' => true, + 'engine' => null, +], +``` + +## phpunit.xml + +Or if you use a separate testing `.env` file, set these values in there. + +```xml + + + + +``` + +## Usage + +```php + 'test', + ]); + + $this->assertEquals('test', $user->name); + } +} +``` From 8f8bcf94d6c0725bc5538944999390843960e7f0 Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 12 Mar 2020 21:18:46 +1300 Subject: [PATCH 2/2] Fix typos --- docs/hyn/5.4/testing.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/hyn/5.4/testing.md b/docs/hyn/5.4/testing.md index 5b800e41..fc9f0d5f 100644 --- a/docs/hyn/5.4/testing.md +++ b/docs/hyn/5.4/testing.md @@ -17,8 +17,8 @@ MySQL: - Accessible via a SQL editor for debugging - Cons: - Extremely slow tests due to the sheer amount of queries generated - - If using the `prefix` division driver, you may run into duplicate foreign key errors. - - If using the `database` division driver, you will have to manually clean up databases if a test fails with an error. + - If using the `prefix` division driver, you may run into duplicate foreign key errors + - If using the `database` division driver, you will have to manually clean up databases if a test fails with an error - CI servers will require MySQL installed In-memory SQLite: @@ -77,7 +77,7 @@ Schema::table('users', function (Blueprint $table) { ## Boilerplate -### SQLiteDriver.php +### tests/Helpers/SqliteDriver.php ```php