From adf4d784edd2b663b2a9ea928c6046aab6f6f131 Mon Sep 17 00:00:00 2001 From: Mykhailo Shtanko Date: Sun, 21 Aug 2022 18:58:23 +0300 Subject: [PATCH] [TransactionalMessenger] Refactoring, Added tests --- MessageBus/TransactionalMessageBus.php | 35 +++++++++--------- .../TransactionalMessageBusCommitTest.php | 16 ++++++--- .../TransactionalMessageBusRollbackTest.php | 36 +++++++++++++++---- .../Unit/ValueObject/PendingEnvelopeTest.php | 14 +++++--- .../Unit/ValueObject/SucceedEnvelopeTest.php | 6 ++-- ValueObject/PendingEnvelope.php | 7 ++++ 6 files changed, 78 insertions(+), 36 deletions(-) diff --git a/MessageBus/TransactionalMessageBus.php b/MessageBus/TransactionalMessageBus.php index 5f6e70b..9134eec 100644 --- a/MessageBus/TransactionalMessageBus.php +++ b/MessageBus/TransactionalMessageBus.php @@ -55,8 +55,7 @@ public function dispatch(object $message, array $stamps = []): Envelope TransactionHelper::isTransactional($message) ? $this->pendingStorage->append(new PendingEnvelope($envelope)) - : $this->dispatchEnvelope($envelope) - ; + : $this->dispatchEnvelope($envelope); return $envelope; } @@ -85,26 +84,20 @@ public function rollback(\Throwable $exception): void $this->dispatchFailedEnvelopes(); } catch (\Throwable $e) { throw MessageBusException::fromThrowable($e); + } finally { + $this->pendingStorage->clear(); + $this->succeedStorage->clear(); + $this->failedStorage->clear(); } - - $this->pendingStorage->clear(); - $this->succeedStorage->clear(); - $this->failedStorage->clear(); } private function dispatchPendingEnvelopes(CommitType ...$commitTypes): void { - $pendingEnvelopes = ArrayList::collect($this->pendingStorage->iterate()); - - $pendingEnvelopes - ->filter(static fn (PendingEnvelope $pe) => TransactionHelper::isDispatchable($pe->getMessageClass(), ...$commitTypes)) - ->tap(fn (PendingEnvelope $pe) => $this->dispatchEnvelope($pe->envelope)) - ; - - $pendingEnvelopes - ->filter(static fn (PendingEnvelope $pe) => !TransactionHelper::isDispatchable($pe->getMessageClass(), ...$commitTypes)) - ->tap(fn (PendingEnvelope $pe) => $this->pendingStorage->prepend($pe)) - ; + ArrayList::collect($this->pendingStorage->iterate())->tap( + fn (PendingEnvelope $pe) => $pe->isTransactional(...$commitTypes) + ? $this->dispatchEnvelope($pe->envelope) + : $this->pendingStorage->prepend($pe), + ); } private function dispatchSucceedEnvelopes(): void @@ -121,17 +114,21 @@ private function dispatchFailedEnvelopes(): void ; } - private function dispatchEnvelope(Envelope $envelope): void + private function dispatchEnvelope(Envelope $envelope): Envelope { try { $this->succeedStorage->append(new SucceedEnvelope($this->decoratedBus->dispatch($envelope))); } catch (\Throwable $e) { $this->failedStorage->append(new FailedEnvelope($envelope, $e)); + } finally { + return $envelope; } } - private function dispatchEvent(Event $event): void + private function dispatchEvent(Event $event): Event { $this->eventDispatcher->dispatch($event); + + return $event; } } diff --git a/Tests/Unit/MessageBus/TransactionalMessageBusCommitTest.php b/Tests/Unit/MessageBus/TransactionalMessageBusCommitTest.php index d355581..87c2696 100644 --- a/Tests/Unit/MessageBus/TransactionalMessageBusCommitTest.php +++ b/Tests/Unit/MessageBus/TransactionalMessageBusCommitTest.php @@ -78,16 +78,16 @@ public function testCommitMethod( $this->eventDispatcher ->expects(self::exactly($expectsEventDispatcher)) ->method('dispatch') - ->willReturnCallback(fn (object $event) => self::assertInstanceOf($eventClass, $event)) + ->willThrowException(new \Exception('Something goes wrong')) ; + + $this->expectException(MessageBusException::class); } else { $this->eventDispatcher ->expects(self::exactly($expectsEventDispatcher)) ->method('dispatch') - ->willThrowException(new \Exception('Something goes wrong')) + ->willReturnCallback(fn (object $event) => self::assertInstanceOf($eventClass, $event)) ; - - $this->expectException(MessageBusException::class); } $envelope = $this->messageBus->dispatch($message); @@ -99,6 +99,14 @@ public function testCommitMethod( self::assertSame($failedCount, $this->failedStorage->count()); } + /** @throws \ReflectionException */ + public function testPrivateDispatchEnvelopeMethod(): void + { + $envelope = EnvelopeHelper::wrap(new TransactionalOnTerminateMessage()); + + self::assertSame(spl_object_hash($envelope), spl_object_hash((new \ReflectionMethod($this->messageBus, 'dispatchEnvelope'))->invoke($this->messageBus, $envelope))); + } + public function dataProvider(): iterable { yield sprintf('%s is succeed commit', ClassHelper::getShortName(TransactionalOnTerminateMessage::class)) => [ diff --git a/Tests/Unit/MessageBus/TransactionalMessageBusRollbackTest.php b/Tests/Unit/MessageBus/TransactionalMessageBusRollbackTest.php index 9a271d1..77300ee 100644 --- a/Tests/Unit/MessageBus/TransactionalMessageBusRollbackTest.php +++ b/Tests/Unit/MessageBus/TransactionalMessageBusRollbackTest.php @@ -5,6 +5,7 @@ namespace FRZB\Component\TransactionalMessenger\Tests\Unit\MessageBus; use FRZB\Component\TransactionalMessenger\Event\DispatchFailedEvent; +use FRZB\Component\TransactionalMessenger\Exception\MessageBusException; use FRZB\Component\TransactionalMessenger\Helper\ClassHelper; use FRZB\Component\TransactionalMessenger\Helper\EnvelopeHelper; use FRZB\Component\TransactionalMessenger\MessageBus\TransactionalMessageBus as TransactionalMessageBusImpl; @@ -50,7 +51,8 @@ public function testRollbackMethod( int $pendingCount, int $succeedCount, int $failedCount, - int $expectsEventDispatcher + int $expectsEventDispatcher, + bool $isEventDispatcherThrows, ): void { $this->decoratedBus ->expects(self::never()) @@ -58,11 +60,21 @@ public function testRollbackMethod( ->willReturn(EnvelopeHelper::wrap($message)) ; - $this->eventDispatcher - ->expects(self::exactly($expectsEventDispatcher)) - ->method('dispatch') - ->willReturnCallback(fn (DispatchFailedEvent $event) => self::assertSame(spl_object_hash($message), spl_object_hash($event->envelope->envelope->getMessage()))) - ; + if ($isEventDispatcherThrows) { + $this->eventDispatcher + ->expects(self::exactly($expectsEventDispatcher)) + ->method('dispatch') + ->willThrowException(new \Exception('Something goes wrong')) + ; + + $this->expectException(MessageBusException::class); + } else { + $this->eventDispatcher + ->expects(self::exactly($expectsEventDispatcher)) + ->method('dispatch') + ->willReturnCallback(fn (DispatchFailedEvent $event) => self::assertSame(spl_object_hash($message), spl_object_hash($event->envelope->envelope->getMessage()))) + ; + } $envelope = $this->messageBus->dispatch($message); $this->messageBus->rollback(new \Exception('Something goes wrong')); @@ -81,6 +93,7 @@ public function dataProvider(): iterable 'succeed_count' => 0, 'failed_count' => 0, 'expects_event_dispatcher' => 1, + 'is_event_dispatcher_throws' => false, ]; yield sprintf('%s is dispatched delayed', ClassHelper::getShortName(TransactionalOnResponseMessage::class)) => [ @@ -89,6 +102,7 @@ public function dataProvider(): iterable 'succeed_count' => 0, 'failed_count' => 0, 'expects_event_dispatcher' => 1, + 'is_event_dispatcher_throws' => false, ]; yield sprintf('%s is dispatched delayed', ClassHelper::getShortName(TransactionalOnHandledMessage::class)) => [ @@ -97,6 +111,16 @@ public function dataProvider(): iterable 'succeed_count' => 0, 'failed_count' => 0, 'expects_event_dispatcher' => 1, + 'is_event_dispatcher_throws' => false, + ]; + + yield sprintf('%s event dispatcher throws', ClassHelper::getShortName(TransactionalOnHandledMessage::class)) => [ + 'message' => new TransactionalOnHandledMessage(), + 'pending_count' => 0, + 'succeed_count' => 0, + 'failed_count' => 0, + 'expects_event_dispatcher' => 1, + 'is_event_dispatcher_throws' => true, ]; } } diff --git a/Tests/Unit/ValueObject/PendingEnvelopeTest.php b/Tests/Unit/ValueObject/PendingEnvelopeTest.php index 11c4f1b..4d25906 100644 --- a/Tests/Unit/ValueObject/PendingEnvelopeTest.php +++ b/Tests/Unit/ValueObject/PendingEnvelopeTest.php @@ -4,6 +4,7 @@ namespace FRZB\Component\TransactionalMessenger\Tests\Unit\ValueObject; +use FRZB\Component\TransactionalMessenger\Enum\CommitType; use FRZB\Component\TransactionalMessenger\Helper\EnvelopeHelper; use FRZB\Component\TransactionalMessenger\Tests\Stub\Message\TransactionalOnHandledMessage; use FRZB\Component\TransactionalMessenger\Tests\Stub\Message\TransactionalOnResponseMessage; @@ -18,28 +19,33 @@ class PendingEnvelopeTest extends TestCase { #[DataProvider('dataProvider')] - public function testConstructorMethod(object $message): void + public function testConstructorMethod(object $message, array $commitTypes): void { $envelope = EnvelopeHelper::wrap($message); $whenPended = new \DateTimeImmutable(); - $failedEnvelope = new PendingEnvelope($envelope, $whenPended); + $pendingEnvelope = new PendingEnvelope($envelope, $whenPended); - self::assertSame($whenPended, $failedEnvelope->whenPended); - self::assertSame(spl_object_hash($message), spl_object_hash($failedEnvelope->envelope->getMessage())); + self::assertSame($whenPended, $pendingEnvelope->whenPended); + self::assertSame(spl_object_hash($message), spl_object_hash($pendingEnvelope->envelope->getMessage())); + self::assertSame($message::class, $pendingEnvelope->getMessageClass()); + self::assertTrue($pendingEnvelope->isTransactional(...$commitTypes)); } public function dataProvider(): iterable { yield 'TransactionalOnTerminateMessage with PendingEnvelope' => [ 'message' => new TransactionalOnTerminateMessage(), + 'commitTypes' => [CommitType::OnTerminate], ]; yield 'TransactionalOnResponseMessage with PendingEnvelope' => [ 'message' => new TransactionalOnResponseMessage(), + 'commitTypes' => [CommitType::OnResponse], ]; yield 'TransactionalOnHandledMessage with PendingEnvelope' => [ 'message' => new TransactionalOnHandledMessage(), + 'commitTypes' => [CommitType::OnHandled], ]; } } diff --git a/Tests/Unit/ValueObject/SucceedEnvelopeTest.php b/Tests/Unit/ValueObject/SucceedEnvelopeTest.php index 21d0ed6..8f53efd 100644 --- a/Tests/Unit/ValueObject/SucceedEnvelopeTest.php +++ b/Tests/Unit/ValueObject/SucceedEnvelopeTest.php @@ -22,10 +22,10 @@ public function testConstructorMethod(object $message): void { $envelope = EnvelopeHelper::wrap($message); $whenDispatched = new \DateTimeImmutable(); - $failedEnvelope = new SucceedEnvelope($envelope, $whenDispatched); + $succeedEnvelope = new SucceedEnvelope($envelope, $whenDispatched); - self::assertSame($whenDispatched, $failedEnvelope->whenDispatched); - self::assertSame(spl_object_hash($message), spl_object_hash($failedEnvelope->envelope->getMessage())); + self::assertSame($whenDispatched, $succeedEnvelope->whenDispatched); + self::assertSame(spl_object_hash($message), spl_object_hash($succeedEnvelope->envelope->getMessage())); } public function dataProvider(): iterable diff --git a/ValueObject/PendingEnvelope.php b/ValueObject/PendingEnvelope.php index e388a92..63358a8 100644 --- a/ValueObject/PendingEnvelope.php +++ b/ValueObject/PendingEnvelope.php @@ -4,6 +4,8 @@ namespace FRZB\Component\TransactionalMessenger\ValueObject; +use FRZB\Component\TransactionalMessenger\Enum\CommitType; +use FRZB\Component\TransactionalMessenger\Helper\TransactionHelper; use JetBrains\PhpStorm\Immutable; use Symfony\Component\Messenger\Envelope; @@ -21,4 +23,9 @@ public function getMessageClass(): string { return $this->envelope->getMessage()::class; } + + public function isTransactional(CommitType ...$commitTypes): bool + { + return TransactionHelper::isDispatchable($this->getMessageClass(), ...$commitTypes); + } }