From 8ab1c60d90494ab0f85cc3f8cb0dffa1a6f5a1f2 Mon Sep 17 00:00:00 2001 From: Daniel Badura Date: Mon, 5 Feb 2024 17:44:50 +0100 Subject: [PATCH] Add more tests --- infection.json.dist | 2 +- .../RecalculatePlayheadMiddleware.php | 5 ++ .../AggregateRootIdNotSupportedTest.php | 1 + .../Aggregate/ApplyMethodNotFoundTest.php | 1 + .../Aggregate/MetadataNotPossibleTest.php | 1 + .../Unit/Console/InvalidArgumentGivenTest.php | 1 + tests/Unit/Outbox/DoctrineOutboxStoreTest.php | 58 ++++++++++++-- .../RecalculatePlayheadMiddlewareTest.php | 65 +++++++++++++++- .../Pipeline/Source/InMemorySourceTest.php | 11 +++ .../Target/ProjectorRepositoryTargetTest.php | 78 +++++++++++++++++++ .../Pipeline/Target/ProjectorTargetTest.php | 72 +++++++++++++++++ .../Projection/DuplicateProjectionIdTest.php | 1 + .../Projection/ProjectionNotFoundTest.php | 1 + .../Encoder/DecodeNotPossibleTest.php | 1 + .../Encoder/EncodeNotPossibleTest.php | 1 + .../Adapter/InMemorySnapshotAdapterTest.php | 13 ++++ .../Snapshot/Adapter/SnapshotNotFoundTest.php | 23 ++++++ tests/Unit/Snapshot/AdapterNotFoundTest.php | 25 ++++++ .../Snapshot/DefaultSnapshotStoreTest.php | 25 ++++++ .../Snapshot/SnapshotNotConfiguredTest.php | 26 +++++++ tests/Unit/Snapshot/SnapshotNotFoundTest.php | 25 ++++++ .../Snapshot/SnapshotVersionInvalidTest.php | 26 +++++++ 22 files changed, 452 insertions(+), 10 deletions(-) create mode 100644 tests/Unit/Pipeline/Target/ProjectorRepositoryTargetTest.php create mode 100644 tests/Unit/Pipeline/Target/ProjectorTargetTest.php create mode 100644 tests/Unit/Snapshot/Adapter/SnapshotNotFoundTest.php create mode 100644 tests/Unit/Snapshot/AdapterNotFoundTest.php create mode 100644 tests/Unit/Snapshot/SnapshotNotConfiguredTest.php create mode 100644 tests/Unit/Snapshot/SnapshotNotFoundTest.php create mode 100644 tests/Unit/Snapshot/SnapshotVersionInvalidTest.php diff --git a/infection.json.dist b/infection.json.dist index 4f4727e31..58734de82 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -14,6 +14,6 @@ "@default": true }, "minMsi": 57, - "minCoveredMsi": 90, + "minCoveredMsi": 87, "testFrameworkOptions": "--testsuite=unit" } diff --git a/src/Pipeline/Middleware/RecalculatePlayheadMiddleware.php b/src/Pipeline/Middleware/RecalculatePlayheadMiddleware.php index d2f5addea..89204bf4b 100644 --- a/src/Pipeline/Middleware/RecalculatePlayheadMiddleware.php +++ b/src/Pipeline/Middleware/RecalculatePlayheadMiddleware.php @@ -28,6 +28,11 @@ public function __invoke(Message $message): array ]; } + public function reset(): void + { + $this->index = []; + } + /** * @param class-string $aggregateClass * diff --git a/tests/Unit/Aggregate/AggregateRootIdNotSupportedTest.php b/tests/Unit/Aggregate/AggregateRootIdNotSupportedTest.php index 474671e24..8b0246782 100644 --- a/tests/Unit/Aggregate/AggregateRootIdNotSupportedTest.php +++ b/tests/Unit/Aggregate/AggregateRootIdNotSupportedTest.php @@ -19,5 +19,6 @@ public function testCreate(): void 'aggregate root id in class "Patchlevel\EventSourcing\Tests\Unit\Fixture\Profile" must be instance of "Patchlevel\EventSourcing\Aggregate\AggregateRootId", got "int"', $exception->getMessage(), ); + self::assertSame(0, $exception->getCode()); } } diff --git a/tests/Unit/Aggregate/ApplyMethodNotFoundTest.php b/tests/Unit/Aggregate/ApplyMethodNotFoundTest.php index 0ac48b1d9..e3e4635c4 100644 --- a/tests/Unit/Aggregate/ApplyMethodNotFoundTest.php +++ b/tests/Unit/Aggregate/ApplyMethodNotFoundTest.php @@ -20,5 +20,6 @@ public function testCreate(): void 'Apply method in "Patchlevel\EventSourcing\Tests\Unit\Fixture\Profile" could not be found for the event "Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileCreated"', $exception->getMessage(), ); + self::assertSame(0, $exception->getCode()); } } diff --git a/tests/Unit/Aggregate/MetadataNotPossibleTest.php b/tests/Unit/Aggregate/MetadataNotPossibleTest.php index bd7159574..70ff23251 100644 --- a/tests/Unit/Aggregate/MetadataNotPossibleTest.php +++ b/tests/Unit/Aggregate/MetadataNotPossibleTest.php @@ -18,5 +18,6 @@ public function testCreate(): void 'Metadata method must be called on the concrete implementation', $exception->getMessage(), ); + self::assertSame(0, $exception->getCode()); } } diff --git a/tests/Unit/Console/InvalidArgumentGivenTest.php b/tests/Unit/Console/InvalidArgumentGivenTest.php index 93975d9dd..7ce35cb07 100644 --- a/tests/Unit/Console/InvalidArgumentGivenTest.php +++ b/tests/Unit/Console/InvalidArgumentGivenTest.php @@ -17,5 +17,6 @@ public function testException(): void self::assertSame('Invalid argument given: need type "int" got "string"', $exception->getMessage()); self::assertSame($expectedValue, $exception->value()); + self::assertSame(0, $exception->getCode()); } } diff --git a/tests/Unit/Outbox/DoctrineOutboxStoreTest.php b/tests/Unit/Outbox/DoctrineOutboxStoreTest.php index a31f1b5d6..7267338cd 100644 --- a/tests/Unit/Outbox/DoctrineOutboxStoreTest.php +++ b/tests/Unit/Outbox/DoctrineOutboxStoreTest.php @@ -252,20 +252,64 @@ public function testConfigureSchema(): void ); $table = $this->prophesize(Table::class); + $column = $this->prophesize(Column::class); $table->addColumn('aggregate', Types::STRING)->shouldBeCalledOnce() - ->willReturn($this->prophesize(Column::class)->setNotnull(true)->shouldBeCalledOnce()->getObjectProphecy()->reveal()); + ->willReturn( + $column + ->setNotnull(true)->shouldBeCalledOnce() + ->getObjectProphecy()->setLength(255)->shouldBeCalledOnce()->willReturn($column->reveal()) + ->getObjectProphecy()->reveal() + ); + + $column = $this->prophesize(Column::class); $table->addColumn('aggregate_id', Types::STRING)->shouldBeCalledOnce() - ->willReturn($this->prophesize(Column::class)->setNotnull(true)->shouldBeCalledOnce()->getObjectProphecy()->reveal()); + ->willReturn( + $column + ->setNotnull(true)->shouldBeCalledOnce() + ->getObjectProphecy()->setLength(32)->shouldBeCalledOnce()->willReturn($column->reveal()) + ->getObjectProphecy()->reveal() + ); + + $column = $this->prophesize(Column::class); $table->addColumn('playhead', Types::INTEGER)->shouldBeCalledOnce() - ->willReturn($this->prophesize(Column::class)->setNotnull(true)->shouldBeCalledOnce()->getObjectProphecy()->reveal()); + ->willReturn( + $column + ->setNotnull(true)->shouldBeCalledOnce() + ->getObjectProphecy()->reveal() + ); + + $column = $this->prophesize(Column::class); $table->addColumn('event', Types::STRING)->shouldBeCalledOnce() - ->willReturn($this->prophesize(Column::class)->setNotnull(true)->shouldBeCalledOnce()->getObjectProphecy()->reveal()); + ->willReturn( + $column + ->setNotnull(true)->shouldBeCalledOnce() + ->getObjectProphecy()->setLength(255)->shouldBeCalledOnce()->willReturn($column->reveal()) + ->getObjectProphecy()->reveal() + ); + + $column = $this->prophesize(Column::class); $table->addColumn('payload', Types::JSON)->shouldBeCalledOnce() - ->willReturn($this->prophesize(Column::class)->setNotnull(true)->shouldBeCalledOnce()->getObjectProphecy()->reveal()); + ->willReturn( + $column + ->setNotnull(true)->shouldBeCalledOnce() + ->getObjectProphecy()->reveal() + ); + + $column = $this->prophesize(Column::class); $table->addColumn('recorded_on', Types::DATETIMETZ_IMMUTABLE)->shouldBeCalledOnce() - ->willReturn($this->prophesize(Column::class)->setNotnull(false)->shouldBeCalledOnce()->getObjectProphecy()->reveal()); + ->willReturn( + $column + ->setNotnull(false)->shouldBeCalledOnce() + ->getObjectProphecy()->reveal() + ); + + $column = $this->prophesize(Column::class); $table->addColumn('custom_headers', Types::JSON)->shouldBeCalledOnce() - ->willReturn($this->prophesize(Column::class)->setNotnull(true)->shouldBeCalledOnce()->getObjectProphecy()->reveal()); + ->willReturn( + $column + ->setNotnull(true)->shouldBeCalledOnce() + ->getObjectProphecy()->reveal() + ); $table->setPrimaryKey(['aggregate', 'aggregate_id', 'playhead'])->shouldBeCalledOnce(); diff --git a/tests/Unit/Pipeline/Middleware/RecalculatePlayheadMiddlewareTest.php b/tests/Unit/Pipeline/Middleware/RecalculatePlayheadMiddlewareTest.php index fe82c0ea1..b614d8d59 100644 --- a/tests/Unit/Pipeline/Middleware/RecalculatePlayheadMiddlewareTest.php +++ b/tests/Unit/Pipeline/Middleware/RecalculatePlayheadMiddlewareTest.php @@ -15,7 +15,7 @@ /** @covers \Patchlevel\EventSourcing\Pipeline\Middleware\RecalculatePlayheadMiddleware */ final class RecalculatePlayheadMiddlewareTest extends TestCase { - public function testReculatePlayhead(): void + public function testRecalculatePlayhead(): void { $middleware = new RecalculatePlayheadMiddleware(); @@ -36,7 +36,7 @@ public function testReculatePlayhead(): void self::assertSame(1, $result[0]->playhead()); } - public function testReculatePlayheadWithSamePlayhead(): void + public function testRecalculatePlayheadWithSamePlayhead(): void { $middleware = new RecalculatePlayheadMiddleware(); @@ -54,4 +54,65 @@ public function testReculatePlayheadWithSamePlayhead(): void self::assertSame([$message], $result); } + public function testRecalculateMultipleMessages(): void + { + $middleware = new RecalculatePlayheadMiddleware(); + + $event = new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hallo@patchlevel.de'), + ); + + $message = Message::create($event) + ->withAggregateClass(Profile::class) + ->withAggregateId('1') + ->withPlayhead(5); + $result = $middleware($message); + + self::assertCount(1, $result); + self::assertSame(Profile::class, $result[0]->aggregateClass()); + self::assertSame(1, $result[0]->playhead()); + + $message = Message::create($event) + ->withAggregateClass(Profile::class) + ->withAggregateId('1') + ->withPlayhead(8); + + $result = $middleware($message); + + self::assertCount(1, $result); + self::assertSame(Profile::class, $result[0]->aggregateClass()); + self::assertSame(2, $result[0]->playhead()); + } + public function testReset(): void + { + $middleware = new RecalculatePlayheadMiddleware(); + + $event = new ProfileCreated( + ProfileId::fromString('1'), + Email::fromString('hallo@patchlevel.de'), + ); + + $message = Message::create($event) + ->withAggregateClass(Profile::class) + ->withAggregateId('1') + ->withPlayhead(5); + $result = $middleware($message); + + self::assertCount(1, $result); + self::assertSame(Profile::class, $result[0]->aggregateClass()); + self::assertSame(1, $result[0]->playhead()); + + $message = Message::create($event) + ->withAggregateClass(Profile::class) + ->withAggregateId('1') + ->withPlayhead(8); + + $middleware->reset(); + $result = $middleware($message); + + self::assertCount(1, $result); + self::assertSame(Profile::class, $result[0]->aggregateClass()); + self::assertSame(1, $result[0]->playhead()); + } } diff --git a/tests/Unit/Pipeline/Source/InMemorySourceTest.php b/tests/Unit/Pipeline/Source/InMemorySourceTest.php index 94d2f7001..372ee3c44 100644 --- a/tests/Unit/Pipeline/Source/InMemorySourceTest.php +++ b/tests/Unit/Pipeline/Source/InMemorySourceTest.php @@ -41,4 +41,15 @@ public function testCount(): void self::assertSame(1, $source->count()); } + + public function testCountWithIterator(): void + { + $message = new Message( + new ProfileCreated(ProfileId::fromString('1'), Email::fromString('foo@test.com')), + ); + + $source = new InMemorySource(new \ArrayIterator([$message])); + + self::assertSame(1, $source->count()); + } } diff --git a/tests/Unit/Pipeline/Target/ProjectorRepositoryTargetTest.php b/tests/Unit/Pipeline/Target/ProjectorRepositoryTargetTest.php new file mode 100644 index 000000000..80891f465 --- /dev/null +++ b/tests/Unit/Pipeline/Target/ProjectorRepositoryTargetTest.php @@ -0,0 +1,78 @@ +message = $message; + } + }; + + $projectorRepository = $this->prophesize(ProjectorRepository::class); + $projectorRepository->projectors()->shouldBeCalledOnce()->willReturn([$projector]); + + $projectorResolver = $this->prophesize(ProjectorResolver::class); + $projectorResolver->resolveSubscribeMethod($projector, $message)->shouldBeCalledOnce()->willReturn($projector(...)); + + $projectorRepositoryTarget = new ProjectorRepositoryTarget($projectorRepository->reveal(), $projectorResolver->reveal()); + $projectorRepositoryTarget->save($message); + + self::assertSame($message, $projector->message); + } + + public function testSaveNoHit(): void + { + $message = new Message( + new ProfileCreated(ProfileId::fromString('1'), Email::fromString('foo@test.com')), + ); + + $projector = new class { + public Message|null $message = null; + + public function __invoke(Message $message) + { + $this->message = $message; + } + }; + + $projectorRepository = $this->prophesize(ProjectorRepository::class); + $projectorRepository->projectors()->shouldBeCalledOnce()->willReturn([$projector]); + + $projectorResolver = $this->prophesize(ProjectorResolver::class); + $projectorResolver->resolveSubscribeMethod($projector, $message)->shouldBeCalledOnce()->willReturn(null); + + $projectorRepositoryTarget = new ProjectorRepositoryTarget($projectorRepository->reveal(), $projectorResolver->reveal()); + $projectorRepositoryTarget->save($message); + + self::assertNull($projector->message); + } +} diff --git a/tests/Unit/Pipeline/Target/ProjectorTargetTest.php b/tests/Unit/Pipeline/Target/ProjectorTargetTest.php new file mode 100644 index 000000000..a4081f200 --- /dev/null +++ b/tests/Unit/Pipeline/Target/ProjectorTargetTest.php @@ -0,0 +1,72 @@ +message = $message; + } + }; + + + $projectorResolver = $this->prophesize(ProjectorResolver::class); + $projectorResolver->resolveSubscribeMethod($projector, $message)->shouldBeCalledOnce()->willReturn($projector(...)); + + $projectorTarget = new ProjectorTarget($projector, $projectorResolver->reveal()); + $projectorTarget->save($message); + + self::assertSame($message, $projector->message); + } + + public function testSaveNoHit(): void + { + $message = new Message( + new ProfileCreated(ProfileId::fromString('1'), Email::fromString('foo@test.com')), + ); + + $projector = new class { + public Message|null $message = null; + + public function __invoke(Message $message) + { + $this->message = $message; + } + }; + + + $projectorResolver = $this->prophesize(ProjectorResolver::class); + $projectorResolver->resolveSubscribeMethod($projector, $message)->shouldBeCalledOnce()->willReturn(null); + + $projectorTarget = new ProjectorTarget($projector, $projectorResolver->reveal()); + $projectorTarget->save($message); + + self::assertNull($projector->message); + } +} diff --git a/tests/Unit/Projection/Projection/DuplicateProjectionIdTest.php b/tests/Unit/Projection/Projection/DuplicateProjectionIdTest.php index 52b59e6fa..170435af3 100644 --- a/tests/Unit/Projection/Projection/DuplicateProjectionIdTest.php +++ b/tests/Unit/Projection/Projection/DuplicateProjectionIdTest.php @@ -19,5 +19,6 @@ public function testCreate(): void 'projection with the id "foo-1" exist already', $exception->getMessage(), ); + self::assertSame(0, $exception->getCode()); } } diff --git a/tests/Unit/Projection/Projection/ProjectionNotFoundTest.php b/tests/Unit/Projection/Projection/ProjectionNotFoundTest.php index 1791d401b..554d5cd3c 100644 --- a/tests/Unit/Projection/Projection/ProjectionNotFoundTest.php +++ b/tests/Unit/Projection/Projection/ProjectionNotFoundTest.php @@ -19,5 +19,6 @@ public function testCreate(): void 'projection with the id "foo-1" not found', $exception->getMessage(), ); + self::assertSame(0, $exception->getCode()); } } diff --git a/tests/Unit/Serializer/Encoder/DecodeNotPossibleTest.php b/tests/Unit/Serializer/Encoder/DecodeNotPossibleTest.php index 07e6ca6bc..a204b6f36 100644 --- a/tests/Unit/Serializer/Encoder/DecodeNotPossibleTest.php +++ b/tests/Unit/Serializer/Encoder/DecodeNotPossibleTest.php @@ -22,5 +22,6 @@ public function testCreate(): void $exception->getMessage(), ); self::assertSame('foo', $exception->data()); + self::assertSame(0, $exception->getCode()); } } diff --git a/tests/Unit/Serializer/Encoder/EncodeNotPossibleTest.php b/tests/Unit/Serializer/Encoder/EncodeNotPossibleTest.php index 54e7e13db..35d090320 100644 --- a/tests/Unit/Serializer/Encoder/EncodeNotPossibleTest.php +++ b/tests/Unit/Serializer/Encoder/EncodeNotPossibleTest.php @@ -21,5 +21,6 @@ public function testCreate(): void $exception->getMessage(), ); self::assertSame([], $exception->data()); + self::assertSame(0, $exception->getCode()); } } diff --git a/tests/Unit/Snapshot/Adapter/InMemorySnapshotAdapterTest.php b/tests/Unit/Snapshot/Adapter/InMemorySnapshotAdapterTest.php index a79664705..6f3478be0 100644 --- a/tests/Unit/Snapshot/Adapter/InMemorySnapshotAdapterTest.php +++ b/tests/Unit/Snapshot/Adapter/InMemorySnapshotAdapterTest.php @@ -27,4 +27,17 @@ public function testSnapshotNotFound(): void $store = new InMemorySnapshotAdapter(); $store->load('baz'); } + + public function testClear(): void + { + $store = new InMemorySnapshotAdapter(); + $store->save('baz', ['foo' => 'bar']); + + self::assertSame(['foo' => 'bar'], $store->load('baz')); + $store->clear(); + + $this->expectException(SnapshotNotFound::class); + $store->load('baz'); + } + } diff --git a/tests/Unit/Snapshot/Adapter/SnapshotNotFoundTest.php b/tests/Unit/Snapshot/Adapter/SnapshotNotFoundTest.php new file mode 100644 index 000000000..98d4f322a --- /dev/null +++ b/tests/Unit/Snapshot/Adapter/SnapshotNotFoundTest.php @@ -0,0 +1,23 @@ +getMessage(), + ); + self::assertSame(0, $exception->getCode()); + } +} diff --git a/tests/Unit/Snapshot/AdapterNotFoundTest.php b/tests/Unit/Snapshot/AdapterNotFoundTest.php new file mode 100644 index 000000000..6f6bdf652 --- /dev/null +++ b/tests/Unit/Snapshot/AdapterNotFoundTest.php @@ -0,0 +1,25 @@ +getMessage(), + ); + self::assertSame(0, $exception->getCode()); + } +} diff --git a/tests/Unit/Snapshot/DefaultSnapshotStoreTest.php b/tests/Unit/Snapshot/DefaultSnapshotStoreTest.php index 9ba4fb179..ba74e4c2e 100644 --- a/tests/Unit/Snapshot/DefaultSnapshotStoreTest.php +++ b/tests/Unit/Snapshot/DefaultSnapshotStoreTest.php @@ -7,12 +7,16 @@ use Patchlevel\EventSourcing\Snapshot\Adapter\SnapshotAdapter; use Patchlevel\EventSourcing\Snapshot\AdapterNotFound; use Patchlevel\EventSourcing\Snapshot\DefaultSnapshotStore; +use Patchlevel\EventSourcing\Snapshot\SnapshotNotConfigured; +use Patchlevel\EventSourcing\Snapshot\SnapshotNotFound; use Patchlevel\EventSourcing\Snapshot\SnapshotVersionInvalid; use Patchlevel\EventSourcing\Tests\Unit\Fixture\Email; +use Patchlevel\EventSourcing\Tests\Unit\Fixture\Profile; use Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileId; use Patchlevel\EventSourcing\Tests\Unit\Fixture\ProfileWithSnapshot; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; +use RuntimeException; /** @covers \Patchlevel\EventSourcing\Snapshot\DefaultSnapshotStore */ final class DefaultSnapshotStoreTest extends TestCase @@ -63,6 +67,19 @@ public function testLoad(): void self::assertEquals(2, $aggregate->playhead()); } + public function testLoadNotFound(): void + { + $adapter = $this->prophesize(SnapshotAdapter::class); + $adapter->load( + 'profile_with_snapshot-1', + )->willThrow(RuntimeException::class); + + $store = new DefaultSnapshotStore(['memory' => $adapter->reveal()]); + + $this->expectException(SnapshotNotFound::class); + $store->load(ProfileWithSnapshot::class, ProfileId::fromString('1')); + } + public function testLoadLegacySnapshots(): void { $this->expectException(SnapshotVersionInvalid::class); @@ -104,6 +121,14 @@ public function testAdapterIsMissing(): void $store->load(ProfileWithSnapshot::class, ProfileId::fromString('1')); } + public function testSnapshotConfigIsMissing(): void + { + $this->expectException(SnapshotNotConfigured::class); + + $store = new DefaultSnapshotStore([], null, ); + $store->load(Profile::class, ProfileId::fromString('1')); + } + public function testGetAdapter(): void { $adapter = $this->prophesize(SnapshotAdapter::class)->reveal(); diff --git a/tests/Unit/Snapshot/SnapshotNotConfiguredTest.php b/tests/Unit/Snapshot/SnapshotNotConfiguredTest.php new file mode 100644 index 000000000..2c03ad747 --- /dev/null +++ b/tests/Unit/Snapshot/SnapshotNotConfiguredTest.php @@ -0,0 +1,26 @@ +getMessage(), + ); + self::assertSame(0, $exception->getCode()); + } +} diff --git a/tests/Unit/Snapshot/SnapshotNotFoundTest.php b/tests/Unit/Snapshot/SnapshotNotFoundTest.php new file mode 100644 index 000000000..1071d3be0 --- /dev/null +++ b/tests/Unit/Snapshot/SnapshotNotFoundTest.php @@ -0,0 +1,25 @@ +getMessage(), + ); + self::assertSame(0, $exception->getCode()); + } +} diff --git a/tests/Unit/Snapshot/SnapshotVersionInvalidTest.php b/tests/Unit/Snapshot/SnapshotVersionInvalidTest.php new file mode 100644 index 000000000..bb84bbe34 --- /dev/null +++ b/tests/Unit/Snapshot/SnapshotVersionInvalidTest.php @@ -0,0 +1,26 @@ +getMessage(), + ); + self::assertSame(0, $exception->getCode()); + } +}