mirror of
https://github.com/shlinkio/shlink.git
synced 2025-02-25 18:45:27 -06:00
Added API tests covering creating short URLs with new findIfExists param
This commit is contained in:
parent
c4fd8d5120
commit
810b25ff14
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,6 +5,7 @@ composer.phar
|
|||||||
vendor/
|
vendor/
|
||||||
.env
|
.env
|
||||||
data/database.sqlite
|
data/database.sqlite
|
||||||
|
data/shlink-tests.db
|
||||||
data/GeoLite2-City.mmdb
|
data/GeoLite2-City.mmdb
|
||||||
docs/swagger-ui*
|
docs/swagger-ui*
|
||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
|
@ -1,12 +1,23 @@
|
|||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Psr\Log;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
'dependencies' => [
|
'dependencies' => [
|
||||||
'lazy_services' => [
|
'lazy_services' => [
|
||||||
'write_proxy_files' => false,
|
'write_proxy_files' => false,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'initializers' => [
|
||||||
|
function (ContainerInterface $container, $instance) {
|
||||||
|
if ($instance instanceof Log\LoggerAwareInterface) {
|
||||||
|
$instance->setLogger($container->get(Log\LoggerInterface::class));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -19,7 +19,7 @@ $testHelper = $container->get(TestHelper::class);
|
|||||||
$config = $container->get('config');
|
$config = $container->get('config');
|
||||||
$em = $container->get(EntityManager::class);
|
$em = $container->get(EntityManager::class);
|
||||||
|
|
||||||
$testHelper->createTestDb();
|
$testHelper->createTestDb($config['entity_manager']['connection']['path']);
|
||||||
ApiTest\ApiTestCase::setApiClient($container->get('shlink_test_api_client'));
|
ApiTest\ApiTestCase::setApiClient($container->get('shlink_test_api_client'));
|
||||||
ApiTest\ApiTestCase::setSeedFixturesCallback(function () use ($testHelper, $em, $config) {
|
ApiTest\ApiTestCase::setSeedFixturesCallback(function () use ($testHelper, $em, $config) {
|
||||||
$testHelper->seedFixtures($em, $config['data_fixtures'] ?? []);
|
$testHelper->seedFixtures($em, $config['data_fixtures'] ?? []);
|
||||||
|
@ -14,6 +14,7 @@ if (! file_exists('.env')) {
|
|||||||
|
|
||||||
/** @var ContainerInterface $container */
|
/** @var ContainerInterface $container */
|
||||||
$container = require __DIR__ . '/../container.php';
|
$container = require __DIR__ . '/../container.php';
|
||||||
|
$config = $container->get('config');
|
||||||
|
|
||||||
$container->get(TestHelper::class)->createTestDb();
|
$container->get(TestHelper::class)->createTestDb($config['entity_manager']['connection']['path']);
|
||||||
DbTest\DatabaseTestCase::setEntityManager($container->get('em'));
|
DbTest\DatabaseTestCase::setEntityManager($container->get('em'));
|
||||||
|
@ -6,7 +6,6 @@ namespace ShlinkioTest\Shlink;
|
|||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use Zend\ConfigAggregator\ConfigAggregator;
|
use Zend\ConfigAggregator\ConfigAggregator;
|
||||||
use Zend\ServiceManager\Factory\InvokableFactory;
|
use Zend\ServiceManager\Factory\InvokableFactory;
|
||||||
use function realpath;
|
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
use function sys_get_temp_dir;
|
use function sys_get_temp_dir;
|
||||||
|
|
||||||
@ -51,7 +50,8 @@ return [
|
|||||||
'entity_manager' => [
|
'entity_manager' => [
|
||||||
'connection' => [
|
'connection' => [
|
||||||
'driver' => 'pdo_sqlite',
|
'driver' => 'pdo_sqlite',
|
||||||
'path' => realpath(sys_get_temp_dir()) . '/shlink-tests.db',
|
'path' => sys_get_temp_dir() . '/shlink-tests.db',
|
||||||
|
// 'path' => __DIR__ . '/../../data/shlink-tests.db',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -197,6 +197,10 @@
|
|||||||
"maxVisits": {
|
"maxVisits": {
|
||||||
"description": "The maximum number of allowed visits for this short code",
|
"description": "The maximum number of allowed visits for this short code",
|
||||||
"type": "number"
|
"type": "number"
|
||||||
|
},
|
||||||
|
"findIfExists": {
|
||||||
|
"description": "Will force existing matching URL to be returned if found, instead of creating a new one",
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,12 @@ use Doctrine\Common\DataFixtures\Purger\ORMPurger;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Component\Process\Process;
|
use Symfony\Component\Process\Process;
|
||||||
use function file_exists;
|
use function file_exists;
|
||||||
use function realpath;
|
|
||||||
use function sys_get_temp_dir;
|
|
||||||
use function unlink;
|
use function unlink;
|
||||||
|
|
||||||
class TestHelper
|
class TestHelper
|
||||||
{
|
{
|
||||||
public function createTestDb(): void
|
public function createTestDb(string $shlinkDbPath): void
|
||||||
{
|
{
|
||||||
$shlinkDbPath = realpath(sys_get_temp_dir()) . '/shlink-tests.db';
|
|
||||||
if (file_exists($shlinkDbPath)) {
|
if (file_exists($shlinkDbPath)) {
|
||||||
unlink($shlinkDbPath);
|
unlink($shlinkDbPath);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,8 @@ class CreateShortUrlAction extends AbstractCreateShortUrlAction
|
|||||||
$this->getOptionalDate($postData, 'validSince'),
|
$this->getOptionalDate($postData, 'validSince'),
|
||||||
$this->getOptionalDate($postData, 'validUntil'),
|
$this->getOptionalDate($postData, 'validUntil'),
|
||||||
$postData['customSlug'] ?? null,
|
$postData['customSlug'] ?? null,
|
||||||
isset($postData['maxVisits']) ? (int) $postData['maxVisits'] : null
|
$postData['maxVisits'] ?? null,
|
||||||
|
$postData['findIfExists'] ?? null
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ class CreateShortUrlActionTest extends ApiTestCase
|
|||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function createsNewShortUrlWhenOnlyLongUrlIsProvided()
|
public function createsNewShortUrlWhenOnlyLongUrlIsProvided(): void
|
||||||
{
|
{
|
||||||
$expectedKeys = ['shortCode', 'shortUrl', 'longUrl', 'dateCreated', 'visitsCount', 'tags'];
|
$expectedKeys = ['shortCode', 'shortUrl', 'longUrl', 'dateCreated', 'visitsCount', 'tags'];
|
||||||
[$statusCode, $payload] = $this->createShortUrl();
|
[$statusCode, $payload] = $this->createShortUrl();
|
||||||
@ -26,7 +26,7 @@ class CreateShortUrlActionTest extends ApiTestCase
|
|||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function createsNewShortUrlWithCustomSlug()
|
public function createsNewShortUrlWithCustomSlug(): void
|
||||||
{
|
{
|
||||||
[$statusCode, $payload] = $this->createShortUrl(['customSlug' => 'my cool slug']);
|
[$statusCode, $payload] = $this->createShortUrl(['customSlug' => 'my cool slug']);
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ class CreateShortUrlActionTest extends ApiTestCase
|
|||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function createsNewShortUrlWithTags()
|
public function createsNewShortUrlWithTags(): void
|
||||||
{
|
{
|
||||||
[$statusCode, $payload] = $this->createShortUrl(['tags' => ['foo', 'bar', 'baz']]);
|
[$statusCode, $payload] = $this->createShortUrl(['tags' => ['foo', 'bar', 'baz']]);
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ class CreateShortUrlActionTest extends ApiTestCase
|
|||||||
* @test
|
* @test
|
||||||
* @dataProvider provideMaxVisits
|
* @dataProvider provideMaxVisits
|
||||||
*/
|
*/
|
||||||
public function createsNewShortUrlWithVisitsLimit(int $maxVisits)
|
public function createsNewShortUrlWithVisitsLimit(int $maxVisits): void
|
||||||
{
|
{
|
||||||
[$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl(['maxVisits' => $maxVisits]);
|
[$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl(['maxVisits' => $maxVisits]);
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ class CreateShortUrlActionTest extends ApiTestCase
|
|||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function createsShortUrlWithValidSince()
|
public function createsShortUrlWithValidSince(): void
|
||||||
{
|
{
|
||||||
[$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl([
|
[$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl([
|
||||||
'validSince' => Chronos::now()->addDay()->toAtomString(),
|
'validSince' => Chronos::now()->addDay()->toAtomString(),
|
||||||
@ -91,7 +91,7 @@ class CreateShortUrlActionTest extends ApiTestCase
|
|||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
*/
|
*/
|
||||||
public function createsShortUrlWithValidUntil()
|
public function createsShortUrlWithValidUntil(): void
|
||||||
{
|
{
|
||||||
[$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl([
|
[$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl([
|
||||||
'validUntil' => Chronos::now()->subDay()->toAtomString(),
|
'validUntil' => Chronos::now()->subDay()->toAtomString(),
|
||||||
@ -104,6 +104,76 @@ class CreateShortUrlActionTest extends ApiTestCase
|
|||||||
$this->assertEquals(self::STATUS_NOT_FOUND, $lastResp->getStatusCode());
|
$this->assertEquals(self::STATUS_NOT_FOUND, $lastResp->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @dataProvider provideMatchingBodies
|
||||||
|
*/
|
||||||
|
public function returnsAnExistingShortUrlWhenRequested(array $body): void
|
||||||
|
{
|
||||||
|
|
||||||
|
[$firstStatusCode, ['shortCode' => $firstShortCode]] = $this->createShortUrl($body);
|
||||||
|
|
||||||
|
$body['findIfExists'] = true;
|
||||||
|
[$secondStatusCode, ['shortCode' => $secondShortCode]] = $this->createShortUrl($body);
|
||||||
|
|
||||||
|
$this->assertEquals(self::STATUS_OK, $firstStatusCode);
|
||||||
|
$this->assertEquals(self::STATUS_OK, $secondStatusCode);
|
||||||
|
$this->assertEquals($firstShortCode, $secondShortCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideMatchingBodies(): array
|
||||||
|
{
|
||||||
|
$longUrl = 'https://www.alejandrocelaya.com';
|
||||||
|
|
||||||
|
return [
|
||||||
|
'only long URL' => [['longUrl' => $longUrl]],
|
||||||
|
'long URL and tags' => [['longUrl' => $longUrl, 'tags' => ['boo', 'far']]],
|
||||||
|
'long URL custom slug' => [['longUrl' => $longUrl, 'customSlug' => 'my cool slug']],
|
||||||
|
'several params' => [[
|
||||||
|
'longUrl' => $longUrl,
|
||||||
|
'tags' => ['boo', 'far'],
|
||||||
|
'validSince' => Chronos::now()->toAtomString(),
|
||||||
|
'maxVisits' => 7,
|
||||||
|
]],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function returnsErrorWhenRequestingReturnExistingButCustomSlugIsInUse(): void
|
||||||
|
{
|
||||||
|
$longUrl = 'https://www.alejandrocelaya.com';
|
||||||
|
|
||||||
|
[$firstStatusCode] = $this->createShortUrl(['longUrl' => $longUrl]);
|
||||||
|
[$secondStatusCode] = $this->createShortUrl([
|
||||||
|
'longUrl' => $longUrl,
|
||||||
|
'customSlug' => 'custom',
|
||||||
|
'findIfExists' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(self::STATUS_OK, $firstStatusCode);
|
||||||
|
$this->assertEquals(self::STATUS_BAD_REQUEST, $secondStatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function createsNewShortUrlIfRequestedToFindButThereIsNoMatch(): void
|
||||||
|
{
|
||||||
|
[$firstStatusCode, ['shortCode' => $firstShortCode]] = $this->createShortUrl([
|
||||||
|
'longUrl' => 'https://www.alejandrocelaya.com',
|
||||||
|
]);
|
||||||
|
[$secondStatusCode, ['shortCode' => $secondShortCode]] = $this->createShortUrl([
|
||||||
|
'longUrl' => 'https://www.alejandrocelaya.com/projects',
|
||||||
|
'findIfExists' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(self::STATUS_OK, $firstStatusCode);
|
||||||
|
$this->assertEquals(self::STATUS_OK, $secondStatusCode);
|
||||||
|
$this->assertNotEquals($firstShortCode, $secondShortCode);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array {
|
* @return array {
|
||||||
* @var int $statusCode
|
* @var int $statusCode
|
||||||
@ -112,7 +182,9 @@ class CreateShortUrlActionTest extends ApiTestCase
|
|||||||
*/
|
*/
|
||||||
private function createShortUrl(array $body = []): array
|
private function createShortUrl(array $body = []): array
|
||||||
{
|
{
|
||||||
|
if (! isset($body['longUrl'])) {
|
||||||
$body['longUrl'] = 'https://app.shlink.io';
|
$body['longUrl'] = 'https://app.shlink.io';
|
||||||
|
}
|
||||||
$resp = $this->callApiWithKey(self::METHOD_POST, '/short-urls', [RequestOptions::JSON => $body]);
|
$resp = $this->callApiWithKey(self::METHOD_POST, '/short-urls', [RequestOptions::JSON => $body]);
|
||||||
$payload = $this->getJsonResponsePayload($resp);
|
$payload = $this->getJsonResponsePayload($resp);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user