Comments (30)
@sausin, I found a great solution.
Try to use the following TestCase.php
:
namespace Tests;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Event;
use Spatie\Multitenancy\Concerns\UsesMultitenancyConfig;
use Spatie\Multitenancy\Events\MadeTenantCurrentEvent;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication, DatabaseTransactions, UsesMultitenancyConfig;
protected function connectionsToTransact()
{
return [
$this->landlordDatabaseConnectionName(),
$this->tenantDatabaseConnectionName(),
];
}
protected function setUp(): void
{
parent::setUp();
Event::listen(MadeTenantCurrentEvent::class, function () {
$this->beginDatabaseTransaction();
});
}
}
I have already tried, and seems that works very well. If you confirm it, we will upgrade the documentation.
Thanks
from laravel-multitenancy.
@masterix21 Not sure I understand correctly, but manually specifying the transaction in each test could work but then I would need to update all of my tests (1000+). Also, the default connection was specified as the tenant
connection. Changing it to the landlord
connection makes no difference either.
Also the issue from laravel framework linked above indicates that specifying the connection to transact should work and is in fact 'working' but the transactions are being counted on the incorrect connection so the end result is not as expected.
If you meant something else, please let me know!
EDIT:- If you were looking for the output from the command, I get a list of the tables from the tenant
database correctly. I had to change the command for sqlite DB::connection('tenant_testing_connection')->select(DB::raw("SELECT name FROM sqlite_master WHERE type='table'"))
from laravel-multitenancy.
@masterix21 I've already tried this, as mentioned above, with no success
from laravel-multitenancy.
Ok, now is better to close the issue, because for me has been solved. If you need more help for it, please reply anyway to it.
Thank you.
from laravel-multitenancy.
Feel free to send PRs to the docs. Each page contains a edit button that allows you to create a PR quickly 👍
from laravel-multitenancy.
hi @sausin, can you post a test example, please?
from laravel-multitenancy.
Sure! Please see below an example test on the reset route:
<?php
namespace Tests\Feature\Controllers\Auth;
use App\User;
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Str;
use Tests\TestCase;
class ForgotPasswordControllerTest extends TestCase
{
use DatabaseTransactions;
/** @test */
public function it_resends_verification_email()
{
Event::fake();
Notification::fake();
$u = User::create([
'name' => Str::random(10),
'email' => $e = Str::random(10).'@example.com',
'phone_number' => 00001112345,
'password' => Hash::make('password'),
]);
$this->postJson('/password/email', ['email' => $e])
->assertOk();
Notification::assertSentTo($u, ResetPassword::class);
}
}
I have a unique constraint on the phone_number
field. The test runs fine the first time (as there is no entry for the above phone_number
. Running it again, it throws up errors that the unique constraint got violated (because the previous run did not end in rollback of the transaction).
The test was running fine before (hundreds of times).
A simple workaround in the above example would be to use a random number on the field, but that wouldn't solve the issue that the DatabaseTransactions
features aren't functioning.
Thanks!
from laravel-multitenancy.
Just to add some info to the discussion, I did some more digging and investigations are listed below:
-
the
beginDatabaseTransaction
method in theDatabaseTransactions
trait is not able to get results fromconnectionsToTransact
. In the setup listed above, the connections array is empty -
Adding this
protected $connectionsToTransact = ['tenant_testing_connection'];
to theTestCase.php
provides the trait method the necessary info, but it makes no difference. The transaction feature still doesn't work
EDIT:- Using the array should have worked. So why doesn't it 😬 ?
from laravel-multitenancy.
Okay, so diving into the codebase of laravel, I think I have located the issue. The transactions are actually being reported corresponding to the landlord
database and not the tenant
database.
Got this by looking at the workings inside the rollBack
method in ManagesTransactions
class. I am guessing that something is happening in this package which is messing up the database reporting.
from laravel-multitenancy.
@sausin DB facade use your default connection, but nothing prohibit to specify a connection:
DB::connection('tenant')->transaction(function () {
return DB::connection('tenant')->select(DB::raw('SHOW TABLES'));
});
Try and tell me if it works.
from laravel-multitenancy.
If you need to use a tenant connection as default, use "tenant" as the default connection. See the PR: #59.
We are talking with @freekmurze from many weeks, but there are a lot of things that don't convince him and others that are uncleared for me.
from laravel-multitenancy.
@masterix21 Using the tenant
as default connection doesn't change anything on this issue unfortunately. It would definitely be awesome to get some thoughts on this from @freekmurze
from laravel-multitenancy.
@sausin isn't simple to help somebody without the code (your test code above said nothing of your problem), anyway I hope that @freekmurze could help you.
Have you already tried to use RefreshDatabase
instead of DatabaseTransactions
? It seems that DatabaseTransactions
has been removed from Laravel documentation (but it's available in the API).
In the meanwhile, try to extend your TestCase (for the tenant) with:
protected function setUp(): void
{
parent::setUp();
DB::connection('tenant')->beginTransaction();
}
protected function tearDown(): void
{
DB::connection('tenant')->rollBack();
parent::tearDown();
}
from laravel-multitenancy.
@masterix21 Indeed, the recommended way is to use RefreshDatabase
in the docs. However, for my test setup DatabaseTransactions
is exactly what I need to use. Under the hood, RefreshDatabase
(as I understand it) makes a choice between using DatabaseTransactions
or DatabaseMigrations
.
Thanks for the tip above! I'm trying it with some mixed results right now. Will report back 👍
from laravel-multitenancy.
@masterix21 the above tip was definitely an improvement, thanks! Tests seem to be working when run in isolation but failing when run in a batch. Wow, this is just 😢
Edit: I am thinking this could be related to some weird behavior on the database connection
from laravel-multitenancy.
@sausin, great. Do you have a full example to understand if it depends on the spatie/laravel-multitenancy package? If you can, please create a repository on GitHub with a testable project to understand better: it should help us. Thanks.
from laravel-multitenancy.
@masterix21 I'll try to setup a repo with tests
from laravel-multitenancy.
@sausin, I have an update for the past problem. If you see the DatabaseTransactions
trait, it has:
protected function connectionsToTransact()
{
return property_exists($this, 'connectionsToTransact')
? $this->connectionsToTransact : [null];
}
It means that if you specify a property called connectionsToTransact in your test, the trait will begin a transaction for all connections of array:
protected $connectionsToTransact = [
'landlord',
'tenant',
];
Had you already tried it before using setUp()
and tearDown()
?
from laravel-multitenancy.
Sorry, you're right
from laravel-multitenancy.
The consequently observed behaviour is what's really strange. I don't understand how that's happening.
I've also hit some random bugs which make no sense to me (and as I mentioned above, most of the relevant tests just pass when run independently).
Trying to setup a repo so that the discussion can be easier 👍
from laravel-multitenancy.
Ok, I have simulated all your examples, and now I'm synced with you.
- the
beginDatabaseTransaction
method in theDatabaseTransactions
trait is not able to get results fromconnectionsToTransact
. In the setup listed above, the connections array is empty
Yes, you're right. There are no nicely solutions at the moment. The only way seems to be to create a copy of DatabaseTransactions
trait with a new name (for example TenantAwareDatabaseTransactions
) to call your $this->beginDatabaseTransaction()
as follow:
use TenantAwareDatabaseTransactions;
protected function setUp(): void
{
parent::setUp();
Tenant::first()->makeCurrent();
$this->beginDatabaseTransaction();
}
from laravel-multitenancy.
Closing this, as it seems to have been answered.
from laravel-multitenancy.
@freekmurze We've not been able to resolve the issue being noted in the comment above.
Also, even when the manually specifying the transactions in the TestCase
class (thanks @masterix21 for the tip), the tests haven't reached passing stage (unlike before when they were all passing even when run randomly across many runs).
from laravel-multitenancy.
@masterix21 This setup is great 😃 and simplifies things quite a bit. I just had to add Tenant::first()->makeCurrent();
in the setUp
method at the end for things to work. Another thing that has been required is an overridden middleware class:
<?php
namespace App\Http\Middleware;
use Closure;
use Spatie\Multitenancy\Http\Middleware\EnsureValidTenantSession as MiddlewareEnsureValidTenantSession;
class EnsureValidTenantSession extends MiddlewareEnsureValidTenantSession
{
public function handle($request, Closure $next)
{
if (app()->environment() === 'testing') {
return $next($request);
} else {
return parent::handle($request, $next);
}
}
}
I still have some weird errors. Setting up the test repo is long overdue (my bad 😞). I'll try to do it asap
from laravel-multitenancy.
Yes sure, thanks a lot for all the help @masterix21
from laravel-multitenancy.
@masterix21 So the last set of issues pending for me involve dispatch
. I have a model App\SomeModel
which has observer on creating
, created
and updating
events.
On the created
event, I am dispatching a job which takes the model as input. This setup works fine in reality (using the web interface of the app) but the tests fail with this error
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\SomeModel].
The created
method looks like this:
public function created(SomeModel $someModel): void
{
dispatch(new DoSomethingWithNewModel($someModel))->onQueue('do-something');
}
If I comment out the dispatch line, the tests work fine.
Appreciate the help 😃
from laravel-multitenancy.
I was also experiencing this problem.
A quick test of the solution provided by @masterix21 is looking good, nice one.
Definitely would be good to have a testing section in the docs.
from laravel-multitenancy.
@freekmurze PR #101 is in place
from laravel-multitenancy.
Thank you
from laravel-multitenancy.
Least I could've done 👍
from laravel-multitenancy.
Related Issues (20)
- Current tenant not determined when dispatching queued closures HOT 6
- When dispatching a Tenant Aware Job in sync mode from a test, any prior/current DB transaction is cleared HOT 2
- Model ignore tenant when add Observer HOT 2
- Tenant password reset token is being stored on landlord password_reset_tokens table HOT 1
- Prefixing cache doesn't work fine with file-store HOT 3
- Conflict with Rabbitmq package from vyuldashev HOT 1
- Scheduler : Large (longer) jobs, multiple tenants, stops.
- Tenant-Aware Job Scheduling with Horizon HOT 4
- MakeQueueTenantAwareAction seems to break active requests when Queue Connection is sync HOT 4
- base table or view not found with AWS SQS queue for job TenantAware HOT 12
- randomly receive Invalid catalog name: 1046 No database selected (Connection: mysql, SQL: insert into failed_jobs (uuid, connection, queue, payload, exception, failed_at) on queue sqs HOT 5
- Tenant Aware Queue Fails No Database Selected when running from supervisor in a multi tenant environment using AWS SQS FIFO HOT 2
- Update documentation at https://spatie.be to `v3` HOT 3
- in_array(): Argument #2 ($haystack) must be of type array, null given {"exception":"[object] (TypeError(code: 0): in_array(): Argument #2 ($haystack) must be of type array, null given at /spatie/laravel-multitenancy/src/Actions/MakeQueueTenantAwareAction.php:79) HOT 1
- Cache issue with spatie/laravel-permission in TenantAware Command HOT 5
- Issue with the has function on different connections HOT 1
- I want to Connect to mongo DB for some tables but it is giving "Database connection [mongodb] not configured.", exception: "InvalidArgumentException",…} error
- Custom cache driver missing when switching Tenant HOT 2
- Cannot schedule jobs in Laravel 11 HOT 3
- Can't make route not tenant aware
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from laravel-multitenancy.