From f2b6eda96c7ea837bfa8b7e9991154c9444e850c Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Wed, 23 Jul 2025 08:13:00 +0200 Subject: [PATCH 1/2] Add infra necessary to run API tests with specific server config --- .gitignore | 1 + composer.json | 3 +- config/container.php | 2 + config/test/constants.php | 2 + .../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, 171 insertions(+), 3 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 f04124d4d..3152018dd 100644 --- a/composer.json +++ b/composer.json @@ -74,7 +74,8 @@ "shlinkio/php-coding-standard": "~2.5.0", "shlinkio/shlink-test-utils": "^4.3.1", "symfony/var-dumper": "^7.3", - "veewee/composer-run-parallel": "^1.4" + "veewee/composer-run-parallel": "^1.4", + "webimpress/safe-writer": "^2.2" }, "conflict": { "symfony/var-exporter": ">=6.3.9,<=6.4.0" diff --git a/config/container.php b/config/container.php index 31e406a3d..842aa9932 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 f2ad124d6..dee3d5950 100644 --- a/config/test/constants.php +++ b/config/test/constants.php @@ -19,3 +19,5 @@ . 'Version/18.4 Safari/605.1.15'; const CHROMEOS_USER_AGENT = '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 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 = <<