Browse Source

Added API tests covering creating short URLs with new findIfExists param

Alejandro Celaya 5 years ago
parent
commit
810b25ff14

+ 1 - 0
.gitignore

@@ -5,6 +5,7 @@ composer.phar
 vendor/
 .env
 data/database.sqlite
+data/shlink-tests.db
 data/GeoLite2-City.mmdb
 docs/swagger-ui*
 docker-compose.override.yml

+ 11 - 0
config/autoload/dependencies.local.php.dist

@@ -1,12 +1,23 @@
 <?php
 declare(strict_types=1);
 
+use Psr\Container\ContainerInterface;
+use Psr\Log;
+
 return [
 
     'dependencies' => [
         'lazy_services' => [
             'write_proxy_files' => false,
         ],
+
+        'initializers' => [
+            function (ContainerInterface $container, $instance) {
+                if ($instance instanceof Log\LoggerAwareInterface) {
+                    $instance->setLogger($container->get(Log\LoggerInterface::class));
+                }
+            },
+        ],
     ],
 
 ];

+ 1 - 1
config/test/bootstrap_api_tests.php

@@ -19,7 +19,7 @@ $testHelper = $container->get(TestHelper::class);
 $config = $container->get('config');
 $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::setSeedFixturesCallback(function () use ($testHelper, $em, $config) {
     $testHelper->seedFixtures($em, $config['data_fixtures'] ?? []);

+ 2 - 1
config/test/bootstrap_db_tests.php

@@ -14,6 +14,7 @@ if (! file_exists('.env')) {
 
 /** @var ContainerInterface $container */
 $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'));

+ 2 - 2
config/test/test_config.global.php

@@ -6,7 +6,6 @@ namespace ShlinkioTest\Shlink;
 use GuzzleHttp\Client;
 use Zend\ConfigAggregator\ConfigAggregator;
 use Zend\ServiceManager\Factory\InvokableFactory;
-use function realpath;
 use function sprintf;
 use function sys_get_temp_dir;
 
@@ -51,7 +50,8 @@ return [
     'entity_manager' => [
         'connection' => [
             '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',
         ],
     ],
 

+ 4 - 0
docs/swagger/paths/v1_short-urls.json

@@ -197,6 +197,10 @@
                             "maxVisits": {
                                 "description": "The maximum number of allowed visits for this short code",
                                 "type": "number"
+                            },
+                            "findIfExists": {
+                                "description": "Will force existing matching URL to be returned if found, instead of creating a new one",
+                                "type": "boolean"
                             }
                         }
                     }

+ 1 - 4
module/Common/test-db/TestHelper.php

@@ -9,15 +9,12 @@ use Doctrine\Common\DataFixtures\Purger\ORMPurger;
 use Doctrine\ORM\EntityManagerInterface;
 use Symfony\Component\Process\Process;
 use function file_exists;
-use function realpath;
-use function sys_get_temp_dir;
 use function unlink;
 
 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)) {
             unlink($shlinkDbPath);
         }

+ 2 - 1
module/Rest/src/Action/ShortUrl/CreateShortUrlAction.php

@@ -35,7 +35,8 @@ class CreateShortUrlAction extends AbstractCreateShortUrlAction
                 $this->getOptionalDate($postData, 'validSince'),
                 $this->getOptionalDate($postData, 'validUntil'),
                 $postData['customSlug'] ?? null,
-                isset($postData['maxVisits']) ? (int) $postData['maxVisits'] : null
+                $postData['maxVisits'] ?? null,
+                $postData['findIfExists'] ?? null
             )
         );
     }

+ 79 - 7
module/Rest/test-api/Action/CreateShortUrlActionTest.php

@@ -12,7 +12,7 @@ class CreateShortUrlActionTest extends ApiTestCase
     /**
      * @test
      */
-    public function createsNewShortUrlWhenOnlyLongUrlIsProvided()
+    public function createsNewShortUrlWhenOnlyLongUrlIsProvided(): void
     {
         $expectedKeys = ['shortCode', 'shortUrl', 'longUrl', 'dateCreated', 'visitsCount', 'tags'];
         [$statusCode, $payload] = $this->createShortUrl();
@@ -26,7 +26,7 @@ class CreateShortUrlActionTest extends ApiTestCase
     /**
      * @test
      */
-    public function createsNewShortUrlWithCustomSlug()
+    public function createsNewShortUrlWithCustomSlug(): void
     {
         [$statusCode, $payload] = $this->createShortUrl(['customSlug' => 'my cool slug']);
 
@@ -37,7 +37,7 @@ class CreateShortUrlActionTest extends ApiTestCase
     /**
      * @test
      */
-    public function createsNewShortUrlWithTags()
+    public function createsNewShortUrlWithTags(): void
     {
         [$statusCode, $payload] = $this->createShortUrl(['tags' => ['foo', 'bar', 'baz']]);
 
@@ -49,7 +49,7 @@ class CreateShortUrlActionTest extends ApiTestCase
      * @test
      * @dataProvider provideMaxVisits
      */
-    public function createsNewShortUrlWithVisitsLimit(int $maxVisits)
+    public function createsNewShortUrlWithVisitsLimit(int $maxVisits): void
     {
         [$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl(['maxVisits' => $maxVisits]);
 
@@ -75,7 +75,7 @@ class CreateShortUrlActionTest extends ApiTestCase
     /**
      * @test
      */
-    public function createsShortUrlWithValidSince()
+    public function createsShortUrlWithValidSince(): void
     {
         [$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl([
             'validSince' => Chronos::now()->addDay()->toAtomString(),
@@ -91,7 +91,7 @@ class CreateShortUrlActionTest extends ApiTestCase
     /**
      * @test
      */
-    public function createsShortUrlWithValidUntil()
+    public function createsShortUrlWithValidUntil(): void
     {
         [$statusCode, ['shortCode' => $shortCode]] = $this->createShortUrl([
             'validUntil' => Chronos::now()->subDay()->toAtomString(),
@@ -104,6 +104,76 @@ class CreateShortUrlActionTest extends ApiTestCase
         $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 {
      *     @var int $statusCode
@@ -112,7 +182,9 @@ class CreateShortUrlActionTest extends ApiTestCase
      */
     private function createShortUrl(array $body = []): array
     {
-        $body['longUrl'] = 'https://app.shlink.io';
+        if (! isset($body['longUrl'])) {
+            $body['longUrl'] = 'https://app.shlink.io';
+        }
         $resp = $this->callApiWithKey(self::METHOD_POST, '/short-urls', [RequestOptions::JSON => $body]);
         $payload = $this->getJsonResponsePayload($resp);