mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-23 21:27:44 +03:00
Created ExtraPathRedirectMiddleware test
This commit is contained in:
parent
20575a2b0f
commit
eabaa94e06
2 changed files with 153 additions and 0 deletions
|
@ -11,6 +11,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
|
|||
|
||||
Now, when calling the `GET /{shorCode}/qr-code` URL, you can pass the `errorCorrection` query param with values `L` for Low, `M` for Medium, `Q` for Quartile or `H` for High.
|
||||
|
||||
* [#1080](https://github.com/shlinkio/shlink/issues/1080) Added support to redirect to URLs as soon as the path starts with a valid short code, appending the rest of the path to the redirected long URL.
|
||||
|
||||
With this, if you have the `https://example.com/abc123` short URL redirecting to `https://www.twitter.com`, a visit to `https://example.com/abc123/shlinkio` will take you to `https://www.twitter.com/shlinkio`.
|
||||
|
||||
This behavior needs to be actively opted in, via installer config options or env vars.
|
||||
|
||||
### Changed
|
||||
* *Nothing*
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ShlinkioTest\Shlink\Core\ShortUrl\Middleware;
|
||||
|
||||
use Laminas\Diactoros\Response\RedirectResponse;
|
||||
use Laminas\Diactoros\ServerRequestFactory;
|
||||
use Laminas\Diactoros\Uri;
|
||||
use Mezzio\Router\Route;
|
||||
use Mezzio\Router\RouteResult;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||
use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType;
|
||||
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlRedirectionBuilderInterface;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Middleware\ExtraPathRedirectMiddleware;
|
||||
use Shlinkio\Shlink\Core\Util\RedirectResponseHelperInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\RequestTrackerInterface;
|
||||
|
||||
class ExtraPathRedirectMiddlewareTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
private ExtraPathRedirectMiddleware $middleware;
|
||||
private ObjectProphecy $resolver;
|
||||
private ObjectProphecy $requestTracker;
|
||||
private ObjectProphecy $redirectionBuilder;
|
||||
private ObjectProphecy $redirectResponseHelper;
|
||||
private UrlShortenerOptions $options;
|
||||
private ObjectProphecy $handler;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->resolver = $this->prophesize(ShortUrlResolverInterface::class);
|
||||
$this->requestTracker = $this->prophesize(RequestTrackerInterface::class);
|
||||
$this->redirectionBuilder = $this->prophesize(ShortUrlRedirectionBuilderInterface::class);
|
||||
$this->redirectResponseHelper = $this->prophesize(RedirectResponseHelperInterface::class);
|
||||
$this->options = new UrlShortenerOptions(['append_extra_path' => true]);
|
||||
|
||||
$this->middleware = new ExtraPathRedirectMiddleware(
|
||||
$this->resolver->reveal(),
|
||||
$this->requestTracker->reveal(),
|
||||
$this->redirectionBuilder->reveal(),
|
||||
$this->redirectResponseHelper->reveal(),
|
||||
$this->options,
|
||||
);
|
||||
|
||||
$this->handler = $this->prophesize(RequestHandlerInterface::class);
|
||||
$this->handler->handle(Argument::cetera())->willReturn(new RedirectResponse(''));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider provideNonRedirectingRequests
|
||||
*/
|
||||
public function handlerIsCalledWhenConfigPreventsRedirectWithExtraPath(
|
||||
bool $appendExtraPath,
|
||||
ServerRequestInterface $request
|
||||
): void {
|
||||
$this->options->appendExtraPath = $appendExtraPath;
|
||||
|
||||
$this->middleware->process($request, $this->handler->reveal());
|
||||
|
||||
$this->resolver->resolveEnabledShortUrl(Argument::cetera())->shouldNotHaveBeenCalled();
|
||||
$this->requestTracker->trackIfApplicable(Argument::cetera())->shouldNotHaveBeenCalled();
|
||||
$this->redirectionBuilder->buildShortUrlRedirect(Argument::cetera())->shouldNotHaveBeenCalled();
|
||||
$this->redirectResponseHelper->buildRedirectResponse(Argument::cetera())->shouldNotHaveBeenCalled();
|
||||
}
|
||||
|
||||
public function provideNonRedirectingRequests(): iterable
|
||||
{
|
||||
$baseReq = ServerRequestFactory::fromGlobals();
|
||||
$buildReq = static fn (?NotFoundType $type): ServerRequestInterface =>
|
||||
$baseReq->withAttribute(NotFoundType::class, $type);
|
||||
|
||||
yield 'disabled option' => [false, $buildReq(NotFoundType::fromRequest($baseReq, '/foo/bar'))];
|
||||
yield 'base_url error' => [true, $buildReq(NotFoundType::fromRequest($baseReq, ''))];
|
||||
yield 'invalid_short_url error' => [
|
||||
true,
|
||||
$buildReq(NotFoundType::fromRequest($baseReq, ''))->withAttribute(
|
||||
RouteResult::class,
|
||||
RouteResult::fromRoute(new Route(
|
||||
'',
|
||||
$this->prophesize(MiddlewareInterface::class)->reveal(),
|
||||
['GET'],
|
||||
)),
|
||||
),
|
||||
];
|
||||
yield 'no error type' => [true, $buildReq(null)];
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function handlerIsCalledWhenNoShortUrlIsFound(): void
|
||||
{
|
||||
$type = $this->prophesize(NotFoundType::class);
|
||||
$type->isRegularNotFound()->willReturn(true);
|
||||
$request = ServerRequestFactory::fromGlobals()->withAttribute(NotFoundType::class, $type->reveal())
|
||||
->withUri(new Uri('/shortCode/bar/baz'));
|
||||
|
||||
$resolve = $this->resolver->resolveEnabledShortUrl(Argument::cetera())->willThrow(
|
||||
ShortUrlNotFoundException::class,
|
||||
);
|
||||
|
||||
$this->middleware->process($request, $this->handler->reveal());
|
||||
|
||||
$resolve->shouldHaveBeenCalledOnce();
|
||||
$this->requestTracker->trackIfApplicable(Argument::cetera())->shouldNotHaveBeenCalled();
|
||||
$this->redirectionBuilder->buildShortUrlRedirect(Argument::cetera())->shouldNotHaveBeenCalled();
|
||||
$this->redirectResponseHelper->buildRedirectResponse(Argument::cetera())->shouldNotHaveBeenCalled();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function visitIsTrackedAndRedirectIsReturnedWhenShortUrlIsFound(): void
|
||||
{
|
||||
$type = $this->prophesize(NotFoundType::class);
|
||||
$type->isRegularNotFound()->willReturn(true);
|
||||
$request = ServerRequestFactory::fromGlobals()->withAttribute(NotFoundType::class, $type->reveal())
|
||||
->withUri(new Uri('https://doma.in/shortCode/bar/baz'));
|
||||
$shortUrl = ShortUrl::withLongUrl('');
|
||||
$identifier = ShortUrlIdentifier::fromShortCodeAndDomain('shortCode', 'doma.in');
|
||||
|
||||
$resolve = $this->resolver->resolveEnabledShortUrl($identifier)->willReturn($shortUrl);
|
||||
$buildLongUrl = $this->redirectionBuilder->buildShortUrlRedirect($shortUrl, [], '/bar/baz')->willReturn(
|
||||
'the_built_long_url',
|
||||
);
|
||||
$buildResp = $this->redirectResponseHelper->buildRedirectResponse('the_built_long_url')->willReturn(
|
||||
new RedirectResponse(''),
|
||||
);
|
||||
|
||||
$this->middleware->process($request, $this->handler->reveal());
|
||||
|
||||
$resolve->shouldHaveBeenCalledOnce();
|
||||
$buildLongUrl->shouldHaveBeenCalledOnce();
|
||||
$buildResp->shouldHaveBeenCalledOnce();
|
||||
$this->requestTracker->trackIfApplicable($shortUrl, $request)->shouldHaveBeenCalledOnce();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue