diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index cf66d7ef1b113..9b14be1b5c725 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 6.4 --- + * Add `LoggerAssertionsTrait` * Add `AbstractController::renderBlock()` and `renderBlockView()` * Add native return type to `Translator` and to `Application::reset()` * Deprecate the integration of Doctrine annotations, either uninstall the `doctrine/annotations` package or disable the integration by setting `framework.annotations` to `false` diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php index 8d27b757f14f1..1240d1ad1152d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php @@ -25,6 +25,7 @@ */ abstract class KernelTestCase extends TestCase { + use LoggerAssertionsTrait; use MailerAssertionsTrait; use NotificationAssertionsTrait; diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/LoggerAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/LoggerAssertionsTrait.php new file mode 100644 index 0000000000000..8d6dd579bbeda --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Test/LoggerAssertionsTrait.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Test; + +use Monolog\Handler\TestHandler; +use Monolog\Logger; +use Monolog\LogRecord; + +trait LoggerAssertionsTrait +{ + public static function assertLogExists(string $expectedLog, string $level = Logger::DEBUG): void + { + self::ensureMonologHandlerIsAvailable(); + + /** @var TestHandler $logger */ + $logger = self::getContainer()->get('monolog.handler.test'); + + self::assertTrue($logger->hasRecordThatPasses( + function (array|LogRecord $record) use ($expectedLog) { + return $record['message'] === $expectedLog; + }, + $level, + )); + } + + public static function assertLogMatches(string $expectedRegex, string $level = Logger::DEBUG): void + { + self::ensureMonologHandlerIsAvailable(); + + /** @var TestHandler $logger */ + $logger = self::getContainer()->get('monolog.handler.test'); + + self::assertTrue($logger->hasRecordThatMatches($expectedRegex, $level)); + } + + public static function assertLogContains(string $expectedLog, string $level = Logger::DEBUG): void + { + self::ensureMonologHandlerIsAvailable(); + + /** @var TestHandler $logger */ + $logger = self::getContainer()->get('monolog.handler.test'); + + self::assertTrue($logger->hasRecordThatContains($expectedLog, $level)); + } + + /** + * @internal + */ + private static function ensureMonologHandlerIsAvailable(): void + { + if (!self::getContainer()->has('monolog.handler.test')) { + self::fail('The "monolog.handler.test" service is not available. Try registering the service "Monolog\Handler\TestHandler" as "monolog.handler.test" in your test configuration.'); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/LoggerController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/LoggerController.php new file mode 100644 index 0000000000000..3694ed77b394f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/LoggerController.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller; + +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpFoundation\Response; + +final class LoggerController +{ + public function index(LoggerInterface $logger) + { + $logger->debug('test1_'.__CLASS__); + $logger->debug('test2_'.__CLASS__); + $logger->debug('test3_'.__CLASS__); + + return new Response(); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Logger/TestLogger.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Logger/TestLogger.php new file mode 100644 index 0000000000000..e0527cc04cb83 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Logger/TestLogger.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Logger; + +use Monolog\Logger; + +class TestLogger extends Logger +{ + public array $logs = []; + + public function __construct($handler) + { + parent::__construct(__CLASS__, [$handler]); + } + + public function log($level, $message, array $context = []): void + { + $this->logs[] = [ + 'level' => $level, + 'message' => (string) $message, + 'context' => $context, + ]; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Logger/TestLoggerWithoutHandler.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Logger/TestLoggerWithoutHandler.php new file mode 100644 index 0000000000000..18d4371c2bedb --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Logger/TestLoggerWithoutHandler.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Logger; + +use Monolog\Logger; + +class TestLoggerWithoutHandler extends Logger +{ + public array $logs = []; + + public function __construct() + { + parent::__construct(__CLASS__); + } + + public function log($level, $message, array $context = []): void + { + $this->logs[] = [ + 'level' => $level, + 'message' => (string) $message, + 'context' => $context, + ]; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml index 5630ed621048f..8907b65102565 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml @@ -68,3 +68,7 @@ uid: send_notification: path: /send_notification defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\NotificationController::indexAction } + +log: + path: /log + defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController::index } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/LoggerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/LoggerTest.php new file mode 100644 index 0000000000000..fb9a52d86d074 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/LoggerTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; + +use PHPUnit\Framework\AssertionFailedError; + +final class LoggerTest extends AbstractWebTestCase +{ + public function testLoggerAssertion() + { + $client = $this->createClient(['test_case' => 'Logger', 'root_config' => 'config.yml', 'debug' => true]); + $client->request('GET', '/log'); + + $this->assertLogExists('test1_Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController'); + $this->assertLogMatches('/(test2_).*(LoggerController)/'); + $this->assertLogContains('test3'); + } + + public function testLoggerAssertionWithoutTestHandler() + { + $client = $this->createClient(['test_case' => 'LoggerWithoutHandler', 'root_config' => 'config.yml', 'debug' => true]); + $client->request('GET', '/log'); + + try { + $this->assertLogExists('test1_Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController'); + } catch (AssertionFailedError $e) { + $this->assertSame('The "monolog.handler.test" service is not available. Try registering the service "Monolog\Handler\TestHandler" as "monolog.handler.test" in your test configuration.', $e->getMessage()); + } + + try { + $this->assertLogMatches('/(test2_).*(LoggerController)/'); + } catch (AssertionFailedError $e) { + $this->assertSame('The "monolog.handler.test" service is not available. Try registering the service "Monolog\Handler\TestHandler" as "monolog.handler.test" in your test configuration.', $e->getMessage()); + } + + try { + $this->assertLogContains('test3'); + } catch (AssertionFailedError $e) { + $this->assertSame('The "monolog.handler.test" service is not available. Try registering the service "Monolog\Handler\TestHandler" as "monolog.handler.test" in your test configuration.', $e->getMessage()); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/bundles.php new file mode 100644 index 0000000000000..15ff182c6fed5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/bundles.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle; + +return [ + new FrameworkBundle(), + new TestBundle(), +]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/config.yml new file mode 100644 index 0000000000000..c91beb5873782 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/config.yml @@ -0,0 +1,6 @@ +imports: + - { resource: ../config/default.yml } + - { resource: services.yml } + +framework: + profiler: ~ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/routing.yml new file mode 100644 index 0000000000000..8d3bcd42ec8d5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/routing.yml @@ -0,0 +1,2 @@ +_loggertest_bundle: + resource: '@TestBundle/Resources/config/routing.yml' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/services.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/services.yml new file mode 100644 index 0000000000000..aea1942fb5572 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Logger/services.yml @@ -0,0 +1,13 @@ +services: + _defaults: + public: true + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController: + tags: ['controller.service_arguments'] + + monolog.handler.test: + class: Monolog\Handler\TestHandler + + logger: + class: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Logger\TestLogger + arguments: ['@monolog.handler.test'] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/bundles.php new file mode 100644 index 0000000000000..15ff182c6fed5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/bundles.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle; + +return [ + new FrameworkBundle(), + new TestBundle(), +]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/config.yml new file mode 100644 index 0000000000000..c91beb5873782 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/config.yml @@ -0,0 +1,6 @@ +imports: + - { resource: ../config/default.yml } + - { resource: services.yml } + +framework: + profiler: ~ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/routing.yml new file mode 100644 index 0000000000000..8d3bcd42ec8d5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/routing.yml @@ -0,0 +1,2 @@ +_loggertest_bundle: + resource: '@TestBundle/Resources/config/routing.yml' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/services.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/services.yml new file mode 100644 index 0000000000000..7484719dbb5fe --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/LoggerWithoutHandler/services.yml @@ -0,0 +1,9 @@ +services: + _defaults: + public: true + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\LoggerController: + tags: ['controller.service_arguments'] + + logger: + class: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Logger\TestLoggerWithoutHandler