From 87ba7a7179deaa46d9d2a36a1aaf116b9ebf8ef0 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 26 Jan 2019 09:09:49 +0100 Subject: [PATCH 01/10] Updated structure for tests config files --- build.sh | 2 +- config/config.php | 4 ++++ .../test/bootstrap_db_tests.php | 6 +++--- config/test/swoole.global.php | 12 ++++++++++++ module/Common/test-db/ApiTest/ApiTestCase.php | 10 ++++++++++ .../test-db/{DbUnit => DbTest}/DatabaseTestCase.php | 4 +--- .../test-db/Repository/ShortUrlRepositoryTest.php | 2 +- module/Core/test-db/Repository/TagRepositoryTest.php | 2 +- .../Core/test-db/Repository/VisitRepositoryTest.php | 2 +- phpunit-db.xml | 9 +++++---- 10 files changed, 39 insertions(+), 14 deletions(-) rename db_tests_bootstrap.php => config/test/bootstrap_db_tests.php (76%) create mode 100644 config/test/swoole.global.php create mode 100644 module/Common/test-db/ApiTest/ApiTestCase.php rename module/Common/test-db/{DbUnit => DbTest}/DatabaseTestCase.php (82%) diff --git a/build.sh b/build.sh index cab2f4d3..dd287783 100755 --- a/build.sh +++ b/build.sh @@ -28,11 +28,11 @@ rsync -av * "${builtcontent}" \ --exclude=docs \ --exclude=indocker \ --exclude=docker* \ - --exclude=func_tests_bootstrap.php \ --exclude=php* \ --exclude=infection.json \ --exclude=phpstan.neon \ --exclude=config/autoload/*local* \ + --exclude=config/test \ --exclude=**/test* \ --exclude=build* cd "${builtcontent}" diff --git a/config/config.php b/config/config.php index 1c87f66e..9b28cf82 100644 --- a/config/config.php +++ b/config/config.php @@ -6,6 +6,7 @@ namespace Shlinkio\Shlink; use Acelaya\ExpressiveErrorHandler; use Zend\ConfigAggregator; use Zend\Expressive; +use function Shlinkio\Shlink\Common\env; return (new ConfigAggregator\ConfigAggregator([ Expressive\ConfigProvider::class, @@ -21,4 +22,7 @@ return (new ConfigAggregator\ConfigAggregator([ Rest\ConfigProvider::class, new ConfigAggregator\PhpFileProvider('config/autoload/{{,*.}global,{,*.}local}.php'), new ConfigAggregator\ZendConfigProvider('config/params/{generated_config.php,*.config.{php,json}}'), + env('APP_ENV') === 'test' + ? new ConfigAggregator\PhpFileProvider('config/test/*.global.php') + : new ConfigAggregator\ArrayProvider([]), ], 'data/cache/app_config.php'))->getMergedConfig(); diff --git a/db_tests_bootstrap.php b/config/test/bootstrap_db_tests.php similarity index 76% rename from db_tests_bootstrap.php rename to config/test/bootstrap_db_tests.php index 4bf09ba9..4a1bce4d 100644 --- a/db_tests_bootstrap.php +++ b/config/test/bootstrap_db_tests.php @@ -2,7 +2,7 @@ declare(strict_types=1); use Psr\Container\ContainerInterface; -use ShlinkioTest\Shlink\Common\DbUnit\DatabaseTestCase; +use ShlinkioTest\Shlink\Common\DbTest\DatabaseTestCase; use Symfony\Component\Process\Process; // Create an empty .env file @@ -16,10 +16,10 @@ if (file_exists($shlinkDbPath)) { } /** @var ContainerInterface $container */ -$container = require __DIR__ . '/config/test-container.php'; +$container = require __DIR__ . '/../test-container.php'; // Create database -$process = new Process(['vendor/bin/doctrine', 'orm:schema-tool:create', '--no-interaction', '-q', '--test'], __DIR__); +$process = new Process(['vendor/bin/doctrine', 'orm:schema-tool:create', '--no-interaction', '-q', '--test']); $process->inheritEnvironmentVariables() ->mustRun(); diff --git a/config/test/swoole.global.php b/config/test/swoole.global.php new file mode 100644 index 00000000..f922dd7a --- /dev/null +++ b/config/test/swoole.global.php @@ -0,0 +1,12 @@ + [ + 'swoole-http-server' => [ + 'port' => 9999, + ], + ], + +]; diff --git a/module/Common/test-db/ApiTest/ApiTestCase.php b/module/Common/test-db/ApiTest/ApiTestCase.php new file mode 100644 index 00000000..e947eba9 --- /dev/null +++ b/module/Common/test-db/ApiTest/ApiTestCase.php @@ -0,0 +1,10 @@ +getEntityManager()->createQueryBuilder(); $qb->delete($entityClass, 'x'); $qb->getQuery()->execute(); } - // Clear entity manager $this->getEntityManager()->clear(); } } diff --git a/module/Core/test-db/Repository/ShortUrlRepositoryTest.php b/module/Core/test-db/Repository/ShortUrlRepositoryTest.php index c7f809b9..ae42e813 100644 --- a/module/Core/test-db/Repository/ShortUrlRepositoryTest.php +++ b/module/Core/test-db/Repository/ShortUrlRepositoryTest.php @@ -11,7 +11,7 @@ use Shlinkio\Shlink\Core\Entity\Visit; use Shlinkio\Shlink\Core\Model\ShortUrlMeta; use Shlinkio\Shlink\Core\Model\Visitor; use Shlinkio\Shlink\Core\Repository\ShortUrlRepository; -use ShlinkioTest\Shlink\Common\DbUnit\DatabaseTestCase; +use ShlinkioTest\Shlink\Common\DbTest\DatabaseTestCase; use function count; class ShortUrlRepositoryTest extends DatabaseTestCase diff --git a/module/Core/test-db/Repository/TagRepositoryTest.php b/module/Core/test-db/Repository/TagRepositoryTest.php index 9292753c..fb43bfe1 100644 --- a/module/Core/test-db/Repository/TagRepositoryTest.php +++ b/module/Core/test-db/Repository/TagRepositoryTest.php @@ -5,7 +5,7 @@ namespace ShlinkioTest\Shlink\Core\Repository; use Shlinkio\Shlink\Core\Entity\Tag; use Shlinkio\Shlink\Core\Repository\TagRepository; -use ShlinkioTest\Shlink\Common\DbUnit\DatabaseTestCase; +use ShlinkioTest\Shlink\Common\DbTest\DatabaseTestCase; class TagRepositoryTest extends DatabaseTestCase { diff --git a/module/Core/test-db/Repository/VisitRepositoryTest.php b/module/Core/test-db/Repository/VisitRepositoryTest.php index 1841f5a0..ed059a37 100644 --- a/module/Core/test-db/Repository/VisitRepositoryTest.php +++ b/module/Core/test-db/Repository/VisitRepositoryTest.php @@ -10,7 +10,7 @@ use Shlinkio\Shlink\Core\Entity\Visit; use Shlinkio\Shlink\Core\Entity\VisitLocation; use Shlinkio\Shlink\Core\Model\Visitor; use Shlinkio\Shlink\Core\Repository\VisitRepository; -use ShlinkioTest\Shlink\Common\DbUnit\DatabaseTestCase; +use ShlinkioTest\Shlink\Common\DbTest\DatabaseTestCase; use function sprintf; class VisitRepositoryTest extends DatabaseTestCase diff --git a/phpunit-db.xml b/phpunit-db.xml index f514afd9..eab4be28 100644 --- a/phpunit-db.xml +++ b/phpunit-db.xml @@ -1,9 +1,10 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.5/phpunit.xsd" + bootstrap="./config/test/bootstrap_db_tests.php" + colors="true" +> ./module/*/test-db From c4af1471f03263337fb1efb59dc35cca3a8ae6a2 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 26 Jan 2019 09:42:01 +0100 Subject: [PATCH 02/10] Simplified and united configs for tests --- composer.json | 2 +- config/cli-config.php | 12 +---------- config/test-container.php | 14 ------------- config/test/bootstrap_db_tests.php | 21 +++++++------------ config/test/swoole.global.php | 12 ----------- config/test/test_config.global.php | 31 ++++++++++++++++++++++++++++ module/Common/test-db/TestHelper.php | 25 ++++++++++++++++++++++ 7 files changed, 65 insertions(+), 52 deletions(-) delete mode 100644 config/test-container.php delete mode 100644 config/test/swoole.global.php create mode 100644 config/test/test_config.global.php create mode 100644 module/Common/test-db/TestHelper.php diff --git a/composer.json b/composer.json index d78860a1..7f519c51 100644 --- a/composer.json +++ b/composer.json @@ -111,7 +111,7 @@ ], "test:unit": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov", "test:unit:ci": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov --coverage-clover=build/clover.xml --coverage-xml=build/coverage-xml --log-junit=build/phpunit.junit.xml", - "test:db": "phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-db.xml --coverage-php build/coverage-db.cov", + "test:db": "APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-db.xml --coverage-php build/coverage-db.cov", "test:pretty": [ "@test", diff --git a/config/cli-config.php b/config/cli-config.php index 774b3412..3c80ee16 100644 --- a/config/cli-config.php +++ b/config/cli-config.php @@ -6,18 +6,8 @@ use Doctrine\ORM\Tools\Console\ConsoleRunner; use Interop\Container\ContainerInterface; use Zend\ServiceManager\ServiceManager; -// If the "--test" flag was provided, we are on a test environment -$isTest = false; -foreach ($_SERVER['argv'] as $i => $arg) { - if ($arg === '--test') { - unset($_SERVER['argv'][$i]); - $isTest = true; - break; - } -} - /** @var ContainerInterface|ServiceManager $container */ -$container = $isTest ? include __DIR__ . '/test-container.php' : include __DIR__ . '/container.php'; +$container = include __DIR__ . '/container.php'; $em = $container->get(EntityManager::class); return ConsoleRunner::createHelperSet($em); diff --git a/config/test-container.php b/config/test-container.php deleted file mode 100644 index 8a3f4606..00000000 --- a/config/test-container.php +++ /dev/null @@ -1,14 +0,0 @@ -setAllowOverride(true); -$config = $container->get('config'); -$config['entity_manager']['connection'] = [ - 'driver' => 'pdo_sqlite', - 'path' => realpath(sys_get_temp_dir()) . '/shlink-tests.db', -]; -$container->setService('config', $config); - -return $container; diff --git a/config/test/bootstrap_db_tests.php b/config/test/bootstrap_db_tests.php index 4a1bce4d..2639d152 100644 --- a/config/test/bootstrap_db_tests.php +++ b/config/test/bootstrap_db_tests.php @@ -1,26 +1,19 @@ inheritEnvironmentVariables() - ->mustRun(); - -DatabaseTestCase::$em = $container->get('em'); +$container->get(TestHelper::class)->createTestDb(); +DbTest\DatabaseTestCase::$em = $container->get('em'); diff --git a/config/test/swoole.global.php b/config/test/swoole.global.php deleted file mode 100644 index f922dd7a..00000000 --- a/config/test/swoole.global.php +++ /dev/null @@ -1,12 +0,0 @@ - [ - 'swoole-http-server' => [ - 'port' => 9999, - ], - ], - -]; diff --git a/config/test/test_config.global.php b/config/test/test_config.global.php new file mode 100644 index 00000000..8757bb34 --- /dev/null +++ b/config/test/test_config.global.php @@ -0,0 +1,31 @@ + [ + 'swoole-http-server' => [ + 'port' => 9999, + ], + ], + + 'dependencies' => [ + 'factories' => [ + Common\TestHelper::class => InvokableFactory::class, + ], + ], + + 'entity_manager' => [ + 'connection' => [ + 'driver' => 'pdo_sqlite', + 'path' => realpath(sys_get_temp_dir()) . '/shlink-tests.db', + ], + ], + +]; diff --git a/module/Common/test-db/TestHelper.php b/module/Common/test-db/TestHelper.php new file mode 100644 index 00000000..634456fc --- /dev/null +++ b/module/Common/test-db/TestHelper.php @@ -0,0 +1,25 @@ +inheritEnvironmentVariables() + ->mustRun(); + } +} From 22d61fead7045907d4b86f844ac544f21c135cf3 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 26 Jan 2019 10:19:20 +0100 Subject: [PATCH 03/10] Prepared configs for API tests --- composer.json | 6 ++++++ config/test/bootstrap_api_tests.php | 18 ++++++++++++++++ config/test/test_config.global.php | 6 ++++++ module/Common/test-db/ApiTest/ApiTestCase.php | 21 ++++++++++++++++++- .../Middleware/AuthenticationTest.php | 21 +++++++++++++++++++ phpunit-api.xml | 19 +++++++++++++++++ 6 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 config/test/bootstrap_api_tests.php create mode 100644 module/Rest/test-api/Middleware/AuthenticationTest.php create mode 100644 phpunit-api.xml diff --git a/composer.json b/composer.json index 7f519c51..7cf7dcc5 100644 --- a/composer.json +++ b/composer.json @@ -78,6 +78,7 @@ "psr-4": { "ShlinkioTest\\Shlink\\CLI\\": "module/CLI/test", "ShlinkioTest\\Shlink\\Rest\\": "module/Rest/test", + "ShlinkioApiTest\\Shlink\\Rest\\": "module/Rest/test-api", "ShlinkioTest\\Shlink\\Core\\": [ "module/Core/test", "module/Core/test-db" @@ -112,6 +113,11 @@ "test:unit": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov", "test:unit:ci": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov --coverage-clover=build/clover.xml --coverage-xml=build/coverage-xml --log-junit=build/phpunit.junit.xml", "test:db": "APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-db.xml --coverage-php build/coverage-db.cov", + "test:api": [ + "APP_ENV=test vendor/bin/zend-expressive-swoole start -d", + "APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-api.xml", + "APP_ENV=test vendor/bin/zend-expressive-swoole stop" + ], "test:pretty": [ "@test", diff --git a/config/test/bootstrap_api_tests.php b/config/test/bootstrap_api_tests.php new file mode 100644 index 00000000..6ccde6b7 --- /dev/null +++ b/config/test/bootstrap_api_tests.php @@ -0,0 +1,18 @@ +get(TestHelper::class)->createTestDb(); +ApiTest\ApiTestCase::setApiClient($container->get('shlink_test_api_client')); diff --git a/config/test/test_config.global.php b/config/test/test_config.global.php index 8757bb34..72f6e307 100644 --- a/config/test/test_config.global.php +++ b/config/test/test_config.global.php @@ -3,6 +3,7 @@ declare(strict_types=1); namespace ShlinkioTest\Shlink; +use GuzzleHttp\Client; use Zend\ServiceManager\Factory\InvokableFactory; use function realpath; use function sys_get_temp_dir; @@ -12,12 +13,17 @@ return [ 'zend-expressive-swoole' => [ 'swoole-http-server' => [ 'port' => 9999, + 'host' => '127.0.0.1', + 'process-name' => 'shlink_test', ], ], 'dependencies' => [ 'factories' => [ Common\TestHelper::class => InvokableFactory::class, + 'shlink_test_api_client' => function () { + return new Client(['base_uri' => 'http://localhost:9999/']); + }, ], ], diff --git a/module/Common/test-db/ApiTest/ApiTestCase.php b/module/Common/test-db/ApiTest/ApiTestCase.php index e947eba9..0a190822 100644 --- a/module/Common/test-db/ApiTest/ApiTestCase.php +++ b/module/Common/test-db/ApiTest/ApiTestCase.php @@ -3,8 +3,27 @@ declare(strict_types=1); namespace ShlinkioTest\Shlink\Common\ApiTest; +use Fig\Http\Message\RequestMethodInterface; +use Fig\Http\Message\StatusCodeInterface; +use GuzzleHttp\ClientInterface; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\ResponseInterface; -abstract class ApiTestCase extends TestCase +abstract class ApiTestCase extends TestCase implements StatusCodeInterface, RequestMethodInterface { + /** @var ClientInterface */ + private static $client; + + public static function setApiClient(ClientInterface $client): void + { + self::$client = $client; + } + + /** + * @throws \GuzzleHttp\Exception\GuzzleException + */ + protected function callApi(string $method, string $uri, array $options = []): ResponseInterface + { + return self::$client->request($method, $uri, $options); + } } diff --git a/module/Rest/test-api/Middleware/AuthenticationTest.php b/module/Rest/test-api/Middleware/AuthenticationTest.php new file mode 100644 index 00000000..dc6032fc --- /dev/null +++ b/module/Rest/test-api/Middleware/AuthenticationTest.php @@ -0,0 +1,21 @@ +expectException(ClientException::class); + $this->expectExceptionCode(self::STATUS_UNAUTHORIZED); + + $this->callApi(self::METHOD_GET, '/rest/v1/short-codes'); + } +} diff --git a/phpunit-api.xml b/phpunit-api.xml new file mode 100644 index 00000000..69132097 --- /dev/null +++ b/phpunit-api.xml @@ -0,0 +1,19 @@ + + + + + ./module/*/test-api + + + + + + ./module/*/src + + + From fa753ad6fb2c07ac2ff0f2f9dcdf4414db62d65c Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 26 Jan 2019 10:59:24 +0100 Subject: [PATCH 04/10] Added api test to test:ci command --- composer.json | 3 ++- config/test/test_config.global.php | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7cf7dcc5..250987b5 100644 --- a/composer.json +++ b/composer.json @@ -108,7 +108,8 @@ ], "test:ci": [ "@test:unit:ci", - "@test:db" + "@test:db", + "@test:api" ], "test:unit": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov", "test:unit:ci": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov --coverage-clover=build/clover.xml --coverage-xml=build/coverage-xml --log-junit=build/phpunit.junit.xml", diff --git a/config/test/test_config.global.php b/config/test/test_config.global.php index 72f6e307..6d359c19 100644 --- a/config/test/test_config.global.php +++ b/config/test/test_config.global.php @@ -4,12 +4,16 @@ declare(strict_types=1); namespace ShlinkioTest\Shlink; use GuzzleHttp\Client; +use Zend\ConfigAggregator\ConfigAggregator; use Zend\ServiceManager\Factory\InvokableFactory; use function realpath; use function sys_get_temp_dir; return [ + 'debug' => true, + ConfigAggregator::ENABLE_CACHE => false, + 'zend-expressive-swoole' => [ 'swoole-http-server' => [ 'port' => 9999, From f467bed24c0493c021f412db1b8857f0bf0d7eb9 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 27 Jan 2019 10:15:48 +0100 Subject: [PATCH 05/10] Used multiple commands with && instead of composer array for API tests command --- composer.json | 6 +----- config/test/test_config.global.php | 3 +++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 250987b5..fe118ee4 100644 --- a/composer.json +++ b/composer.json @@ -114,11 +114,7 @@ "test:unit": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov", "test:unit:ci": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov --coverage-clover=build/clover.xml --coverage-xml=build/coverage-xml --log-junit=build/phpunit.junit.xml", "test:db": "APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-db.xml --coverage-php build/coverage-db.cov", - "test:api": [ - "APP_ENV=test vendor/bin/zend-expressive-swoole start -d", - "APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-api.xml", - "APP_ENV=test vendor/bin/zend-expressive-swoole stop" - ], + "test:api": "APP_ENV=test vendor/bin/zend-expressive-swoole start -d && echo 'Waiting 2 seconds for server to start...' && sleep 2 && APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-api.xml && APP_ENV=test vendor/bin/zend-expressive-swoole stop", "test:pretty": [ "@test", diff --git a/config/test/test_config.global.php b/config/test/test_config.global.php index 6d359c19..79f36791 100644 --- a/config/test/test_config.global.php +++ b/config/test/test_config.global.php @@ -19,6 +19,9 @@ return [ 'port' => 9999, 'host' => '127.0.0.1', 'process-name' => 'shlink_test', + 'options' => [ + 'pid_file' => sys_get_temp_dir() . '/shlink-test-swoole.pid', + ], ], ], From 558e259b846360123440a807daa570354f1840bd Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 27 Jan 2019 10:30:38 +0100 Subject: [PATCH 06/10] Minor refactorings --- composer.json | 1 + config/test/bootstrap_db_tests.php | 2 +- module/Common/test-db/ApiTest/ApiTestCase.php | 5 ++++- module/Common/test-db/DbTest/DatabaseTestCase.php | 9 +++++++-- module/Rest/test-api/Middleware/AuthenticationTest.php | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index fe118ee4..2e20ed83 100644 --- a/composer.json +++ b/composer.json @@ -141,6 +141,7 @@ "test:unit": "Runs unit test suites", "test:unit:ci": "Runs unit test suites, generating all needed reports and logs for CI envs", "test:db": "Runs database test suites (covering entity repositories)", + "test:api": "Runs API test suites", "test:pretty": "Runs all test suites and generates an HTML code coverage report", "test:unit:pretty": "Runs unit test suites and generates an HTML code coverage report", "infect": "Checks unit tests quality applying mutation testing", diff --git a/config/test/bootstrap_db_tests.php b/config/test/bootstrap_db_tests.php index 2639d152..58bc2174 100644 --- a/config/test/bootstrap_db_tests.php +++ b/config/test/bootstrap_db_tests.php @@ -16,4 +16,4 @@ if (! file_exists('.env')) { $container = require __DIR__ . '/../container.php'; $container->get(TestHelper::class)->createTestDb(); -DbTest\DatabaseTestCase::$em = $container->get('em'); +DbTest\DatabaseTestCase::setEntityManager($container->get('em')); diff --git a/module/Common/test-db/ApiTest/ApiTestCase.php b/module/Common/test-db/ApiTest/ApiTestCase.php index 0a190822..1aae1065 100644 --- a/module/Common/test-db/ApiTest/ApiTestCase.php +++ b/module/Common/test-db/ApiTest/ApiTestCase.php @@ -8,9 +8,12 @@ use Fig\Http\Message\StatusCodeInterface; use GuzzleHttp\ClientInterface; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; +use function sprintf; abstract class ApiTestCase extends TestCase implements StatusCodeInterface, RequestMethodInterface { + private const PATH_PREFX = '/rest/v1'; + /** @var ClientInterface */ private static $client; @@ -24,6 +27,6 @@ abstract class ApiTestCase extends TestCase implements StatusCodeInterface, Requ */ protected function callApi(string $method, string $uri, array $options = []): ResponseInterface { - return self::$client->request($method, $uri, $options); + return self::$client->request($method, sprintf('%s%s', self::PATH_PREFX, $uri), $options); } } diff --git a/module/Common/test-db/DbTest/DatabaseTestCase.php b/module/Common/test-db/DbTest/DatabaseTestCase.php index ba8b031d..dc102c8c 100644 --- a/module/Common/test-db/DbTest/DatabaseTestCase.php +++ b/module/Common/test-db/DbTest/DatabaseTestCase.php @@ -11,11 +11,16 @@ abstract class DatabaseTestCase extends TestCase protected const ENTITIES_TO_EMPTY = []; /** @var EntityManagerInterface */ - public static $em; + private static $em; + + public static function setEntityManager(EntityManagerInterface $em): void + { + self::$em = $em; + } protected function getEntityManager(): EntityManagerInterface { - return static::$em; + return self::$em; } public function tearDown() diff --git a/module/Rest/test-api/Middleware/AuthenticationTest.php b/module/Rest/test-api/Middleware/AuthenticationTest.php index dc6032fc..1b0d776e 100644 --- a/module/Rest/test-api/Middleware/AuthenticationTest.php +++ b/module/Rest/test-api/Middleware/AuthenticationTest.php @@ -16,6 +16,6 @@ class AuthenticationTest extends ApiTestCase $this->expectException(ClientException::class); $this->expectExceptionCode(self::STATUS_UNAUTHORIZED); - $this->callApi(self::METHOD_GET, '/rest/v1/short-codes'); + $this->callApi(self::METHOD_GET, '/short-codes'); } } From 76d8fd102383ea7fc587b1fb6684fe53877d60a8 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 27 Jan 2019 10:54:04 +0100 Subject: [PATCH 07/10] Improved how API tests are executed --- bin/test/run-api-tests.sh | 14 ++++++ build.sh | 1 + composer.json | 2 +- .../Middleware/AuthenticationTest.php | 45 +++++++++++++++++-- 4 files changed, 57 insertions(+), 5 deletions(-) create mode 100755 bin/test/run-api-tests.sh diff --git a/bin/test/run-api-tests.sh b/bin/test/run-api-tests.sh new file mode 100755 index 00000000..5086ce41 --- /dev/null +++ b/bin/test/run-api-tests.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh +set -e + +export APP_ENV=test + +# Try to stop server just in case it hanged in last execution +vendor/bin/zend-expressive-swoole stop + +echo 'Starting server...' +vendor/bin/zend-expressive-swoole start -d +sleep 2 + +vendor/bin/phpunit --order-by=random -c phpunit-api.xml +vendor/bin/zend-expressive-swoole stop diff --git a/build.sh b/build.sh index dd287783..99c82087 100755 --- a/build.sh +++ b/build.sh @@ -17,6 +17,7 @@ echo 'Copying project files...' rm -rf "${builtcontent}" mkdir -p "${builtcontent}" rsync -av * "${builtcontent}" \ + --exclude=bin/test \ --exclude=data/infra \ --exclude=data/travis \ --exclude=data/migrations_template.txt \ diff --git a/composer.json b/composer.json index 2e20ed83..b8ce3e66 100644 --- a/composer.json +++ b/composer.json @@ -114,7 +114,7 @@ "test:unit": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov", "test:unit:ci": "phpdbg -qrr vendor/bin/phpunit --order-by=random --coverage-php build/coverage-unit.cov --coverage-clover=build/clover.xml --coverage-xml=build/coverage-xml --log-junit=build/phpunit.junit.xml", "test:db": "APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-db.xml --coverage-php build/coverage-db.cov", - "test:api": "APP_ENV=test vendor/bin/zend-expressive-swoole start -d && echo 'Waiting 2 seconds for server to start...' && sleep 2 && APP_ENV=test phpdbg -qrr vendor/bin/phpunit --order-by=random -c phpunit-api.xml && APP_ENV=test vendor/bin/zend-expressive-swoole stop", + "test:api": "bin/test/run-api-tests.sh", "test:pretty": [ "@test", diff --git a/module/Rest/test-api/Middleware/AuthenticationTest.php b/module/Rest/test-api/Middleware/AuthenticationTest.php index 1b0d776e..1e5dea06 100644 --- a/module/Rest/test-api/Middleware/AuthenticationTest.php +++ b/module/Rest/test-api/Middleware/AuthenticationTest.php @@ -4,18 +4,55 @@ declare(strict_types=1); namespace ShlinkioApiTest\Shlink\Rest\Middleware; use GuzzleHttp\Exception\ClientException; +use Shlinkio\Shlink\Rest\Authentication\Plugin\ApiKeyHeaderPlugin; +use Shlinkio\Shlink\Rest\Authentication\RequestToHttpAuthPlugin; +use Shlinkio\Shlink\Rest\Util\RestUtils; use ShlinkioTest\Shlink\Common\ApiTest\ApiTestCase; +use function implode; +use function Shlinkio\Shlink\Common\json_decode; +use function sprintf; class AuthenticationTest extends ApiTestCase { /** * @test */ - public function unauthorizedIsReturnedIfNoAuthenticationIsSent() + public function authorizationErrorIsReturnedIfNoApiKeyIsSent() { - $this->expectException(ClientException::class); - $this->expectExceptionCode(self::STATUS_UNAUTHORIZED); + try { + $this->callApi(self::METHOD_GET, '/short-codes'); + } catch (ClientException $e) { + ['error' => $error, 'message' => $message] = json_decode((string) $e->getResponse()->getBody()); - $this->callApi(self::METHOD_GET, '/short-codes'); + $this->assertEquals(self::STATUS_UNAUTHORIZED, $e->getCode()); + $this->assertEquals(RestUtils::INVALID_AUTHORIZATION_ERROR, $error); + $this->assertEquals( + sprintf( + 'Expected one of the following authentication headers, but none were provided, ["%s"]', + implode('", "', RequestToHttpAuthPlugin::SUPPORTED_AUTH_HEADERS) + ), + $message + ); + } + } + + /** + * @test + */ + public function apiKeyErrorIsReturnedWhenProvidedApiKeyIsInvalid() + { + try { + $this->callApi(self::METHOD_GET, '/short-codes', [ + 'headers' => [ + ApiKeyHeaderPlugin::HEADER_NAME => 'invalid', + ], + ]); + } catch (ClientException $e) { + ['error' => $error, 'message' => $message] = json_decode((string) $e->getResponse()->getBody()); + + $this->assertEquals(self::STATUS_UNAUTHORIZED, $e->getCode()); + $this->assertEquals(RestUtils::INVALID_API_KEY_ERROR, $error); + $this->assertEquals('Provided API key does not exist or is invalid.', $message); + } } } From ce515767ce8dcaae5006096162f2b42088c0d74c Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 27 Jan 2019 10:56:14 +0100 Subject: [PATCH 08/10] Updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d570c89d..400083cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this The status code can be `200 OK` in case of success or `503 Service Unavailable` in case of error, while the `status` property will be one of `pass` or `fail`, as defined in the [Health check RFC](https://inadarei.github.io/rfc-healthcheck/). +* [#336](https://github.com/shlinkio/shlink/issues/336) Added an API test suite which performs API calls to an actual instance of the web service. + #### Changed * [#320](https://github.com/shlinkio/shlink/issues/320) Replaced query builder by plain DQL for all queries which do not need to be dynamically generated. From 05c7672de3a8c3f7f6b2c2d83de9a17a2a4af35a Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 27 Jan 2019 12:14:18 +0100 Subject: [PATCH 09/10] Improved API tests by adding fixtures --- composer.json | 1 + config/test/bootstrap_api_tests.php | 10 ++++- config/test/test_config.global.php | 6 +++ module/Common/test-db/TestHelper.php | 19 +++++++++ .../Rest/test-api/Fixtures/ApiKeyFixture.php | 36 ++++++++++++++++ .../test-api/Fixtures/ShortUrlsFixture.php | 41 +++++++++++++++++++ module/Rest/test-api/Fixtures/TagsFixture.php | 37 +++++++++++++++++ .../Rest/test-api/Fixtures/VisitsFixture.php | 35 ++++++++++++++++ .../Middleware/AuthenticationTest.php | 14 ++++++- 9 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 module/Rest/test-api/Fixtures/ApiKeyFixture.php create mode 100644 module/Rest/test-api/Fixtures/ShortUrlsFixture.php create mode 100644 module/Rest/test-api/Fixtures/TagsFixture.php create mode 100644 module/Rest/test-api/Fixtures/VisitsFixture.php diff --git a/composer.json b/composer.json index b8ce3e66..0c8af151 100644 --- a/composer.json +++ b/composer.json @@ -51,6 +51,7 @@ }, "require-dev": { "devster/ubench": "^2.0", + "doctrine/data-fixtures": "^1.3", "filp/whoops": "^2.0", "infection/infection": "^0.11.0", "phpstan/phpstan": "^0.10.0", diff --git a/config/test/bootstrap_api_tests.php b/config/test/bootstrap_api_tests.php index 6ccde6b7..c39042fa 100644 --- a/config/test/bootstrap_api_tests.php +++ b/config/test/bootstrap_api_tests.php @@ -3,6 +3,7 @@ declare(strict_types=1); namespace ShlinkioTest\Shlink\Common; +use Doctrine\ORM\EntityManager; use Psr\Container\ContainerInterface; use function file_exists; use function touch; @@ -14,5 +15,12 @@ if (! file_exists('.env')) { /** @var ContainerInterface $container */ $container = require __DIR__ . '/../container.php'; -$container->get(TestHelper::class)->createTestDb(); +$testHelper = $container->get(TestHelper::class); +$config = $container->get('config'); + +$testHelper->createTestDb(); + +$em = $container->get(EntityManager::class); +$testHelper->seedFixtures($em, $config['data_fixtures'] ?? []); + ApiTest\ApiTestCase::setApiClient($container->get('shlink_test_api_client')); diff --git a/config/test/test_config.global.php b/config/test/test_config.global.php index 79f36791..069268b5 100644 --- a/config/test/test_config.global.php +++ b/config/test/test_config.global.php @@ -41,4 +41,10 @@ return [ ], ], + 'data_fixtures' => [ + 'paths' => [ + __DIR__ . '/../../module/Rest/test-api/Fixtures', + ], + ], + ]; diff --git a/module/Common/test-db/TestHelper.php b/module/Common/test-db/TestHelper.php index 634456fc..fc24657d 100644 --- a/module/Common/test-db/TestHelper.php +++ b/module/Common/test-db/TestHelper.php @@ -3,6 +3,9 @@ declare(strict_types=1); namespace ShlinkioTest\Shlink\Common; +use Doctrine\Common\DataFixtures\Executor\ORMExecutor; +use Doctrine\Common\DataFixtures\Loader; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Process\Process; use function file_exists; use function realpath; @@ -22,4 +25,20 @@ class TestHelper $process->inheritEnvironmentVariables() ->mustRun(); } + + public function seedFixtures(EntityManagerInterface $em, array $config): void + { + $paths = $config['paths'] ?? []; + if (empty($paths)) { + return; + } + + $loader = new Loader(); + foreach ($paths as $path) { + $loader->loadFromDirectory($path); + } + + $executor = new ORMExecutor($em); + $executor->execute($loader->getFixtures(), true); + } } diff --git a/module/Rest/test-api/Fixtures/ApiKeyFixture.php b/module/Rest/test-api/Fixtures/ApiKeyFixture.php new file mode 100644 index 00000000..8990faa2 --- /dev/null +++ b/module/Rest/test-api/Fixtures/ApiKeyFixture.php @@ -0,0 +1,36 @@ +persist($this->buildApiKey('valid_api_key', true)); + $manager->persist($this->buildApiKey('disabled_api_key', false)); + $manager->persist($this->buildApiKey('expired_api_key', true, Chronos::now()->subDay())); + $manager->flush(); + } + + private function buildApiKey(string $key, bool $enabled, Chronos $expiresAt = null): ApiKey + { + $apiKey = new ApiKey($expiresAt); + $refObj = new ReflectionObject($apiKey); + $keyProp = $refObj->getProperty('key'); + $keyProp->setAccessible(true); + $keyProp->setValue($apiKey, $key); + + if (! $enabled) { + $apiKey->disable(); + } + + return $apiKey; + } +} diff --git a/module/Rest/test-api/Fixtures/ShortUrlsFixture.php b/module/Rest/test-api/Fixtures/ShortUrlsFixture.php new file mode 100644 index 00000000..438b819e --- /dev/null +++ b/module/Rest/test-api/Fixtures/ShortUrlsFixture.php @@ -0,0 +1,41 @@ +setShortCode('abc123'); + $manager->persist($abcShortUrl); + + $defShortUrl = (new ShortUrl( + 'https://shlink.io', + ShortUrlMeta::createFromParams(Chronos::now()->addDays(3)) + ))->setShortCode('def456'); + $manager->persist($defShortUrl); + + $customShortUrl = new ShortUrl( + 'https://shlink.io', + ShortUrlMeta::createFromParams(null, null, 'custom', 2) + ); + $manager->persist($customShortUrl); + + $manager->flush(); + + $this->addReference('abc123_short_url', $abcShortUrl); + $this->addReference('def456_short_url', $defShortUrl); + } +} diff --git a/module/Rest/test-api/Fixtures/TagsFixture.php b/module/Rest/test-api/Fixtures/TagsFixture.php new file mode 100644 index 00000000..c5e84648 --- /dev/null +++ b/module/Rest/test-api/Fixtures/TagsFixture.php @@ -0,0 +1,37 @@ +persist($fooTag); + $barTag = new Tag('bar'); + $manager->persist($barTag); + + /** @var ShortUrl $abcShortUrl */ + $abcShortUrl = $this->getReference('abc123_short_url'); + $abcShortUrl->setTags(new ArrayCollection([$fooTag])); + + /** @var ShortUrl $defShortUrl */ + $defShortUrl = $this->getReference('def456_short_url'); + $defShortUrl->setTags(new ArrayCollection([$fooTag, $barTag])); + + $manager->flush(); + } +} diff --git a/module/Rest/test-api/Fixtures/VisitsFixture.php b/module/Rest/test-api/Fixtures/VisitsFixture.php new file mode 100644 index 00000000..cd9cabfd --- /dev/null +++ b/module/Rest/test-api/Fixtures/VisitsFixture.php @@ -0,0 +1,35 @@ +getReference('abc123_short_url'); + $manager->persist(new Visit($abcShortUrl, new Visitor('shlink-tests-agent', '', '44.55.66.77'))); + $manager->persist(new Visit($abcShortUrl, new Visitor('shlink-tests-agent', 'https://google.com', '4.5.6.7'))); + $manager->persist(new Visit($abcShortUrl, new Visitor('shlink-tests-agent', '', '1.2.3.4'))); + + /** @var ShortUrl $defShortUrl */ + $defShortUrl = $this->getReference('def456_short_url'); + $manager->persist(new Visit($defShortUrl, new Visitor('shlink-tests-agent', '', '127.0.0.1'))); + $manager->persist(new Visit($defShortUrl, new Visitor('shlink-tests-agent', 'https://app.shlink.io', ''))); + + $manager->flush(); + } +} diff --git a/module/Rest/test-api/Middleware/AuthenticationTest.php b/module/Rest/test-api/Middleware/AuthenticationTest.php index 1e5dea06..a4692b9d 100644 --- a/module/Rest/test-api/Middleware/AuthenticationTest.php +++ b/module/Rest/test-api/Middleware/AuthenticationTest.php @@ -38,13 +38,14 @@ class AuthenticationTest extends ApiTestCase /** * @test + * @dataProvider provideInvalidApiKeys */ - public function apiKeyErrorIsReturnedWhenProvidedApiKeyIsInvalid() + public function apiKeyErrorIsReturnedWhenProvidedApiKeyIsInvalid(string $apiKey) { try { $this->callApi(self::METHOD_GET, '/short-codes', [ 'headers' => [ - ApiKeyHeaderPlugin::HEADER_NAME => 'invalid', + ApiKeyHeaderPlugin::HEADER_NAME => $apiKey, ], ]); } catch (ClientException $e) { @@ -55,4 +56,13 @@ class AuthenticationTest extends ApiTestCase $this->assertEquals('Provided API key does not exist or is invalid.', $message); } } + + public function provideInvalidApiKeys(): array + { + return [ + 'key which does not exist' => ['invalid'], + 'key which is expired' => ['expired_api_key'], + 'key which is disabled' => ['disabled_api_key'], + ]; + } } From d6a7a6ce667d578c9103e3b4a0b6aa11a1ad1932 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 27 Jan 2019 12:35:00 +0100 Subject: [PATCH 10/10] Created new API test --- config/test/test_config.global.php | 7 ++ module/Common/test-db/ApiTest/ApiTestCase.php | 19 ++++++ .../test-api/Action/ListShortUrlsTest.php | 64 +++++++++++++++++++ .../test-api/Fixtures/ShortUrlsFixture.php | 21 ++++-- .../Middleware/AuthenticationTest.php | 2 +- 5 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 module/Rest/test-api/Action/ListShortUrlsTest.php diff --git a/config/test/test_config.global.php b/config/test/test_config.global.php index 069268b5..3de2584e 100644 --- a/config/test/test_config.global.php +++ b/config/test/test_config.global.php @@ -14,6 +14,13 @@ return [ 'debug' => true, ConfigAggregator::ENABLE_CACHE => false, + 'url_shortener' => [ + 'domain' => [ + 'schema' => 'http', + 'hostname' => 'doma.in', + ], + ], + 'zend-expressive-swoole' => [ 'swoole-http-server' => [ 'port' => 9999, diff --git a/module/Common/test-db/ApiTest/ApiTestCase.php b/module/Common/test-db/ApiTest/ApiTestCase.php index 1aae1065..29959837 100644 --- a/module/Common/test-db/ApiTest/ApiTestCase.php +++ b/module/Common/test-db/ApiTest/ApiTestCase.php @@ -8,6 +8,8 @@ use Fig\Http\Message\StatusCodeInterface; use GuzzleHttp\ClientInterface; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; +use Shlinkio\Shlink\Rest\Authentication\Plugin\ApiKeyHeaderPlugin; +use function Shlinkio\Shlink\Common\json_decode; use function sprintf; abstract class ApiTestCase extends TestCase implements StatusCodeInterface, RequestMethodInterface @@ -29,4 +31,21 @@ abstract class ApiTestCase extends TestCase implements StatusCodeInterface, Requ { return self::$client->request($method, sprintf('%s%s', self::PATH_PREFX, $uri), $options); } + + /** + * @throws \GuzzleHttp\Exception\GuzzleException + */ + protected function callApiWithKey(string $method, string $uri, array $options = []): ResponseInterface + { + $headers = $options['headers'] ?? []; + $headers[ApiKeyHeaderPlugin::HEADER_NAME] = 'valid_api_key'; + $options['headers'] = $headers; + + return $this->callApi($method, $uri, $options); + } + + protected function getJsonResponsePayload(ResponseInterface $resp): array + { + return json_decode((string) $resp->getBody()); + } } diff --git a/module/Rest/test-api/Action/ListShortUrlsTest.php b/module/Rest/test-api/Action/ListShortUrlsTest.php new file mode 100644 index 00000000..3e63da8b --- /dev/null +++ b/module/Rest/test-api/Action/ListShortUrlsTest.php @@ -0,0 +1,64 @@ +callApiWithKey(self::METHOD_GET, '/short-urls'); + $respPayload = $this->getJsonResponsePayload($resp); + + $this->assertEquals(self::STATUS_OK, $resp->getStatusCode()); + $this->assertEquals([ + 'shortUrls' => [ + 'data' => [ + [ + 'shortCode' => 'abc123', + 'shortUrl' => 'http://doma.in/abc123', + 'longUrl' => 'https://shlink.io', + 'dateCreated' => '2019-01-01T00:00:00+00:00', + 'visitsCount' => 3, + 'tags' => ['foo'], + 'originalUrl' => 'https://shlink.io', + ], + [ + 'shortCode' => 'def456', + 'shortUrl' => 'http://doma.in/def456', + 'longUrl' => + 'https://blog.alejandrocelaya.com/2017/12/09' + . '/acmailer-7-0-the-most-important-release-in-a-long-time/', + 'dateCreated' => '2019-01-01T00:00:00+00:00', + 'visitsCount' => 2, + 'tags' => ['foo', 'bar'], + 'originalUrl' => + 'https://blog.alejandrocelaya.com/2017/12/09' + . '/acmailer-7-0-the-most-important-release-in-a-long-time/', + ], + [ + 'shortCode' => 'custom', + 'shortUrl' => 'http://doma.in/custom', + 'longUrl' => 'https://shlink.io', + 'dateCreated' => '2019-01-01T00:00:00+00:00', + 'visitsCount' => 0, + 'tags' => [], + 'originalUrl' => 'https://shlink.io', + ], + ], + 'pagination' => [ + 'currentPage' => 1, + 'pagesCount' => 1, + 'itemsPerPage' => 10, + 'itemsInCurrentPage' => 3, + 'totalItems' => 3, + ], + ], + ], $respPayload); + } +} diff --git a/module/Rest/test-api/Fixtures/ShortUrlsFixture.php b/module/Rest/test-api/Fixtures/ShortUrlsFixture.php index 438b819e..62c16c74 100644 --- a/module/Rest/test-api/Fixtures/ShortUrlsFixture.php +++ b/module/Rest/test-api/Fixtures/ShortUrlsFixture.php @@ -6,6 +6,7 @@ namespace ShlinkioApiTest\Shlink\Rest\Fixtures; use Cake\Chronos\Chronos; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\Persistence\ObjectManager; +use ReflectionObject; use Shlinkio\Shlink\Core\Entity\ShortUrl; use Shlinkio\Shlink\Core\Model\ShortUrlMeta; @@ -18,19 +19,19 @@ class ShortUrlsFixture extends AbstractFixture */ public function load(ObjectManager $manager): void { - $abcShortUrl = (new ShortUrl('https://shlink.io'))->setShortCode('abc123'); + $abcShortUrl = $this->setShortUrlDate(new ShortUrl('https://shlink.io'))->setShortCode('abc123'); $manager->persist($abcShortUrl); - $defShortUrl = (new ShortUrl( - 'https://shlink.io', + $defShortUrl = $this->setShortUrlDate(new ShortUrl( + 'https://blog.alejandrocelaya.com/2017/12/09/acmailer-7-0-the-most-important-release-in-a-long-time/', ShortUrlMeta::createFromParams(Chronos::now()->addDays(3)) ))->setShortCode('def456'); $manager->persist($defShortUrl); - $customShortUrl = new ShortUrl( + $customShortUrl = $this->setShortUrlDate(new ShortUrl( 'https://shlink.io', ShortUrlMeta::createFromParams(null, null, 'custom', 2) - ); + )); $manager->persist($customShortUrl); $manager->flush(); @@ -38,4 +39,14 @@ class ShortUrlsFixture extends AbstractFixture $this->addReference('abc123_short_url', $abcShortUrl); $this->addReference('def456_short_url', $defShortUrl); } + + private function setShortUrlDate(ShortUrl $shortUrl): ShortUrl + { + $ref = new ReflectionObject($shortUrl); + $dateProp = $ref->getProperty('dateCreated'); + $dateProp->setAccessible(true); + $dateProp->setValue($shortUrl, Chronos::create(2019, 1, 1, 0, 0, 0)); + + return $shortUrl; + } } diff --git a/module/Rest/test-api/Middleware/AuthenticationTest.php b/module/Rest/test-api/Middleware/AuthenticationTest.php index a4692b9d..c87b3c01 100644 --- a/module/Rest/test-api/Middleware/AuthenticationTest.php +++ b/module/Rest/test-api/Middleware/AuthenticationTest.php @@ -22,7 +22,7 @@ class AuthenticationTest extends ApiTestCase try { $this->callApi(self::METHOD_GET, '/short-codes'); } catch (ClientException $e) { - ['error' => $error, 'message' => $message] = json_decode((string) $e->getResponse()->getBody()); + ['error' => $error, 'message' => $message] = $this->getJsonResponsePayload($e->getResponse()); $this->assertEquals(self::STATUS_UNAUTHORIZED, $e->getCode()); $this->assertEquals(RestUtils::INVALID_AUTHORIZATION_ERROR, $error);