diff --git a/src/Message/IdEnvelope.php b/src/Message/IdEnvelope.php index bbf0d67f..b321cb8c 100644 --- a/src/Message/IdEnvelope.php +++ b/src/Message/IdEnvelope.php @@ -21,7 +21,7 @@ public function __construct( public static function fromMessage(MessageInterface $message): self { - return new self($message, $message->getMetadata()[self::MESSAGE_ID_KEY] ?? null); + return new self($message, self::getIdFromMessage($message)); } public function setId(string|int|null $id): void @@ -31,11 +31,27 @@ public function setId(string|int|null $id): void public function getId(): string|int|null { - return $this->id ?? $this->message->getMetadata()[self::MESSAGE_ID_KEY] ?? null; + return $this->id ?? self::getIdFromMessage($this->message); } private function getEnvelopeMetadata(): array { return [self::MESSAGE_ID_KEY => $this->getId()]; } + + private static function getIdFromMessage(MessageInterface $message): string|int|null + { + $id = $message->getMetadata()[self::MESSAGE_ID_KEY] ?? null; + if ($id instanceof \Stringable) { + $id = (string) $id; + } + + // We don't throw an error as this value could come from external sources, + // and we should process the message either way + if (!is_string($id) && !is_int($id)) { + return null; + } + + return $id; + } } diff --git a/tests/Unit/Message/IdEnvelopeTest.php b/tests/Unit/Message/IdEnvelopeTest.php new file mode 100644 index 00000000..8e866056 --- /dev/null +++ b/tests/Unit/Message/IdEnvelopeTest.php @@ -0,0 +1,112 @@ +createMessage(); + $id = 'test-id'; + + $envelope = new IdEnvelope($message, $id); + + $this->assertSame($message, $envelope->getMessage()); + $this->assertSame($id, $envelope->getId()); + } + + public function testFromMessageWithStringId(): void + { + $id = 'test-id'; + $message = $this->createMessage([IdEnvelope::MESSAGE_ID_KEY => $id]); + + $envelope = IdEnvelope::fromMessage($message); + + $this->assertSame($id, $envelope->getId()); + } + + public function testFromMessageWithIntId(): void + { + $id = 123; + $message = $this->createMessage([IdEnvelope::MESSAGE_ID_KEY => $id]); + + $envelope = IdEnvelope::fromMessage($message); + + $this->assertSame($id, $envelope->getId()); + } + + public function testFromMessageWithNullId(): void + { + $message = $this->createMessage(); + + $envelope = IdEnvelope::fromMessage($message); + + $this->assertNull($envelope->getId()); + } + + public function testFromMessageWithObjectHavingToString(): void + { + $stringableObject = new class () { + public function __toString(): string + { + return 'object-id'; + } + }; + $message = $this->createMessage([IdEnvelope::MESSAGE_ID_KEY => $stringableObject]); + $envelope = IdEnvelope::fromMessage($message); + + $this->assertSame('object-id', $envelope->getId()); + } + + public function testFromMessageWithInvalidIdType(): void + { + $invalidId = ['array-cannot-be-id']; + $message = $this->createMessage([IdEnvelope::MESSAGE_ID_KEY => $invalidId]); + $message = IdEnvelope::fromMessage($message); + + $this->assertNull($message->getId()); + } + + public function testGetEnvelopeMetadata(): void + { + $id = 'test-id'; + $message = $this->createMessage(); + $envelope = new IdEnvelope($message, $id); + + $metadata = $envelope->getMetadata(); + + $this->assertArrayHasKey(IdEnvelope::MESSAGE_ID_KEY, $metadata); + $this->assertSame($id, $metadata[IdEnvelope::MESSAGE_ID_KEY]); + } + + public function testFromData(): void + { + $handlerName = 'test-handler'; + $data = ['key' => 'value']; + $metadata = ['meta' => 'data', IdEnvelope::MESSAGE_ID_KEY => 'test-id']; + + /** + * @var IdEnvelope $envelope + */ + $envelope = IdEnvelope::fromData($handlerName, $data, $metadata); + + $this->assertInstanceOf(IdEnvelope::class, $envelope); + $this->assertSame($handlerName, $envelope->getHandlerName()); + $this->assertSame($data, $envelope->getData()); + $this->assertArrayHasKey('meta', $envelope->getMetadata()); + $this->assertSame('data', $envelope->getMetadata()['meta']); + $this->assertSame('test-id', $envelope->getId()); + } + + private function createMessage(array $metadata = []): MessageInterface + { + return new Message('test-handler', ['test-data'], $metadata); + } +} diff --git a/tests/Unit/Middleware/FailureHandling/FailureEnvelopeTest.php b/tests/Unit/Middleware/FailureHandling/FailureEnvelopeTest.php new file mode 100644 index 00000000..e3991cc7 --- /dev/null +++ b/tests/Unit/Middleware/FailureHandling/FailureEnvelopeTest.php @@ -0,0 +1,83 @@ +createMessage(); + $metadata = ['attempt' => 1, 'error' => 'Test error']; + + $envelope = new FailureEnvelope($message, $metadata); + + $this->assertSame($message, $envelope->getMessage()); + $this->assertArrayHasKey(FailureEnvelope::FAILURE_META_KEY, $envelope->getMetadata()); + $this->assertSame($metadata, $envelope->getMetadata()[FailureEnvelope::FAILURE_META_KEY]); + } + + public function testFromMessageWithExistingMetadata(): void + { + $existingMetadata = ['attempt' => 1]; + $message = $this->createMessage([FailureEnvelope::FAILURE_META_KEY => $existingMetadata]); + + $envelope = FailureEnvelope::fromMessage($message); + + $this->assertSame($existingMetadata, $envelope->getMetadata()[FailureEnvelope::FAILURE_META_KEY]); + } + + public function testFromMessageWithoutMetadata(): void + { + $message = $this->createMessage(); + + $envelope = FailureEnvelope::fromMessage($message); + + $this->assertArrayHasKey(FailureEnvelope::FAILURE_META_KEY, $envelope->getMetadata()); + $this->assertSame([], $envelope->getMetadata()[FailureEnvelope::FAILURE_META_KEY]); + } + + public function testMetadataMerging(): void + { + $existingMetadata = ['attempt' => 1, 'firstError' => 'First error']; + $message = $this->createMessage([FailureEnvelope::FAILURE_META_KEY => $existingMetadata]); + $newMetadata = ['attempt' => 2, 'lastError' => 'Last error']; + + $envelope = new FailureEnvelope($message, $newMetadata); + + $mergedMetadata = $envelope->getMetadata()[FailureEnvelope::FAILURE_META_KEY]; + $this->assertSame(2, $mergedMetadata['attempt']); + $this->assertSame('First error', $mergedMetadata['firstError']); + $this->assertSame('Last error', $mergedMetadata['lastError']); + } + + public function testFromData(): void + { + $handlerName = 'test-handler'; + $data = ['key' => 'value']; + $metadata = [ + 'meta' => 'data', + FailureEnvelope::FAILURE_META_KEY => ['attempt' => 1], + ]; + + $envelope = FailureEnvelope::fromData($handlerName, $data, $metadata); + + $this->assertInstanceOf(FailureEnvelope::class, $envelope); + $this->assertSame($handlerName, $envelope->getHandlerName()); + $this->assertSame($data, $envelope->getData()); + $this->assertArrayHasKey('meta', $envelope->getMetadata()); + $this->assertSame('data', $envelope->getMetadata()['meta']); + $this->assertSame(['attempt' => 1], $envelope->getMetadata()[FailureEnvelope::FAILURE_META_KEY]); + } + + private function createMessage(array $metadata = []): MessageInterface + { + return new Message('test-handler', ['test-data'], $metadata); + } +} diff --git a/tests/Unit/Middleware/FailureHandling/Implementation/SendAgainMiddlewareTest.php b/tests/Unit/Middleware/FailureHandling/Implementation/SendAgainMiddlewareTest.php index 665c6bea..92351a8d 100644 --- a/tests/Unit/Middleware/FailureHandling/Implementation/SendAgainMiddlewareTest.php +++ b/tests/Unit/Middleware/FailureHandling/Implementation/SendAgainMiddlewareTest.php @@ -151,9 +151,6 @@ public function testQueueSendingStrategies( $this->expectExceptionMessage('testException'); } - $metaInitial = [FailureEnvelope::FAILURE_META_KEY => $metaInitial]; - $metaResult = [FailureEnvelope::FAILURE_META_KEY => $metaResult]; - $handler = $this->getHandler($metaResult, $suites); $queue = $this->getPreparedQueue($metaResult, $suites); @@ -162,7 +159,7 @@ public function testQueueSendingStrategies( new Message( 'test', null, - $metaInitial + [FailureEnvelope::FAILURE_META_KEY => $metaInitial] ), new Exception('testException'), $queue @@ -194,7 +191,7 @@ private function getHandler(array $metaResult, bool $suites): MessageFailureHand $pipelineAssertion = static function (FailureHandlingRequest $request) use ( $metaResult ): FailureHandlingRequest { - Assert::assertEquals($metaResult, $request->getMessage()->getMetadata()); + Assert::assertEquals($metaResult, $request->getMessage()->getMetadata()[FailureEnvelope::FAILURE_META_KEY] ?? []); throw $request->getException(); }; @@ -209,7 +206,7 @@ private function getHandler(array $metaResult, bool $suites): MessageFailureHand private function getPreparedQueue(array $metaResult, bool $suites): QueueInterface { $queueAssertion = static function (MessageInterface $message) use ($metaResult): MessageInterface { - Assert::assertEquals($metaResult, $message->getMetadata()); + Assert::assertEquals($metaResult, $message->getMetadata()[FailureEnvelope::FAILURE_META_KEY] ?? []); return $message; };