From 8c79c1867d5927c60b8f94381af73e76396fbe48 Mon Sep 17 00:00:00 2001 From: David Badura Date: Mon, 13 Dec 2021 11:01:38 +0100 Subject: [PATCH] check playhead mismatch --- docs/tests.md | 2 +- src/Aggregate/AggregateRoot.php | 5 + src/Aggregate/PlayheadSequenceMismatch.php | 13 ++ src/Aggregate/SnapshotableAggregateRoot.php | 5 + tests/Unit/Aggregate/AggregateRootTest.php | 26 +++- .../SnapshotableAggregateRootTest.php | 131 +++++++----------- 6 files changed, 99 insertions(+), 83 deletions(-) create mode 100644 src/Aggregate/PlayheadSequenceMismatch.php diff --git a/docs/tests.md b/docs/tests.md index c333847ef..15f1d2ef4 100644 --- a/docs/tests.md +++ b/docs/tests.md @@ -25,7 +25,7 @@ final class ProfileTest extends TestCase $id = ProfileId::generate(); $events = [ - ProfileCreated::raise($id, Email::fromString('foo@email.com')), + ProfileCreated::raise($id, Email::fromString('foo@email.com'))->recordNow(1), ]; $profile = Profile::createFromEventStream($events); diff --git a/src/Aggregate/AggregateRoot.php b/src/Aggregate/AggregateRoot.php index dfebf8bf2..d8311fdc9 100644 --- a/src/Aggregate/AggregateRoot.php +++ b/src/Aggregate/AggregateRoot.php @@ -55,6 +55,11 @@ public static function createFromEventStream(array $stream): self foreach ($stream as $message) { $self->playhead++; + + if ($self->playhead !== $message->playhead()) { + throw new PlayheadSequenceMismatch(); + } + $self->apply($message); } diff --git a/src/Aggregate/PlayheadSequenceMismatch.php b/src/Aggregate/PlayheadSequenceMismatch.php new file mode 100644 index 000000000..0ea2c8c0f --- /dev/null +++ b/src/Aggregate/PlayheadSequenceMismatch.php @@ -0,0 +1,13 @@ +playhead++; + + if ($self->playhead !== $message->playhead()) { + throw new PlayheadSequenceMismatch(); + } + $self->apply($message); } diff --git a/tests/Unit/Aggregate/AggregateRootTest.php b/tests/Unit/Aggregate/AggregateRootTest.php index 7eddbe000..90e06dfc4 100644 --- a/tests/Unit/Aggregate/AggregateRootTest.php +++ b/tests/Unit/Aggregate/AggregateRootTest.php @@ -4,6 +4,7 @@ namespace Patchlevel\EventSourcing\Tests\Unit\Aggregate; +use Patchlevel\EventSourcing\Aggregate\PlayheadSequenceMismatch; use Patchlevel\EventSourcing\Tests\Unit\Fixture\Email; use Patchlevel\EventSourcing\Tests\Unit\Fixture\Message; use Patchlevel\EventSourcing\Tests\Unit\Fixture\MessageId; @@ -106,14 +107,14 @@ public function testInitliazingState(): void ProfileCreated::raise( ProfileId::fromString('1'), Email::fromString('profile@test.com') - ), + )->recordNow(1), MessagePublished::raise( ProfileId::fromString('1'), Message::create( MessageId::fromString('2'), 'message value' ) - ), + )->recordNow(2), ]; $profile = Profile::createFromEventStream($eventStream); @@ -121,4 +122,25 @@ public function testInitliazingState(): void self::assertEquals('1', $profile->id()->toString()); self::assertCount(1, $profile->messages()); } + + public function testPlayheadSequenceMismatch(): void + { + $this->expectException(PlayheadSequenceMismatch::class); + + $eventStream = [ + ProfileCreated::raise( + ProfileId::fromString('1'), + Email::fromString('profile@test.com') + )->recordNow(1), + MessagePublished::raise( + ProfileId::fromString('1'), + Message::create( + MessageId::fromString('2'), + 'message value' + ) + )->recordNow(1), + ]; + + Profile::createFromEventStream($eventStream); + } } diff --git a/tests/Unit/Aggregate/SnapshotableAggregateRootTest.php b/tests/Unit/Aggregate/SnapshotableAggregateRootTest.php index 329fc4ba4..d3dcd8a30 100644 --- a/tests/Unit/Aggregate/SnapshotableAggregateRootTest.php +++ b/tests/Unit/Aggregate/SnapshotableAggregateRootTest.php @@ -4,127 +4,98 @@ namespace Patchlevel\EventSourcing\Tests\Unit\Aggregate; +use Patchlevel\EventSourcing\Aggregate\PlayheadSequenceMismatch; use Patchlevel\EventSourcing\Snapshot\Snapshot; use Patchlevel\EventSourcing\Tests\Unit\Fixture\Email; use Patchlevel\EventSourcing\Tests\Unit\Fixture\Message; use Patchlevel\EventSourcing\Tests\Unit\Fixture\MessageId; use Patchlevel\EventSourcing\Tests\Unit\Fixture\MessagePublished; -use Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileCreated; use Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileId; use Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileWithSnapshot; use PHPUnit\Framework\TestCase; class SnapshotableAggregateRootTest extends TestCase { - public function testCreateAggregate(): void + public function testSerialize(): void { $id = ProfileId::fromString('1'); - $email = Email::fromString('d.a.badura@gmail.com'); + $email = Email::fromString('david.badura@patchlevel.de'); $profile = ProfileWithSnapshot::createProfile($id, $email); + $snapshot = $profile->toSnapshot(); - self::assertEquals('1', $profile->aggregateRootId()); - self::assertEquals(1, $profile->playhead()); - self::assertEquals($id, $profile->id()); - self::assertEquals($email, $profile->email()); - - $events = $profile->releaseEvents(); - - self::assertCount(1, $events); - $event = $events[0]; - self::assertEquals(1, $event->playhead()); - } - - public function testExecuteMethod(): void - { - $profileId = ProfileId::fromString('1'); - $email = Email::fromString('d.a.badura@gmail.com'); - - $messageId = MessageId::fromString('2'); - - $profile = ProfileWithSnapshot::createProfile($profileId, $email); - - $events = $profile->releaseEvents(); - - self::assertCount(1, $events); - self::assertEquals(1, $profile->playhead()); - $event = $events[0]; - self::assertEquals(1, $event->playhead()); - - $profile->publishMessage( - Message::create( - $messageId, - 'foo' - ) + self::assertEquals('1', $snapshot->id()); + self::assertEquals(1, $snapshot->playhead()); + self::assertEquals(ProfileWithSnapshot::class, $snapshot->aggregate()); + self::assertEquals( + [ + 'id' => '1', + 'email' => 'david.badura@patchlevel.de', + ], + $snapshot->payload() ); - - self::assertEquals('1', $profile->aggregateRootId()); - self::assertEquals(2, $profile->playhead()); - self::assertEquals($profileId, $profile->id()); - self::assertEquals($email, $profile->email()); - - $events = $profile->releaseEvents(); - - self::assertCount(1, $events); - $event = $events[0]; - self::assertEquals(2, $event->playhead()); } - public function testEventWithoutApplyMethod(): void + public function testInitliazingState(): void { - $visitorProfile = ProfileWithSnapshot::createProfile( - ProfileId::fromString('1'), - Email::fromString('visitor@test.com') - ); - - $events = $visitorProfile->releaseEvents(); - self::assertCount(1, $events); - self::assertEquals(1, $visitorProfile->playhead()); - $event = $events[0]; - self::assertEquals(1, $event->playhead()); + $eventStream = [ + MessagePublished::raise( + ProfileId::fromString('1'), + Message::create( + MessageId::fromString('2'), + 'message value' + ) + )->recordNow(2), + ]; - $visitedProfile = ProfileWithSnapshot::createProfile( - ProfileId::fromString('2'), - Email::fromString('visited@test.com') + $snapshot = new Snapshot( + ProfileWithSnapshot::class, + '1', + 1, + [ + 'id' => '1', + 'email' => 'profile@test.com', + ] ); - $events = $visitedProfile->releaseEvents(); - self::assertCount(1, $events); - self::assertEquals(1, $visitedProfile->playhead()); - $event = $events[0]; - self::assertEquals(1, $event->playhead()); - - $visitorProfile->visitProfile($visitedProfile->id()); + $profile = ProfileWithSnapshot::createFromSnapshot($snapshot, $eventStream); - $events = $visitedProfile->releaseEvents(); - self::assertCount(0, $events); - self::assertEquals(1, $visitedProfile->playhead()); + self::assertEquals('1', $profile->id()->toString()); + self::assertCount(1, $profile->messages()); } - public function testInitliazingState(): void + public function testCreateFromSnapshot(): void { $eventStream = [ - ProfileCreated::raise( - ProfileId::fromString('1'), - Email::fromString('profile@test.com') - ), MessagePublished::raise( ProfileId::fromString('1'), Message::create( MessageId::fromString('2'), 'message value' ) - ), + )->recordNow(2), ]; - $profile = ProfileWithSnapshot::createFromEventStream($eventStream); + $snapshot = new Snapshot( + ProfileWithSnapshot::class, + '1', + 1, + [ + 'id' => '1', + 'email' => 'profile@test.com', + ] + ); + + $profile = ProfileWithSnapshot::createFromSnapshot($snapshot, $eventStream); self::assertEquals('1', $profile->id()->toString()); self::assertCount(1, $profile->messages()); } - public function testCreateFromSnapshot(): void + public function testPlayheadSequenceMismatch(): void { + $this->expectException(PlayheadSequenceMismatch::class); + $eventStream = [ MessagePublished::raise( ProfileId::fromString('1'), @@ -132,7 +103,7 @@ public function testCreateFromSnapshot(): void MessageId::fromString('2'), 'message value' ) - ), + )->recordNow(5), ]; $snapshot = new Snapshot(