mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-24 09:50:17 -06:00
Refactored and fixed unit tests
This commit is contained in:
parent
5213faa0a1
commit
3b56fc3760
@ -16,7 +16,7 @@ class DeleteShortUrlException extends DomainException implements ProblemDetailsE
|
|||||||
use CommonProblemDetailsExceptionTrait;
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
private const TITLE = 'Cannot delete short URL';
|
private const TITLE = 'Cannot delete short URL';
|
||||||
public const TYPE = 'INVALID_SHORTCODE_DELETION'; // FIXME Should be INVALID_SHORT_URL_DELETION
|
private const TYPE = 'INVALID_SHORTCODE_DELETION'; // FIXME Should be INVALID_SHORT_URL_DELETION
|
||||||
|
|
||||||
/** @var int */
|
/** @var int */
|
||||||
private $visitsThreshold;
|
private $visitsThreshold;
|
||||||
|
@ -16,7 +16,7 @@ class InvalidUrlException extends DomainException implements ProblemDetailsExcep
|
|||||||
use CommonProblemDetailsExceptionTrait;
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
private const TITLE = 'Invalid URL';
|
private const TITLE = 'Invalid URL';
|
||||||
public const TYPE = 'INVALID_URL';
|
private const TYPE = 'INVALID_URL';
|
||||||
|
|
||||||
public static function fromUrl(string $url, ?Throwable $previous = null): self
|
public static function fromUrl(string $url, ?Throwable $previous = null): self
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ class NonUniqueSlugException extends InvalidArgumentException implements Problem
|
|||||||
use CommonProblemDetailsExceptionTrait;
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
private const TITLE = 'Invalid custom slug';
|
private const TITLE = 'Invalid custom slug';
|
||||||
public const TYPE = 'INVALID_SLUG';
|
private const TYPE = 'INVALID_SLUG';
|
||||||
|
|
||||||
public static function fromSlug(string $slug, ?string $domain): self
|
public static function fromSlug(string $slug, ?string $domain): self
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ class ShortUrlNotFoundException extends DomainException implements ProblemDetail
|
|||||||
use CommonProblemDetailsExceptionTrait;
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
private const TITLE = 'Short URL not found';
|
private const TITLE = 'Short URL not found';
|
||||||
public const TYPE = 'INVALID_SHORTCODE';
|
private const TYPE = 'INVALID_SHORTCODE';
|
||||||
|
|
||||||
public static function fromNotFoundShortCode(string $shortCode, ?string $domain = null): self
|
public static function fromNotFoundShortCode(string $shortCode, ?string $domain = null): self
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ class TagNotFoundException extends DomainException implements ProblemDetailsExce
|
|||||||
use CommonProblemDetailsExceptionTrait;
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
private const TITLE = 'Tag not found';
|
private const TITLE = 'Tag not found';
|
||||||
public const TYPE = 'TAG_NOT_FOUND';
|
private const TYPE = 'TAG_NOT_FOUND';
|
||||||
|
|
||||||
public static function fromTag(string $tag): self
|
public static function fromTag(string $tag): self
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ class ValidationException extends InvalidArgumentException implements ProblemDet
|
|||||||
use CommonProblemDetailsExceptionTrait;
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
private const TITLE = 'Invalid data';
|
private const TITLE = 'Invalid data';
|
||||||
public const TYPE = 'INVALID_ARGUMENT';
|
private const TYPE = 'INVALID_ARGUMENT';
|
||||||
|
|
||||||
/** @var array */
|
/** @var array */
|
||||||
private $invalidElements;
|
private $invalidElements;
|
||||||
|
@ -10,7 +10,6 @@ use Psr\Log\LoggerInterface;
|
|||||||
use Shlinkio\Shlink\Rest\Authentication\JWTServiceInterface;
|
use Shlinkio\Shlink\Rest\Authentication\JWTServiceInterface;
|
||||||
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
||||||
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
|
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
|
||||||
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
|
||||||
use Zend\Diactoros\Response\JsonResponse;
|
use Zend\Diactoros\Response\JsonResponse;
|
||||||
|
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
|
@ -9,7 +9,6 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
|||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
|
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
|
||||||
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
||||||
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
|
||||||
use Zend\Diactoros\Response\JsonResponse;
|
use Zend\Diactoros\Response\JsonResponse;
|
||||||
|
|
||||||
class EditShortUrlTagsAction extends AbstractRestAction
|
class EditShortUrlTagsAction extends AbstractRestAction
|
||||||
|
@ -16,7 +16,7 @@ class MissingAuthenticationException extends RuntimeException implements Problem
|
|||||||
use CommonProblemDetailsExceptionTrait;
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
private const TITLE = 'Invalid authorization';
|
private const TITLE = 'Invalid authorization';
|
||||||
public const TYPE = 'INVALID_AUTHORIZATION';
|
private const TYPE = 'INVALID_AUTHORIZATION';
|
||||||
|
|
||||||
public static function fromExpectedTypes(array $expectedTypes): self
|
public static function fromExpectedTypes(array $expectedTypes): self
|
||||||
{
|
{
|
||||||
|
@ -14,17 +14,10 @@ class VerifyAuthenticationException extends RuntimeException implements ProblemD
|
|||||||
{
|
{
|
||||||
use CommonProblemDetailsExceptionTrait;
|
use CommonProblemDetailsExceptionTrait;
|
||||||
|
|
||||||
/** @var string */
|
|
||||||
private $errorCode;
|
|
||||||
/** @var string */
|
|
||||||
private $publicMessage;
|
|
||||||
|
|
||||||
public static function forInvalidApiKey(): self
|
public static function forInvalidApiKey(): self
|
||||||
{
|
{
|
||||||
$e = new self('Provided API key does not exist or is invalid.');
|
$e = new self('Provided API key does not exist or is invalid.');
|
||||||
|
|
||||||
$e->publicMessage = $e->getMessage();
|
|
||||||
$e->errorCode = 'INVALID_API_KEY';
|
|
||||||
$e->detail = $e->getMessage();
|
$e->detail = $e->getMessage();
|
||||||
$e->title = 'Invalid API key';
|
$e->title = 'Invalid API key';
|
||||||
$e->type = 'INVALID_API_KEY';
|
$e->type = 'INVALID_API_KEY';
|
||||||
@ -41,8 +34,6 @@ class VerifyAuthenticationException extends RuntimeException implements ProblemD
|
|||||||
. 'token on every new request on the Authorization header'
|
. 'token on every new request on the Authorization header'
|
||||||
);
|
);
|
||||||
|
|
||||||
$e->publicMessage = $e->getMessage();
|
|
||||||
$e->errorCode = 'INVALID_AUTH_TOKEN';
|
|
||||||
$e->detail = $e->getMessage();
|
$e->detail = $e->getMessage();
|
||||||
$e->title = 'Invalid auth token';
|
$e->title = 'Invalid auth token';
|
||||||
$e->type = 'INVALID_AUTH_TOKEN';
|
$e->type = 'INVALID_AUTH_TOKEN';
|
||||||
@ -56,8 +47,6 @@ class VerifyAuthenticationException extends RuntimeException implements ProblemD
|
|||||||
{
|
{
|
||||||
$e = new self('You need to provide the Bearer type in the Authorization header.');
|
$e = new self('You need to provide the Bearer type in the Authorization header.');
|
||||||
|
|
||||||
$e->publicMessage = $e->getMessage();
|
|
||||||
$e->errorCode = 'INVALID_AUTHORIZATION';
|
|
||||||
$e->detail = $e->getMessage();
|
$e->detail = $e->getMessage();
|
||||||
$e->title = 'Invalid authorization';
|
$e->title = 'Invalid authorization';
|
||||||
$e->type = 'INVALID_AUTHORIZATION';
|
$e->type = 'INVALID_AUTHORIZATION';
|
||||||
@ -71,8 +60,6 @@ class VerifyAuthenticationException extends RuntimeException implements ProblemD
|
|||||||
{
|
{
|
||||||
$e = new self(sprintf('Provided authorization type %s is not supported. Use Bearer instead.', $providedType));
|
$e = new self(sprintf('Provided authorization type %s is not supported. Use Bearer instead.', $providedType));
|
||||||
|
|
||||||
$e->publicMessage = $e->getMessage();
|
|
||||||
$e->errorCode = 'INVALID_AUTHORIZATION';
|
|
||||||
$e->detail = $e->getMessage();
|
$e->detail = $e->getMessage();
|
||||||
$e->title = 'Invalid authorization';
|
$e->title = 'Invalid authorization';
|
||||||
$e->type = 'INVALID_AUTHORIZATION';
|
$e->type = 'INVALID_AUTHORIZATION';
|
||||||
@ -80,14 +67,4 @@ class VerifyAuthenticationException extends RuntimeException implements ProblemD
|
|||||||
|
|
||||||
return $e;
|
return $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getErrorCode(): string
|
|
||||||
{
|
|
||||||
return $this->errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPublicMessage(): string
|
|
||||||
{
|
|
||||||
return $this->publicMessage;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shlinkio\Shlink\Rest\Util;
|
|
||||||
|
|
||||||
use Shlinkio\Shlink\Rest\Exception as Rest;
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
class RestUtils
|
|
||||||
{
|
|
||||||
public const INVALID_AUTHORIZATION_ERROR = Rest\MissingAuthenticationException::TYPE;
|
|
||||||
}
|
|
@ -37,7 +37,7 @@ class RequestToAuthPluginTest extends TestCase
|
|||||||
|
|
||||||
$this->expectException(MissingAuthenticationException::class);
|
$this->expectException(MissingAuthenticationException::class);
|
||||||
$this->expectExceptionMessage(sprintf(
|
$this->expectExceptionMessage(sprintf(
|
||||||
'None of the valid authentication mechanisms where provided. Expected one of ["%s"]',
|
'Expected one of the following authentication headers, but none were provided, ["%s"]',
|
||||||
implode('", "', RequestToHttpAuthPlugin::SUPPORTED_AUTH_HEADERS)
|
implode('", "', RequestToHttpAuthPlugin::SUPPORTED_AUTH_HEADERS)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -4,62 +4,16 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace ShlinkioTest\Shlink\Rest\Exception;
|
namespace ShlinkioTest\Shlink\Rest\Exception;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Shlinkio\Shlink\Common\Util\StringUtilsTrait;
|
|
||||||
use Shlinkio\Shlink\Rest\Exception\VerifyAuthenticationException;
|
use Shlinkio\Shlink\Rest\Exception\VerifyAuthenticationException;
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
use function array_map;
|
|
||||||
use function random_int;
|
|
||||||
use function range;
|
|
||||||
|
|
||||||
class VerifyAuthenticationExceptionTest extends TestCase
|
class VerifyAuthenticationExceptionTest extends TestCase
|
||||||
{
|
{
|
||||||
use StringUtilsTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
* @dataProvider provideConstructorData
|
|
||||||
*/
|
|
||||||
public function constructCreatesExpectedException(
|
|
||||||
string $errorCode,
|
|
||||||
string $publicMessage,
|
|
||||||
string $message,
|
|
||||||
int $code,
|
|
||||||
?Throwable $prev
|
|
||||||
): void {
|
|
||||||
$e = new VerifyAuthenticationException($errorCode, $publicMessage, $message, $code, $prev);
|
|
||||||
|
|
||||||
$this->assertEquals($code, $e->getCode());
|
|
||||||
$this->assertEquals($message, $e->getMessage());
|
|
||||||
$this->assertEquals($errorCode, $e->getErrorCode());
|
|
||||||
$this->assertEquals($publicMessage, $e->getPublicMessage());
|
|
||||||
$this->assertEquals($prev, $e->getPrevious());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideConstructorData(): iterable
|
|
||||||
{
|
|
||||||
return array_map(function (int $i) {
|
|
||||||
return [
|
|
||||||
$this->generateRandomString(),
|
|
||||||
$this->generateRandomString(30),
|
|
||||||
$this->generateRandomString(50),
|
|
||||||
$i,
|
|
||||||
random_int(0, 1) === 1 ? new Exception('Prev') : null,
|
|
||||||
];
|
|
||||||
}, range(10, 20));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function defaultConstructorValuesAreKept(): void
|
public function createsExpectedExceptionForInvalidApiKey(): void
|
||||||
{
|
{
|
||||||
$e = new VerifyAuthenticationException('foo', 'bar');
|
$e = VerifyAuthenticationException::forInvalidApiKey();
|
||||||
|
|
||||||
$this->assertEquals(0, $e->getCode());
|
$this->assertEquals('Provided API key does not exist or is invalid.', $e->getMessage());
|
||||||
$this->assertEquals('', $e->getMessage());
|
|
||||||
$this->assertEquals('foo', $e->getErrorCode());
|
|
||||||
$this->assertEquals('bar', $e->getPublicMessage());
|
|
||||||
$this->assertNull($e->getPrevious());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace ShlinkioTest\Shlink\Rest\Middleware;
|
namespace ShlinkioTest\Shlink\Rest\Middleware;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Fig\Http\Message\RequestMethodInterface;
|
use Fig\Http\Message\RequestMethodInterface;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Prophecy\Argument;
|
use Prophecy\Argument;
|
||||||
use Prophecy\Prophecy\ObjectProphecy;
|
use Prophecy\Prophecy\ObjectProphecy;
|
||||||
use Psr\Container\ContainerExceptionInterface;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Psr\Http\Server\MiddlewareInterface;
|
use Psr\Http\Server\MiddlewareInterface;
|
||||||
@ -17,20 +15,13 @@ use Psr\Http\Server\RequestHandlerInterface;
|
|||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Shlinkio\Shlink\Rest\Action\AuthenticateAction;
|
use Shlinkio\Shlink\Rest\Action\AuthenticateAction;
|
||||||
use Shlinkio\Shlink\Rest\Authentication\Plugin\AuthenticationPluginInterface;
|
use Shlinkio\Shlink\Rest\Authentication\Plugin\AuthenticationPluginInterface;
|
||||||
use Shlinkio\Shlink\Rest\Authentication\RequestToHttpAuthPlugin;
|
|
||||||
use Shlinkio\Shlink\Rest\Authentication\RequestToHttpAuthPluginInterface;
|
use Shlinkio\Shlink\Rest\Authentication\RequestToHttpAuthPluginInterface;
|
||||||
use Shlinkio\Shlink\Rest\Exception\MissingAuthenticationException;
|
|
||||||
use Shlinkio\Shlink\Rest\Exception\VerifyAuthenticationException;
|
|
||||||
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
|
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
|
||||||
use Shlinkio\Shlink\Rest\Util\RestUtils;
|
|
||||||
use Throwable;
|
|
||||||
use Zend\Diactoros\Response;
|
use Zend\Diactoros\Response;
|
||||||
use Zend\Diactoros\ServerRequest;
|
use Zend\Diactoros\ServerRequest;
|
||||||
use Zend\Expressive\Router\Route;
|
use Zend\Expressive\Router\Route;
|
||||||
use Zend\Expressive\Router\RouteResult;
|
use Zend\Expressive\Router\RouteResult;
|
||||||
|
|
||||||
use function implode;
|
|
||||||
use function sprintf;
|
|
||||||
use function Zend\Stratigility\middleware;
|
use function Zend\Stratigility\middleware;
|
||||||
|
|
||||||
class AuthenticationMiddlewareTest extends TestCase
|
class AuthenticationMiddlewareTest extends TestCase
|
||||||
@ -93,72 +84,6 @@ class AuthenticationMiddlewareTest extends TestCase
|
|||||||
)->withMethod(RequestMethodInterface::METHOD_OPTIONS)];
|
)->withMethod(RequestMethodInterface::METHOD_OPTIONS)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @test
|
|
||||||
* @dataProvider provideExceptions
|
|
||||||
*/
|
|
||||||
public function errorIsReturnedWhenNoValidAuthIsProvided(Throwable $e): void
|
|
||||||
{
|
|
||||||
$request = (new ServerRequest())->withAttribute(
|
|
||||||
RouteResult::class,
|
|
||||||
RouteResult::fromRoute(new Route('bar', $this->getDummyMiddleware()), [])
|
|
||||||
);
|
|
||||||
$fromRequest = $this->requestToPlugin->fromRequest(Argument::any())->willThrow($e);
|
|
||||||
$logWarning = $this->logger->warning('Invalid or no authentication provided. {e}', ['e' => $e])->will(
|
|
||||||
function () {
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
/** @var Response\JsonResponse $response */
|
|
||||||
$response = $this->middleware->process($request, $this->prophesize(RequestHandlerInterface::class)->reveal());
|
|
||||||
$payload = $response->getPayload();
|
|
||||||
|
|
||||||
$this->assertEquals(RestUtils::INVALID_AUTHORIZATION_ERROR, $payload['error']);
|
|
||||||
$this->assertEquals(sprintf(
|
|
||||||
'Expected one of the following authentication headers, but none were provided, ["%s"]',
|
|
||||||
implode('", "', RequestToHttpAuthPlugin::SUPPORTED_AUTH_HEADERS)
|
|
||||||
), $payload['message']);
|
|
||||||
$fromRequest->shouldHaveBeenCalledOnce();
|
|
||||||
$logWarning->shouldHaveBeenCalledOnce();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideExceptions(): iterable
|
|
||||||
{
|
|
||||||
$containerException = new class extends Exception implements ContainerExceptionInterface {
|
|
||||||
};
|
|
||||||
|
|
||||||
yield 'container exception' => [$containerException];
|
|
||||||
yield 'authentication exception' => [MissingAuthenticationException::fromExpectedTypes([])];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @test */
|
|
||||||
public function errorIsReturnedWhenVerificationFails(): void
|
|
||||||
{
|
|
||||||
$request = (new ServerRequest())->withAttribute(
|
|
||||||
RouteResult::class,
|
|
||||||
RouteResult::fromRoute(new Route('bar', $this->getDummyMiddleware()), [])
|
|
||||||
);
|
|
||||||
$e = VerifyAuthenticationException::forInvalidApiKey();
|
|
||||||
$plugin = $this->prophesize(AuthenticationPluginInterface::class);
|
|
||||||
|
|
||||||
$verify = $plugin->verify($request)->willThrow($e);
|
|
||||||
$fromRequest = $this->requestToPlugin->fromRequest(Argument::any())->willReturn($plugin->reveal());
|
|
||||||
$logWarning = $this->logger->warning('Authentication verification failed. {e}', ['e' => $e])->will(
|
|
||||||
function () {
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
/** @var Response\JsonResponse $response */
|
|
||||||
$response = $this->middleware->process($request, $this->prophesize(RequestHandlerInterface::class)->reveal());
|
|
||||||
$payload = $response->getPayload();
|
|
||||||
|
|
||||||
$this->assertEquals('the_error', $payload['error']);
|
|
||||||
$this->assertEquals('the_message', $payload['message']);
|
|
||||||
$verify->shouldHaveBeenCalledOnce();
|
|
||||||
$fromRequest->shouldHaveBeenCalledOnce();
|
|
||||||
$logWarning->shouldHaveBeenCalledOnce();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function updatedResponseIsReturnedWhenVerificationPasses(): void
|
public function updatedResponseIsReturnedWhenVerificationPasses(): void
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
parameters:
|
parameters:
|
||||||
ignoreErrors:
|
ignoreErrors:
|
||||||
- '#is not subtype of Throwable#'
|
|
||||||
- '#Undefined variable: \$metadata#'
|
- '#Undefined variable: \$metadata#'
|
||||||
- '#AbstractQuery::setParameters()#'
|
- '#AbstractQuery::setParameters()#'
|
||||||
- '#mustRun()#'
|
- '#mustRun()#'
|
||||||
|
Loading…
Reference in New Issue
Block a user