From 29b90457f385171416678e057a18db4eb6569dad Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Wed, 23 Jul 2025 08:13:00 +0200 Subject: [PATCH 1/4] Add infra necessary to run API tests with specific server config --- .gitignore | 1 + composer.json | 3 +- config/container.php | 2 + config/test/constants.php | 18 +----- .../Rest/test-api/Action/MercureInfoTest.php | 34 +++++++++++ module/Rest/test-api/Middleware/CorsTest.php | 4 +- .../Rest/test-api/Utils/ApiTestsExtension.php | 19 ++++++ .../Utils/CleanDynamicEnvVarsTestListener.php | 29 +++++++++ .../Utils/EnvSpecificTestListener.php | 61 +++++++++++++++++++ module/Rest/test-api/Utils/WithEnvVars.php | 15 +++++ phpunit-api.xml | 4 ++ 11 files changed, 170 insertions(+), 20 deletions(-) create mode 100644 module/Rest/test-api/Action/MercureInfoTest.php create mode 100644 module/Rest/test-api/Utils/ApiTestsExtension.php create mode 100644 module/Rest/test-api/Utils/CleanDynamicEnvVarsTestListener.php create mode 100644 module/Rest/test-api/Utils/EnvSpecificTestListener.php create mode 100644 module/Rest/test-api/Utils/WithEnvVars.php diff --git a/.gitignore b/.gitignore index 4061960bb..414fc83b4 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ data/infra/matomo docs/mercure.html .phpunit.result.cache docs/swagger/openapi-inlined.json +config/test/dynamic_test_env.php diff --git a/composer.json b/composer.json index 2bc071d16..d61304080 100644 --- a/composer.json +++ b/composer.json @@ -72,7 +72,8 @@ "shlinkio/shlink-mago-config": "^1.0", "shlinkio/shlink-test-utils": "^4.5", "symfony/var-dumper": "^8.1", - "veewee/composer-run-parallel": "^1.5" + "veewee/composer-run-parallel": "^1.5", + "webimpress/safe-writer": "^2.2" }, "autoload": { "psr-4": { diff --git a/config/container.php b/config/container.php index 5ccccfa9d..8ad0f651f 100644 --- a/config/container.php +++ b/config/container.php @@ -16,6 +16,8 @@ require 'vendor/autoload.php'; +// Promote env vars from dynamic test config +loadEnvVarsFromConfig('config/test/dynamic_test_env.php', enumValues(EnvVars::class)); // Promote env vars from installer, dev config or test config loadEnvVarsFromConfig( EnvVars::isTestEnv() ? 'config/test/shlink_test_env.php' : 'config/params/*.php', diff --git a/config/test/constants.php b/config/test/constants.php index 7610f2f96..e447f58ae 100644 --- a/config/test/constants.php +++ b/config/test/constants.php @@ -32,20 +32,4 @@ 'Mozilla/5.0 (X11; CrOS x86_64 16181.61.0) AppleWebKit/537.36 (KHTML, like Gecko) ' . 'Chrome/134.0.6998.198 Safari/537.36'; -const BROWSER_CHROME_USER_AGENT = - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' - . 'Chrome/146.0.0.0 Safari/537.36'; - -const BROWSER_FIREFOX_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0'; - -const BROWSER_EDGE_USER_AGENT = - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' - . 'Chrome/146.0.0.0 Safari/537.36 Edg/146.0.3856.62'; - -const BROWSER_SAFARI_USER_AGENT = - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 15_7_4) AppleWebKit/605.1.15 ' - . '(KHTML, like Gecko) Version/26.0 Safari/605.1.15'; - -const BROWSER_OPERA_USER_AGENT = - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' - . 'Chrome/146.0.0.0 Safari/537.36 OPR/128.0.0.0'; +const DYNAMIC_ENV_VARS_FILE = __DIR__ . '/../../config/test/dynamic_test_env.php'; diff --git a/module/Rest/test-api/Action/MercureInfoTest.php b/module/Rest/test-api/Action/MercureInfoTest.php new file mode 100644 index 000000000..6bb1c0bb4 --- /dev/null +++ b/module/Rest/test-api/Action/MercureInfoTest.php @@ -0,0 +1,34 @@ +callApiWithKey('GET', '/mercure-info'); + self::assertEquals(501, $resp->getStatusCode()); + } + + #[Test, WithEnvVars([ + EnvVars::MERCURE_ENABLED->value => true, + EnvVars::MERCURE_PUBLIC_HUB_URL->value => 'https://mercure.example.com', + EnvVars::MERCURE_JWT_SECRET->value => 'mercure_jwt_key_long_enough_to_avoid_error', + ])] + public function errorIsReturnedIfMercureServerIsNotConfigured(): void + { + $resp = $this->callApiWithKey('GET', '/mercure-info'); + $payload = $this->getJsonResponsePayload($resp); + + self::assertEquals(200, $resp->getStatusCode()); + self::assertEquals('https://mercure.example.com/.well-known/mercure', $payload['mercureHubUrl']); + } +} diff --git a/module/Rest/test-api/Middleware/CorsTest.php b/module/Rest/test-api/Middleware/CorsTest.php index 4ed3f2cbc..1f022d385 100644 --- a/module/Rest/test-api/Middleware/CorsTest.php +++ b/module/Rest/test-api/Middleware/CorsTest.php @@ -61,8 +61,8 @@ public function preflightRequestsIncludeExtraCorsHeaders(string $endpoint, strin ]); self::assertEquals(204, $resp->getStatusCode()); - self::assertTrue($resp->hasHeader('Access-Control-Allow-Origin')); - self::assertTrue($resp->hasHeader('Access-Control-Max-Age')); + self::assertEquals('*', $resp->getHeaderLine('Access-Control-Allow-Origin')); + self::assertEquals('3600', $resp->getHeaderLine('Access-Control-Max-Age')); self::assertEquals($expectedAllowedMethods, $resp->getHeaderLine('Access-Control-Allow-Methods')); self::assertEquals($allowedHeaders, $resp->getHeaderLine('Access-Control-Allow-Headers')); } diff --git a/module/Rest/test-api/Utils/ApiTestsExtension.php b/module/Rest/test-api/Utils/ApiTestsExtension.php new file mode 100644 index 000000000..2b57a07d4 --- /dev/null +++ b/module/Rest/test-api/Utils/ApiTestsExtension.php @@ -0,0 +1,19 @@ +registerSubscriber(new EnvSpecificTestListener()); + $facade->registerSubscriber(new CleanDynamicEnvVarsTestListener()); + } +} diff --git a/module/Rest/test-api/Utils/CleanDynamicEnvVarsTestListener.php b/module/Rest/test-api/Utils/CleanDynamicEnvVarsTestListener.php new file mode 100644 index 000000000..f2a766e3a --- /dev/null +++ b/module/Rest/test-api/Utils/CleanDynamicEnvVarsTestListener.php @@ -0,0 +1,29 @@ +mustRun(); + } + } +} diff --git a/module/Rest/test-api/Utils/EnvSpecificTestListener.php b/module/Rest/test-api/Utils/EnvSpecificTestListener.php new file mode 100644 index 000000000..ba33ebd0b --- /dev/null +++ b/module/Rest/test-api/Utils/EnvSpecificTestListener.php @@ -0,0 +1,61 @@ +test(); + $className = $test->className(); + $methodName = $test->methodName(); + + $reflection = new ReflectionMethod($className, $methodName); + $attributes = $reflection->getAttributes(WithEnvVars::class); + + // If the method has the attribute, generate a temporary env file, and restart the RoadRunner server + if (! empty($attributes)) { + /** @var WithEnvVars $withEnvVars */ + $withEnvVars = $attributes[0]->newInstance(); + $this->createDynamicEnvVarsFile($withEnvVars->envVars); + $this->restartServer(); + } + } + + private function createDynamicEnvVarsFile(array $envVars): void + { + $template = <<