From 7bf69d90174665baec48bdbdecee55643a020080 Mon Sep 17 00:00:00 2001 From: Anton Zubariev Date: Fri, 20 Dec 2024 12:28:18 +0200 Subject: [PATCH] ACP-4631: MessageBus observability improvement (#11252) ACP-4631 MessageBus observability improvement --- .../Business/Logger/MessageLogger.php | 160 ++++++++++ .../Logger/MessageLoggerInterface.php | 30 ++ .../Business/Logger/MessagePublishLogger.php | 129 -------- .../Logger/MessagePublishLoggerInterface.php | 30 -- .../Business/MessageBrokerBusinessFactory.php | 21 +- .../LogMessageHandlingResultMiddleware.php | 54 ++++ .../Business/Publisher/MessagePublisher.php | 29 +- .../Zed/MessageBroker/MessageBrokerConfig.php | 85 +++++ ...LogMessageHandlingResultMiddlewareTest.php | 293 ++++++++++++++++++ .../Publisher/MessagePublisherTest.php | 159 +--------- 10 files changed, 643 insertions(+), 347 deletions(-) create mode 100644 src/Spryker/Zed/MessageBroker/Business/Logger/MessageLogger.php create mode 100644 src/Spryker/Zed/MessageBroker/Business/Logger/MessageLoggerInterface.php delete mode 100644 src/Spryker/Zed/MessageBroker/Business/Logger/MessagePublishLogger.php delete mode 100644 src/Spryker/Zed/MessageBroker/Business/Logger/MessagePublishLoggerInterface.php create mode 100644 src/Spryker/Zed/MessageBroker/Business/Middleware/LogMessageHandlingResultMiddleware.php create mode 100644 tests/SprykerTest/Zed/MessageBroker/Business/Middleware/LogMessageHandlingResultMiddlewareTest.php diff --git a/src/Spryker/Zed/MessageBroker/Business/Logger/MessageLogger.php b/src/Spryker/Zed/MessageBroker/Business/Logger/MessageLogger.php new file mode 100644 index 0000000..3a7276c --- /dev/null +++ b/src/Spryker/Zed/MessageBroker/Business/Logger/MessageLogger.php @@ -0,0 +1,160 @@ +messageBrokerConfig = $messageBrokerConfig; + } + + /** + * @param \Symfony\Component\Messenger\Envelope $envelope + * @param float $startMicrotime + * + * @return void + */ + public function logInfo(Envelope $envelope, float $startMicrotime): void + { + /** @var \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer */ + $messageTransfer = $envelope->getMessage(); + $isEnvelopeReceived = $this->isEnvelopeReceived($envelope); + $logContext = $this->getContext($messageTransfer, $startMicrotime, $isEnvelopeReceived); + + $this->getLogger()->log(Logger::INFO, '', [ + static::KEY_CODE => $isEnvelopeReceived + ? $this->messageBrokerConfig->getMessageBrokerConsumeSuccessCode() + : $this->messageBrokerConfig->getMessageBrokerCallSuccessCode(), + static::KEY_CODE_NAME => $isEnvelopeReceived + ? $this->messageBrokerConfig->getMessageBrokerConsumeSuccessCodeName() + : $this->messageBrokerConfig->getMessageBrokerCallSuccessCodeName(), + ] + $logContext); + } + + /** + * @param \Symfony\Component\Messenger\Envelope $envelope + * @param float $startMicrotime + * @param string $errorMessage + * + * @return void + */ + public function logError(Envelope $envelope, float $startMicrotime, string $errorMessage): void + { + /** @var \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer */ + $messageTransfer = $envelope->getMessage(); + $isEnvelopeReceived = $this->isEnvelopeReceived($envelope); + $logContext = $this->getContext($messageTransfer, $startMicrotime, $isEnvelopeReceived); + + $this->getLogger()->log(Logger::ERROR, $errorMessage, [ + static::KEY_CODE => $isEnvelopeReceived + ? $this->messageBrokerConfig->getMessageBrokerConsumeErrorCode() + : $this->messageBrokerConfig->getMessageBrokerCallErrorCode(), + static::KEY_CODE_NAME => $isEnvelopeReceived + ? $this->messageBrokerConfig->getMessageBrokerConsumeErrorCodeName() + : $this->messageBrokerConfig->getMessageBrokerCallErrorCodeName(), + ] + $logContext); + } + + /** + * @param \Symfony\Component\Messenger\Envelope $envelope + * + * @return bool + */ + protected function isEnvelopeReceived(Envelope $envelope): bool + { + return $envelope->last(ReceivedStamp::class) !== null; + } + + /** + * @param \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer + * @param float $startMicrotime + * @param bool $isEnvelopeReceived + * + * @return array + */ + protected function getContext( + TransferInterface $messageTransfer, + float $startMicrotime, + bool $isEnvelopeReceived + ): array { + $context = [ + 'duration' => sprintf('%ss', $this->getDurationInSeconds($startMicrotime)), + 'activityType' => $isEnvelopeReceived ? 'Message consuming' : 'Message publishing', + ] + $this->getLoggerMessageAttributes($messageTransfer); + + if ($this->messageBrokerConfig->isMessageBodyIncludedInLogs()) { + $messageBody = $messageTransfer->toArray(); + unset($messageBody['message_attributes']); + $context['messageBody'] = $messageBody; + } + + return $context; + } + + /** + * @param \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer + * + * @return array + */ + protected function getLoggerMessageAttributes(TransferInterface $messageTransfer): array + { + $loggerMessageAttributes = []; + if (method_exists($messageTransfer, 'getMessageAttributes') && $messageTransfer->getMessageAttributes()) { + $loggerMessageAttributes = array_diff_key( + $messageTransfer->getMessageAttributes()->toArrayRecursiveCamelCased(), + array_flip($this->messageBrokerConfig->getProtectedMessageAttributes()), + ); + } + + //It is not allowed to log authorization token for security reasons + if (isset($loggerMessageAttributes[MessageAttributesTransfer::AUTHORIZATION])) { + unset($loggerMessageAttributes[MessageAttributesTransfer::AUTHORIZATION]); + } + + return $loggerMessageAttributes; + } + + /** + * @param float $startMicrotime + * + * @return float + */ + protected function getDurationInSeconds(float $startMicrotime): float + { + return round(microtime(true) - $startMicrotime, 2); + } +} diff --git a/src/Spryker/Zed/MessageBroker/Business/Logger/MessageLoggerInterface.php b/src/Spryker/Zed/MessageBroker/Business/Logger/MessageLoggerInterface.php new file mode 100644 index 0000000..258bf20 --- /dev/null +++ b/src/Spryker/Zed/MessageBroker/Business/Logger/MessageLoggerInterface.php @@ -0,0 +1,30 @@ +messageBrokerConfig = $messageBrokerConfig; - } - - /** - * @param \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer - * @param float $startMicrotime - * - * @return void - */ - public function logInfo( - TransferInterface $messageTransfer, - float $startMicrotime - ): void { - $logContext = $this->getContext($messageTransfer, $startMicrotime); - - $this->getLogger()->log(Logger::INFO, '', [ - static::KEY_CODE => $this->messageBrokerConfig->getMessageBrokerCallSuccessCode(), - static::KEY_CODE_NAME => $this->messageBrokerConfig->getMessageBrokerCallSuccessCodeName(), - ] + $logContext); - } - - /** - * @param \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer - * @param float $startMicrotime - * @param string $message - * - * @return void - */ - public function logError( - TransferInterface $messageTransfer, - float $startMicrotime, - string $message - ): void { - $logContext = $this->getContext($messageTransfer, $startMicrotime); - - $this->getLogger()->log(Logger::ERROR, $message, [ - static::KEY_CODE => $this->messageBrokerConfig->getMessageBrokerCallErrorCode(), - static::KEY_CODE_NAME => $this->messageBrokerConfig->getMessageBrokerCallErrorCodeName(), - ] + $logContext); - } - - /** - * @param \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer - * @param float $startMicrotime - * - * @return array - */ - protected function getContext( - TransferInterface $messageTransfer, - float $startMicrotime - ): array { - return [ - 'duration' => $this->getDuration($startMicrotime), - 'activityType' => 'Message publishing', - ] + $this->getLoggerMessageAttributes($messageTransfer); - } - - /** - * @param \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer - * - * @return array - */ - protected function getLoggerMessageAttributes(TransferInterface $messageTransfer): array - { - $loggerMessageAttributes = []; - if (method_exists($messageTransfer, 'getMessageAttributes') && $messageTransfer->getMessageAttributes()) { - $loggerMessageAttributes = array_diff_key( - $messageTransfer->getMessageAttributes()->toArrayRecursiveCamelCased(), - array_flip($this->messageBrokerConfig->getProtectedMessageAttributes()), - ); - } - - //It is not allowed to log authorization token for security reasons - if (isset($loggerMessageAttributes[MessageAttributesTransfer::AUTHORIZATION])) { - unset($loggerMessageAttributes[MessageAttributesTransfer::AUTHORIZATION]); - } - - return $loggerMessageAttributes; - } - - /** - * @param float $startMicrotime - * - * @return int - */ - protected function getDuration(float $startMicrotime): int - { - return (int)ceil((microtime(true) - $startMicrotime) * 1000); - } -} diff --git a/src/Spryker/Zed/MessageBroker/Business/Logger/MessagePublishLoggerInterface.php b/src/Spryker/Zed/MessageBroker/Business/Logger/MessagePublishLoggerInterface.php deleted file mode 100644 index 1bcd366..0000000 --- a/src/Spryker/Zed/MessageBroker/Business/Logger/MessagePublishLoggerInterface.php +++ /dev/null @@ -1,30 +0,0 @@ -createMessageDecorator(), $this->createMessageBus(), - $this->createMessagePublishLogger(), $this->getConfig(), ); } /** - * @return \Spryker\Zed\MessageBroker\Business\Logger\MessagePublishLoggerInterface + * @return \Spryker\Zed\MessageBroker\Business\Logger\MessageLoggerInterface */ - public function createMessagePublishLogger(): MessagePublishLoggerInterface + public function createMessageLogger(): MessageLoggerInterface { - return new MessagePublishLogger($this->getConfig()); + return new MessageLogger($this->getConfig()); } /** @@ -116,6 +116,7 @@ public function getMiddlewares(): array { return array_merge( [ + $this->createLogMessageHandlingResultMiddleware(), $this->createLogHandleMessageExceptionMiddleware(), ], $this->getMiddlewarePlugins(), @@ -128,6 +129,14 @@ public function getMiddlewares(): array ); } + /** + * @return \Symfony\Component\Messenger\Middleware\MiddlewareInterface + */ + public function createLogMessageHandlingResultMiddleware(): MiddlewareInterface + { + return new LogMessageHandlingResultMiddleware($this->createMessageLogger()); + } + /** * @return \Symfony\Component\Messenger\Middleware\MiddlewareInterface */ diff --git a/src/Spryker/Zed/MessageBroker/Business/Middleware/LogMessageHandlingResultMiddleware.php b/src/Spryker/Zed/MessageBroker/Business/Middleware/LogMessageHandlingResultMiddleware.php new file mode 100644 index 0000000..92abe36 --- /dev/null +++ b/src/Spryker/Zed/MessageBroker/Business/Middleware/LogMessageHandlingResultMiddleware.php @@ -0,0 +1,54 @@ +messagePublishLogger = $messagePublishLogger; + } + + /** + * @param \Symfony\Component\Messenger\Envelope $envelope + * @param \Symfony\Component\Messenger\Middleware\StackInterface $stack + * + * @throws \Throwable + * + * @return \Symfony\Component\Messenger\Envelope + */ + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $startMicrotime = microtime(true); + + try { + $envelope = $stack->next()->handle($envelope, $stack); + $this->messagePublishLogger->logInfo($envelope, $startMicrotime); + + return $envelope; + } catch (Throwable $exception) { + $this->messagePublishLogger->logError($envelope, $startMicrotime, $exception->getMessage()); + + throw $exception; + } + } +} diff --git a/src/Spryker/Zed/MessageBroker/Business/Publisher/MessagePublisher.php b/src/Spryker/Zed/MessageBroker/Business/Publisher/MessagePublisher.php index a0563ed..03ed77f 100644 --- a/src/Spryker/Zed/MessageBroker/Business/Publisher/MessagePublisher.php +++ b/src/Spryker/Zed/MessageBroker/Business/Publisher/MessagePublisher.php @@ -7,13 +7,11 @@ namespace Spryker\Zed\MessageBroker\Business\Publisher; -use Exception; use Generated\Shared\Transfer\MessageAttributesTransfer; use Generated\Shared\Transfer\MessageResponseTransfer; use Spryker\Shared\Kernel\Transfer\TransferInterface; use Spryker\Shared\Log\LoggerTrait; use Spryker\Zed\MessageBroker\Business\Exception\MessageBrokerException; -use Spryker\Zed\MessageBroker\Business\Logger\MessagePublishLoggerInterface; use Spryker\Zed\MessageBroker\Business\MessageAttributeProvider\MessageAttributeProviderInterface; use Spryker\Zed\MessageBroker\MessageBrokerConfig; use Symfony\Component\Messenger\MessageBusInterface; @@ -32,11 +30,6 @@ class MessagePublisher implements MessagePublisherInterface */ protected MessageBusInterface $messageBus; - /** - * @var \Spryker\Zed\MessageBroker\Business\Logger\MessagePublishLoggerInterface - */ - protected MessagePublishLoggerInterface $messagePublishLogger; - /** * @var \Spryker\Zed\MessageBroker\MessageBrokerConfig */ @@ -45,26 +38,21 @@ class MessagePublisher implements MessagePublisherInterface /** * @param \Spryker\Zed\MessageBroker\Business\MessageAttributeProvider\MessageAttributeProviderInterface $messageDecorator * @param \Symfony\Component\Messenger\MessageBusInterface $messageBus - * @param \Spryker\Zed\MessageBroker\Business\Logger\MessagePublishLoggerInterface $messagePublishLogger * @param \Spryker\Zed\MessageBroker\MessageBrokerConfig $messageBrokerConfig */ public function __construct( MessageAttributeProviderInterface $messageDecorator, MessageBusInterface $messageBus, - MessagePublishLoggerInterface $messagePublishLogger, MessageBrokerConfig $messageBrokerConfig ) { $this->messageAttributeProvider = $messageDecorator; $this->messageBus = $messageBus; - $this->messagePublishLogger = $messagePublishLogger; $this->messageBrokerConfig = $messageBrokerConfig; } /** * @param \Spryker\Shared\Kernel\Transfer\TransferInterface $messageTransfer * - * @throws \Exception - * * @return \Generated\Shared\Transfer\MessageResponseTransfer */ public function sendMessage(TransferInterface $messageTransfer): MessageResponseTransfer @@ -76,21 +64,10 @@ public function sendMessage(TransferInterface $messageTransfer): MessageResponse return $messageResponseTransfer; } - $startMicrotime = microtime(true); - - try { - $messageTransfer = $this->provideMessageAttributes($messageTransfer); - $envelope = $this->messageBus->dispatch($messageTransfer); - $messageResponseTransfer->setBody($envelope); - - $this->messagePublishLogger->logInfo($messageTransfer, $startMicrotime); - } catch (Exception $e) { - $this->messagePublishLogger->logError($messageTransfer, $startMicrotime, $e->getMessage()); - - throw $e; - } + $messageTransfer = $this->provideMessageAttributes($messageTransfer); + $envelope = $this->messageBus->dispatch($messageTransfer); - return $messageResponseTransfer; + return $messageResponseTransfer->setBody($envelope); } /** diff --git a/src/Spryker/Zed/MessageBroker/MessageBrokerConfig.php b/src/Spryker/Zed/MessageBroker/MessageBrokerConfig.php index 74f9bab..82a73b3 100644 --- a/src/Spryker/Zed/MessageBroker/MessageBrokerConfig.php +++ b/src/Spryker/Zed/MessageBroker/MessageBrokerConfig.php @@ -32,6 +32,26 @@ class MessageBrokerConfig extends AbstractBundleConfig */ protected const MESSAGE_BROKER_CALL_ERROR_CODE_NAME = 'Message Broker call sendMessage Error'; + /** + * @var int + */ + protected const MESSAGE_BROKER_CONSUME_SUCCESS_CODE = 11002; + + /** + * @var string + */ + protected const MESSAGE_BROKER_CONSUME_SUCCESS_CODE_NAME = 'Message Broker consume message Success'; + + /** + * @var int + */ + protected const MESSAGE_BROKER_CONSUME_ERROR_CODE = 11003; + + /** + * @var string + */ + protected const MESSAGE_BROKER_CONSUME_ERROR_CODE_NAME = 'Message Broker consume message Error'; + /** * Specification: * - This configuration defines success code for message broker call. @@ -84,6 +104,58 @@ public function getMessageBrokerCallErrorCodeName(): string return static::MESSAGE_BROKER_CALL_ERROR_CODE_NAME; } + /** + * Specification: + * - This configuration defines success code for message broker consume. + * + * @api + * + * @return int + */ + public function getMessageBrokerConsumeSuccessCode(): int + { + return static::MESSAGE_BROKER_CONSUME_SUCCESS_CODE; + } + + /** + * Specification: + * - This configuration defines success code name for message broker consume. + * + * @api + * + * @return string + */ + public function getMessageBrokerConsumeSuccessCodeName(): string + { + return static::MESSAGE_BROKER_CONSUME_SUCCESS_CODE_NAME; + } + + /** + * Specification: + * - This configuration defines error code for message broker consume. + * + * @api + * + * @return int + */ + public function getMessageBrokerConsumeErrorCode(): int + { + return static::MESSAGE_BROKER_CONSUME_ERROR_CODE; + } + + /** + * Specification: + * - This configuration defines error code name for message broker consume. + * + * @api + * + * @return string + */ + public function getMessageBrokerConsumeErrorCodeName(): string + { + return static::MESSAGE_BROKER_CONSUME_ERROR_CODE_NAME; + } + /** * Specification: * - This configuration can to be done via environment variable. @@ -160,6 +232,19 @@ public function isDefaultApplicationLoggerUsed(): bool return false; } + /** + * Specification: + * - This configuration defines whether message body must be logged by message logger. + * + * @api + * + * @return bool + */ + public function isMessageBodyIncludedInLogs(): bool + { + return false; + } + /** * Specification: * - This configuration defines log file path. diff --git a/tests/SprykerTest/Zed/MessageBroker/Business/Middleware/LogMessageHandlingResultMiddlewareTest.php b/tests/SprykerTest/Zed/MessageBroker/Business/Middleware/LogMessageHandlingResultMiddlewareTest.php new file mode 100644 index 0000000..b80d640 --- /dev/null +++ b/tests/SprykerTest/Zed/MessageBroker/Business/Middleware/LogMessageHandlingResultMiddlewareTest.php @@ -0,0 +1,293 @@ +tester->getMessageAttributesTransfer([ + MessageAttributesTransfer::TRANSFER_NAME => static::TRANSFER_NAME, + MessageAttributesTransfer::EVENT => static::TRANSFER_NAME, + MessageAttributesTransfer::NAME => static::TRANSFER_NAME, + ]); + $messageBrokerTestMessageTransfer = (new MessageBrokerTestMessageTransfer()) + ->setMessageAttributes($messageAttributesTransfer); + + $loggerMock = $this->createMock(LoggerInterface::class); + $logMessageHandlingResultMiddleware = (new LogMessageHandlingResultMiddleware($this->getMessageLoggerMock($loggerMock))); + + $middlewareMock = $this->getMiddlewareMock(); + $stackMock = $this->getStackMock($middlewareMock); + + $envelope = Envelope::wrap($messageBrokerTestMessageTransfer); + $middlewareMock->expects($this->once())->method('handle')->willReturn($envelope); + + $context = $this->getMessageLogDataFromMessageAttributesTransfer( + $messageAttributesTransfer, + static::TRANSFER_NAME, + ); + $expectedLog = [ + 'code' => $this->tester->getModuleConfig()->getMessageBrokerCallSuccessCode(), + 'codeName' => $this->tester->getModuleConfig()->getMessageBrokerCallSuccessCodeName(), + 'duration' => '0s', + 'activityType' => 'Message publishing', + ] + $context; + + // Assert + $loggerMock->expects($this->once()) + ->method('log') + ->with(Logger::INFO, '', $expectedLog); + + // Act + $logMessageHandlingResultMiddleware->handle($envelope, $stackMock); + } + + /** + * @return void + */ + public function testLogMessageHandlingResultMiddlewareWritesSuccessLogInCaseOfSuccessfulMessageReceiving(): void + { + // Arrange + $messageAttributesTransfer = $this->tester->getMessageAttributesTransfer([ + MessageAttributesTransfer::TRANSFER_NAME => static::TRANSFER_NAME, + MessageAttributesTransfer::EVENT => static::TRANSFER_NAME, + MessageAttributesTransfer::NAME => static::TRANSFER_NAME, + ]); + $messageBrokerTestMessageTransfer = (new MessageBrokerTestMessageTransfer()) + ->setMessageAttributes($messageAttributesTransfer); + + $loggerMock = $this->createMock(LoggerInterface::class); + $logMessageHandlingResultMiddleware = (new LogMessageHandlingResultMiddleware($this->getMessageLoggerMock($loggerMock))); + + $middlewareMock = $this->getMiddlewareMock(); + $stackMock = $this->getStackMock($middlewareMock); + + $envelope = Envelope::wrap($messageBrokerTestMessageTransfer, [new ReceivedStamp('test')]); + $middlewareMock->expects($this->once())->method('handle')->willReturn($envelope); + + $context = $this->getMessageLogDataFromMessageAttributesTransfer( + $messageAttributesTransfer, + static::TRANSFER_NAME, + ); + $expectedLog = [ + 'code' => $this->tester->getModuleConfig()->getMessageBrokerConsumeSuccessCode(), + 'codeName' => $this->tester->getModuleConfig()->getMessageBrokerConsumeSuccessCodeName(), + 'duration' => '0s', + 'activityType' => 'Message consuming', + ] + $context; + + // Assert + $loggerMock->expects($this->once()) + ->method('log') + ->with(Logger::INFO, '', $expectedLog); + + // Act + $logMessageHandlingResultMiddleware->handle($envelope, $stackMock); + } + + /** + * @return void + */ + public function testLogMessageHandlingResultMiddlewareWritesErrorLogInCaseOfNotSuccessfulMessageSending(): void + { + // Arrange + $messageAttributesTransfer = $this->tester->getMessageAttributesTransfer([ + MessageAttributesTransfer::TRANSFER_NAME => static::TRANSFER_NAME, + MessageAttributesTransfer::EVENT => static::TRANSFER_NAME, + MessageAttributesTransfer::NAME => static::TRANSFER_NAME, + ]); + $messageBrokerTestMessageTransfer = (new MessageBrokerTestMessageTransfer()) + ->setMessageAttributes($messageAttributesTransfer); + + $loggerMock = $this->createMock(LoggerInterface::class); + $logMessageHandlingResultMiddleware = (new LogMessageHandlingResultMiddleware($this->getMessageLoggerMock($loggerMock))); + + $middlewareMock = $this->getMiddlewareMock(); + $stackMock = $this->getStackMock($middlewareMock); + + $exceptionMessage = 'TestException'; + $middlewareMock->expects($this->once()) + ->method('handle') + ->willThrowException(new MessageBrokerException($exceptionMessage)); + + $context = $this->getMessageLogDataFromMessageAttributesTransfer( + $messageAttributesTransfer, + static::TRANSFER_NAME, + ); + $expectedLog = [ + 'code' => $this->tester->getModuleConfig()->getMessageBrokerCallErrorCode(), + 'codeName' => $this->tester->getModuleConfig()->getMessageBrokerCallErrorCodeName(), + 'duration' => '0s', + 'activityType' => 'Message publishing', + ] + $context; + + // Assert + $loggerMock->expects($this->once()) + ->method('log') + ->with(Logger::ERROR, $exceptionMessage, $expectedLog); + $this->expectException(MessageBrokerException::class); + + // Act + $logMessageHandlingResultMiddleware->handle(Envelope::wrap($messageBrokerTestMessageTransfer), $stackMock); + } + + /** + * @return void + */ + public function testLogMessageHandlingResultMiddlewareWritesErrorLogInCaseOfNotSuccessfulMessageReceiving(): void + { + // Arrange + $messageAttributesTransfer = $this->tester->getMessageAttributesTransfer([ + MessageAttributesTransfer::TRANSFER_NAME => static::TRANSFER_NAME, + MessageAttributesTransfer::EVENT => static::TRANSFER_NAME, + MessageAttributesTransfer::NAME => static::TRANSFER_NAME, + ]); + $messageBrokerTestMessageTransfer = (new MessageBrokerTestMessageTransfer()) + ->setMessageAttributes($messageAttributesTransfer); + + $loggerMock = $this->createMock(LoggerInterface::class); + $logMessageHandlingResultMiddleware = (new LogMessageHandlingResultMiddleware($this->getMessageLoggerMock($loggerMock))); + + $middlewareMock = $this->getMiddlewareMock(); + $stackMock = $this->getStackMock($middlewareMock); + + $exceptionMessage = 'TestException'; + $middlewareMock->expects($this->once()) + ->method('handle') + ->willThrowException(new MessageBrokerException($exceptionMessage)); + + $context = $this->getMessageLogDataFromMessageAttributesTransfer( + $messageAttributesTransfer, + static::TRANSFER_NAME, + ); + $expectedLog = [ + 'code' => $this->tester->getModuleConfig()->getMessageBrokerConsumeErrorCode(), + 'codeName' => $this->tester->getModuleConfig()->getMessageBrokerConsumeErrorCodeName(), + 'duration' => '0s', + 'activityType' => 'Message consuming', + ] + $context; + + // Assert + $loggerMock->expects($this->once()) + ->method('log') + ->with(Logger::ERROR, $exceptionMessage, $expectedLog); + $this->expectException(MessageBrokerException::class); + + // Act + $logMessageHandlingResultMiddleware->handle( + Envelope::wrap($messageBrokerTestMessageTransfer, [new ReceivedStamp('test')]), + $stackMock, + ); + } + + /** + * @param \Generated\Shared\Transfer\MessageAttributesTransfer $messageAttributesTransfer + * @param string $transferName + * + * @return array + */ + protected function getMessageLogDataFromMessageAttributesTransfer( + MessageAttributesTransfer $messageAttributesTransfer, + string $transferName + ): array { + $messageAttributesLogData = $messageAttributesTransfer->toArrayRecursiveCamelCased(); + $messageAttributesLogData['transferName'] = $transferName; + $messageAttributesLogData['event'] = $transferName; + $messageAttributesLogData['name'] = $transferName; + + if (isset($messageAttributesLogData[MessageAttributesTransfer::AUTHORIZATION])) { + unset($messageAttributesLogData[MessageAttributesTransfer::AUTHORIZATION]); + } + + return $messageAttributesLogData; + } + + /** + * @param \Psr\Log\LoggerInterface $loggerMock + * + * @return \Spryker\Zed\MessageBroker\Business\Logger\MessageLogger|\PHPUnit\Framework\MockObject\MockObject + */ + protected function getMessageLoggerMock(LoggerInterface $loggerMock): MessageLogger + { + $messageLoggerMock = $this->getMockBuilder(MessageLogger::class) + ->setConstructorArgs([ + $this->tester->getFactory()->getConfig(), + ]) + ->onlyMethods([ + 'getLogger', + 'getDurationInSeconds', + ]) + ->getMock(); + + $messageLoggerMock->expects($this->once())->method('getLogger')->willReturn($loggerMock); + $messageLoggerMock->method('getDurationInSeconds')->willReturn(0.0); + + return $messageLoggerMock; + } + + /** + * @return \Symfony\Component\Messenger\Middleware\MiddlewareInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected function getMiddlewareMock(): MiddlewareInterface + { + return $this->createMock(MiddlewareInterface::class); + } + + /** + * @param \Symfony\Component\Messenger\Middleware\MiddlewareInterface $middlewareMock + * + * @return \Symfony\Component\Messenger\Middleware\StackInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected function getStackMock(MiddlewareInterface $middlewareMock): StackInterface + { + $stackMock = $this->createMock(StackInterface::class); + $stackMock->expects($this->once())->method('next')->willReturn($middlewareMock); + + return $stackMock; + } +} diff --git a/tests/SprykerTest/Zed/MessageBroker/Business/Publisher/MessagePublisherTest.php b/tests/SprykerTest/Zed/MessageBroker/Business/Publisher/MessagePublisherTest.php index 64c2ff4..60e66b7 100644 --- a/tests/SprykerTest/Zed/MessageBroker/Business/Publisher/MessagePublisherTest.php +++ b/tests/SprykerTest/Zed/MessageBroker/Business/Publisher/MessagePublisherTest.php @@ -8,18 +8,8 @@ namespace SprykerTest\Zed\MessageBroker\Business\Publisher; use Codeception\Test\Unit; -use Generated\Shared\Transfer\MessageAttributesTransfer; -use Generated\Shared\Transfer\MessageBrokerTestMessageTransfer; use Generated\Shared\Transfer\OutgoingMessageTransfer; -use Monolog\Logger; -use Psr\Log\LoggerInterface; use Spryker\Zed\MessageBroker\Business\Exception\MessageBrokerException; -use Spryker\Zed\MessageBroker\Business\Logger\MessagePublishLogger; -use Spryker\Zed\MessageBroker\Business\Publisher\MessagePublisher; -use Spryker\Zed\MessageBroker\Business\Publisher\MessagePublisherInterface; -use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\MessageBus; -use Symfony\Component\Messenger\MessageBusInterface; /** * Auto-generated group annotations @@ -60,161 +50,18 @@ public function testPublishMessageThrowsExceptionWhenPassedTransferDoesNotHaveMe /** * @return void */ - public function testPublishMessageWritesSuccessLogInCaseOfSuccessfulMessageSending(): void - { - // Arrange - $messageBrokerTestMessageTransfer = new MessageBrokerTestMessageTransfer(); - $messageAttributesTransfer = $this->tester->getMessageAttributesTransfer(); - $messageBrokerTestMessageTransfer->setMessageAttributes($messageAttributesTransfer); - - $loggerMock = $this->createMock(LoggerInterface::class); - $messageBusMock = $this->createMock(MessageBus::class); - - $envelope = Envelope::wrap($messageBrokerTestMessageTransfer, []); - $messageBusMock->method('dispatch')->willReturn($envelope); - $messagePublisher = $this->getMessagePublisherMock($loggerMock, $messageBusMock); - - $context = $this->getMessageLogDataFromMessageAttributesTransfer( - $messageAttributesTransfer, - 'MessageBrokerTestMessage', - ); - $expectedLog = [ - 'code' => 11000, - 'codeName' => 'Message Broker call sendMessage Success', - 'duration' => 0, - 'activityType' => 'Message publishing', - ] + $context; - - // Assert - $loggerMock->expects($this->once()) - ->method('log') - ->with(Logger::INFO, '', $expectedLog); - - // Act - $messagePublisher->sendMessage($messageBrokerTestMessageTransfer); - } - - /** - * @return void - */ - public function testPublishMessageWritesErrorLogInCaseOfNotSuccessfulMessageSending(): void - { - // Arrange - $messageBrokerTestMessageTransfer = new MessageBrokerTestMessageTransfer(); - $messageAttributesTransfer = $this->tester->getMessageAttributesTransfer(); - $messageBrokerTestMessageTransfer->setMessageAttributes($messageAttributesTransfer); - - $loggerMock = $this->createMock(LoggerInterface::class); - $messageBusMock = $this->createMock(MessageBus::class); - $messageBusMock->method('dispatch')->willThrowException(new MessageBrokerException('TestException')); - $messagePublisher = $this->getMessagePublisherMock($loggerMock, $messageBusMock); - - $context = $this->getMessageLogDataFromMessageAttributesTransfer( - $messageAttributesTransfer, - 'MessageBrokerTestMessage', - ); - $expectedLog = [ - 'code' => 11001, - 'codeName' => 'Message Broker call sendMessage Error', - 'duration' => 0, - 'activityType' => 'Message publishing', - ] + $context; - - // Assert - $loggerMock->expects($this->once()) - ->method('log') - ->with(Logger::ERROR, 'TestException', $expectedLog); - $this->expectException(MessageBrokerException::class); - - // Act - $messagePublisher->sendMessage($messageBrokerTestMessageTransfer); - } - - /** - * @return void - */ - public function testPublishMessageWritesErrorLogInCaseOfMessageAttributesMethodDoesntExist(): void + public function testPublishMessageThrowsExceptionInCaseOfMessageAttributesMethodDoesntExist(): void { // Arrange + $this->tester->enableMessageBroker(); $outgoingMessageTransfer = new OutgoingMessageTransfer(); - $loggerMock = $this->createMock(LoggerInterface::class); - $messageBusMock = $this->createMock(MessageBus::class); - $messagePublisher = $this->getMessagePublisherMock($loggerMock, $messageBusMock); - - $expectedLog = [ - 'code' => 11001, - 'codeName' => 'Message Broker call sendMessage Error', - 'duration' => 0, - 'activityType' => 'Message publishing', - ]; + $messagePublisher = $this->tester->getFactory()->createMessagePublisher(); // Assert - $errorText = sprintf( - 'The passed "%s" transfer object must have an attribute "messageAttributes" but it was not found. Please add "" to your transfer definition.', - get_class($outgoingMessageTransfer), - ); - $loggerMock->expects($this->once()) - ->method('log') - ->with(Logger::ERROR, $errorText, $expectedLog); $this->expectException(MessageBrokerException::class); // Act $messagePublisher->sendMessage($outgoingMessageTransfer); } - - /** - * @param \Generated\Shared\Transfer\MessageAttributesTransfer $messageAttributesTransfer - * @param string $transferName - * - * @return array - */ - protected function getMessageLogDataFromMessageAttributesTransfer( - MessageAttributesTransfer $messageAttributesTransfer, - string $transferName - ): array { - $messageAttributesLogData = $messageAttributesTransfer->toArrayRecursiveCamelCased(); - $messageAttributesLogData['transferName'] = $transferName; - $messageAttributesLogData['event'] = $transferName; - $messageAttributesLogData['name'] = $transferName; - - if (isset($messageAttributesLogData[MessageAttributesTransfer::AUTHORIZATION])) { - unset($messageAttributesLogData[MessageAttributesTransfer::AUTHORIZATION]); - } - - return $messageAttributesLogData; - } - - /** - * @param \Psr\Log\LoggerInterface $loggerMock - * @param \Symfony\Component\Messenger\MessageBusInterface $messageBusMock - * - * @return \Spryker\Zed\MessageBroker\Business\Publisher\MessagePublisherInterface - */ - protected function getMessagePublisherMock( - LoggerInterface $loggerMock, - MessageBusInterface $messageBusMock - ): MessagePublisherInterface { - $messagePublishLoggerMock = $this->getMockBuilder(MessagePublishLogger::class) - ->setConstructorArgs([ - $this->tester->getFactory()->getConfig(), - ]) - ->onlyMethods([ - 'getLogger', - 'getDuration', - ]) - ->getMock(); - - $messagePublishLoggerMock->method('getLogger')->willReturn($loggerMock); - $messagePublishLoggerMock->method('getDuration')->willReturn(0); - - $messagePublisher = $this->createTestProxy(MessagePublisher::class, [ - $this->tester->getFactory()->createMessageDecorator(), - $messageBusMock, - $messagePublishLoggerMock, - $this->tester->getModuleConfig(), - ]); - - return $messagePublisher; - } }