Skip to content

Commit 1d05399

Browse files
committed
Add infra necessary to run API tests with specific server config
1 parent 51dd671 commit 1d05399

File tree

11 files changed

+171
-3
lines changed

11 files changed

+171
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ data/infra/matomo
1313
docs/mercure.html
1414
.phpunit.result.cache
1515
docs/swagger/openapi-inlined.json
16+
config/test/dynamic_test_env.php

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@
7474
"shlinkio/php-coding-standard": "~2.4.2",
7575
"shlinkio/shlink-test-utils": "^4.3.1",
7676
"symfony/var-dumper": "^7.3",
77-
"veewee/composer-run-parallel": "^1.4"
77+
"veewee/composer-run-parallel": "^1.4",
78+
"webimpress/safe-writer": "^2.2"
7879
},
7980
"conflict": {
8081
"symfony/var-exporter": ">=6.3.9,<=6.4.0"

config/container.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
require 'vendor/autoload.php';
1818

19+
// Promote env vars from dynamic test config
20+
loadEnvVarsFromConfig('config/test/dynamic_test_env.php', enumValues(EnvVars::class));
1921
// Promote env vars from installer, dev config or test config
2022
loadEnvVarsFromConfig(
2123
EnvVars::isTestEnv() ? 'config/test/shlink_test_env.php' : 'config/params/*.php',

config/test/constants.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@
1919
. 'Version/18.4 Safari/605.1.15';
2020
const CHROMEOS_USER_AGENT = 'Mozilla/5.0 (X11; CrOS x86_64 16181.61.0) AppleWebKit/537.36 (KHTML, like Gecko) '
2121
. 'Chrome/134.0.6998.198 Safari/537.36';
22+
23+
const DYNAMIC_ENV_VARS_FILE = __DIR__ . '/../../config/test/dynamic_test_env.php';
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ShlinkioApiTest\Shlink\Rest\Action;
6+
7+
use PHPUnit\Framework\Attributes\Test;
8+
use Shlinkio\Shlink\Core\Config\EnvVars;
9+
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
10+
use ShlinkioApiTest\Shlink\Rest\Utils\WithEnvVars;
11+
12+
class MercureInfoTest extends ApiTestCase
13+
{
14+
#[Test]
15+
public function mercureServerInfoIsReturnedIfConfigured(): void
16+
{
17+
$resp = $this->callApiWithKey('GET', '/mercure-info');
18+
self::assertEquals(501, $resp->getStatusCode());
19+
}
20+
21+
#[Test, WithEnvVars([
22+
EnvVars::MERCURE_ENABLED->value => true,
23+
EnvVars::MERCURE_PUBLIC_HUB_URL->value => 'https://mercure.example.com',
24+
EnvVars::MERCURE_JWT_SECRET->value => 'mercure_jwt_key_long_enough_to_avoid_error',
25+
])]
26+
public function errorIsReturnedIfMercureServerIsNotConfigured(): void
27+
{
28+
$resp = $this->callApiWithKey('GET', '/mercure-info');
29+
$payload = $this->getJsonResponsePayload($resp);
30+
31+
self::assertEquals(200, $resp->getStatusCode());
32+
self::assertEquals('https://mercure.example.com/.well-known/mercure', $payload['mercureHubUrl']);
33+
}
34+
}

module/Rest/test-api/Middleware/CorsTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ public function preflightRequestsIncludeExtraCorsHeaders(string $endpoint, strin
5959
]);
6060

6161
self::assertEquals(204, $resp->getStatusCode());
62-
self::assertTrue($resp->hasHeader('Access-Control-Allow-Origin'));
63-
self::assertTrue($resp->hasHeader('Access-Control-Max-Age'));
62+
self::assertEquals('*', $resp->getHeaderLine('Access-Control-Allow-Origin'));
63+
self::assertEquals('3600', $resp->getHeaderLine('Access-Control-Max-Age'));
6464
self::assertEquals($expectedAllowedMethods, $resp->getHeaderLine('Access-Control-Allow-Methods'));
6565
self::assertEquals($allowedHeaders, $resp->getHeaderLine('Access-Control-Allow-Headers'));
6666
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ShlinkioApiTest\Shlink\Rest\Utils;
6+
7+
use PHPUnit\Runner\Extension\Extension;
8+
use PHPUnit\Runner\Extension\Facade;
9+
use PHPUnit\Runner\Extension\ParameterCollection;
10+
use PHPUnit\TextUI\Configuration\Configuration;
11+
12+
class ApiTestsExtension implements Extension
13+
{
14+
public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void
15+
{
16+
$facade->registerSubscriber(new EnvSpecificTestListener());
17+
$facade->registerSubscriber(new CleanDynamicEnvVarsTestListener());
18+
}
19+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ShlinkioApiTest\Shlink\Rest\Utils;
6+
7+
use PHPUnit\Event\Test\Finished;
8+
use PHPUnit\Event\Test\FinishedSubscriber;
9+
use Symfony\Component\Process\Process;
10+
11+
use function file_exists;
12+
use function unlink;
13+
14+
use const ShlinkioTest\Shlink\DYNAMIC_ENV_VARS_FILE;
15+
16+
/**
17+
* Tries to delete the dynamic env vars after a test has finished, if any, so that it does not affect subsequent tests
18+
*/
19+
class CleanDynamicEnvVarsTestListener implements FinishedSubscriber
20+
{
21+
public function notify(Finished $event): void
22+
{
23+
if (file_exists(DYNAMIC_ENV_VARS_FILE)) {
24+
unlink(DYNAMIC_ENV_VARS_FILE);
25+
// Restart server again so that it removes the env vars from the file that has just been deleted
26+
(new Process(['bin/rr', 'reset', '-c=config/roadrunner/.rr.test.yml']))->mustRun();
27+
}
28+
}
29+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ShlinkioApiTest\Shlink\Rest\Utils;
6+
7+
use PHPUnit\Event\Test\PreparationStarted;
8+
use PHPUnit\Event\Test\PreparationStartedSubscriber;
9+
use ReflectionMethod;
10+
use Symfony\Component\Process\Process;
11+
use Webimpress\SafeWriter\FileWriter;
12+
13+
use function sprintf;
14+
use function var_export;
15+
16+
use const ShlinkioTest\Shlink\DYNAMIC_ENV_VARS_FILE;
17+
18+
/**
19+
* Checks if a test to be executed has the WithEnvVars attribute, and if so, creates a file with the env vars it defines
20+
* and restarts RoadRunner test server so that those env vars are applied.
21+
*/
22+
class EnvSpecificTestListener implements PreparationStartedSubscriber
23+
{
24+
public function notify(PreparationStarted $event): void
25+
{
26+
$test = $event->test();
27+
$className = $test->className();
28+
$methodName = $test->methodName();
29+
30+
$reflection = new ReflectionMethod($className, $methodName);
31+
$attributes = $reflection->getAttributes(WithEnvVars::class);
32+
33+
// If the method has the attribute, generate a temporary env file, and restart the RoadRunner server
34+
if (! empty($attributes)) {
35+
/** @var WithEnvVars $withEnvVars */
36+
$withEnvVars = $attributes[0]->newInstance();
37+
$this->createDynamicEnvVarsFile($withEnvVars->envVars);
38+
$this->restartServer();
39+
}
40+
}
41+
42+
private function createDynamicEnvVarsFile(array $envVars): void
43+
{
44+
$template = <<<TEMPLATE
45+
<?php
46+
47+
/* Shlink config generated by %s */
48+
49+
return %s;
50+
51+
TEMPLATE;
52+
$content = sprintf($template, self::class, var_export($envVars, return: true));
53+
54+
FileWriter::writeFile(DYNAMIC_ENV_VARS_FILE, $content);
55+
}
56+
57+
private function restartServer(): void
58+
{
59+
(new Process(['bin/rr', 'reset', '-c=config/roadrunner/.rr.test.yml']))->mustRun();
60+
}
61+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ShlinkioApiTest\Shlink\Rest\Utils;
6+
7+
use Attribute;
8+
9+
#[Attribute(Attribute::TARGET_METHOD)]
10+
final readonly class WithEnvVars
11+
{
12+
public function __construct(public array $envVars)
13+
{
14+
}
15+
}

0 commit comments

Comments
 (0)