Added more strict checks on API errors tests

This commit is contained in:
Alejandro Celaya 2019-11-27 20:48:35 +01:00
parent 5266743a0c
commit d83d2f82bd
8 changed files with 156 additions and 40 deletions

View File

@ -10,6 +10,7 @@ use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
use function Functional\map;
use function range;
use function sprintf;
class CreateShortUrlActionTest extends ApiTestCase
{
@ -40,10 +41,25 @@ class CreateShortUrlActionTest extends ApiTestCase
*/
public function failsToCreateShortUrlWithDuplicatedSlug(string $slug, ?string $domain): void
{
$suffix = $domain === null ? '' : sprintf(' for domain "%s"', $domain);
$detail = sprintf('Provided slug "%s" is already in use%s.', $slug, $suffix);
[$statusCode, $payload] = $this->createShortUrl(['customSlug' => $slug, 'domain' => $domain]);
$this->assertEquals(self::STATUS_BAD_REQUEST, $statusCode);
$this->assertEquals('INVALID_SLUG', $payload['error']);
$this->assertEquals(self::STATUS_BAD_REQUEST, $payload['status']);
$this->assertEquals($detail, $payload['detail']);
$this->assertEquals($detail, $payload['message']); // Deprecated
$this->assertEquals('INVALID_SLUG', $payload['type']);
$this->assertEquals('INVALID_SLUG', $payload['error']); // Deprecated
$this->assertEquals('Invalid custom slug', $payload['title']);
$this->assertEquals($slug, $payload['customSlug']);
if ($domain !== null) {
$this->assertEquals($domain, $payload['domain']);
} else {
$this->assertArrayNotHasKey('domain', $payload);
}
}
/** @test */
@ -203,10 +219,19 @@ class CreateShortUrlActionTest extends ApiTestCase
/** @test */
public function failsToCreateShortUrlWithInvalidOriginalUrl(): void
{
[$statusCode, $payload] = $this->createShortUrl(['longUrl' => 'https://this-has-to-be-invalid.com']);
$url = 'https://this-has-to-be-invalid.com';
$expectedDetail = sprintf('Provided URL %s is invalid. Try with a different one.', $url);
[$statusCode, $payload] = $this->createShortUrl(['longUrl' => $url]);
$this->assertEquals(self::STATUS_BAD_REQUEST, $statusCode);
$this->assertEquals('INVALID_URL', $payload['error']);
$this->assertEquals(self::STATUS_BAD_REQUEST, $payload['status']);
$this->assertEquals('INVALID_URL', $payload['type']);
$this->assertEquals('INVALID_URL', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Invalid URL', $payload['title']);
$this->assertEquals($url, $payload['url']);
}
/**

View File

@ -11,11 +11,19 @@ class DeleteShortUrlActionTest extends ApiTestCase
/** @test */
public function notFoundErrorIsReturnWhenDeletingInvalidUrl(): void
{
$expectedDetail = 'No URL found with short code "invalid"';
$resp = $this->callApiWithKey(self::METHOD_DELETE, '/short-urls/invalid');
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals('INVALID_SHORTCODE', $error);
$this->assertEquals(self::STATUS_NOT_FOUND, $payload['status']);
$this->assertEquals('INVALID_SHORTCODE', $payload['type']);
$this->assertEquals('INVALID_SHORTCODE', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Short URL not found', $payload['title']);
$this->assertEquals('invalid', $payload['shortCode']);
}
/** @test */
@ -25,11 +33,17 @@ class DeleteShortUrlActionTest extends ApiTestCase
for ($i = 0; $i < 20; $i++) {
$this->assertEquals(self::STATUS_FOUND, $this->callShortUrl('abc123')->getStatusCode());
}
$expectedDetail = 'Impossible to delete short URL with short code "abc123" since it has more than "15" visits.';
$resp = $this->callApiWithKey(self::METHOD_DELETE, '/short-urls/abc123');
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_UNPROCESSABLE_ENTITY, $resp->getStatusCode());
$this->assertEquals('INVALID_SHORTCODE_DELETION', $error);
$this->assertEquals(self::STATUS_UNPROCESSABLE_ENTITY, $payload['status']);
$this->assertEquals('INVALID_SHORTCODE_DELETION', $payload['type']);
$this->assertEquals('INVALID_SHORTCODE_DELETION', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Cannot delete short URL', $payload['title']);
}
}

View File

@ -12,22 +12,37 @@ class EditShortUrlActionTest extends ApiTestCase
/** @test */
public function tryingToEditInvalidUrlReturnsNotFoundError(): void
{
$expectedDetail = 'No URL found with short code "invalid"';
$resp = $this->callApiWithKey(self::METHOD_PATCH, '/short-urls/invalid', [RequestOptions::JSON => []]);
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals('INVALID_SHORTCODE', $error);
$this->assertEquals(self::STATUS_NOT_FOUND, $payload['status']);
$this->assertEquals('INVALID_SHORTCODE', $payload['type']);
$this->assertEquals('INVALID_SHORTCODE', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Short URL not found', $payload['title']);
$this->assertEquals('invalid', $payload['shortCode']);
}
/** @test */
public function providingInvalidDataReturnsBadRequest(): void
{
$expectedDetail = 'Provided data is not valid';
$resp = $this->callApiWithKey(self::METHOD_PATCH, '/short-urls/invalid', [RequestOptions::JSON => [
'maxVisits' => 'not_a_number',
]]);
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode());
$this->assertEquals('INVALID_ARGUMENT', $error);
$this->assertEquals(self::STATUS_BAD_REQUEST, $payload['status']);
$this->assertEquals('INVALID_ARGUMENT', $payload['type']);
$this->assertEquals('INVALID_ARGUMENT', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Invalid data', $payload['title']);
}
}

View File

@ -12,22 +12,37 @@ class EditShortUrlTagsActionTest extends ApiTestCase
/** @test */
public function notProvidingTagsReturnsBadRequest(): void
{
$expectedDetail = 'Provided data is not valid';
$resp = $this->callApiWithKey(self::METHOD_PUT, '/short-urls/abc123/tags', [RequestOptions::JSON => []]);
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode());
$this->assertEquals('INVALID_ARGUMENT', $error);
$this->assertEquals(self::STATUS_BAD_REQUEST, $payload['status']);
$this->assertEquals('INVALID_ARGUMENT', $payload['type']);
$this->assertEquals('INVALID_ARGUMENT', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Invalid data', $payload['title']);
}
/** @test */
public function providingInvalidShortCodeReturnsBadRequest(): void
{
$expectedDetail = 'No URL found with short code "invalid"';
$resp = $this->callApiWithKey(self::METHOD_PUT, '/short-urls/invalid/tags', [RequestOptions::JSON => [
'tags' => ['foo', 'bar'],
]]);
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals('INVALID_SHORTCODE', $error);
$this->assertEquals(self::STATUS_NOT_FOUND, $payload['status']);
$this->assertEquals('INVALID_SHORTCODE', $payload['type']);
$this->assertEquals('INVALID_SHORTCODE', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Short URL not found', $payload['title']);
$this->assertEquals('invalid', $payload['shortCode']);
}
}

View File

@ -11,10 +11,18 @@ class GetVisitsActionTest extends ApiTestCase
/** @test */
public function tryingToGetVisitsForInvalidUrlReturnsNotFoundError(): void
{
$expectedDetail = 'No URL found with short code "invalid"';
$resp = $this->callApiWithKey(self::METHOD_GET, '/short-urls/invalid/visits');
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals('INVALID_SHORTCODE', $error);
$this->assertEquals(self::STATUS_NOT_FOUND, $payload['status']);
$this->assertEquals('INVALID_SHORTCODE', $payload['type']);
$this->assertEquals('INVALID_SHORTCODE', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Short URL not found', $payload['title']);
$this->assertEquals('invalid', $payload['shortCode']);
}
}

View File

@ -11,10 +11,18 @@ class ResolveShortUrlActionTest extends ApiTestCase
/** @test */
public function tryingToResolveInvalidUrlReturnsNotFoundError(): void
{
$expectedDetail = 'No URL found with short code "invalid"';
$resp = $this->callApiWithKey(self::METHOD_GET, '/short-urls/invalid');
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals('INVALID_SHORTCODE', $error);
$this->assertEquals(self::STATUS_NOT_FOUND, $payload['status']);
$this->assertEquals('INVALID_SHORTCODE', $payload['type']);
$this->assertEquals('INVALID_SHORTCODE', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Short URL not found', $payload['title']);
$this->assertEquals('invalid', $payload['shortCode']);
}
}

View File

@ -15,11 +15,18 @@ class UpdateTagActionTest extends ApiTestCase
*/
public function notProvidingTagsReturnsBadRequest(array $body): void
{
$expectedDetail = 'Provided data is not valid';
$resp = $this->callApiWithKey(self::METHOD_PUT, '/tags', [RequestOptions::JSON => $body]);
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_BAD_REQUEST, $resp->getStatusCode());
$this->assertEquals('INVALID_ARGUMENT', $error);
$this->assertEquals(self::STATUS_BAD_REQUEST, $payload['status']);
$this->assertEquals('INVALID_ARGUMENT', $payload['type']);
$this->assertEquals('INVALID_ARGUMENT', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Invalid data', $payload['title']);
}
public function provideInvalidBody(): iterable
@ -32,13 +39,20 @@ class UpdateTagActionTest extends ApiTestCase
/** @test */
public function tryingToRenameInvalidTagReturnsNotFound(): void
{
$expectedDetail = 'Tag with name "invalid_tag" could not be found';
$resp = $this->callApiWithKey(self::METHOD_PUT, '/tags', [RequestOptions::JSON => [
'oldName' => 'invalid_tag',
'newName' => 'foo',
]]);
['error' => $error] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_NOT_FOUND, $resp->getStatusCode());
$this->assertEquals('TAG_NOT_FOUND', $error);
$this->assertEquals(self::STATUS_NOT_FOUND, $payload['status']);
$this->assertEquals('TAG_NOT_FOUND', $payload['type']);
$this->assertEquals('TAG_NOT_FOUND', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Tag not found', $payload['title']);
}
}

View File

@ -16,18 +16,21 @@ class AuthenticationTest extends ApiTestCase
/** @test */
public function authorizationErrorIsReturnedIfNoApiKeyIsSent(): void
{
$expectedDetail = sprintf(
'Expected one of the following authentication headers, but none were provided, ["%s"]',
implode('", "', RequestToHttpAuthPlugin::SUPPORTED_AUTH_HEADERS)
);
$resp = $this->callApi(self::METHOD_GET, '/short-codes');
['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $resp->getStatusCode());
$this->assertEquals('INVALID_AUTHORIZATION', $error);
$this->assertEquals(
sprintf(
'Expected one of the following authentication headers, but none were provided, ["%s"]',
implode('", "', RequestToHttpAuthPlugin::SUPPORTED_AUTH_HEADERS)
),
$message
);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $payload['status']);
$this->assertEquals('INVALID_AUTHORIZATION', $payload['type']);
$this->assertEquals('INVALID_AUTHORIZATION', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Invalid authorization', $payload['title']);
}
/**
@ -36,16 +39,22 @@ class AuthenticationTest extends ApiTestCase
*/
public function apiKeyErrorIsReturnedWhenProvidedApiKeyIsInvalid(string $apiKey): void
{
$expectedDetail = 'Provided API key does not exist or is invalid.';
$resp = $this->callApi(self::METHOD_GET, '/short-codes', [
'headers' => [
Plugin\ApiKeyHeaderPlugin::HEADER_NAME => $apiKey,
],
]);
['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $resp->getStatusCode());
$this->assertEquals('INVALID_API_KEY', $error);
$this->assertEquals('Provided API key does not exist or is invalid.', $message);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $payload['status']);
$this->assertEquals('INVALID_API_KEY', $payload['type']);
$this->assertEquals('INVALID_API_KEY', $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals('Invalid API key', $payload['title']);
}
public function provideInvalidApiKeys(): iterable
@ -61,19 +70,24 @@ class AuthenticationTest extends ApiTestCase
*/
public function authorizationErrorIsReturnedIfInvalidDataIsProvided(
string $authValue,
string $expectedMessage,
string $expectedError
string $expectedDetail,
string $expectedType,
string $expectedTitle
): void {
$resp = $this->callApi(self::METHOD_GET, '/short-codes', [
'headers' => [
Plugin\AuthorizationHeaderPlugin::HEADER_NAME => $authValue,
],
]);
['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($resp);
$payload = $this->getJsonResponsePayload($resp);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $resp->getStatusCode());
$this->assertEquals($expectedError, $error);
$this->assertEquals($expectedMessage, $message);
$this->assertEquals(self::STATUS_UNAUTHORIZED, $payload['status']);
$this->assertEquals($expectedType, $payload['type']);
$this->assertEquals($expectedType, $payload['error']); // Deprecated
$this->assertEquals($expectedDetail, $payload['detail']);
$this->assertEquals($expectedDetail, $payload['message']); // Deprecated
$this->assertEquals($expectedTitle, $payload['title']);
}
public function provideInvalidAuthorizations(): iterable
@ -82,17 +96,20 @@ class AuthenticationTest extends ApiTestCase
'invalid',
'You need to provide the Bearer type in the Authorization header.',
'INVALID_AUTHORIZATION',
'Invalid authorization',
];
yield 'invalid type' => [
'Basic invalid',
'Provided authorization type Basic is not supported. Use Bearer instead.',
'INVALID_AUTHORIZATION',
'Invalid authorization',
];
yield 'invalid JWT' => [
'Bearer invalid',
'Missing or invalid auth token provided. Perform a new authentication request and send provided '
. 'token on every new request on the Authorization header',
'INVALID_AUTH_TOKEN',
'Invalid auth token',
];
}
}