Skip to content

Commit

Permalink
test: Add unit tests for the resolution helper
Browse files Browse the repository at this point in the history
  • Loading branch information
ollieread committed Nov 19, 2024
1 parent 994871e commit 7d73645
Showing 1 changed file with 297 additions and 0 deletions.
297 changes: 297 additions & 0 deletions tests/Unit/Support/ResolutionHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,31 @@
namespace Sprout\Tests\Unit\Support;

use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Mockery\MockInterface;
use PHPUnit\Framework\Attributes\Test;
use Sprout\Exceptions\MisconfigurationException;
use Sprout\Exceptions\NoTenantFound;
use Sprout\Managers\IdentityResolverManager;
use Sprout\Managers\TenancyManager;
use Sprout\Support\ResolutionHelper;
use Sprout\Support\ResolutionHook;
use Sprout\Tests\Unit\UnitTestCase;
use Workbench\App\Models\TenantModel;
use function Sprout\resolver;
use function Sprout\sprout;

class ResolutionHelperTest extends UnitTestCase
{
protected function defineEnvironment($app): void
{
tap($app['config'], static function ($config) {
$config->set('multitenancy.defaults.resolver', 'path');
$config->set('multitenancy.providers.tenants.model', TenantModel::class);
$config->set('multitenancy.resolvers.subdomain.domain', 'localhost');
});
}

#[Test]
public function parsesMiddlewareOptions(): void
{
Expand Down Expand Up @@ -45,4 +62,284 @@ public function throwsExceptionWhenHandlingResolutionForUnsupportedHook(): void

ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Booting);
}

#[Test]
public function returnsFalseIfThereIsAlreadyATenant(): void
{
/** @var \Sprout\Contracts\Tenancy<TenantModel> $tenancy */
$tenancy = app(TenancyManager::class)->get();

$tenancy->setTenant(TenantModel::factory()->createOne());

/** @var \Sprout\Contracts\IdentityResolver $resolver */
$resolver = app(IdentityResolverManager::class)->get('path');

/** @var \Illuminate\Http\Request $fakeRequest */
$fakeRequest = $this->mock(Request::class);

$this->assertTrue($tenancy->check());
$this->assertTrue($resolver->canResolve($fakeRequest, $tenancy, ResolutionHook::Routing));
$this->assertFalse(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, $resolver->getName(), $tenancy->getName()));
}

#[Test]
public function returnsFalseIfTheResolverCannotResolve(): void
{
/** @var \Sprout\Contracts\Tenancy<TenantModel> $tenancy */
$tenancy = app(TenancyManager::class)->get();

/** @var \Sprout\Contracts\IdentityResolver $resolver */
$resolver = app(IdentityResolverManager::class)->get('path');

$tenancy->setTenant(TenantModel::factory()->createOne())
->resolvedVia($resolver)
->resolvedAt(ResolutionHook::Routing);

/** @var \Illuminate\Http\Request $fakeRequest */
$fakeRequest = $this->mock(Request::class);

$this->assertTrue($tenancy->check());
$this->assertFalse($resolver->canResolve($fakeRequest, $tenancy, ResolutionHook::Routing));
$this->assertFalse(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, $resolver->getName(), $tenancy->getName()));
}

#[Test]
public function resolvesTenantUsingRouteParameters(): void
{
$tenant = TenantModel::factory()->createOne();

/** @var \Sprout\Contracts\Tenancy<TenantModel> $tenancy */
$tenancy = app(TenancyManager::class)->get();

/** @var \Sprout\Contracts\IdentityResolver&\Sprout\Contracts\IdentityResolverUsesParameters $resolver */
$resolver = app(IdentityResolverManager::class)->get('path');

/** @var \Illuminate\Routing\Route $fakeRoute */
$fakeRoute = $this->mock(Route::class, function (MockInterface $mock) use ($tenant, $tenancy, $resolver) {
$parameterName = $resolver->getRouteParameterName($tenancy);

$mock->shouldReceive('hasParameter')
->with($parameterName)
->andReturn(true);

$mock->shouldReceive('parameter')
->with($parameterName)
->andReturn($tenant->getTenantIdentifier());

$mock->shouldReceive('forgetParameter')
->with($parameterName);
});

/** @var \Illuminate\Http\Request $fakeRequest */
$fakeRequest = $this->mock(Request::class, function (MockInterface $mock) use ($fakeRoute) {
$mock->shouldReceive('route')->andReturn($fakeRoute);
});

$this->assertTrue(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, $resolver->getName(), $tenancy->getName()));
$this->assertSame($tenancy, sprout()->getCurrentTenancy());
$this->assertTrue($tenancy->check());
$this->assertTrue($tenant->is($tenancy->tenant()));
$this->assertTrue($tenancy->wasResolved());
$this->assertSame($resolver, $tenancy->resolver());
$this->assertSame(ResolutionHook::Routing, $tenancy->hook());

$tenancy->setTenant(null);

$this->assertTrue(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing));
$this->assertSame($tenancy, sprout()->getCurrentTenancy());
$this->assertTrue($tenancy->check());
$this->assertTrue($tenant->is($tenancy->tenant()));
$this->assertTrue($tenancy->wasResolved());
$this->assertSame($resolver, $tenancy->resolver());
$this->assertSame(ResolutionHook::Routing, $tenancy->hook());
}

#[Test]
public function throwsAnExceptionWhenUnableToIdentifyATenantFromTheRoute(): void
{
/** @var \Sprout\Contracts\Tenancy<TenantModel> $tenancy */
$tenancy = app(TenancyManager::class)->get();

/** @var \Sprout\Contracts\IdentityResolver&\Sprout\Contracts\IdentityResolverUsesParameters $resolver */
$resolver = app(IdentityResolverManager::class)->get('path');

/** @var \Illuminate\Routing\Route $fakeRoute */
$fakeRoute = $this->mock(Route::class, function (MockInterface $mock) use ($tenancy, $resolver) {
$parameterName = $resolver->getRouteParameterName($tenancy);

$mock->shouldReceive('hasParameter')
->with($parameterName)
->andReturn(true);

$mock->shouldReceive('parameter')
->with($parameterName)
->andReturn('fake-identifier');

$mock->shouldReceive('forgetParameter')
->with($parameterName);
});

/** @var \Illuminate\Http\Request $fakeRequest */
$fakeRequest = $this->mock(Request::class, function (MockInterface $mock) use ($fakeRoute) {
$mock->shouldReceive('route')->andReturn($fakeRoute);
});

$this->expectException(NoTenantFound::class);
$this->expectExceptionMessage('No valid tenant [' . $tenancy->getName() . '] found [' . $resolver->getName() . ']');

ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, $resolver->getName(), $tenancy->getName());

$this->expectException(NoTenantFound::class);
$this->expectExceptionMessage('No valid tenant [' . $tenancy->getName() . '] found [subdomain]');

ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing);
}

#[Test]
public function returnsFalseWhenUnableToIdentifyATenantFromTheRouteAndToldNotToThrow(): void
{
/** @var \Sprout\Contracts\Tenancy<TenantModel> $tenancy */
$tenancy = app(TenancyManager::class)->get();

/** @var \Sprout\Contracts\IdentityResolver&\Sprout\Contracts\IdentityResolverUsesParameters $resolver */
$resolver = app(IdentityResolverManager::class)->get('path');

/** @var \Illuminate\Routing\Route $fakeRoute */
$fakeRoute = $this->mock(Route::class, function (MockInterface $mock) use ($tenancy, $resolver) {
$parameterName = $resolver->getRouteParameterName($tenancy);

$mock->shouldReceive('hasParameter')
->with($parameterName)
->andReturn(true);

$mock->shouldReceive('parameter')
->with($parameterName)
->andReturn('fake-identifier');

$mock->shouldReceive('forgetParameter')
->with($parameterName);
});

/** @var \Illuminate\Http\Request $fakeRequest */
$fakeRequest = $this->mock(Request::class, function (MockInterface $mock) use ($fakeRoute) {
$mock->shouldReceive('route')->andReturn($fakeRoute);
});

$this->assertFalse(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, $resolver->getName(), $tenancy->getName(), false));
$this->assertSame($tenancy, sprout()->getCurrentTenancy());
$this->assertFalse($tenancy->check());
$this->assertFalse($tenancy->wasResolved());
$this->assertNull($tenancy->resolver());
$this->assertNull($tenancy->hook());

$this->assertFalse(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, throw: false));
$this->assertSame($tenancy, sprout()->getCurrentTenancy());
$this->assertFalse($tenancy->check());
$this->assertFalse($tenancy->wasResolved());
$this->assertNull($tenancy->resolver());
$this->assertNull($tenancy->hook());
}

#[Test]
public function resolvesTenantWithoutRouteParameters(): void
{
$tenant = TenantModel::factory()->createOne();

/** @var \Sprout\Contracts\Tenancy<TenantModel> $tenancy */
$tenancy = app(TenancyManager::class)->get();

/** @var \Sprout\Contracts\IdentityResolver&\Sprout\Contracts\IdentityResolverUsesParameters $resolver */
$resolver = app(IdentityResolverManager::class)->get('path');

/** @var \Illuminate\Http\Request $fakeRequest */
$fakeRequest = $this->mock(Request::class, function (MockInterface $mock) use ($tenant) {
$mock->shouldReceive('route')->andReturnNull();

$mock->shouldReceive('segment')
->with(1)
->andReturn($tenant->getTenantIdentifier());
});

$this->assertTrue(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, $resolver->getName(), $tenancy->getName()));
$this->assertSame($tenancy, sprout()->getCurrentTenancy());
$this->assertTrue($tenancy->check());
$this->assertTrue($tenant->is($tenancy->tenant()));
$this->assertTrue($tenancy->wasResolved());
$this->assertSame($resolver, $tenancy->resolver());
$this->assertSame(ResolutionHook::Routing, $tenancy->hook());

$tenancy->setTenant(null);

$this->assertTrue(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing));
$this->assertSame($tenancy, sprout()->getCurrentTenancy());
$this->assertTrue($tenancy->check());
$this->assertTrue($tenant->is($tenancy->tenant()));
$this->assertTrue($tenancy->wasResolved());
$this->assertSame($resolver, $tenancy->resolver());
$this->assertSame(ResolutionHook::Routing, $tenancy->hook());
}

#[Test]
public function throwsAnExceptionWhenUnableToIdentifyATenantFromTheRequest(): void
{
/** @var \Sprout\Contracts\Tenancy<TenantModel> $tenancy */
$tenancy = app(TenancyManager::class)->get();

/** @var \Sprout\Contracts\IdentityResolver&\Sprout\Contracts\IdentityResolverUsesParameters $resolver */
$resolver = app(IdentityResolverManager::class)->get('path');

/** @var \Illuminate\Http\Request $fakeRequest */
$fakeRequest = $this->mock(Request::class, function (MockInterface $mock) {
$mock->shouldReceive('route')->andReturnNull();

$mock->shouldReceive('segment')
->with(1)
->andReturn('fake-identifier');
});

$this->expectException(NoTenantFound::class);
$this->expectExceptionMessage('No valid tenant [' . $tenancy->getName() . '] found [' . $resolver->getName() . ']');

ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, $resolver->getName(), $tenancy->getName());

$this->expectException(NoTenantFound::class);
$this->expectExceptionMessage('No valid tenant [' . $tenancy->getName() . '] found [subdomain]');

ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing);
}

#[Test]
public function returnsFalseWhenUnableToIdentifyATenantFromTheRequestAndToldNotToThrow(): void
{
/** @var \Sprout\Contracts\Tenancy<TenantModel> $tenancy */
$tenancy = app(TenancyManager::class)->get();

/** @var \Sprout\Contracts\IdentityResolver&\Sprout\Contracts\IdentityResolverUsesParameters $resolver */
$resolver = app(IdentityResolverManager::class)->get('path');

/** @var \Illuminate\Http\Request $fakeRequest */
$fakeRequest = $this->mock(Request::class, function (MockInterface $mock) {
$mock->shouldReceive('route')->andReturnNull();

$mock->shouldReceive('segment')
->with(1)
->andReturn('fake-identifier');
});

$this->assertFalse(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, $resolver->getName(), $tenancy->getName(), false));
$this->assertSame($tenancy, sprout()->getCurrentTenancy());
$this->assertFalse($tenancy->check());
$this->assertFalse($tenancy->wasResolved());
$this->assertNull($tenancy->resolver());
$this->assertNull($tenancy->hook());

$tenancy->setTenant(null);

$this->assertFalse(ResolutionHelper::handleResolution($fakeRequest, ResolutionHook::Routing, throw: false));
$this->assertSame($tenancy, sprout()->getCurrentTenancy());
$this->assertFalse($tenancy->check());
$this->assertFalse($tenancy->wasResolved());
$this->assertNull($tenancy->resolver());
$this->assertNull($tenancy->hook());
}
}

0 comments on commit 7d73645

Please sign in to comment.