diff --git a/composer.json b/composer.json index 50577c41..782fd2b9 100644 --- a/composer.json +++ b/composer.json @@ -37,11 +37,11 @@ "php-http/mock-client": "^1.6.0", "symfony/process": "^6.4|| ^7.0", "symfony/http-kernel": "^6.4|| ^7.0", - "phpunit/phpunit": "^9" + "phpunit/phpunit": "^10.5" }, "conflict": { "toflar/psr6-symfony-http-cache-store": "<2.2.1", - "phpunit/phpunit": "<8" + "phpunit/phpunit": "<10" }, "suggest": { "friendsofsymfony/http-cache-bundle": "For integration with the Symfony framework", diff --git a/doc/testing-your-application.rst b/doc/testing-your-application.rst index 231d2d36..eb15d6ae 100644 --- a/doc/testing-your-application.rst +++ b/doc/testing-your-application.rst @@ -36,19 +36,19 @@ Web Server You will need to run a web server to provide the PHP application you want to test. The test cases only handle running the proxy server. It’s easiest to -use PHP’s built in web server. Include the WebServerListener in your -``phpunit.xml``: +use PHP’s built in web server. Include the WebServerSubscriber in your +``phpunit.xml``, either using the extension provided by this package or your own: .. literalinclude:: ../phpunit.xml.dist :prepend: - + :language: xml - :start-after: - :end-before: + :start-after: + :end-before: :append: - + Then set the ``webserver`` group on your test to start PHP’s web server before diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 30158d09..45a42c5c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,31 +1,31 @@ - - - - - ./tests/ - - - - - ./src - - + + + ./tests/ + + - - - + + + - - - - - + + + + + + + + + ./src + + diff --git a/src/Test/Legacy/WebServerListener.php b/src/Test/Legacy/WebServerListener.php deleted file mode 100644 index 69fe98d9..00000000 --- a/src/Test/Legacy/WebServerListener.php +++ /dev/null @@ -1,145 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FOS\HttpCache\Test\Legacy; - -use FOS\HttpCache\Test\WebServerListenerTrait; -use PHPUnit\Framework\TestListener; - -/** - * A PHPUnit test listener that starts and stops the PHP built-in web server. - * - * This legacy version is for PHPUnit 5.x (min 5.4.4 required, due to FC layer). - * - * This listener is configured with a couple of constants from the phpunit.xml - * file. To define constants in the phpunit file, use this syntax: - * - * - * - * - * WEB_SERVER_HOSTNAME host name of the web server (required) - * WEB_SERVER_PORT port to listen on (required) - * WEB_SERVER_DOCROOT path to the document root for the server (required) - */ -class WebServerListener implements TestListener -{ - /** @var WebServerListenerTrait */ - private $trait; - - public function __construct() - { - $this->trait = new WebServerListenerTrait(); - } - - /** - * Make sure the PHP built-in web server is running for tests with group - * 'webserver'. - */ - public function startTestSuite(\PHPUnit_Framework_TestSuite $suite) - { - $this->trait->startTestSuite($suite); - } - - /** - * We don't need these. - */ - public function endTestSuite(\PHPUnit_Framework_TestSuite $suite) - { - } - - public function addError(\PHPUnit_Framework_Test $test, \Exception $e, $time) - { - } - - public function addFailure(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_AssertionFailedError $e, $time) - { - } - - public function addIncompleteTest(\PHPUnit_Framework_Test $test, \Exception $e, $time) - { - } - - public function addSkippedTest(\PHPUnit_Framework_Test $test, \Exception $e, $time) - { - } - - public function startTest(\PHPUnit_Framework_Test $test) - { - } - - public function endTest(\PHPUnit_Framework_Test $test, $time) - { - } - - public function addRiskyTest(\PHPUnit_Framework_Test $test, \Exception $e, $time) - { - } - - /** - * Get web server hostname. - * - * @return string - * - * @throws \Exception - */ - protected function getHostName() - { - return $this->trait->getHostName(); - } - - /** - * Get web server port. - * - * @return int - * - * @throws \Exception - */ - protected function getPort() - { - return $this->trait->getPort(); - } - - /** - * Get web server port. - * - * @return int - * - * @throws \Exception - */ - protected function getDocRoot() - { - return $this->trait->getDocRoot(); - } - - /** - * Start PHP built-in web server. - * - * @return int PID - */ - protected function startPhpWebServer() - { - return $this->trait->startPhpWebServer(); - } - - /** - * Wait for caching proxy to be started up and reachable. - * - * @param string $ip - * @param int $port - * @param int $timeout Timeout in milliseconds - * - * @throws \RuntimeException If proxy is not reachable within timeout - */ - protected function waitFor($ip, $port, $timeout) - { - $this->trait->waitFor($ip, $port, $timeout); - } -} diff --git a/src/Test/Legacy/WebServerListener6.php b/src/Test/Legacy/WebServerListener6.php deleted file mode 100644 index 4689e5ba..00000000 --- a/src/Test/Legacy/WebServerListener6.php +++ /dev/null @@ -1,153 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FOS\HttpCache\Test\Legacy; - -use FOS\HttpCache\Test\WebServerListenerTrait; -use PHPUnit\Framework\AssertionFailedError; -use PHPUnit\Framework\Test; -use PHPUnit\Framework\TestListener; -use PHPUnit\Framework\TestSuite; -use PHPUnit\Framework\Warning; - -/** - * A PHPUnit test listener that starts and stops the PHP built-in web server. - * - * This legacy version is for PHPUnit 6.x. - * - * This listener is configured with a couple of constants from the phpunit.xml - * file. To define constants in the phpunit file, use this syntax: - * - * - * - * - * WEB_SERVER_HOSTNAME host name of the web server (required) - * WEB_SERVER_PORT port to listen on (required) - * WEB_SERVER_DOCROOT path to the document root for the server (required) - */ -class WebServerListener6 implements TestListener -{ - /** @var WebServerListenerTrait */ - private $trait; - - public function __construct() - { - $this->trait = new WebServerListenerTrait(); - } - - /** - * Make sure the PHP built-in web server is running for tests with group - * 'webserver'. - */ - public function startTestSuite(TestSuite $suite) - { - $this->trait->startTestSuite($suite); - } - - /** - * We don't need these. - */ - public function endTestSuite(TestSuite $suite) - { - } - - public function addError(Test $test, \Exception $e, $time) - { - } - - public function addFailure(Test $test, AssertionFailedError $e, $time) - { - } - - public function addIncompleteTest(Test $test, \Exception $e, $time) - { - } - - public function addSkippedTest(Test $test, \Exception $e, $time) - { - } - - public function startTest(Test $test) - { - } - - public function endTest(Test $test, $time) - { - } - - public function addRiskyTest(Test $test, \Exception $e, $time) - { - } - - public function addWarning(Test $test, Warning $e, $time) - { - } - - /** - * Get web server hostname. - * - * @return string - * - * @throws \Exception - */ - protected function getHostName() - { - return $this->trait->getHostName(); - } - - /** - * Get web server port. - * - * @return int - * - * @throws \Exception - */ - protected function getPort() - { - return $this->trait->getPort(); - } - - /** - * Get web server port. - * - * @return int - * - * @throws \Exception - */ - protected function getDocRoot() - { - return $this->trait->getDocRoot(); - } - - /** - * Start PHP built-in web server. - * - * @return int PID - */ - protected function startPhpWebServer() - { - return $this->trait->startPhpWebServer(); - } - - /** - * Wait for caching proxy to be started up and reachable. - * - * @param string $ip - * @param int $port - * @param int $timeout Timeout in milliseconds - * - * @throws \RuntimeException If proxy is not reachable within timeout - */ - protected function waitFor($ip, $port, $timeout) - { - $this->trait->waitFor($ip, $port, $timeout); - } -} diff --git a/src/Test/WebServerListener.php b/src/Test/WebServerListener.php deleted file mode 100644 index c630bd01..00000000 --- a/src/Test/WebServerListener.php +++ /dev/null @@ -1,162 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace FOS\HttpCache\Test; - -use FOS\HttpCache\Test\Legacy\WebServerListener6; -use PHPUnit\Framework\AssertionFailedError; -use PHPUnit\Framework\Test; -use PHPUnit\Framework\TestListener as TestListenerInterface; -use PHPUnit\Framework\TestSuite; -use PHPUnit\Framework\Warning; -use PHPUnit\Runner\Version; - -if (class_exists(\PHPUnit_Runner_Version::class) && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { - /* - * Using an early return instead of a else does not work when using the PHPUnit phar due to some weird PHP behavior - * (the class gets defined without executing the code before it and so the definition is not properly conditional) - */ - class_alias('FOS\HttpCache\Test\Legacy\WebServerListener', 'FOS\HttpCache\Test\WebServerListener'); -} elseif (version_compare(Version::id(), '7.0.0', '<')) { - class_alias(WebServerListener6::class, 'FOS\HttpCache\Test\WebServerListener'); -} else { - /** - * A PHPUnit test listener that starts and stops the PHP built-in web server. - * - * This listener is configured with a couple of constants from the phpunit.xml - * file. To define constants in the phpunit file, use this syntax: - * - * - * - * - * WEB_SERVER_HOSTNAME host name of the web server (required) - * WEB_SERVER_PORT port to listen on (required) - * WEB_SERVER_DOCROOT path to the document root for the server (required) - */ - class WebServerListener implements TestListenerInterface - { - /** @var WebServerListenerTrait */ - private $trait; - - public function __construct() - { - $this->trait = new WebServerListenerTrait(); - } - - /** - * Make sure the PHP built-in web server is running for tests with group - * 'webserver'. - */ - public function startTestSuite(TestSuite $suite): void - { - $this->trait->startTestSuite($suite); - } - - /** - * We don't need these. - */ - public function endTestSuite(TestSuite $suite): void - { - } - - public function addError(Test $test, \Throwable $e, float $time): void - { - } - - public function addFailure(Test $test, AssertionFailedError $e, float $time): void - { - } - - public function addIncompleteTest(Test $test, \Throwable $e, float $time): void - { - } - - public function addSkippedTest(Test $test, \Throwable $e, float $time): void - { - } - - public function startTest(Test $test): void - { - } - - public function endTest(Test $test, float $time): void - { - } - - public function addRiskyTest(Test $test, \Throwable $e, float $time): void - { - } - - public function addWarning(Test $test, Warning $e, float $time): void - { - } - - /** - * Get web server hostname. - * - * @return string - * - * @throws \Exception - */ - protected function getHostName() - { - return $this->trait->getHostName(); - } - - /** - * Get web server port. - * - * @return int - * - * @throws \Exception - */ - protected function getPort() - { - return $this->trait->getPort(); - } - - /** - * Get web server port. - * - * @return int - * - * @throws \Exception - */ - protected function getDocRoot() - { - return $this->trait->getDocRoot(); - } - - /** - * Start PHP built-in web server. - * - * @return int PID - */ - protected function startPhpWebServer() - { - return $this->trait->startPhpWebServer(); - } - - /** - * Wait for caching proxy to be started up and reachable. - * - * @param string $ip - * @param int $port - * @param int $timeout Timeout in milliseconds - * - * @throws \RuntimeException If proxy is not reachable within timeout - */ - protected function waitFor($ip, $port, $timeout) - { - $this->trait->waitFor($ip, $port, $timeout); - } - } -} diff --git a/src/Test/WebServerListenerTrait.php b/src/Test/WebServerSubscriber.php similarity index 58% rename from src/Test/WebServerListenerTrait.php rename to src/Test/WebServerSubscriber.php index 895708f2..8fc8726c 100644 --- a/src/Test/WebServerListenerTrait.php +++ b/src/Test/WebServerSubscriber.php @@ -11,49 +11,51 @@ namespace FOS\HttpCache\Test; -/** - * This fake trait is used to have the same code and behavior between WebServerListener and its legacy version. - */ -class WebServerListenerTrait +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber; + +class WebServerSubscriber implements ExecutionStartedSubscriber { /** * PHP web server PID. - * - * @var int */ - protected $pid; + private int $pid; - /** - * Make sure the PHP built-in web server is running for tests with group - * 'webserver'. - */ - public function startTestSuite($suite) + public function notify(ExecutionStarted $event): void { - // Only run on PHP >= 5.4 as PHP below that and HHVM don't have a - // built-in web server - if (defined('HHVM_VERSION')) { - return; - } - - if (null !== $this->pid || !in_array('webserver', $suite->getGroups())) { + if (!isset($this->pid)) { + // TODO: can we detect if 'webserver' is in the list of groups of the test suite? return; } $this->pid = $pid = $this->startPhpWebServer(); - register_shutdown_function(function () use ($pid) { + register_shutdown_function(static function () use ($pid): void { exec('kill '.$pid); }); } /** - * Get web server hostname. - * - * @return string + * Start PHP built-in web server. * - * @throws \Exception + * @return int PID */ - public function getHostName() + public function startPhpWebServer(): int + { + $command = sprintf( + 'php -S %s:%d -t %s >/dev/null 2>&1 & echo $!', + '127.0.0.1', + $this->getPort(), + $this->getDocRoot() + ); + exec($command, $output); + + $this->waitFor($this->getHostName(), (int) $this->getPort(), 2000); + + return $output[0]; + } + + public function getHostName(): string { if (!defined('WEB_SERVER_HOSTNAME')) { throw new \Exception('Set WEB_SERVER_HOSTNAME in your phpunit.xml'); @@ -62,14 +64,7 @@ public function getHostName() return WEB_SERVER_HOSTNAME; } - /** - * Get web server port. - * - * @return int - * - * @throws \Exception - */ - public function getPort() + public function getPort(): string { if (!defined('WEB_SERVER_PORT')) { throw new \Exception('Set WEB_SERVER_PORT in your phpunit.xml'); @@ -78,14 +73,7 @@ public function getPort() return WEB_SERVER_PORT; } - /** - * Get web server port. - * - * @return int - * - * @throws \Exception - */ - public function getDocRoot() + public function getDocRoot(): string { if (!defined('WEB_SERVER_DOCROOT')) { throw new \Exception('Set WEB_SERVER_DOCROOT in your phpunit.xml'); @@ -94,36 +82,14 @@ public function getDocRoot() return WEB_SERVER_DOCROOT; } - /** - * Start PHP built-in web server. - * - * @return int PID - */ - public function startPhpWebServer() - { - $command = sprintf( - 'php -S %s:%d -t %s >/dev/null 2>&1 & echo $!', - '127.0.0.1', - $this->getPort(), - $this->getDocRoot() - ); - exec($command, $output); - - $this->waitFor($this->getHostName(), $this->getPort(), 2000); - - return $output[0]; - } - /** * Wait for caching proxy to be started up and reachable. * - * @param string $ip - * @param int $port - * @param int $timeout Timeout in milliseconds + * @param int $timeout Timeout in milliseconds * * @throws \RuntimeException If proxy is not reachable within timeout */ - public function waitFor($ip, $port, $timeout) + public function waitFor(string $ip, int $port, int $timeout): void { for ($i = 0; $i < $timeout; ++$i) { if (@fsockopen($ip, $port)) { diff --git a/src/Test/WebServerSubscriberExtension.php b/src/Test/WebServerSubscriberExtension.php new file mode 100644 index 00000000..d22d5cfa --- /dev/null +++ b/src/Test/WebServerSubscriberExtension.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FOS\HttpCache\Test; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; + +class WebServerSubscriberExtension implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + $facade->registerSubscriber(new WebServerSubscriber()); + } +} diff --git a/tests/Unit/CacheInvalidatorTest.php b/tests/Unit/CacheInvalidatorTest.php index 15134372..4fe02c46 100644 --- a/tests/Unit/CacheInvalidatorTest.php +++ b/tests/Unit/CacheInvalidatorTest.php @@ -157,7 +157,7 @@ public function testInvalidateRegex(): void $cacheInvalidator->invalidateRegex('/a', 'b', ['example.com']); } - public function provideOperations(): iterable + public static function provideOperations(): iterable { yield from [ ['invalidatePath', '/'], diff --git a/tests/Unit/ProxyClient/HttpDispatcherTest.php b/tests/Unit/ProxyClient/HttpDispatcherTest.php index ce26f96c..ce44ebcd 100644 --- a/tests/Unit/ProxyClient/HttpDispatcherTest.php +++ b/tests/Unit/ProxyClient/HttpDispatcherTest.php @@ -97,7 +97,7 @@ private function doTestException(\Exception $exception, string $type, string $me $httpDispatcher->flush(); } - public function exceptionProvider(): array + public static function exceptionProvider(): array { /** @var RequestInterface $request */ $request = \Mockery::mock(RequestInterface::class) diff --git a/tests/Unit/ProxyClient/MultiplexerClientTest.php b/tests/Unit/ProxyClient/MultiplexerClientTest.php index ca42ca92..dbd9880a 100644 --- a/tests/Unit/ProxyClient/MultiplexerClientTest.php +++ b/tests/Unit/ProxyClient/MultiplexerClientTest.php @@ -163,11 +163,11 @@ public function testClear(): void $this->assertSame($multiplexer, $multiplexer->clear()); } - public function provideInvalidClient(): array + public static function provideInvalidClient(): array { return [ [['this-is-not-an-object']], - [[$this]], + [[new \stdClass()]], ]; } diff --git a/tests/Unit/SymfonyCache/UserContextListenerTest.php b/tests/Unit/SymfonyCache/UserContextListenerTest.php index 49bb5260..b55aaf26 100644 --- a/tests/Unit/SymfonyCache/UserContextListenerTest.php +++ b/tests/Unit/SymfonyCache/UserContextListenerTest.php @@ -35,7 +35,7 @@ public function setUp(): void /** * UserContextListener default options to simulate the correct headers. */ - public function provideConfigOptions(): array + public static function provideConfigOptions(): array { $userContextListener = new UserContextListener(); $ref = new \ReflectionObject($userContextListener); diff --git a/tests/Unit/TagHeaderFormatter/MaxHeaderValueLengthFormatterTest.php b/tests/Unit/TagHeaderFormatter/MaxHeaderValueLengthFormatterTest.php index b366efc9..bcb970ce 100644 --- a/tests/Unit/TagHeaderFormatter/MaxHeaderValueLengthFormatterTest.php +++ b/tests/Unit/TagHeaderFormatter/MaxHeaderValueLengthFormatterTest.php @@ -60,7 +60,7 @@ private function getFormatter(int $maxLength): MaxHeaderValueLengthFormatter ); } - public function tooLongProvider(): array + public static function tooLongProvider(): array { return [ [3, ['foo', 'bar', 'baz'], ['foo', 'bar', 'baz']], diff --git a/tests/Unit/Test/PHPUnit/AbstractCacheConstraintTest.php b/tests/Unit/Test/PHPUnit/AbstractCacheConstraintTestCase.php similarity index 92% rename from tests/Unit/Test/PHPUnit/AbstractCacheConstraintTest.php rename to tests/Unit/Test/PHPUnit/AbstractCacheConstraintTestCase.php index b335c95c..62a34c89 100644 --- a/tests/Unit/Test/PHPUnit/AbstractCacheConstraintTest.php +++ b/tests/Unit/Test/PHPUnit/AbstractCacheConstraintTestCase.php @@ -16,7 +16,7 @@ use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; -abstract class AbstractCacheConstraintTest extends TestCase +abstract class AbstractCacheConstraintTestCase extends TestCase { use MockeryPHPUnitIntegration; diff --git a/tests/Unit/Test/PHPUnit/IsCacheHitConstraintTest.php b/tests/Unit/Test/PHPUnit/IsCacheHitConstraintTestCase.php similarity index 96% rename from tests/Unit/Test/PHPUnit/IsCacheHitConstraintTest.php rename to tests/Unit/Test/PHPUnit/IsCacheHitConstraintTestCase.php index d1e73cd2..195df43a 100644 --- a/tests/Unit/Test/PHPUnit/IsCacheHitConstraintTest.php +++ b/tests/Unit/Test/PHPUnit/IsCacheHitConstraintTestCase.php @@ -15,7 +15,7 @@ use GuzzleHttp\Psr7\Stream; use PHPUnit\Framework\ExpectationFailedException; -class IsCacheHitConstraintTest extends AbstractCacheConstraintTest +class IsCacheHitConstraintTestCase extends AbstractCacheConstraintTestCase { private IsCacheHitConstraint $constraint; diff --git a/tests/Unit/Test/PHPUnit/IsCacheMissConstraintTest.php b/tests/Unit/Test/PHPUnit/IsCacheMissConstraintTestCase.php similarity index 93% rename from tests/Unit/Test/PHPUnit/IsCacheMissConstraintTest.php rename to tests/Unit/Test/PHPUnit/IsCacheMissConstraintTestCase.php index bb00c09b..e86c3051 100644 --- a/tests/Unit/Test/PHPUnit/IsCacheMissConstraintTest.php +++ b/tests/Unit/Test/PHPUnit/IsCacheMissConstraintTestCase.php @@ -14,7 +14,7 @@ use FOS\HttpCache\Test\PHPUnit\IsCacheMissConstraint; use PHPUnit\Framework\ExpectationFailedException; -class IsCacheMissConstraintTest extends AbstractCacheConstraintTest +class IsCacheMissConstraintTestCase extends AbstractCacheConstraintTestCase { private IsCacheMissConstraint $constraint; diff --git a/tests/Unit/Test/Proxy/VarnishProxyTest.php b/tests/Unit/Test/Proxy/VarnishProxyTest.php index f15ed513..44178fd4 100644 --- a/tests/Unit/Test/Proxy/VarnishProxyTest.php +++ b/tests/Unit/Test/Proxy/VarnishProxyTest.php @@ -24,7 +24,7 @@ public function testInvalidConfigFileThrowsException(): void new VarnishProxy('nope.vcl'); } - public function allowInlineFlagProvider(): array + public static function allowInlineFlagProvider(): array { return [[true], [false]]; }