diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..bc3ab5c1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ba672677..179b293f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,8 +9,13 @@ jobs: uses: actions/checkout@v2 - name: Docker pull run: docker-compose pull php + - name: Docker caching + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true + - name: Start PHP container + run: docker-compose up --detach --build --no-deps php - name: Run composer validate - run: docker-compose run --rm --no-deps php composer validate --strict --no-interaction --ansi + run: docker-compose exec -T php composer validate --strict --no-interaction --ansi run-php-cs-fixer: name: php-cs-fixer runs-on: ubuntu-latest @@ -19,16 +24,21 @@ jobs: uses: actions/checkout@v2 - name: Docker pull run: docker-compose pull php + - name: Docker caching + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true - name: Composer caching uses: actions/cache@v2 with: path: ./build/.composer key: ${{ runner.os }}-composer-v1-${{ hashFiles('composer.json') }} restore-keys: ${{ runner.os }}-composer-v1- + - name: Start PHP container + run: docker-compose up --detach --build --no-deps php - name: Install dependencies - run: docker-compose run --rm --no-deps php composer --no-scripts install --no-interaction --ansi + run: docker-compose exec -T php composer --no-scripts install --no-interaction --ansi - name: Run php-cs-fixer - run: docker-compose run --rm --no-deps php bin/php-cs-fixer fix --diff --dry-run --ansi --config=.php-cs-fixer.dist.php + run: docker-compose exec -T php bin/php-cs-fixer fix --diff --dry-run --ansi --config=.php-cs-fixer.dist.php run-phpunit: name: phpunit runs-on: ubuntu-latest @@ -37,22 +47,32 @@ jobs: uses: actions/checkout@v2 - name: Docker pull run: docker-compose pull + - name: Docker caching + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true - name: Composer caching uses: actions/cache@v2 with: path: ./build/.composer key: ${{ runner.os }}-composer-v1-${{ hashFiles('composer.json') }} restore-keys: ${{ runner.os }}-composer-v1- + - name: Start containers + run: docker-compose up --detach --build - name: Install dependencies - run: docker-compose run --rm php composer install --no-scripts --no-interaction --ansi + run: docker-compose exec -T php composer install --no-scripts --no-interaction --ansi - name: Run phpunit - run: docker-compose run --rm php xphp bin/phpunit --color=always --configuration=phpunit.xml.dist - - name: Upload coverage report to codecov.io - uses: codecov/codecov-action@v1 + run: docker-compose exec -T php xphp -dxdebug.mode=coverage bin/phpunit --color=always --configuration=phpunit.xml.dist + - name: Upload coverage report to Codecov.io + uses: codecov/codecov-action@v2 with: files: ./build/.phpunit/clover.xml fail_ci_if_error: true verbose: true +# - name: Upload coverage report to GitHub.com +# uses: actions/upload-artifact@v2 +# with: +# name: Code Coverage Report +# path: build/.phpunit/code-coverage/* run-rector: name: rector runs-on: ubuntu-latest @@ -61,16 +81,21 @@ jobs: uses: actions/checkout@v2 - name: Docker pull run: docker-compose pull php + - name: Docker caching + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true - name: Composer caching uses: actions/cache@v2 with: path: ./build/.composer key: ${{ runner.os }}-composer-v1-${{ hashFiles('composer.json') }} restore-keys: ${{ runner.os }}-composer-v1- + - name: Start PHP container + run: docker-compose up --detach --build --no-deps php - name: Install dependencies - run: docker-compose run --rm --no-deps php composer install --no-interaction --ansi + run: docker-compose exec -T php composer install --no-interaction --ansi - name: Run rector - run: docker-compose run --rm --no-deps php bin/rector --no-progress-bar --dry-run --ansi + run: docker-compose exec -T php bin/rector --no-progress-bar --dry-run --ansi run-deptrac: name: deptrac runs-on: ubuntu-latest @@ -79,13 +104,64 @@ jobs: uses: actions/checkout@v2 - name: Docker pull run: docker-compose pull php + - name: Docker caching + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true - name: Composer caching uses: actions/cache@v2 with: path: ./build/.composer key: ${{ runner.os }}-composer-v1-${{ hashFiles('composer.json') }} restore-keys: ${{ runner.os }}-composer-v1- + - name: Start PHP container + run: docker-compose up --detach --build --no-deps php - name: Install dependencies - run: docker-compose run --rm --no-deps php composer install --no-scripts --no-interaction --ansi + run: docker-compose exec -T php composer install --no-scripts --no-interaction --ansi - name: Run deptrac - run: docker-compose run --rm --no-deps php bin/deptrac --no-progress --no-interaction --cache-file=./build/.deptrac/.deptrac.cache --ansi + run: docker-compose exec -T php bin/deptrac --no-progress --no-interaction --cache-file=./build/.deptrac/.deptrac.cache --ansi + run-phpstan: + name: phpstan + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Docker pull + run: docker-compose pull php + - name: Docker caching + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true + - name: Composer caching + uses: actions/cache@v2 + with: + path: ./build/.composer + key: ${{ runner.os }}-composer-v1-${{ hashFiles('composer.json') }} + restore-keys: ${{ runner.os }}-composer-v1- + - name: Start PHP container + run: docker-compose up --detach --build --no-deps php + - name: Install dependencies + run: docker-compose exec -T php composer install --no-scripts --no-interaction --ansi + - name: Run phpstan + run: docker-compose exec -T php bin/phpstan analyse -c phpstan.neon + run-psalm: + name: psalm + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Docker pull + run: docker-compose pull php + - name: Docker caching + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true + - name: Composer caching + uses: actions/cache@v2 + with: + path: ./build/.composer + key: ${{ runner.os }}-composer-v1-${{ hashFiles('composer.json') }} + restore-keys: ${{ runner.os }}-composer-v1- + - name: Start PHP container + run: docker-compose up --detach --build --no-deps php + - name: Install dependencies + run: docker-compose exec -T php composer install --no-scripts --no-interaction --ansi + - name: Run psalm + run: docker-compose exec -T php bin/psalm diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 3d0204ec..eb5f9850 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -3,6 +3,7 @@ $config = new PhpCsFixer\Config(); $finder = PhpCsFixer\Finder::create(); $finder + // The vendor directory is excluded by default. ->exclude('.github') ->exclude('bin') ->exclude('build') @@ -30,6 +31,7 @@ 'php_unit_dedicate_assert_internal_type' => true, 'php_unit_mock' => true, 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'no_extra_blank_lines' => true, 'header_comment' => [ 'comment_type' => 'PHPDoc', 'location' => 'after_open', @@ -46,7 +48,6 @@ ], ] ) - //The vendor directory is excluded by default. ->setFinder($finder) ; diff --git a/README.md b/README.md index 5157ed08..b155d22f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,23 @@ -Streak ------- +![Streak](docs/images/logo.png) +------------------------------- + +[![CI](https://github.com/streakphp/streak/actions/workflows/ci.yaml/badge.svg)](https://github.com/streakphp/streak/actions/workflows/ci.yaml) [![codecov](https://codecov.io/gh/streakphp/streak/branch/master/graph/badge.svg)](https://codecov.io/gh/streakphp/streak) -Running test ------------- +Running checks & tests locally +------------------------------ + +`docker-compose up --detach --build` + +`docker-compose exec -T php composer validate --strict --no-interaction --ansi` + +`docker-compose exec -T php composer install --no-scripts --no-interaction --ansi` + +`docker-compose exec -T php xphp -dxdebug.mode=coverage bin/phpunit --color=always --configuration=phpunit.xml.dist` + +`docker-compose exec -T php bin/rector --dry-run --ansi` + +`docker-compose exec -T php bin/deptrac --no-interaction --cache-file=./build/.deptrac/.deptrac.cache --ansi` -`docker-compose run --rm php bin/phpunit` +`docker-compose exec -T php bin/php-cs-fixer fix --diff --dry-run --ansi --config=.php-cs-fixer.dist.php` diff --git a/build/.phpstan/.gitkeep b/build/.phpstan/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/build/.psalm/.gitkeep b/build/.psalm/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/codecov.yml b/codecov.yml index a8cd4f88..bf08d671 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,7 +1,27 @@ +codecov: + branch: master + max_report_age: 24 + require_ci_to_pass: yes + +comment: + layout: "reach, diff, flags, files" + behavior: new + require_changes: false + require_base: true + require_head: true + +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: yes + macro: yes + coverage: precision: 2 round: down - range: "70...100" + range: "90...100" status: project: diff --git a/composer.json b/composer.json index e9141891..db3dbbcb 100644 --- a/composer.json +++ b/composer.json @@ -27,21 +27,23 @@ }, "require": { "php": ">=8.0", - "ext-pdo": "*", "ext-igbinary": "*", - "ext-redis": "*", "ext-json": "*", + "ext-pdo": "*", + "ext-redis": "*", "doctrine/dbal": "^2.13", "psr/log": "^1.1", "ramsey/uuid": "^4.1" }, "require-dev": { - "roave/security-advisories": "dev-latest", "friendsofphp/php-cs-fixer": "^3.0", - "php-amqplib/rabbitmq-bundle": "^2.6.0", - "phpunit/phpunit": "^9.5.4", - "rector/rector": "^0.10.19", - "qossmic/deptrac-shim": "^0.13.0" + "php-amqplib/rabbitmq-bundle": "^2.6", + "phpstan/phpstan": "^1.5", + "phpunit/phpunit": "^9.5", + "qossmic/deptrac-shim": "^0.13", + "rector/rector": "0.12.18", + "roave/security-advisories": "dev-latest", + "vimeo/psalm": "^4.22" }, "config": { "bin-dir": "bin", diff --git a/docker-compose.yml b/docker-compose.yml index 64c66d31..7ffe177e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,14 @@ -version: '3' +version: '3.7' services: php: image: streakphp/php80-cli:latest + init: true volumes: - .:/var/www/project - ./docker/php/etc/php/8.0/cli/php.ini:/etc/php/8.0/cli/php.ini working_dir: /var/www/project + entrypoint: tail -f /dev/null # keep container alive for development depends_on: - postgres - redis @@ -14,7 +16,6 @@ services: COMPOSER_ALLOW_SUPERUSER: 1 COMPOSER_NO_INTERACTION: 1 COMPOSER_CACHE_DIR: /var/www/project/build/.composer - XDEBUG_MODE: 'develop,debug,coverage' postgres: image: postgres:13-alpine diff --git a/docs/images/logo.png b/docs/images/logo.png new file mode 100644 index 00000000..49d1676b Binary files /dev/null and b/docs/images/logo.png differ diff --git a/phpstan.baseline.neon b/phpstan.baseline.neon new file mode 100644 index 00000000..e0c1e8c0 --- /dev/null +++ b/phpstan.baseline.neon @@ -0,0 +1,316 @@ +parameters: + ignoreErrors: + - + message: "#^Instanceof between string and Redis will always evaluate to false\\.$#" + count: 1 + path: src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisStorage.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Subscription\\\\DAO\\\\Subscription\\:\\:\\$lastEventProcessedAt is never read, only written\\.$#" + count: 1 + path: src/Infrastructure/Domain/Event/Subscription/DAO/Subscription.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Subscription\\\\DAO\\\\Subscription\\:\\:\\$startedAt is never read, only written\\.$#" + count: 1 + path: src/Infrastructure/Domain/Event/Subscription/DAO/Subscription.php + + - + message: "#^Property Streak\\\\Application\\\\Sensor\\\\ProcessingTest\\\\AProcessed\\:\\:\\$a is never read, only written\\.$#" + count: 1 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Property Streak\\\\Application\\\\Sensor\\\\ProcessingTest\\\\ArrayProcessed\\:\\:\\$array is never read, only written\\.$#" + count: 1 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Property Streak\\\\Application\\\\Sensor\\\\ProcessingTest\\\\B1Processed\\:\\:\\$b1 is never read, only written\\.$#" + count: 1 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Property Streak\\\\Application\\\\Sensor\\\\ProcessingTest\\\\B2Processed\\:\\:\\$b2 is never read, only written\\.$#" + count: 1 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Property Streak\\\\Application\\\\Sensor\\\\ProcessingTest\\\\BooleanProcessed\\:\\:\\$boolean is never read, only written\\.$#" + count: 1 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Property Streak\\\\Application\\\\Sensor\\\\ProcessingTest\\\\IntegerProcessed\\:\\:\\$integer is never read, only written\\.$#" + count: 1 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Property Streak\\\\Application\\\\Sensor\\\\ProcessingTest\\\\StdClassProcessed\\:\\:\\$stdClass is never read, only written\\.$#" + count: 1 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Property Streak\\\\Application\\\\Sensor\\\\ProcessingTest\\\\StringProcessed\\:\\:\\$string is never read, only written\\.$#" + count: 1 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 2 + path: tests/Application/Sensor/ProcessingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\Command\\\\HandlingTest\\\\CommandHandlingStub\\:\\:handlePrivateMethodHandlingMethod\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/Command/HandlingTest.php + + - + message: "#^Parameter \\#1 \\$name of method Streak\\\\Domain\\\\Event\\\\Envelope\\\\:\\:set\\(\\) expects non\\-empty\\-string, '' given\\.$#" + count: 1 + path: tests/Domain/Event/EnvelopeTest.php + + - + message: "#^Method Streak\\\\Domain\\\\Event\\\\Listener\\\\FilteringTest\\\\ListeningStub1\\:\\:onSupportedEvent1ButPrivate\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/Event/Listener/FilteringTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Listener\\\\ListeningTest\\\\ListeningStub\\:\\:\\$listenerMethodWithNullableEventActivated is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Listener/ListeningTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$arrayOfIntegers is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$arrayOfMixed is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$arrayOfObjects is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$arrayOfStrings is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$entity is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$integer is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$nonInitializedArray is unused\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$nonInitializedInteger is unused\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$nonInitializedObject is unused\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$nonInitializedString is unused\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$object is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$self is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Property Streak\\\\Domain\\\\Event\\\\Sourced\\\\Entity\\\\HelperTest\\\\EventSourcedEntityStub\\:\\:\\$string is never read, only written\\.$#" + count: 1 + path: tests/Domain/Event/Sourced/Entity/HelperTest.php + + - + message: "#^Dead catch \\- Streak\\\\Domain\\\\Exception\\\\EventMismatched is never thrown in the try block\\.$#" + count: 2 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\EventSourcingTest\\\\EventSourcedAggregateRootStub\\:\\:applyEvent1\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\EventSourcingTest\\\\EventSourcedAggregateRootStub\\:\\:applyEvent4\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\EventSourcingTest\\\\EventSourcedAggregateStub\\:\\:applyEvent1\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\EventSourcingTest\\\\EventSourcedAggregateStub\\:\\:applyEvent2\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\EventSourcingTest\\\\EventSourcedEntityStub\\:\\:applyEvent1\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\EventSourcingTest\\\\EventSourcedEntityStub\\:\\:applyEvent2\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\EventSourcingTest\\\\EventSourcedEntityStub\\:\\:applyEvent3\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Method Streak\\\\Domain\\\\EventSourcingTest\\\\EventSourcedEntityStub\\:\\:applyEvent4\\(\\) is unused\\.$#" + count: 1 + path: tests/Domain/EventSourcingTest.php + + - + message: "#^Parameter \\#1 \\$id of class Streak\\\\Infrastructure\\\\Domain\\\\AggregateRoot\\\\Snapshotter\\\\Storage\\\\IdStub constructor expects non\\-empty\\-string, string given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorageTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\ChildObject\\:\\:\\$arrayProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\ChildObject\\:\\:\\$child is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\ChildObject\\:\\:\\$scalarProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\Event1Stub\\:\\:\\$privateAnyTypeProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\Event1Stub\\:\\:\\$privateArrayProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\Event1Stub\\:\\:\\$privateEmptyArrayProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\Event1Stub\\:\\:\\$privateFloatProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\Event1Stub\\:\\:\\$privateIntegerProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\Event1Stub\\:\\:\\$privateStringProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\EventA\\:\\:\\$property1 is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\EventB\\:\\:\\$property2 is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\EventC\\:\\:\\$event is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\NestedResource\\:\\:\\$resource is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\ParentObject\\:\\:\\$arrayProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\ParentObject\\:\\:\\$objectProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Property Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Converter\\\\ParentObject\\:\\:\\$scalarProperty is never read, only written\\.$#" + count: 1 + path: tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php + + - + message: "#^Parameter \\#1 \\$object of method Streak\\\\Infrastructure\\\\Domain\\\\UnitOfWork\\\\EventStoreUnitOfWork\\:\\:add\\(\\) expects Streak\\\\Domain\\\\Event\\\\Producer, stdClass given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWorkTest.php + + - + message: "#^Parameter \\#1 \\$object of method Streak\\\\Infrastructure\\\\Domain\\\\UnitOfWork\\\\EventStoreUnitOfWork\\:\\:has\\(\\) expects Streak\\\\Domain\\\\Event\\\\Producer, stdClass given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWorkTest.php + + - + message: "#^Parameter \\#1 \\$object of method Streak\\\\Infrastructure\\\\Domain\\\\UnitOfWork\\\\EventStoreUnitOfWork\\:\\:remove\\(\\) expects Streak\\\\Domain\\\\Event\\\\Producer, stdClass given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWorkTest.php + + - + message: "#^Parameter \\#1 \\$object of method Streak\\\\Infrastructure\\\\Domain\\\\UnitOfWork\\\\SubscriptionDAOUnitOfWork\\:\\:add\\(\\) expects Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Subscription\\\\DAO\\\\Subscription, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Streak\\\\Domain\\\\Event\\\\Subscription given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php + + - + message: "#^Parameter \\#1 \\$object of method Streak\\\\Infrastructure\\\\Domain\\\\UnitOfWork\\\\SubscriptionDAOUnitOfWork\\:\\:add\\(\\) expects Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Subscription\\\\DAO\\\\Subscription, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\|Streak\\\\Domain\\\\Event\\\\Subscription\\\\Decorator given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php + + - + message: "#^Parameter \\#1 \\$object of method Streak\\\\Infrastructure\\\\Domain\\\\UnitOfWork\\\\SubscriptionDAOUnitOfWork\\:\\:has\\(\\) expects Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Subscription\\\\DAO\\\\Subscription, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Streak\\\\Domain\\\\Event\\\\Subscription given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php + + - + message: "#^Parameter \\#1 \\$object of method Streak\\\\Infrastructure\\\\Domain\\\\UnitOfWork\\\\SubscriptionDAOUnitOfWork\\:\\:has\\(\\) expects Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Subscription\\\\DAO\\\\Subscription, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject\\|Streak\\\\Domain\\\\Event\\\\Subscription\\\\Decorator given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php + + - + message: "#^Parameter \\#1 \\$object of method Streak\\\\Infrastructure\\\\Domain\\\\UnitOfWork\\\\SubscriptionDAOUnitOfWork\\:\\:remove\\(\\) expects Streak\\\\Infrastructure\\\\Domain\\\\Event\\\\Subscription\\\\DAO\\\\Subscription, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Streak\\\\Domain\\\\Event\\\\Subscription given\\.$#" + count: 1 + path: tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..2db2c909 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +includes: + - phpstan.baseline.neon +parameters: + level: 5 + paths: + - src/ + - tests/ + tmpDir: build/.phpstan diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5c578586..376a0ff6 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,6 +4,8 @@ colors="true" cacheResultFile="build/.phpunit/.phpunit.result.cache" bootstrap="tests/bootstrap.php" + beStrictAboutOutputDuringTests="true" + beStrictAboutTodoAnnotatedTests="true" > @@ -11,7 +13,7 @@ - + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 00000000..5df66af5 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/rector.php b/rector.php index 6a68c12e..6d13c5d6 100644 --- a/rector.php +++ b/rector.php @@ -14,6 +14,7 @@ use Rector\CodeQuality\Rector\FuncCall\SingleInArrayToCompareRector; use Rector\CodeQuality\Rector\FuncCall\UnwrapSprintfOneArgumentRector; use Rector\Core\Configuration\Option; +use Rector\Core\ValueObject\PhpVersion; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\SetList; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -35,6 +36,8 @@ $configurator->import(SetList::PHP_80); // $configurator->import(SetList::PRIVATIZATION); + $parameters->set(Option::PARALLEL, true); + $parameters->set(Option::SKIP, [ ]); @@ -48,9 +51,14 @@ ]); // Run Rector only on changed files - $parameters->set(Option::ENABLE_CACHE, true); $parameters->set(Option::CACHE_DIR, __DIR__ . '/build/.rector'); + // is your PHP version different from the one your refactor to? [default: your PHP version], uses PHP_VERSION_ID format + $parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_80); + + // Path to phpstan with extensions, that PHPSTan in Rector uses to determine types + $parameters->set(Option::PHPSTAN_FOR_RECTOR_PATH, __DIR__ . '/phpstan.neon'); + $services = $configurator->services(); $services->set(UnwrapSprintfOneArgumentRector::class); diff --git a/src/Application/CommandBus.php b/src/Application/CommandBus.php index 354c7488..cdc3eef8 100644 --- a/src/Application/CommandBus.php +++ b/src/Application/CommandBus.php @@ -14,7 +14,7 @@ namespace Streak\Application; use Streak\Domain; -use Streak\Domain\Exception\CommandNotSupported; +use Streak\Domain\Exception; /** * @author Alan Gabriel Bem @@ -22,7 +22,8 @@ interface CommandBus { /** - * @throws CommandNotSupported + * @throws Exception\CommandNotSupported + * @throws Exception\ConcurrentWriteDetected */ public function dispatch(Domain\Command $command): void; } diff --git a/src/Application/Sensor.php b/src/Application/Sensor.php index df71c79a..e6128044 100644 --- a/src/Application/Sensor.php +++ b/src/Application/Sensor.php @@ -20,7 +20,7 @@ */ interface Sensor extends Producer { - public function sensorId(): Sensor\Id; + public function id(): Sensor\Id; public function process(...$messages): void; } diff --git a/src/Application/Sensor/Id.php b/src/Application/Sensor/Id.php index ccaa2523..004f56ee 100644 --- a/src/Application/Sensor/Id.php +++ b/src/Application/Sensor/Id.php @@ -13,11 +13,11 @@ namespace Streak\Application\Sensor; -use Streak\Domain\Event\Producer; +use Streak\Domain; /** * @author Alan Gabriel Bem */ -interface Id extends Producer\Id +interface Id extends Domain\Id { } diff --git a/src/Application/Sensor/Identification.php b/src/Application/Sensor/Identification.php index 5f9d6b03..222eb75d 100644 --- a/src/Application/Sensor/Identification.php +++ b/src/Application/Sensor/Identification.php @@ -14,7 +14,6 @@ namespace Streak\Application\Sensor; use Streak\Application\Sensor; -use Streak\Domain; /** * @author Alan Gabriel Bem @@ -28,21 +27,11 @@ public function __construct(Sensor\Id $id) $this->identifyBy($id); } - public function sensorId(): Sensor\Id + public function id(): Sensor\Id { return $this->id; } - public function producerId(): Domain\Id - { - return $this->sensorId(); - } - - public function id(): Domain\Id - { - return $this->sensorId(); - } - protected function identifyBy(Sensor\Id $id): void { $this->id = $id; diff --git a/src/Application/Sensor/Processing.php b/src/Application/Sensor/Processing.php index 8b72e556..9f5dcdd2 100644 --- a/src/Application/Sensor/Processing.php +++ b/src/Application/Sensor/Processing.php @@ -13,8 +13,8 @@ namespace Streak\Application\Sensor; +use Streak\Application\Sensor; use Streak\Domain\Event; -use Streak\Domain\Id; /** * @author Alan Gabriel Bem @@ -27,7 +27,7 @@ trait Processing private $events = []; private $last; - abstract public function producerId(): Id; + abstract public function id(): Sensor\Id; final public function last(): ?Event\Envelope { @@ -140,7 +140,7 @@ final public function process(...$messages): void } if (false === $routed) { - throw new \InvalidArgumentException(); + throw new \InvalidArgumentException('No method found to process message.'); } } } catch (\Throwable $e) { @@ -156,6 +156,6 @@ final public function process(...$messages): void private function addEvent(Event $event): void { - $this->pending[] = Event\Envelope::new($event, $this->producerId()); + $this->pending[] = Event\Envelope::new($event, $this->id()); } } diff --git a/src/Domain/Aggregate.php b/src/Domain/Aggregate.php index 4979bfc4..eff01c7a 100644 --- a/src/Domain/Aggregate.php +++ b/src/Domain/Aggregate.php @@ -24,5 +24,5 @@ */ interface Aggregate extends Domain\Entity { - public function aggregateId(): Domain\Aggregate\Id; + public function id(): Domain\Aggregate\Id; } diff --git a/src/Domain/Aggregate/Comparison.php b/src/Domain/Aggregate/Comparison.php index 4e57a48e..dd1e464e 100644 --- a/src/Domain/Aggregate/Comparison.php +++ b/src/Domain/Aggregate/Comparison.php @@ -19,12 +19,14 @@ /** * @author Alan Gabriel Bem + * + * @see \Streak\Domain\Aggregate\ComparisonTest */ trait Comparison { use Entity\Comparison; - abstract public function aggregateId(): Aggregate\Id; + abstract public function id(): Aggregate\Id; final public function equals(object $aggregate): bool { @@ -36,7 +38,7 @@ final public function equals(object $aggregate): bool return false; } - if (!$this->aggregateId()->equals($aggregate->aggregateId())) { + if (!$this->id()->equals($aggregate->id())) { return false; } diff --git a/src/Domain/Event/Sourced/Aggregate/Id.php b/src/Domain/Aggregate/EventSourcing.php similarity index 59% rename from src/Domain/Event/Sourced/Aggregate/Id.php rename to src/Domain/Aggregate/EventSourcing.php index 525410f5..7f6f9971 100644 --- a/src/Domain/Event/Sourced/Aggregate/Id.php +++ b/src/Domain/Aggregate/EventSourcing.php @@ -11,13 +11,19 @@ declare(strict_types=1); -namespace Streak\Domain\Event\Sourced\Aggregate; +namespace Streak\Domain\Aggregate; use Streak\Domain\Aggregate; +use Streak\Domain\Entity; /** * @author Alan Gabriel Bem + * + * @see \Streak\Domain\EventSourcingTest */ -interface Id extends Aggregate\Id +trait EventSourcing //implements Event\Sourced\Aggregate { + use Entity\EventSourcing; + + abstract public function id(): Aggregate\Id; } diff --git a/src/Domain/Aggregate/Identification.php b/src/Domain/Aggregate/Identification.php index dea44e14..bdc0d436 100644 --- a/src/Domain/Aggregate/Identification.php +++ b/src/Domain/Aggregate/Identification.php @@ -18,6 +18,10 @@ /** * @author Alan Gabriel Bem + * + * @property Aggregate\Id $id + * + * @see \Streak\Domain\Aggregate\IdentificationTest */ trait Identification { @@ -30,7 +34,7 @@ public function __construct(Aggregate\Id $id) $this->identifyBy($id); } - public function aggregateId(): Aggregate\Id + public function id(): Aggregate\Id { return $this->id; } diff --git a/src/Domain/AggregateRoot.php b/src/Domain/AggregateRoot.php index f6346ff0..9e93bf42 100644 --- a/src/Domain/AggregateRoot.php +++ b/src/Domain/AggregateRoot.php @@ -24,5 +24,5 @@ */ interface AggregateRoot extends Domain\Aggregate { - public function aggregateRootId(): AggregateRoot\Id; + public function id(): AggregateRoot\Id; } diff --git a/src/Domain/AggregateRoot/Comparison.php b/src/Domain/AggregateRoot/Comparison.php index 8dc32b74..306b00da 100644 --- a/src/Domain/AggregateRoot/Comparison.php +++ b/src/Domain/AggregateRoot/Comparison.php @@ -19,12 +19,14 @@ /** * @author Alan Gabriel Bem + * + * @see \Streak\Domain\AggregateRoot\ComparisonTest */ trait Comparison { use Aggregate\Comparison; - abstract public function aggregateRootId(): AggregateRoot\Id; + abstract public function id(): AggregateRoot\Id; final public function equals(object $root): bool { @@ -36,7 +38,7 @@ final public function equals(object $root): bool return false; } - if (!$this->aggregateRootId()->equals($root->aggregateRootId())) { + if (!$this->id()->equals($root->id())) { return false; } diff --git a/src/Domain/AggregateRoot/EventSourcing.php b/src/Domain/AggregateRoot/EventSourcing.php new file mode 100644 index 00000000..7171e8c6 --- /dev/null +++ b/src/Domain/AggregateRoot/EventSourcing.php @@ -0,0 +1,155 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Streak\Domain\AggregateRoot; + +use Streak\Domain; +use Streak\Domain\Aggregate; +use Streak\Domain\AggregateRoot; +use Streak\Domain\Event; + +/** + * @author Alan Gabriel Bem + * + * @see \Streak\Domain\EventSourcingTest + */ +trait EventSourcing //implements Event\Sourced\AggregateRoot +{ + use Aggregate\EventSourcing; + + /** + * @var Event\Envelope[] + */ + private array $events = []; + private ?Event\Envelope $lastEvent = null; + private int $version = 0; + + abstract public function id(): AggregateRoot\Id; + + /** + * @throws \Throwable + */ + final public function replay(Event\Stream $stream): void + { + foreach ($stream as $event) { + $this->applyEvent($event); + + $this->version = $event->version(); + } + + $this->events = []; + } + + final public function lastEvent(): ?Event\Envelope + { + return $this->lastEvent; + } + + final public function version(): int + { + return $this->version; + } + + /** + * @return Event\Envelope[] + */ + final public function events(): array + { + return $this->events; + } + + public function commit(): void + { + $this->version += \count($this->events); + $this->events = []; + } + + /** + * @throws Event\Exception\TooManyEventApplyingMethodsFound + * @throws Domain\Exception\EventMismatched + * @throws \Throwable + */ + final public function applyEvent(Event\Envelope $event): void + { + // $event was produced by $this aggregate or one of its embedded entities + if (!$this->id()->equals($event->producerId())) { + throw new Domain\Exception\EventMismatched($this, $event); + } + + if (null === $event->version()) { + $event = $event->defineVersion($this->version + \count($this->events) + 1); + } + + // event was produced but $this root aggregate, so we don't need to go through embedded entities + if ($this->id()->equals($event->entityId())) { + $this->doApplyEvent($event); + + $this->lastEvent = $event; + $this->events[] = $event; + + return; + } + + foreach ($this->eventSourcedEntities() as $entity) { + if ($entity->id()->equals($event->entityId())) { + $aggregate = $entity; + $stack = []; + while ($aggregate = $aggregate->aggregate()) { + $stack[] = $aggregate; // build $stack from bottom to top... + } + /** @var Event\Sourced\Entity[] $stack */ + $stack = array_reverse($stack); // ...and make it from top to bottom + + try { + $this->doApplyEvent($event); + } catch (Event\Exception\NoEventApplyingMethodFound) { + } + + // apply event from aggregate root all the way down, through aggregates graph, to $this + foreach ($stack as $aggregate) { + try { + $aggregate->applyEvent($event); + } catch (Event\Exception\NoEventApplyingMethodFound) { + } + } + $entity->applyEvent($event); + + break; // we don't need to look for next entity + } + } + + $this->lastEvent = $event; + $this->events[] = $event; + } + + /** + * @throws Event\Exception\NoEventApplyingMethodFound + * @throws Event\Exception\TooManyEventApplyingMethodsFound + * @throws \Throwable + */ + private function apply(Event $event): void + { + $envelope = Event\Envelope::new($event, $this->id()); + $envelope = $envelope->defineEntityId($this->id()); + + $this->applyEvent($envelope); + } + + /** + * @return \Generator + */ + private function eventSourcedEntities(): \Generator + { + yield from Event\Sourced\Entity\Helper::for($this)->extractEventSourcedEntities(); + } +} diff --git a/src/Domain/AggregateRoot/Identification.php b/src/Domain/AggregateRoot/Identification.php index 174724ad..527d985f 100644 --- a/src/Domain/AggregateRoot/Identification.php +++ b/src/Domain/AggregateRoot/Identification.php @@ -18,6 +18,10 @@ /** * @author Alan Gabriel Bem + * + * @property AggregateRoot\Id $id + * + * @see \Streak\Domain\AggregateRoot\IdentificationTest */ trait Identification { @@ -30,7 +34,7 @@ public function __construct(AggregateRoot\Id $id) $this->identifyBy($id); } - public function aggregateRootId(): AggregateRoot\Id + public function id(): AggregateRoot\Id { return $this->id; } diff --git a/src/Domain/Comparable.php b/src/Domain/Comparable.php index e7b554ba..18a38864 100644 --- a/src/Domain/Comparable.php +++ b/src/Domain/Comparable.php @@ -18,5 +18,6 @@ */ interface Comparable { + /** @no-named-arguments */ public function equals(object $object): bool; } diff --git a/src/Domain/Entity.php b/src/Domain/Entity.php index 7fe7545a..0420f936 100644 --- a/src/Domain/Entity.php +++ b/src/Domain/Entity.php @@ -18,5 +18,5 @@ */ interface Entity extends Comparable, Identifiable { - public function entityId(): Entity\Id; + public function id(): Entity\Id; } diff --git a/src/Domain/Entity/Comparison.php b/src/Domain/Entity/Comparison.php index d47d7402..3bff3810 100644 --- a/src/Domain/Entity/Comparison.php +++ b/src/Domain/Entity/Comparison.php @@ -18,10 +18,12 @@ /** * @author Alan Gabriel Bem + * + * @see \Streak\Domain\Entity\ComparisonTest */ trait Comparison { - abstract public function entityId(): Entity\Id; + abstract public function id(): Entity\Id; final public function equals(object $entity): bool { @@ -33,7 +35,7 @@ final public function equals(object $entity): bool return false; } - if (!$this->entityId()->equals($entity->entityId())) { + if (!$this->id()->equals($entity->id())) { return false; } diff --git a/src/Domain/Entity/EventSourcing.php b/src/Domain/Entity/EventSourcing.php new file mode 100644 index 00000000..f08380c7 --- /dev/null +++ b/src/Domain/Entity/EventSourcing.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Streak\Domain\Entity; + +use Streak\Domain\Entity; +use Streak\Domain\Event; +use Streak\Domain\Exception\EventMismatched; + +/** + * @author Alan Gabriel Bem + * + * @see \Streak\Domain\EventSourcingTest + */ +trait EventSourcing //implements Event\Sourced\Entity +{ + private ?Event\Sourced\AggregateRoot $aggregateRoot = null; + private ?Event\Sourced\Aggregate $aggregate = null; + + public function registerAggregateRoot(Event\Sourced\AggregateRoot $aggregateRoot): void + { + $this->aggregateRoot = $aggregateRoot; + } + + public function registerAggregate(Event\Sourced\Aggregate $aggregate): void + { + if ($this->id()->equals($aggregate->id())) { + throw new \BadMethodCallException('You can\'t register aggregate on itself.'); + } + + $this->aggregate = $aggregate; + $this->registerAggregateRoot($aggregate->aggregateRoot()); + } + + public function aggregateRoot(): Event\Sourced\AggregateRoot + { + if (null === $this->aggregateRoot) { + throw new \BadMethodCallException(sprintf('Aggregate root no registered. Did you forget to run %s::registerAggregateRoot()?', static::class)); + } + + return $this->aggregateRoot; + } + + public function aggregate(): ?Event\Sourced\Aggregate + { + return $this->aggregate; + } + + abstract public function id(): Entity\Id; + + final public function applyEvent(Event\Envelope $event): void + { + if (false === $this->aggregateRoot()->id()->equals($event->producerId())) { + throw new EventMismatched($this, $event); + } + + $this->doApplyEvent($event); + } + + /** + * @throws Event\Exception\NoEventApplyingMethodFound + * @throws Event\Exception\TooManyEventApplyingMethodsFound + * @throws \Throwable + */ + private function apply(Event $event): void + { + $event = Event\Envelope::new($event, $this->aggregateRoot()->id()); + $event = $event->defineEntityId($this->id()); + + $this->aggregateRoot()->applyEvent($event); + } + + private function doApplyEvent(Event\Envelope $event): void + { + Event\Sourced\Entity\Helper::for($this)->applyEvent($event); + } +} diff --git a/src/Domain/Entity/Identification.php b/src/Domain/Entity/Identification.php index 4efcf70c..4131e0f2 100644 --- a/src/Domain/Entity/Identification.php +++ b/src/Domain/Entity/Identification.php @@ -13,27 +13,23 @@ namespace Streak\Domain\Entity; -use Streak\Domain; use Streak\Domain\Entity; /** * @author Alan Gabriel Bem + * + * @see \Streak\Domain\Entity\IdentificationTest */ trait Identification { - private $id; + private Entity\Id $id; public function __construct(Entity\Id $id) { $this->identifyBy($id); } - public function entityId(): Entity\Id - { - return $this->id; - } - - public function id(): Domain\Id + public function id(): Entity\Id { return $this->id; } diff --git a/src/Domain/Envelope.php b/src/Domain/Envelope.php index 382b79cb..5e6bec7a 100644 --- a/src/Domain/Envelope.php +++ b/src/Domain/Envelope.php @@ -16,6 +16,8 @@ use Streak\Domain\Id\UUID; /** + * @template T of object + * * @author Alan Gabriel Bem */ interface Envelope extends ValueObject @@ -24,12 +26,15 @@ public function uuid(): UUID; public function name(): string; + /** + * @return T + */ public function message(); /** * @param string $name * - * @return float|int|string|null + * @return null|scalar */ public function get($name); diff --git a/src/Domain/Event/Consumer.php b/src/Domain/Event/Consumer.php index 138eef0f..45202781 100644 --- a/src/Domain/Event/Consumer.php +++ b/src/Domain/Event/Consumer.php @@ -18,7 +18,11 @@ /** * @author Alan Gabriel Bem */ -interface Consumer extends Event\Replayable +interface Consumer { - public function lastReplayed(): ?Event\Envelope; // TODO: remove (use last() instead?) + /** + * @throws Event\Exception\NoEventApplyingMethodFound + * @throws Event\Exception\TooManyEventApplyingMethodsFound + */ + public function applyEvent(Event\Envelope $event): void; } diff --git a/src/Domain/Event/Converter.php b/src/Domain/Event/Converter.php index 52ccba95..c9f9e751 100644 --- a/src/Domain/Event/Converter.php +++ b/src/Domain/Event/Converter.php @@ -20,11 +20,13 @@ interface Converter { /** * @throws Exception\ConversionToArrayNotPossible + * @throws \Exception */ public function objectToArray(object $object): array; /** * @throws Exception\ConversionToObjectNotPossible + * @throws \Exception */ public function arrayToObject(array $data): object; } diff --git a/src/Domain/Event/Envelope.php b/src/Domain/Event/Envelope.php index db1dd59f..cb6e1471 100644 --- a/src/Domain/Event/Envelope.php +++ b/src/Domain/Event/Envelope.php @@ -20,6 +20,9 @@ /** * @author Alan Gabriel Bem * + * @template TMessage as Event + * @implements Domain\Envelope + * * @see \Streak\Domain\Event\EnvelopeTest */ final class Envelope implements Domain\Envelope @@ -29,64 +32,111 @@ final class Envelope implements Domain\Envelope public const METADATA_VERSION = 'version'; public const METADATA_PRODUCER_TYPE = 'producer_type'; public const METADATA_PRODUCER_ID = 'producer_id'; - private array $metadata = []; - - public function __construct(UUID $uuid, string $name, private Event $message, Domain\Id $producerId, ?int $version = null) + public const METADATA_ENTITY_TYPE = 'entity_type'; + public const METADATA_ENTITY_ID = 'entity_id'; + + /** + * @var-phpstan non-empty-array + * @var-psalm non-empty-array&array{ + * uuid: non-empty-string, + * name: non-empty-string, + * producer_type: class-string, + * producer_id: non-empty-string, + * entity_type: class-string, + * entity_id: non-empty-string, + * version?: positive-int, + * } + */ + private array $metadata; + + /** + * @param non-empty-string $name + * @param TMessage $message + */ + public function __construct(UUID $uuid, string $name, private Event $message, Domain\Id $producerId, Domain\Id $entityId, ?int $version = null) { - $this->metadata[self::METADATA_UUID] = $uuid->toString(); - $this->metadata[self::METADATA_NAME] = $name; - $this->metadata[self::METADATA_PRODUCER_TYPE] = $producerId::class; - $this->metadata[self::METADATA_PRODUCER_ID] = $producerId->toString(); + $this->metadata = [ + self::METADATA_UUID => $uuid->toString(), + self::METADATA_NAME => $name, + self::METADATA_PRODUCER_TYPE => $producerId::class, + self::METADATA_PRODUCER_ID => $producerId->toString(), + self::METADATA_ENTITY_TYPE => $entityId::class, + self::METADATA_ENTITY_ID => $entityId->toString(), + ]; if (null !== $version) { $this->metadata[self::METADATA_VERSION] = $version; } } - public static function new(Event $event, Domain\Id $producerId, ?int $version = null): self + /** + * @template TEvent of Event + * @param TEvent $message + * + * @return self + */ + public static function new(Event $message, Domain\Id $producerId, ?int $version = null): self { - return new self(UUID::random(), $event::class, $event, $producerId, $version); + return new self(UUID::random(), $message::class, $message, $producerId, $producerId, $version); } public function uuid(): UUID { - return new UUID($this->get(self::METADATA_UUID)); + return new UUID($this->metadata[self::METADATA_UUID]); } + /** + * @return non-empty-string + */ public function name(): string { - return $this->get(self::METADATA_NAME); + return $this->metadata[self::METADATA_NAME]; } - public function message(): Event + public function message() { return $this->message; } public function producerId(): Domain\Id { - return $this->get(self::METADATA_PRODUCER_TYPE)::fromString($this->get(self::METADATA_PRODUCER_ID)); + $class = $this->metadata[self::METADATA_PRODUCER_TYPE]; + $id = $this->metadata[self::METADATA_PRODUCER_ID]; + + /** @var class-string $class */ + return $class::fromString($id); + } + + public function entityId(): Domain\Id + { + $class = $this->metadata[self::METADATA_ENTITY_TYPE]; + $id = $this->metadata[self::METADATA_ENTITY_ID]; + + /** @var class-string $class */ + return $class::fromString($id); } public function version(): ?int { - return $this->get(self::METADATA_VERSION); + return $this->metadata[self::METADATA_VERSION] ?? null; } - public function set(string $name, $value): self + /** + * @param non-empty-string $name + * @return self + */ + public function set(string $name, bool|float|int|string $value): self { - if (empty($name)) { + if (empty($name)) { // @phpstan-ignore-line throw new \InvalidArgumentException('Name of the attribute can not be empty.'); } - if (!is_scalar($value)) { - throw new \InvalidArgumentException(sprintf('Value for attribute "%s" is a scalar.', $name)); - } $new = new self( $this->uuid(), $this->name(), $this->message(), $this->producerId(), - $this->version() + $this->entityId(), + $this->version(), ); $new->metadata = $this->metadata; @@ -117,4 +167,34 @@ public function equals(object $envelope): bool return true; } + + /** + * @return self + */ + public function defineVersion(int $version): self + { + return new self( + $this->uuid(), + $this->name(), + $this->message(), + $this->producerId(), + $this->entityId(), + $version, + ); + } + + /** + * @return self + */ + public function defineEntityId(Domain\Id $entityId): self + { + return new self( + $this->uuid(), + $this->name(), + $this->message(), + $this->producerId(), + $entityId, + $this->version(), + ); + } } diff --git a/src/Domain/Event/Exception/ConversionToObjectNotPossible.php b/src/Domain/Event/Exception/ConversionToObjectNotPossible.php index 2ae9c974..0fc93efd 100644 --- a/src/Domain/Event/Exception/ConversionToObjectNotPossible.php +++ b/src/Domain/Event/Exception/ConversionToObjectNotPossible.php @@ -18,12 +18,8 @@ */ class ConversionToObjectNotPossible extends ConversionNotPossible { - private array $array; - - public function __construct(array $array, \Throwable $previous = null) + public function __construct(private array $array, \Throwable $previous = null) { - $this->array = $array; - parent::__construct($previous); } diff --git a/src/Domain/Event/Exception/NoEventApplyingMethodFound.php b/src/Domain/Event/Exception/NoEventApplyingMethodFound.php index 43724349..ab524c09 100644 --- a/src/Domain/Event/Exception/NoEventApplyingMethodFound.php +++ b/src/Domain/Event/Exception/NoEventApplyingMethodFound.php @@ -22,14 +22,14 @@ */ class NoEventApplyingMethodFound extends \BadMethodCallException { - public function __construct(private Event\Consumer $consumer, private Event\Envelope $event, \Throwable $previous = null) + public function __construct(private object $object, private Event\Envelope $event, \Throwable $previous = null) { parent::__construct('No event applying method found.', 0, $previous); } - public function consumer(): Event\Consumer + public function object(): object { - return $this->consumer; + return $this->object; } public function event(): Event\Envelope diff --git a/src/Domain/Event/Exception/SourcingObjectWithEventFailed.php b/src/Domain/Event/Exception/SourcingObjectWithEventFailed.php index e5a948b0..a3df9899 100644 --- a/src/Domain/Event/Exception/SourcingObjectWithEventFailed.php +++ b/src/Domain/Event/Exception/SourcingObjectWithEventFailed.php @@ -29,7 +29,7 @@ public function __construct(private object $subject, private Event\Envelope $eve parent::__construct($message, 0, $previous); } - public function subject() + public function subject(): object { return $this->subject; } diff --git a/src/Domain/Event/Exception/TooManyEventApplyingMethodsFound.php b/src/Domain/Event/Exception/TooManyEventApplyingMethodsFound.php index 3423f5bb..c8bb2cc3 100644 --- a/src/Domain/Event/Exception/TooManyEventApplyingMethodsFound.php +++ b/src/Domain/Event/Exception/TooManyEventApplyingMethodsFound.php @@ -22,14 +22,14 @@ */ class TooManyEventApplyingMethodsFound extends \BadMethodCallException { - public function __construct(private Event\Consumer $consumer, private Event\Envelope $event, \Throwable $previous = null) + public function __construct(private object $object, private Event\Envelope $event, \Throwable $previous = null) { parent::__construct('Too many event applying methods found.', 0, $previous); } - public function consumer(): Event\Consumer + public function object(): object { - return $this->consumer; + return $this->object; } public function event(): Event\Envelope diff --git a/src/Domain/Event/Listener.php b/src/Domain/Event/Listener.php index fa418c80..70e199f5 100644 --- a/src/Domain/Event/Listener.php +++ b/src/Domain/Event/Listener.php @@ -21,7 +21,7 @@ */ interface Listener extends Identifiable { - public function listenerId(): Listener\Id; + public function id(): Listener\Id; /** * @return bool whether event was processed/is supported diff --git a/src/Domain/Event/Listener/Factory.php b/src/Domain/Event/Listener/Factory.php index 1ca6760d..6a42573d 100644 --- a/src/Domain/Event/Listener/Factory.php +++ b/src/Domain/Event/Listener/Factory.php @@ -15,20 +15,25 @@ use Streak\Domain\Event; use Streak\Domain\Event\Exception\InvalidEventGiven; -use Streak\Domain\Event\Listener; use Streak\Domain\Exception\InvalidIdGiven; /** + * @template T of Event\Listener + * * @author Alan Gabriel Bem */ interface Factory { /** + * @return T + * * @throws InvalidIdGiven */ - public function create(Listener\Id $id): Listener; + public function create(Event\Listener\Id $id): Event\Listener; /** + * @return T + * * @throws InvalidEventGiven */ public function createFor(Event\Envelope $event): Event\Listener; diff --git a/src/Domain/Event/Listener/Identifying.php b/src/Domain/Event/Listener/Identification.php similarity index 79% rename from src/Domain/Event/Listener/Identifying.php rename to src/Domain/Event/Listener/Identification.php index 55d3919c..fa785585 100644 --- a/src/Domain/Event/Listener/Identifying.php +++ b/src/Domain/Event/Listener/Identification.php @@ -13,13 +13,14 @@ namespace Streak\Domain\Event\Listener; -use Streak\Domain; use Streak\Domain\Event\Listener; /** * @author Alan Gabriel Bem + * + * @see \Streak\Domain\Event\Listener\IdentificationTest */ -trait Identifying +trait Identification { private $id; @@ -28,16 +29,11 @@ public function __construct(Listener\Id $id) $this->identifyBy($id); } - public function listenerId(): Listener\Id + public function id(): Listener\Id { return $this->id; } - public function id(): Domain\Id - { - return $this->listenerId(); - } - protected function identifyBy(Listener\Id $id): void { $this->id = $id; diff --git a/src/Domain/Event/Metadata.php b/src/Domain/Event/Metadata.php index b10c7b4d..6e272bbf 100644 --- a/src/Domain/Event/Metadata.php +++ b/src/Domain/Event/Metadata.php @@ -20,6 +20,9 @@ */ final class Metadata { + /** + * @var array + */ private array $metadata = []; private function __construct(array $metadata) @@ -34,7 +37,7 @@ public function set(string $name, string $value): void $this->metadata[$name] = $value; } - public function has(string $name) + public function has(string $name): bool { if (isset($this->metadata[$name])) { return true; @@ -52,7 +55,7 @@ public function get(string $name, string $default = null): ?string return $this->metadata[$name]; } - public static function fromObject($object): self + public static function fromObject(object $object): self { if (!isset($object->__streak_metadata)) { return new self([]); @@ -77,7 +80,7 @@ public static function fromArray(array $metadata): self return new self($metadata); } - public function toObject($object): void + public function toObject(object $object): void { $object->__streak_metadata = $this->metadata; } diff --git a/src/Domain/Event/Producer.php b/src/Domain/Event/Producer.php index 7dfb9e7d..4d27c94f 100644 --- a/src/Domain/Event/Producer.php +++ b/src/Domain/Event/Producer.php @@ -21,7 +21,7 @@ */ interface Producer { - public function producerId(): Domain\Id; + public function id(): Domain\Id; /** * @return Event\Envelope[] diff --git a/src/Domain/Event/Producer/Id.php b/src/Domain/Event/Producer/Id.php deleted file mode 100644 index 40196053..00000000 --- a/src/Domain/Event/Producer/Id.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Producer; - -use Streak\Domain; - -/** - * @author Alan Gabriel Bem - */ -interface Id extends Domain\Id -{ -// public static function from(string $value) : self; -} diff --git a/src/Domain/Event/Replayable.php b/src/Domain/Event/Replayable.php index cb06641a..3eb969ea 100644 --- a/src/Domain/Event/Replayable.php +++ b/src/Domain/Event/Replayable.php @@ -20,5 +20,5 @@ */ interface Replayable // TODO: Rename to Event\Listener\Replayable { - public function replay(Event\Stream $events): void; + public function replay(Event\Stream $stream): void; } diff --git a/src/Domain/Event/Sourced/Aggregate.php b/src/Domain/Event/Sourced/Aggregate.php index 100d3b0c..052e5808 100644 --- a/src/Domain/Event/Sourced/Aggregate.php +++ b/src/Domain/Event/Sourced/Aggregate.php @@ -19,6 +19,6 @@ /** * @author Alan Gabriel Bem */ -interface Aggregate extends Domain\Aggregate, Event\Sourced +interface Aggregate extends Domain\Aggregate, Event\Sourced\Entity { } diff --git a/src/Domain/Event/Sourced/Aggregate/Identification.php b/src/Domain/Event/Sourced/Aggregate/Identification.php deleted file mode 100644 index 68f48bb0..00000000 --- a/src/Domain/Event/Sourced/Aggregate/Identification.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\Aggregate; - -use Streak\Domain; -use Streak\Domain\Aggregate; -use Streak\Domain\Event\Producer; -use Streak\Domain\Event\Sourced as EventSourced; - -/** - * @author Alan Gabriel Bem - */ -trait Identification // implements Producer -{ - use Aggregate\Identification { - Aggregate\Identification::identifyBy as private identifyAggregateBy; - } - - public function __construct(EventSourced\Aggregate\Id $id) - { - $this->identifyBy($id); - } - - public function producerId(): Domain\Id - { - return $this->id; - } - - protected function identifyBy(Aggregate\Id $id): void - { - $this->identifyAggregateBy($id); - } -} diff --git a/src/Domain/Event/Sourced/AggregateRoot.php b/src/Domain/Event/Sourced/AggregateRoot.php index 057ebf9c..3261def3 100644 --- a/src/Domain/Event/Sourced/AggregateRoot.php +++ b/src/Domain/Event/Sourced/AggregateRoot.php @@ -20,7 +20,7 @@ /** * @author Alan Gabriel Bem */ -interface AggregateRoot extends Domain\AggregateRoot, Event\Sourced, Versionable +interface AggregateRoot extends Domain\AggregateRoot, Event\Consumer, Event\Producer, Event\Replayable, Versionable { public function lastEvent(): ?Event\Envelope; } diff --git a/src/Domain/Event/Sourced/AggregateRoot/Id.php b/src/Domain/Event/Sourced/AggregateRoot/Id.php deleted file mode 100644 index 4abdee62..00000000 --- a/src/Domain/Event/Sourced/AggregateRoot/Id.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\AggregateRoot; - -use Streak\Domain\AggregateRoot; - -/** - * @author Alan Gabriel Bem - */ -interface Id extends AggregateRoot\Id -{ -} diff --git a/src/Domain/Event/Sourced/AggregateRoot/Identification.php b/src/Domain/Event/Sourced/AggregateRoot/Identification.php deleted file mode 100644 index 583ac450..00000000 --- a/src/Domain/Event/Sourced/AggregateRoot/Identification.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\AggregateRoot; - -use Streak\Domain; -use Streak\Domain\AggregateRoot; -use Streak\Domain\Event\Producer; -use Streak\Domain\Event\Sourced as EventSourced; - -/** - * @author Alan Gabriel Bem - */ -trait Identification // implements Producer -{ - use AggregateRoot\Identification { - AggregateRoot\Identification::identifyBy as private identifyAggregateRootBy; - } - - public function __construct(EventSourced\AggregateRoot\Id $id) - { - $this->identifyBy($id); - } - - public function producerId(): Domain\Id - { - return $this->id; - } - - protected function identifyBy(AggregateRoot\Id $id): void - { - $this->identifyAggregateRootBy($id); - } -} diff --git a/src/Domain/Event/Sourced/Entity.php b/src/Domain/Event/Sourced/Entity.php index 15e44b3a..47ff4e51 100644 --- a/src/Domain/Event/Sourced/Entity.php +++ b/src/Domain/Event/Sourced/Entity.php @@ -19,6 +19,13 @@ /** * @author Alan Gabriel Bem */ -interface Entity extends Domain\Entity, Event\Sourced +interface Entity extends Domain\Entity, Event\Consumer { + public function registerAggregateRoot(Event\Sourced\AggregateRoot $aggregateRoot): void; + + public function registerAggregate(Event\Sourced\Aggregate $aggregate): void; + + public function aggregateRoot(): Event\Sourced\AggregateRoot; + + public function aggregate(): ?Event\Sourced\Aggregate; } diff --git a/src/Domain/Event/Sourced/Entity/Helper.php b/src/Domain/Event/Sourced/Entity/Helper.php new file mode 100644 index 00000000..76514cb8 --- /dev/null +++ b/src/Domain/Event/Sourced/Entity/Helper.php @@ -0,0 +1,181 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Streak\Domain\Event\Sourced\Entity; + +use Streak\Domain\Event; + +/** + * @author Alan Gabriel Bem + * + * @see \Streak\Domain\Event\Sourced\Entity\HelperTest + */ +final class Helper +{ + private function __construct(private object $object) + { + } + + public static function for(object $object): self + { + return new self($object); + } + + /** + * @throws Event\Exception\NoEventApplyingMethodFound + * @throws Event\Exception\TooManyEventApplyingMethodsFound + * @throws \Throwable + */ + public function applyEvent(Event\Envelope $event): void + { + self::applyEventByArgumentType($event, $this->object); + } + + /** + * @return \Generator + */ + public function extractEventSourcedEntities(): \Generator + { + yield from self::doExtractEventSourcedEntities($this->object); + } + + private static function applyEventByArgumentType(Event\Envelope $event, object &$entity): void + { + $reflection = new \ReflectionObject($entity); + + $methods = []; + foreach ($reflection->getMethods() as $method) { + // Method name must start with "apply" + if ('apply' !== mb_substr($method->getName(), 0, 5)) { + continue; + } + + // ...and have exactly one parameter... + if (1 !== $method->getNumberOfParameters()) { + continue; + } + + // ...which is required... + if (1 !== $method->getNumberOfRequiredParameters()) { + continue; + } + + $parameter = $method->getParameters()[0]; + $parameter = $parameter->getType(); + + // ...is not an union... + if (!$parameter instanceof \ReflectionNamedType) { + continue; + } + + $parameter = $parameter->getName(); + $parameter = new \ReflectionClass($parameter); + + // ..and its an event... + if (false === $parameter->isSubclassOf(Event::class)) { + continue; + } + + $target = new \ReflectionClass($event->message()); + + // .. and $event is type or subtype of defined $parameter + while ($parameter->getName() !== $target->getName()) { + $target = $target->getParentClass(); + + if (false === $target) { + continue 2; + } + } + + $methods[] = $method; + } + + if (0 === \count($methods)) { + throw new Event\Exception\NoEventApplyingMethodFound($entity, $event); + } + + // TODO: filter methods matching given event exactly and if it wont work, than filter by direct ascendants of given event and so on + + if (\count($methods) > 1) { + throw new Event\Exception\TooManyEventApplyingMethodsFound($entity, $event); + } + + $method = array_shift($methods); + + $isPublic = $method->isPublic(); + if (false === $isPublic) { + $method->setAccessible(true); + } + + try { + $method->invoke($entity, $event->message()); + } finally { + if (false === $isPublic) { + $method->setAccessible(false); + } + } + } + + /** + * Extract event sourced entities recursively. + * + * @return \Generator + */ + private static function doExtractEventSourcedEntities(object $object, array &$ignored = []): \Generator + { + $ignored[] = $object; + + $reflection = new \ReflectionObject($object); + foreach ($reflection->getProperties() as $property) { + $public = $property->isPublic(); + + if (false === $public) { + $property->setAccessible(true); + } + + if (false === $property->isInitialized($object)) { + continue; + } + + $entity = $property->getValue($object); + + if (false === $public) { + $property->setAccessible(false); + } + + if (true === is_iterable($entity)) { + $entities = $entity; + } else { + $entities = [$entity]; + } + + foreach ($entities as $entity) { + if (!$entity instanceof Event\Sourced\Entity) { + continue; + } + + foreach ($ignored as $ignore) { + if ($entity->equals($ignore)) { + continue 2; + } + } + + yield $entity; + + foreach (self::doExtractEventSourcedEntities($entity, $ignored) as $entity) { + yield $entity; + } + } + } + } +} diff --git a/src/Domain/Event/Sourced/Entity/Id.php b/src/Domain/Event/Sourced/Entity/Id.php deleted file mode 100644 index beee3e46..00000000 --- a/src/Domain/Event/Sourced/Entity/Id.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\Entity; - -use Streak\Domain\Entity; - -/** - * @author Alan Gabriel Bem - */ -interface Id extends Entity\Id -{ -} diff --git a/src/Domain/Event/Sourced/Entity/Identification.php b/src/Domain/Event/Sourced/Entity/Identification.php deleted file mode 100644 index 8dec9da1..00000000 --- a/src/Domain/Event/Sourced/Entity/Identification.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\Entity; - -use Streak\Domain; -use Streak\Domain\Entity; -use Streak\Domain\Event\Producer; -use Streak\Domain\Event\Sourced as EventSourced; - -/** - * @author Alan Gabriel Bem - */ -trait Identification // implements Producer -{ - use Entity\Identification { - Entity\Identification::identifyBy as private identifyEntityBy; - } - - public function __construct(EventSourced\Entity\Id $id) - { - $this->identifyBy($id); - } - - public function producerId(): Domain\Id - { - return $this->id; - } - - protected function identifyBy(Entity\Id $id): void - { - $this->identifyEntityBy($id); - } -} diff --git a/src/Domain/Event/Sourced.php b/src/Domain/Event/Sourced/Subscription.php similarity index 67% rename from src/Domain/Event/Sourced.php rename to src/Domain/Event/Sourced/Subscription.php index ca13f33a..090dc145 100644 --- a/src/Domain/Event/Sourced.php +++ b/src/Domain/Event/Sourced/Subscription.php @@ -11,14 +11,14 @@ declare(strict_types=1); -namespace Streak\Domain\Event; +namespace Streak\Domain\Event\Sourced; -use Streak\Domain\Comparable; use Streak\Domain\Event; +use Streak\Domain\Versionable; /** * @author Alan Gabriel Bem */ -interface Sourced extends Event\Producer, Event\Consumer, Comparable +interface Subscription extends Event\Subscription, Event\Producer, Event\Replayable, Versionable { } diff --git a/src/Domain/Event/Sourced/Subscription/Id.php b/src/Domain/Event/Sourced/Subscription/Id.php deleted file mode 100644 index ba95641d..00000000 --- a/src/Domain/Event/Sourced/Subscription/Id.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\Subscription; - -use Streak\Domain\Event\Subscription; -use Streak\Domain\Id\UUID; - -/** - * @author Alan Gabriel Bem - */ -class Id extends UUID implements Subscription\Id -{ -} diff --git a/src/Domain/Event/Sourcing.php b/src/Domain/Event/Sourcing.php deleted file mode 100644 index 904aa625..00000000 --- a/src/Domain/Event/Sourcing.php +++ /dev/null @@ -1,231 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event; - -use Streak\Domain; -use Streak\Domain\Event; - -/** - * @author Alan Gabriel Bem - */ -trait Sourcing //implements Event\Consumer, Event\Producer, Domain\Identifiable, Domain\Versionable -{ - /** - * @var Event\Envelope[] - */ - private array $events = []; - private ?Event\Envelope $lastEvent = null; - private bool $replaying = false; - private ?Event\Envelope $lastReplayed = null; - private int $version = 0; - - abstract public function producerId(): Domain\Id; - - /** - * @throws \Throwable - */ - final public function replay(Event\Stream $stream): void - { - try { - $this->replaying = true; - - foreach ($stream as $event) { - $this->applyEvent($event); - } - - $this->replaying = false; - } catch (Exception\SourcingObjectWithEventFailed $exception) { - $this->replaying = false; - - throw $exception; - } - } - - final public function lastReplayed(): ?Event\Envelope - { - return $this->lastReplayed; - } - - final public function lastEvent(): ?Event\Envelope - { - return $this->lastEvent; - } - - final public function version(): int - { - return $this->version; - } - - /** - * @return Event\Envelope[] - */ - final public function events(): array - { - return $this->events; - } - - public function commit(): void - { - $this->version += \count($this->events); - $this->events = []; - } - - /** - * @throws Event\Exception\NoEventApplyingMethodFound - * @throws Event\Exception\TooManyEventApplyingMethodsFound - * @throws \Throwable - */ - private function apply(Event $event): void - { - $event = Event\Envelope::new( - $event, - $this->producerId(), - $this->version + \count($this->events) + 1 // current version + number of not committed events + 1 - ); - - $this->applyEvent($event); - } - - /** - * @throws Event\Exception\NoEventApplyingMethodFound - * @throws Event\Exception\TooManyEventApplyingMethodsFound - * @throws \Throwable - */ - private function applyEvent(Event\Envelope $event): void - { - if (!$this instanceof Event\Consumer) { - throw new Exception\SourcingObjectWithEventFailed($this, $event); - } - - if (!$this->producerId()->equals($event->producerId())) { - throw new Domain\Exception\EventAndConsumerMismatch($this, $event); - } - - try { - $version = $this->version; // backup - $last = $this->lastEvent; // backup - $lastReplayed = $this->lastReplayed; // backup - - if ($this->replaying) { - $this->lastEvent = $event; - $this->version = (int) $event->version(); - $this->lastReplayed = $event; - } else { - $this->lastEvent = $event; - $this->events[] = $event; - } - - $this->doApplyEvent($event); - } catch (\Throwable $e) { - // rollback changes - if ($this->replaying) { - $this->lastEvent = $last; - $this->version = $version; - $this->lastReplayed = $lastReplayed; - } else { - $this->lastEvent = $last; - array_pop($this->events); - } - - throw $e; - } - } - - /** - * @throws Event\Exception\NoEventApplyingMethodFound - * @throws Event\Exception\TooManyEventApplyingMethodsFound - * @throws \Throwable - */ - private function doApplyEvent(Event\Envelope $event): void - { - $reflection = new \ReflectionObject($this); - - $methods = []; - foreach ($reflection->getMethods() as $method) { - // method is not current method... - if (__FUNCTION__ === $method->getName()) { - continue; - } - - // ...and its name must start with "apply" - if ('apply' !== mb_substr($method->getName(), 0, 5)) { - continue; - } - - // ...and have exactly one parameter... - if (1 !== $method->getNumberOfParameters()) { - continue; - } - - // ...which is required... - if (1 !== $method->getNumberOfRequiredParameters()) { - continue; - } - - $parameter = $method->getParameters()[0]; - $parameter = $parameter->getType(); - - // ...is not an union... - if (!$parameter instanceof \ReflectionNamedType) { - continue; - } - - $parameter = $parameter->getName(); - $parameter = new \ReflectionClass($parameter); - - // ..and its an event... - if (false === $parameter->isSubclassOf(Event::class)) { - continue; - } - - $target = new \ReflectionClass($event->message()); - - // .. and $event is type or subtype of defined $parameter - while ($parameter->getName() !== $target->getName()) { - $target = $target->getParentClass(); - - if (false === $target) { - continue 2; - } - } - - $methods[] = $method; - } - - if (0 === \count($methods)) { - throw new Exception\NoEventApplyingMethodFound($this, $event); - } - - // TODO: filter methods matching given event exactly and if it wont work, than filter by direct ascendants of given event and so on - - if (\count($methods) > 1) { - throw new Exception\TooManyEventApplyingMethodsFound($this, $event); - } - - $method = array_shift($methods); - - $isPublic = $method->isPublic(); - if (false === $isPublic) { - $method->setAccessible(true); - } - - try { - $method->invoke($this, $event->message()); - } finally { - if (false === $isPublic) { - $method->setAccessible(false); - } - } - } -} diff --git a/src/Domain/Event/Subscription.php b/src/Domain/Event/Subscription.php index cb94d437..3526223f 100644 --- a/src/Domain/Event/Subscription.php +++ b/src/Domain/Event/Subscription.php @@ -26,7 +26,7 @@ interface Subscription { public function listener(): Event\Listener; - public function subscriptionId(): Event\Listener\Id; + public function id(): Event\Listener\Id; /** * @throws Exception\SubscriptionAlreadyCompleted diff --git a/src/Domain/Event/Subscription/Exception/SubscriptionAlreadyCompleted.php b/src/Domain/Event/Subscription/Exception/SubscriptionAlreadyCompleted.php index 4c0587bc..368f8c14 100644 --- a/src/Domain/Event/Subscription/Exception/SubscriptionAlreadyCompleted.php +++ b/src/Domain/Event/Subscription/Exception/SubscriptionAlreadyCompleted.php @@ -24,7 +24,7 @@ class SubscriptionAlreadyCompleted extends \RuntimeException implements Subscrip { public function __construct(private Subscription $subscription) { - $message = sprintf('Subscription "%s#%s" is already completed.', $this->subscription->subscriptionId()::class, $this->subscription->subscriptionId()->toString()); + $message = sprintf('Subscription "%s#%s" is already completed.', $this->subscription->id()::class, $this->subscription->id()->toString()); parent::__construct($message); } diff --git a/src/Domain/Event/Subscription/Exception/SubscriptionAlreadyStarted.php b/src/Domain/Event/Subscription/Exception/SubscriptionAlreadyStarted.php index 49f6844d..ec3f8e22 100644 --- a/src/Domain/Event/Subscription/Exception/SubscriptionAlreadyStarted.php +++ b/src/Domain/Event/Subscription/Exception/SubscriptionAlreadyStarted.php @@ -24,7 +24,7 @@ class SubscriptionAlreadyStarted extends \RuntimeException implements Subscripti { public function __construct(private Subscription $subscription) { - $id = $this->subscription->subscriptionId(); + $id = $this->subscription->id(); $message = sprintf('Subscription "%s#%s" is already started.', $id::class, $id->toString()); diff --git a/src/Domain/Event/Subscription/Exception/SubscriptionNotStartedYet.php b/src/Domain/Event/Subscription/Exception/SubscriptionNotStartedYet.php index 9044bda9..19c3dd2c 100644 --- a/src/Domain/Event/Subscription/Exception/SubscriptionNotStartedYet.php +++ b/src/Domain/Event/Subscription/Exception/SubscriptionNotStartedYet.php @@ -24,7 +24,7 @@ class SubscriptionNotStartedYet extends \RuntimeException implements Subscriptio { public function __construct(private Subscription $subscription) { - $message = sprintf('Subscription "%s#%s" is not started yet.', $this->subscription->subscriptionId()::class, $this->subscription->subscriptionId()->toString()); + $message = sprintf('Subscription "%s#%s" is not started yet.', $this->subscription->id()::class, $this->subscription->id()->toString()); parent::__construct($message); } diff --git a/src/Domain/Event/Subscription/Exception/SubscriptionPaused.php b/src/Domain/Event/Subscription/Exception/SubscriptionPaused.php index 1bd43cf6..4f925365 100644 --- a/src/Domain/Event/Subscription/Exception/SubscriptionPaused.php +++ b/src/Domain/Event/Subscription/Exception/SubscriptionPaused.php @@ -24,7 +24,7 @@ class SubscriptionPaused extends \RuntimeException implements Subscription\Excep { public function __construct(private Subscription $subscription) { - $message = sprintf('Subscription "%s#%s" is paused.', $this->subscription->subscriptionId()::class, $this->subscription->subscriptionId()->toString()); + $message = sprintf('Subscription "%s#%s" is paused.', $this->subscription->id()::class, $this->subscription->id()->toString()); parent::__construct($message); } diff --git a/src/Domain/Event/Subscription/Exception/SubscriptionRestartNotPossible.php b/src/Domain/Event/Subscription/Exception/SubscriptionRestartNotPossible.php index e495b6d5..db86d57e 100644 --- a/src/Domain/Event/Subscription/Exception/SubscriptionRestartNotPossible.php +++ b/src/Domain/Event/Subscription/Exception/SubscriptionRestartNotPossible.php @@ -24,7 +24,7 @@ class SubscriptionRestartNotPossible extends \RuntimeException implements Subscr { public function __construct(private Subscription $subscription) { - $message = sprintf('Subscription "%s#%s" restart is not possible.', $this->subscription->subscriptionId()::class, $this->subscription->subscriptionId()->toString()); + $message = sprintf('Subscription "%s#%s" restart is not possible.', $this->subscription->id()::class, $this->subscription->id()->toString()); parent::__construct($message); } diff --git a/src/Domain/Event/Subscription/Factory.php b/src/Domain/Event/Subscription/Factory.php index b5ddf677..40d3a030 100644 --- a/src/Domain/Event/Subscription/Factory.php +++ b/src/Domain/Event/Subscription/Factory.php @@ -16,9 +16,14 @@ use Streak\Domain\Event; /** + * @template T of Event\Subscription + * * @author Alan Gabriel Bem */ interface Factory { + /** + * @return T + */ public function create(Event\Listener $listener): Event\Subscription; } diff --git a/src/Domain/Event/Subscription/Repository/Filter.php b/src/Domain/Event/Subscription/Repository/Filter.php index 963fd0f2..d6333781 100644 --- a/src/Domain/Event/Subscription/Repository/Filter.php +++ b/src/Domain/Event/Subscription/Repository/Filter.php @@ -15,6 +15,7 @@ /** * @author Alan Gabriel Bem + * @see \Streak\Domain\Event\Subscription\Repository\FilterTest */ final class Filter { diff --git a/src/Domain/EventStore.php b/src/Domain/EventStore.php index c88ca513..1b9995c3 100644 --- a/src/Domain/EventStore.php +++ b/src/Domain/EventStore.php @@ -13,6 +13,7 @@ namespace Streak\Domain; +use Streak\Domain\Exception; use Streak\Domain\Id\UUID; /** @@ -21,6 +22,9 @@ interface EventStore { /** + * @return array + * + * @throws Exception\EventAlreadyInStore * @throws Exception\ConcurrentWriteDetected * @throws Exception\InvalidAggregateGiven */ diff --git a/src/Domain/Exception/EventAndConsumerMismatch.php b/src/Domain/Exception/EventMismatched.php similarity index 54% rename from src/Domain/Exception/EventAndConsumerMismatch.php rename to src/Domain/Exception/EventMismatched.php index 60746a7d..cfa74d00 100644 --- a/src/Domain/Exception/EventAndConsumerMismatch.php +++ b/src/Domain/Exception/EventMismatched.php @@ -18,18 +18,18 @@ /** * @author Alan Gabriel Bem * - * @see \Streak\Domain\Exception\EventAndConsumerMismatchTest + * @see \Streak\Domain\Exception\EventMismatchedTest */ -class EventAndConsumerMismatch extends \LogicException +class EventMismatched extends \LogicException { - public function __construct(private Event\Consumer $consumer, private Event\Envelope $event, \Throwable $previous = null) + public function __construct(private object $object, private Event\Envelope $event, \Throwable $previous = null) { - parent::__construct('Event mismatched when applying on consumer.', 0, $previous); + parent::__construct('Event mismatched when applying on object.', 0, $previous); } - public function consumer(): Event\Consumer + public function object(): object { - return $this->consumer; + return $this->object; } public function event(): Event\Envelope diff --git a/src/Domain/Id.php b/src/Domain/Id.php index a68b7ec6..6ff97d06 100644 --- a/src/Domain/Id.php +++ b/src/Domain/Id.php @@ -20,7 +20,13 @@ */ interface Id extends Domain\ValueObject { + /** + * @return non-empty-string + */ public function toString(): string; - public static function fromString(string $id): Domain\Id; + /** + * @param non-empty-string $id + */ + public static function fromString(string $id): static; } diff --git a/src/Domain/Id/UUID.php b/src/Domain/Id/UUID.php index 041f0be9..ac00e000 100644 --- a/src/Domain/Id/UUID.php +++ b/src/Domain/Id/UUID.php @@ -25,8 +25,12 @@ */ class UUID implements Domain\Id { + /** @var non-empty-string */ private string $value; + /** + * @param non-empty-string $value + */ final public function __construct(string $value) { $value = mb_strtolower($value); @@ -44,10 +48,10 @@ final public function __construct(string $value) throw new \InvalidArgumentException(); } - $this->value = $value; + $this->value = $value; // @phpstan-ignore-line } - public static function random() + public static function random(): static { $uuid = \Ramsey\Uuid\Uuid::uuid4()->toString(); @@ -72,8 +76,8 @@ public function toString(): string return $this->value; } - public static function fromString(string $uuid): Domain\Id + public static function fromString(string $id): static { - return new static($uuid); + return new static($id); } } diff --git a/src/Infrastructure/Application/Sensor/CommittingSensor.php b/src/Infrastructure/Application/Sensor/CommittingSensor.php index 15feea21..605cea24 100644 --- a/src/Infrastructure/Application/Sensor/CommittingSensor.php +++ b/src/Infrastructure/Application/Sensor/CommittingSensor.php @@ -14,7 +14,6 @@ namespace Streak\Infrastructure\Application\Sensor; use Streak\Application\Sensor; -use Streak\Domain; use Streak\Domain\Event; use Streak\Infrastructure\Domain\UnitOfWork; @@ -29,9 +28,9 @@ public function __construct(private Sensor $sensor, private UnitOfWork $uow) { } - public function producerId(): Domain\Id + public function id(): Sensor\Id { - return $this->sensor->producerId(); + return $this->sensor->id(); } /** @@ -42,11 +41,6 @@ public function events(): array return $this->sensor->events(); } - public function sensorId(): Sensor\Id - { - return $this->sensor->sensorId(); - } - public function process(...$messages): void { $this->sensor->process(...$messages); diff --git a/src/Infrastructure/Application/Sensor/CommittingSensor/Factory.php b/src/Infrastructure/Application/Sensor/CommittingSensor/Factory.php index 78c114cc..38721aeb 100644 --- a/src/Infrastructure/Application/Sensor/CommittingSensor/Factory.php +++ b/src/Infrastructure/Application/Sensor/CommittingSensor/Factory.php @@ -28,7 +28,7 @@ public function __construct(private Sensor\Factory $factory, private UnitOfWork { } - public function create(): Sensor + public function create(): CommittingSensor { $sensor = $this->factory->create(); diff --git a/src/Infrastructure/Application/Sensor/LoggingSensor.php b/src/Infrastructure/Application/Sensor/LoggingSensor.php index 7defaa3c..4d8f293a 100644 --- a/src/Infrastructure/Application/Sensor/LoggingSensor.php +++ b/src/Infrastructure/Application/Sensor/LoggingSensor.php @@ -16,7 +16,6 @@ use Psr\Log\LoggerInterface; use Streak\Application; use Streak\Application\Sensor; -use Streak\Domain; /** * @author Alan Gabriel Bem @@ -29,9 +28,9 @@ public function __construct(private Application\Sensor $sensor, private LoggerIn { } - public function producerId(): Domain\Id + public function id(): Sensor\Id { - return $this->sensor->producerId(); + return $this->sensor->id(); } public function events(): array @@ -39,11 +38,6 @@ public function events(): array return $this->sensor->events(); } - public function sensorId(): Sensor\Id - { - return $this->sensor->sensorId(); - } - public function process(...$messages): void { try { diff --git a/src/Infrastructure/Application/Testing/Sensor/Scenario.php b/src/Infrastructure/Application/Testing/Sensor/Scenario.php index b25c9428..c5e8ee54 100644 --- a/src/Infrastructure/Application/Testing/Sensor/Scenario.php +++ b/src/Infrastructure/Application/Testing/Sensor/Scenario.php @@ -38,9 +38,9 @@ public function given(...$messages): Scenario\Then return $this; } - public function then(Event ...$expected): void + public function then(Event ...$events): void { $actual = array_map(fn (Event\Envelope $event) => $event->message(), $this->sensor->events()); - Assert::assertEquals($expected, $actual, 'Expected events don\'t match produced events.'); + Assert::assertEquals($events, $actual, 'Expected events don\'t match produced events.'); } } diff --git a/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/Exception/SnapshotNotFound.php b/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/Exception/SnapshotNotFound.php index e2de193d..bc809c68 100644 --- a/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/Exception/SnapshotNotFound.php +++ b/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/Exception/SnapshotNotFound.php @@ -24,7 +24,7 @@ class SnapshotNotFound extends \RuntimeException { public function __construct(private AggregateRoot $aggregate) { - parent::__construct(sprintf('Snapshot for aggregate "%s#%s" not found.', $this->aggregate->aggregateRootId()::class, $this->aggregate->aggregateRootId()->toString())); + parent::__construct(sprintf('Snapshot for aggregate "%s#%s" not found.', $this->aggregate->id()::class, $this->aggregate->id()->toString())); } public function aggregate(): AggregateRoot diff --git a/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/InMemoryStorage.php b/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/InMemoryStorage.php index da37a0f8..3ad65d77 100644 --- a/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/InMemoryStorage.php +++ b/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/InMemoryStorage.php @@ -29,7 +29,7 @@ final class InMemoryStorage implements Snapshotter\Storage public function find(AggregateRoot $aggregate): string { foreach ($this->snapshots as [$id, $snapshot]) { - if ($aggregate->aggregateRootId()->equals($id)) { + if ($aggregate->id()->equals($id)) { return $snapshot; } } @@ -37,16 +37,16 @@ public function find(AggregateRoot $aggregate): string throw new Exception\SnapshotNotFound($aggregate); } - public function store(AggregateRoot $aggregate, string $newSnapshot): void + public function store(AggregateRoot $aggregate, string $snapshot): void { - foreach ($this->snapshots as $key => [$id, $snapshot]) { - if ($aggregate->aggregateRootId()->equals($id)) { - $this->snapshots[$key] = [$id, $newSnapshot]; + foreach ($this->snapshots as $key => [$id, $current]) { + if ($aggregate->id()->equals($id)) { + $this->snapshots[$key] = [$id, $snapshot]; return; } } - $this->snapshots[] = [$aggregate->aggregateRootId(), $newSnapshot]; + $this->snapshots[] = [$aggregate->id(), $snapshot]; } } diff --git a/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorage.php b/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorage.php index 96cf905a..6bcedef6 100644 --- a/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorage.php +++ b/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorage.php @@ -73,6 +73,9 @@ private function doFind(AggregateRoot $aggregate): string return $row['snapshot']; } + /** + * @throws TableNotFoundException + */ private function doStore(AggregateRoot $aggregate, string $snapshot): void { $sql = <<<'SQL' diff --git a/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisStorage.php b/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisStorage.php index 88d64cf3..9055aa3c 100644 --- a/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisStorage.php +++ b/src/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisStorage.php @@ -20,14 +20,13 @@ /** * @author Alan Gabriel Bem + * + * @see \Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage\RedisStorageTest */ final class RedisStorage implements Storage, Resettable { - private \Redis $redis; - - public function __construct(\Redis $client) + public function __construct(private \Redis $redis) { - $this->redis = $client; } /** @@ -41,12 +40,17 @@ public function find(AggregateRoot $aggregate): string throw new SnapshotNotFound($aggregate); } + // Redis::get() can return Redis instance when it's in multi() mode. + if ($snapshot instanceof \Redis) { + throw new SnapshotNotFound($aggregate); + } + return $snapshot; } public function store(AggregateRoot $aggregate, string $snapshot): void { - $this->redis->set($this->key($aggregate), (string) $snapshot); + $this->redis->set($this->key($aggregate), $snapshot); } public function reset(): bool @@ -57,9 +61,9 @@ public function reset(): bool private function key(AggregateRoot $aggregate): string { return - \get_class($aggregate). - \get_class($aggregate->aggregateRootId()). - $aggregate->aggregateRootId()->toString() + $aggregate::class. + $aggregate->id()::class. + $aggregate->id()->toString() ; } } diff --git a/src/Infrastructure/Domain/Event/Converter/CompositeConverter.php b/src/Infrastructure/Domain/Event/Converter/CompositeConverter.php index bbf8f50a..9555fcbc 100644 --- a/src/Infrastructure/Domain/Event/Converter/CompositeConverter.php +++ b/src/Infrastructure/Domain/Event/Converter/CompositeConverter.php @@ -38,9 +38,6 @@ public function addConverter(Converter $converter): void $this->converters[] = $converter; } - /** - * @throws Exception\ConversionToArrayNotPossible - */ public function objectToArray(object $object): array { foreach ($this->converters as $converter) { @@ -56,9 +53,6 @@ public function objectToArray(object $object): array throw new Exception\ConversionToArrayNotPossible($object); } - /** - * @throws Exception\ConversionToObjectNotPossible - */ public function arrayToObject(array $data): object { $previous = null; diff --git a/src/Infrastructure/Domain/Event/Converter/NestedObjectConverter.php b/src/Infrastructure/Domain/Event/Converter/NestedObjectConverter.php index db3e1b9f..81c466b6 100644 --- a/src/Infrastructure/Domain/Event/Converter/NestedObjectConverter.php +++ b/src/Infrastructure/Domain/Event/Converter/NestedObjectConverter.php @@ -75,7 +75,7 @@ private function toArray($event): array if (false === $reflection) { break; } - } while ($reflection->getProperties() > 0); + } while (\count($reflection->getProperties()) > 0); } if (\is_array($object)) { @@ -85,7 +85,7 @@ private function toArray($event): array continue; } - if (is_scalar($value)) { + if (\is_scalar($value)) { continue; } if (null === $value) { diff --git a/src/Infrastructure/Domain/Event/InMemoryStream.php b/src/Infrastructure/Domain/Event/InMemoryStream.php index 576e0e0c..102741f1 100644 --- a/src/Infrastructure/Domain/Event/InMemoryStream.php +++ b/src/Infrastructure/Domain/Event/InMemoryStream.php @@ -165,7 +165,7 @@ private function search(Event\Envelope $event): ?int } /** - * @return Event[] + * @return array */ private function filter(): array { diff --git a/src/Infrastructure/Domain/Event/Listener/CompositeFactory.php b/src/Infrastructure/Domain/Event/Listener/CompositeFactory.php index 7ae95266..b736abbe 100644 --- a/src/Infrastructure/Domain/Event/Listener/CompositeFactory.php +++ b/src/Infrastructure/Domain/Event/Listener/CompositeFactory.php @@ -42,7 +42,7 @@ public function create(Listener\Id $id): Listener foreach ($this->factories as $factory) { try { return $factory->create($id); - } catch (Exception\InvalidIdGiven $e) { + } catch (Exception\InvalidIdGiven) { continue; } } diff --git a/src/Infrastructure/Domain/Event/LoggingListener.php b/src/Infrastructure/Domain/Event/LoggingListener.php index f2a57ace..a2ebe843 100644 --- a/src/Infrastructure/Domain/Event/LoggingListener.php +++ b/src/Infrastructure/Domain/Event/LoggingListener.php @@ -32,14 +32,9 @@ public function __construct(private Event\Listener $listener, private LoggerInte { } - public function id(): Domain\Id + public function id(): Listener\Id { - return $this->listenerId(); - } - - public function listenerId(): Listener\Id - { - return $this->listener->listenerId(); + return $this->listener->id(); } public function on(Event\Envelope $event): bool diff --git a/src/Infrastructure/Domain/Event/LoggingListener/Factory.php b/src/Infrastructure/Domain/Event/LoggingListener/Factory.php index 761a368d..798e628c 100644 --- a/src/Infrastructure/Domain/Event/LoggingListener/Factory.php +++ b/src/Infrastructure/Domain/Event/LoggingListener/Factory.php @@ -18,6 +18,8 @@ use Streak\Infrastructure\Domain\Event\LoggingListener; /** + * @implements Event\Listener\Factory + * * @author Alan Gabriel Bem * * @see \Streak\Infrastructure\Domain\Event\LoggingListener\FactoryTest @@ -28,14 +30,14 @@ public function __construct(private Event\Listener\Factory $factory, private Log { } - public function create(Event\Listener\Id $id): Event\Listener + public function create(Event\Listener\Id $id): LoggingListener { $saga = $this->factory->create($id); return new LoggingListener($saga, $this->logger); } - public function createFor(Event\Envelope $event): Event\Listener + public function createFor(Event\Envelope $event): LoggingListener { $listener = $this->factory->createFor($event); diff --git a/src/Infrastructure/Domain/Event/NullListener.php b/src/Infrastructure/Domain/Event/NullListener.php index a98dfa12..ebd12a25 100644 --- a/src/Infrastructure/Domain/Event/NullListener.php +++ b/src/Infrastructure/Domain/Event/NullListener.php @@ -23,15 +23,15 @@ */ class NullListener implements Event\Listener { - use Listener\Identifying; + use Listener\Identification; public function on(Event\Envelope $event): bool { return true; } - public static function from(Event\Listener $listener) + public static function from(Event\Listener $listener): self { - return new self($listener->listenerId()); + return new self($listener->id()); } } diff --git a/src/Infrastructure/Domain/Event/Sourced/Subscription.php b/src/Infrastructure/Domain/Event/Sourced/Subscription.php index b74701ee..e840a0b2 100644 --- a/src/Infrastructure/Domain/Event/Sourced/Subscription.php +++ b/src/Infrastructure/Domain/Event/Sourced/Subscription.php @@ -19,7 +19,6 @@ use Streak\Domain\Event\Listener\State; use Streak\Domain\Event\Subscription\Exception; use Streak\Domain\EventStore; -use Streak\Domain\Versionable; use Streak\Infrastructure\Domain\Event\InMemoryStream; use Streak\Infrastructure\Domain\Event\Sourced\Subscription\Event\SubscriptionCompleted; use Streak\Infrastructure\Domain\Event\Sourced\Subscription\Event\SubscriptionIgnoredEvent; @@ -36,12 +35,8 @@ * * @see \Streak\Infrastructure\Domain\Event\Sourced\SubscriptionTest */ -final class Subscription implements Event\Subscription, Event\Sourced, Versionable +final class Subscription implements Event\Sourced\Subscription { - use Event\Sourcing { - Event\Sourcing::replay as private doReplay; - } - private const LIMIT_TO_INITIAL_STREAM = 0; private State $lastState; private ?Event\Envelope $completedBy = null; @@ -50,11 +45,24 @@ final class Subscription implements Event\Subscription, Event\Sourced, Versionab private bool $starting = false; private $lastProcessedEvent; + /** + * @var Event\Envelope[] + */ + private array $events = []; + private ?Event\Envelope $lastEvent = null; + private bool $replaying = false; + private int $version = 0; + public function __construct(private Event\Listener $listener, private Domain\Clock $clock) { $this->lastState = InMemoryState::empty(); } + public function id(): Listener\Id + { + return $this->listener->id(); + } + /** * @throws Exception\SubscriptionAlreadyCompleted * @throws Exception\SubscriptionNotStartedYet @@ -243,7 +251,6 @@ public function replay(Event\Stream $stream): void $this->doReplay($substream); if ($this->completed()) { - $this->lastReplayed = $last; $this->lastEvent = $last; $this->version = (int) $last->version(); @@ -267,7 +274,6 @@ public function replay(Event\Stream $stream): void $this->doReplay(new InMemoryStream($changed)); } - $this->lastReplayed = $last; $this->lastEvent = $last; $this->version = (int) $last->version(); } @@ -278,23 +284,13 @@ public function equals(object $object): bool return false; } - if (!$this->subscriptionId()->equals($object->subscriptionId())) { + if (!$this->id()->equals($object->id())) { return false; } return true; } - public function producerId(): Domain\Id - { - return $this->subscriptionId(); - } - - public function subscriptionId(): Event\Listener\Id - { - return $this->listener->listenerId(); - } - public function listener(): Listener { return $this->listener; @@ -320,6 +316,45 @@ public function completed(): bool return null !== $this->completedBy; } + public function lastEvent(): ?Event\Envelope + { + return $this->lastEvent; + } + + public function version(): int + { + return $this->version; + } + + /** + * @return Event\Envelope[] + */ + public function events(): array + { + return $this->events; + } + + public function commit(): void + { + $this->version += \count($this->events); + $this->events = []; + } + + /** + * @throws \Throwable + */ + private function doReplay(Event\Stream $stream): void + { + try { + $this->replaying = true; + foreach ($stream as $event) { + $this->applyEvent($event); + } + } finally { + $this->replaying = false; + } + } + /** * @see applySubscriptionListenedToEvent * @see applySubscriptionIgnoredEvent @@ -363,54 +398,42 @@ private function doApplyEvent(Event\Envelope $event): void { if ($event->message() instanceof SubscriptionListenedToEvent) { $this->applySubscriptionListenedToEvent($event); - - return; } if ($event->message() instanceof SubscriptionIgnoredEvent) { $this->applySubscriptionIgnoredEvent($event); - - return; } if ($event->message() instanceof SubscriptionCompleted) { $this->applySubscriptionCompleted(); - - return; } if ($event->message() instanceof SubscriptionStarted) { $this->applySubscriptionStarted($event); - - return; } if ($event->message() instanceof SubscriptionRestarted) { $this->applySubscriptionRestarted($event); - - return; } if ($event->message() instanceof SubscriptionListenersStateChanged) { $this->applySubscriptionListenersStateChanged($event); - - return; } if ($event->message() instanceof SubscriptionPaused) { - $this->applySubscriptionPaused($event); - - return; + $this->applySubscriptionPaused(); } if ($event->message() instanceof SubscriptionUnPaused) { - $this->applySubscriptionUnPaused($event); - - return; + $this->applySubscriptionUnPaused(); } - - throw new Event\Exception\NoEventApplyingMethodFound($this, $event); // @codeCoverageIgnore } + /** + * @param Event\Envelope $event + */ private function applySubscriptionListenedToEvent(Event\Envelope $event): void { $this->starting = false; $this->lastProcessedEvent = $event->message()->event(); } + /** + * @param Event\Envelope $event + */ private function applySubscriptionIgnoredEvent(Event\Envelope $event): void { $this->starting = false; @@ -424,22 +447,28 @@ private function applySubscriptionCompleted(): void $this->paused = false; } + /** + * @param Event\Envelope $event + */ private function applySubscriptionStarted(Event\Envelope $event): void { $this->startedBy = $event->message()->startedBy(); $this->starting = true; } - private function applySubscriptionPaused(Event\Envelope $event): void + private function applySubscriptionPaused(): void { $this->paused = true; } - private function applySubscriptionUnPaused(Event\Envelope $event): void + private function applySubscriptionUnPaused(): void { $this->paused = false; } + /** + * @param Event\Envelope $event + */ private function applySubscriptionRestarted(Event\Envelope $event): void { $this->startedBy = $event->message()->originallyStartedBy(); @@ -448,6 +477,9 @@ private function applySubscriptionRestarted(Event\Envelope $event): void $this->paused = false; } + /** + * @param Event\Envelope $event + */ private function applySubscriptionListenersStateChanged(Event\Envelope $event): void { $state = $event->message()->state(); @@ -457,4 +489,40 @@ private function applySubscriptionListenersStateChanged(Event\Envelope $event): $this->listener->fromState($state); } } + + /** + * @throws Event\Exception\NoEventApplyingMethodFound + * @throws Event\Exception\TooManyEventApplyingMethodsFound + * @throws \Throwable + */ + private function apply(Event $event): void + { + $event = Event\Envelope::new( + $event, + $this->id(), + $this->version + \count($this->events) + 1 + ); + + $this->applyEvent($event); + } + + /** + * @throws \Throwable + */ + private function applyEvent(Event\Envelope $event): void + { + if (!$this->id()->equals($event->producerId())) { + throw new Domain\Exception\EventMismatched($this, $event); + } + + $this->doApplyEvent($event); + + $this->lastEvent = $event; + + if ($this->replaying) { + $this->version = $event->version(); + } else { + $this->events[] = $event; + } + } } diff --git a/src/Infrastructure/Domain/Event/Sourced/Subscription/InMemoryState.php b/src/Infrastructure/Domain/Event/Sourced/Subscription/InMemoryState.php index 8475e505..72b6d265 100644 --- a/src/Infrastructure/Domain/Event/Sourced/Subscription/InMemoryState.php +++ b/src/Infrastructure/Domain/Event/Sourced/Subscription/InMemoryState.php @@ -22,6 +22,9 @@ */ class InMemoryState implements State { + /** + * @var array + */ private array $state = []; private function __construct() @@ -55,7 +58,10 @@ public function get(string $name) return $this->state[$name]; } - public function set(string $name, $value): State + /** + * @param array|scalar|null $value + */ + public function set(string $name, $value): self { $this->validate($name, $value); @@ -94,6 +100,9 @@ public static function empty(): self return new self(); } + /** + * @param array|scalar|null $value + */ private function validate(string $name, $value): void { if (true === empty($name)) { @@ -102,7 +111,7 @@ private function validate(string $name, $value): void $value = [$name => $value]; array_walk_recursive($value, function ($value, $key): void { - if (true === is_scalar($value)) { + if (true === \is_scalar($value)) { return; } if (null === $value) { diff --git a/src/Infrastructure/Domain/Event/Subscriber.php b/src/Infrastructure/Domain/Event/Subscriber.php index 8dcab5e5..ebdf09a5 100644 --- a/src/Infrastructure/Domain/Event/Subscriber.php +++ b/src/Infrastructure/Domain/Event/Subscriber.php @@ -27,7 +27,7 @@ */ class Subscriber implements Event\Listener { - use Event\Listener\Identifying; + use Event\Listener\Identification; public function __construct(private Event\Listener\Factory $listenerFactory, private Event\Subscription\Factory $subscriptionFactory, private Event\Subscription\Repository $subscriptionsRepository) { diff --git a/src/Infrastructure/Domain/Event/Subscription/CommittingSubscription.php b/src/Infrastructure/Domain/Event/Subscription/CommittingSubscription.php index bd84b6f6..55d6ac7f 100644 --- a/src/Infrastructure/Domain/Event/Subscription/CommittingSubscription.php +++ b/src/Infrastructure/Domain/Event/Subscription/CommittingSubscription.php @@ -34,9 +34,9 @@ public function subscription(): Subscription return $this->subscription; } - public function subscriptionId(): Event\Listener\Id + public function id(): Event\Listener\Id { - return $this->subscription->subscriptionId(); + return $this->subscription->id(); } public function listener(): Event\Listener diff --git a/src/Infrastructure/Domain/Event/Subscription/CommittingSubscription/Factory.php b/src/Infrastructure/Domain/Event/Subscription/CommittingSubscription/Factory.php index b46bfc3f..3eb9460c 100644 --- a/src/Infrastructure/Domain/Event/Subscription/CommittingSubscription/Factory.php +++ b/src/Infrastructure/Domain/Event/Subscription/CommittingSubscription/Factory.php @@ -19,6 +19,8 @@ use Streak\Infrastructure\Domain\UnitOfWork; /** + * @implements Event\Subscription\Factory + * * @author Alan Gabriel Bem * * @see \Streak\Infrastructure\Domain\Event\Subscription\CommittingSubscription\FactoryTest @@ -29,7 +31,7 @@ public function __construct(private Subscription\Factory $factory, private UnitO { } - public function create(Event\Listener $listener): Event\Subscription + public function create(Event\Listener $listener): CommittingSubscription { $subscription = $this->factory->create($listener); diff --git a/src/Infrastructure/Domain/Event/Subscription/DAO.php b/src/Infrastructure/Domain/Event/Subscription/DAO.php index 8087dcc0..465ae458 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DAO.php +++ b/src/Infrastructure/Domain/Event/Subscription/DAO.php @@ -30,7 +30,7 @@ public function exists(Listener\Id $id): bool; /** * @param string[] $types * - * @return DAO\Subscription[] + * @return iterable */ public function all(array $types = [], ?bool $completed = null): iterable; } diff --git a/src/Infrastructure/Domain/Event/Subscription/DAO/DAORepository.php b/src/Infrastructure/Domain/Event/Subscription/DAO/DAORepository.php index 489c7f21..0249f855 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DAO/DAORepository.php +++ b/src/Infrastructure/Domain/Event/Subscription/DAO/DAORepository.php @@ -44,7 +44,7 @@ public function find(Event\Listener\Id $id): ?Event\Subscription public function has(Event\Subscription $subscription): bool { - return $this->dao->exists($subscription->subscriptionId()); + return $this->dao->exists($subscription->id()); } public function add(Event\Subscription $subscription): void diff --git a/src/Infrastructure/Domain/Event/Subscription/DAO/DbalPostgresDAO.php b/src/Infrastructure/Domain/Event/Subscription/DAO/DbalPostgresDAO.php index ce593c95..47874063 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DAO/DbalPostgresDAO.php +++ b/src/Infrastructure/Domain/Event/Subscription/DAO/DbalPostgresDAO.php @@ -30,8 +30,13 @@ */ class DbalPostgresDAO implements DAO { - public function __construct(private Subscription\Factory $subscriptions, private Event\Listener\Factory $listeners, private Connection $connection, private Event\Converter $converter) - { + public function __construct( + /** @var Subscription\Factory */ + private Subscription\Factory $subscriptions, + private Event\Listener\Factory $listeners, + private Connection $connection, + private Event\Converter $converter + ) { } /** @@ -69,11 +74,9 @@ public function exists(Listener\Id $id): bool } /** - * @param string[] $types + * @return \Generator * * @throws \Doctrine\DBAL\DBALException - * - * @return Subscription[] */ public function all(array $types = [], ?bool $completed = null): iterable { @@ -87,8 +90,8 @@ public function all(array $types = [], ?bool $completed = null): iterable public function toRow(DAO\Subscription $subscription): array { // dehydrate - $row['subscription_type'] = $subscription->subscriptionId()::class; - $row['subscription_id'] = $subscription->subscriptionId()->toString(); + $row['subscription_type'] = $subscription->id()::class; + $row['subscription_id'] = $subscription->id()->toString(); $row['subscription_version'] = $subscription->version(); $reflection = new \ReflectionObject($subscription); @@ -186,7 +189,7 @@ public function drop(): void $statement->execute(); } - private function fromRow($row): Subscription + private function fromRow($row): DAO\Subscription { $id = $row['subscription_type']; $id = $id::fromString($row['subscription_id']); @@ -306,11 +309,9 @@ private function doSave(DAO\Subscription $subscription): void } /** - * * @throws \Doctrine\DBAL\DBALException - * @return \Streak\Infrastructure\Domain\Event\Subscription\DAO\Subscription|null */ - private function doOne(Event\Listener\Id $id) + private function doOne(Event\Listener\Id $id): ?DAO\Subscription { $sql = 'SELECT subscription_type, subscription_id, subscription_version, state, started_by, started_at, last_processed_event, last_event_processed_at, completed, paused_at FROM subscriptions WHERE subscription_type = :subscription_type AND subscription_id = :subscription_id LIMIT 1'; @@ -354,6 +355,8 @@ private function doExists(Listener\Id $id): bool } /** + * @return \Generator + * * @throws \Doctrine\DBAL\DBALException */ private function doAll(array $types, ?bool $completed): \Generator diff --git a/src/Infrastructure/Domain/Event/Subscription/DAO/IdentityMappingDao.php b/src/Infrastructure/Domain/Event/Subscription/DAO/IdentityMappingDao.php index b00a14aa..be4e54ea 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DAO/IdentityMappingDao.php +++ b/src/Infrastructure/Domain/Event/Subscription/DAO/IdentityMappingDao.php @@ -83,7 +83,7 @@ public function shouldSave(Subscription $subscription): bool private function key(Subscription $subscription): string { - return sprintf('%s_%s', $subscription->subscriptionId()::class, $subscription->subscriptionId()->toString()); + return sprintf('%s_%s', $subscription->id()::class, $subscription->id()->toString()); } private function rememberVersion(Subscription $subscription): void diff --git a/src/Infrastructure/Domain/Event/Subscription/DAO/InMemoryDAO.php b/src/Infrastructure/Domain/Event/Subscription/DAO/InMemoryDAO.php index 145234dd..cac5f52f 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DAO/InMemoryDAO.php +++ b/src/Infrastructure/Domain/Event/Subscription/DAO/InMemoryDAO.php @@ -32,7 +32,7 @@ class InMemoryDAO implements DAO public function save(Subscription $subscription): void { foreach ($this->subscriptions as $key => $stored) { - if ($stored->subscriptionId()->equals($subscription->subscriptionId())) { + if ($stored->id()->equals($subscription->id())) { $this->subscriptions[$key] = $subscription; return; @@ -45,7 +45,7 @@ public function save(Subscription $subscription): void public function one(Listener\Id $id): ?Subscription { foreach ($this->subscriptions as $key => $stored) { - if ($stored->subscriptionId()->equals($id)) { + if ($stored->id()->equals($id)) { return $stored; } } @@ -60,9 +60,9 @@ public function exists(Listener\Id $id): bool public function all(array $types = [], ?bool $completed = null): iterable { - foreach ($this->subscriptions as $key => $stored) { + foreach ($this->subscriptions as $stored) { if (\count($types)) { - $type = $stored->subscriptionId()::class; + $type = $stored->id()::class; if (false === \in_array($type, $types)) { continue; } diff --git a/src/Infrastructure/Domain/Event/Subscription/DAO/Subscription.php b/src/Infrastructure/Domain/Event/Subscription/DAO/Subscription.php index c995f50e..29b2e418 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DAO/Subscription.php +++ b/src/Infrastructure/Domain/Event/Subscription/DAO/Subscription.php @@ -16,6 +16,7 @@ use Streak\Domain\Clock; use Streak\Domain\Event; use Streak\Domain\Event\Listener; +use Streak\Domain\Event\Listener\State; use Streak\Domain\Event\Subscription\Exception; use Streak\Domain\EventStore; use Streak\Infrastructure\Domain\Event\Sourced\Subscription\InMemoryState; @@ -28,12 +29,12 @@ class Subscription implements Event\Subscription { private const LIMIT_TO_INITIAL_STREAM = 0; - private InMemoryState $state; + private State $state; private ?Event\Envelope $startedBy = null; - private ?\DateTimeImmutable $startedAt = null; + private ?\DateTimeImmutable $startedAt = null; // @TODO: check if needed private ?\DateTimeImmutable $pausedAt = null; private ?Event\Envelope $lastProcessedEvent = null; - private ?\DateTimeImmutable $lastEventProcessedAt = null; + private ?\DateTimeImmutable $lastEventProcessedAt = null; // @TODO: check if needed private int $version = 0; private bool $completed = false; @@ -47,9 +48,9 @@ public function listener(): Listener return $this->listener; } - public function subscriptionId(): Listener\Id + public function id(): Listener\Id { - return $this->listener->listenerId(); + return $this->listener->id(); } public function subscribeTo(EventStore $store, ?int $limit = null): iterable diff --git a/src/Infrastructure/Domain/Event/Subscription/DAO/Subscription/Factory.php b/src/Infrastructure/Domain/Event/Subscription/DAO/Subscription/Factory.php index 3568288c..ccfc119e 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DAO/Subscription/Factory.php +++ b/src/Infrastructure/Domain/Event/Subscription/DAO/Subscription/Factory.php @@ -15,9 +15,11 @@ use Streak\Domain\Clock; use Streak\Domain\Event; -use Streak\Infrastructure\Domain\Event\Subscription\DAO\Subscription; +use Streak\Infrastructure\Domain\Event\Subscription\DAO; /** + * @implements Event\Subscription\Factory + * * @author Alan Gabriel Bem * * @see \Streak\Infrastructure\Domain\Event\Subscription\DAO\Subscription\FactoryTest @@ -28,8 +30,8 @@ public function __construct(private Clock $clock) { } - public function create(Event\Listener $listener): Event\Subscription + public function create(Event\Listener $listener): DAO\Subscription { - return new Subscription($listener, $this->clock); + return new DAO\Subscription($listener, $this->clock); } } diff --git a/src/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription.php b/src/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription.php index fb34627b..84272f7d 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription.php +++ b/src/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription.php @@ -40,9 +40,9 @@ public function listener(): Listener return $this->subscription->listener(); } - public function subscriptionId(): Listener\Id + public function id(): Listener\Id { - return $this->subscription->subscriptionId(); + return $this->subscription->id(); } public function subscribeTo(EventStore $store, ?int $limit = null): iterable diff --git a/src/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription/Factory.php b/src/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription/Factory.php index 86c89620..0fc0e64c 100644 --- a/src/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription/Factory.php +++ b/src/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription/Factory.php @@ -18,6 +18,8 @@ use Streak\Infrastructure\Domain\Event\Subscription\DbalTransactionalSubscription; /** + * @implements Event\Subscription\Factory + * * @author Alan Gabriel Bem * * @see \Streak\Infrastructure\Domain\Event\Subscription\DbalTransactionalSubscription\FactoryTest @@ -35,7 +37,7 @@ public function __construct(private Event\Subscription\Factory $factory, private $this->maxTransactionSize = $maxTransactionSize; } - public function create(Event\Listener $listener): Event\Subscription + public function create(Event\Listener $listener): DbalTransactionalSubscription { $subscription = $this->factory->create($listener); diff --git a/src/Infrastructure/Domain/Event/Subscription/EventSourcedRepository.php b/src/Infrastructure/Domain/Event/Subscription/EventSourcedRepository.php index 0f530343..4a71a14a 100644 --- a/src/Infrastructure/Domain/Event/Subscription/EventSourcedRepository.php +++ b/src/Infrastructure/Domain/Event/Subscription/EventSourcedRepository.php @@ -43,7 +43,7 @@ public function find(Event\Listener\Id $id): ?Event\Subscription $unwrapped = $this->unwrap($subscription); $filter = new EventStore\Filter(); - $filter = $filter->filterProducerIds($unwrapped->producerId()); + $filter = $filter->filterProducerIds($unwrapped->id()); $stream = $this->store->stream($filter); @@ -66,7 +66,7 @@ public function has(Event\Subscription $subscription): bool $unwrapped = $this->unwrap($subscription); $filter = new EventStore\Filter(); - $filter = $filter->filterProducerIds($unwrapped->producerId()); + $filter = $filter->filterProducerIds($unwrapped->id()); $stream = $this->store->stream($filter); @@ -104,6 +104,7 @@ public function all(?Filter $filter = null): iterable $ids = []; foreach ($stream as $event) { + /** @var $event Event\Envelope */ if ($event->message() instanceof SubscriptionStarted) { $ids[] = $event->producerId(); } @@ -137,21 +138,18 @@ public function all(?Filter $filter = null): iterable } } - /** - * @return Event\Sourced|Subscription - */ - private function unwrap(Event\Subscription $subscription): Event\Sourced + private function unwrap(Event\Subscription $subscription): Event\Sourced\Subscription { $exception = new Exception\ObjectNotSupported($subscription); - if ($subscription instanceof Event\Sourced) { + if ($subscription instanceof Event\Sourced\Subscription) { return $subscription; } while ($subscription instanceof Subscription\Decorator) { $subscription = $subscription->subscription(); - if ($subscription instanceof Event\Sourced) { + if ($subscription instanceof Event\Sourced\Subscription) { return $subscription; } } diff --git a/src/Infrastructure/Domain/Event/Subscription/LazyLoadedSubscription.php b/src/Infrastructure/Domain/Event/Subscription/LazyLoadedSubscription.php index 92857113..bae41b48 100644 --- a/src/Infrastructure/Domain/Event/Subscription/LazyLoadedSubscription.php +++ b/src/Infrastructure/Domain/Event/Subscription/LazyLoadedSubscription.php @@ -31,7 +31,7 @@ public function __construct(private Listener\Id $id, private Subscription\Reposi { } - public function subscriptionId(): Listener\Id + public function id(): Listener\Id { return $this->id; } @@ -74,7 +74,7 @@ public function completed(): bool public function subscription(): Subscription { if (null === $this->subscription) { - $this->subscription = $this->repository->find($this->subscriptionId()); + $this->subscription = $this->repository->find($this->id()); } return $this->subscription; diff --git a/src/Infrastructure/Domain/EventBus/InMemoryEventBus.php b/src/Infrastructure/Domain/EventBus/InMemoryEventBus.php index c7eac191..01277abf 100644 --- a/src/Infrastructure/Domain/EventBus/InMemoryEventBus.php +++ b/src/Infrastructure/Domain/EventBus/InMemoryEventBus.php @@ -24,12 +24,12 @@ class InMemoryEventBus implements EventBus { /** - * @var Event\Listener[] + * @var \SplQueue */ - private \SplObjectStorage $listeners; + private \SplQueue $listeners; /** - * @var Event[] + * @var Event\Envelope[] */ private array $events = []; @@ -37,17 +37,28 @@ class InMemoryEventBus implements EventBus public function __construct() { - $this->listeners = new \SplObjectStorage(); + $this->listeners = new \SplQueue(); } public function add(Event\Listener $listener): void { - $this->listeners->attach($listener); + foreach ($this->listeners as $current) { + if ($current->id()->equals($listener->id())) { + return; + } + } + + $this->listeners->enqueue($listener); } public function remove(Event\Listener $listener): void { - $this->listeners->detach($listener); + foreach ($this->listeners as $key => $current) { + if ($current->id()->equals($listener->id())) { + unset($this->listeners[$key]); + return; + } + } } public function publish(Event\Envelope ...$events): void diff --git a/src/Infrastructure/Domain/EventBus/NullEventBus.php b/src/Infrastructure/Domain/EventBus/NullEventBus.php index 43d72800..99e8fcc3 100644 --- a/src/Infrastructure/Domain/EventBus/NullEventBus.php +++ b/src/Infrastructure/Domain/EventBus/NullEventBus.php @@ -33,7 +33,7 @@ public function remove(Event\Listener $listener): void { } - public function publish(Event\Envelope ...$messages): void + public function publish(Event\Envelope ...$events): void { } } diff --git a/src/Infrastructure/Domain/EventStore/DbalPostgresEventStore.php b/src/Infrastructure/Domain/EventStore/DbalPostgresEventStore.php index 849201c9..0bb95097 100644 --- a/src/Infrastructure/Domain/EventStore/DbalPostgresEventStore.php +++ b/src/Infrastructure/Domain/EventStore/DbalPostgresEventStore.php @@ -451,7 +451,7 @@ public function event(UUID $uuid): ?Event\Envelope return $this->fromRow($row); } - public function producerId($class, $id): Domain\Id + private function toId($class, $id): Domain\Id { $reflection = new \ReflectionClass($class); @@ -572,8 +572,10 @@ private function select( $from = $this->session[$from->uuid()->toString()]; } - $where[] = ' (number >= :from) '; - $parameters['from'] = $from->get(self::EVENT_METADATA_NUMBER); + if ($from->get(self::EVENT_METADATA_NUMBER)) { + $where[] = ' (number >= :from) '; + $parameters['from'] = $from->get(self::EVENT_METADATA_NUMBER); + } } if ($to) { @@ -581,8 +583,10 @@ private function select( $to = $this->session[$to->uuid()->toString()]; } - $where[] = ' (number <= :to) '; - $parameters['to'] = $to->get(self::EVENT_METADATA_NUMBER); + if ($to->get(self::EVENT_METADATA_NUMBER)) { + $where[] = ' (number <= :to) '; + $parameters['to'] = $to->get(self::EVENT_METADATA_NUMBER); + } } if ($after) { @@ -590,8 +594,10 @@ private function select( $after = $this->session[$after->uuid()->toString()]; } - $where[] = ' (number > :after) '; - $parameters['after'] = $after->get(self::EVENT_METADATA_NUMBER); + if ($after->get(self::EVENT_METADATA_NUMBER)) { + $where[] = ' (number > :after) '; + $parameters['after'] = $after->get(self::EVENT_METADATA_NUMBER); + } } if ($before) { @@ -599,8 +605,10 @@ private function select( $before = $this->session[$before->uuid()->toString()]; } - $where[] = ' (number < :before) '; - $parameters['before'] = $before->get(self::EVENT_METADATA_NUMBER); + if ($before->get(self::EVENT_METADATA_NUMBER)) { + $where[] = ' (number < :before) '; + $parameters['before'] = $before->get(self::EVENT_METADATA_NUMBER); + } } $where = implode(' AND ', $where); @@ -643,18 +651,22 @@ private function fromRow(array $row): Event\Envelope $body = json_decode($body, true); $body = $this->converter->arrayToObject($body); - $producerId = $this->producerId($row['producer_type'], $row['producer_id']); + /* TODO: store entity type and id as columns */ + $metadata = $row['metadata']; + $metadata = json_decode($metadata, true); + + $producerId = $this->toId($row['producer_type'], $row['producer_id']); + $entityId = $this->toId($metadata['entity_type'], $metadata['entity_id']); $event = new Event\Envelope( $uuid, $row['type'], $body, $producerId, - $row['producer_version'] + $entityId, + $row['producer_version'], ); - $metadata = $row['metadata']; - $metadata = json_decode($metadata, true); $metadata[self::EVENT_METADATA_NUMBER] = $row['number']; foreach ($metadata as $name => $value) { @@ -679,7 +691,7 @@ private function toRow(Event\Envelope $event): array ]; } - private function extractIdForConcurrentWrite(UniqueConstraintViolationException $e) + private function extractIdForConcurrentWrite(UniqueConstraintViolationException $e): Domain\Id|null { // example: // SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "events_producer_type_producer_id_producer_version_key" @@ -702,10 +714,10 @@ private function extractIdForConcurrentWrite(UniqueConstraintViolationException return null; // @codeCoverageIgnore } - return $this->producerId($matches['type'], $matches['id']); + return $this->toId($matches['type'], $matches['id']); } - private function extractIdForEventAlreadyInStore(UniqueConstraintViolationException $e) + private function extractIdForEventAlreadyInStore(UniqueConstraintViolationException $e): UUID|null { // example: // SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "events_uuid_key" diff --git a/src/Infrastructure/Domain/Serializer.php b/src/Infrastructure/Domain/Serializer.php index a477381c..5fb5bccb 100644 --- a/src/Infrastructure/Domain/Serializer.php +++ b/src/Infrastructure/Domain/Serializer.php @@ -20,5 +20,5 @@ interface Serializer { public function serialize($subject): string; - public function unserialize($serialized); + public function unserialize(string $serialized); } diff --git a/src/Infrastructure/Domain/Serializer/IGBinarySerializer.php b/src/Infrastructure/Domain/Serializer/IGBinarySerializer.php index 5bccb1b5..59f824ae 100644 --- a/src/Infrastructure/Domain/Serializer/IGBinarySerializer.php +++ b/src/Infrastructure/Domain/Serializer/IGBinarySerializer.php @@ -27,7 +27,7 @@ public function serialize($subject): string return igbinary_serialize($subject); } - public function unserialize($serialized) + public function unserialize(string $serialized) { return igbinary_unserialize($serialized); } diff --git a/src/Infrastructure/Domain/Serializer/PhpSerializer.php b/src/Infrastructure/Domain/Serializer/PhpSerializer.php index f2873f25..d15f75b3 100644 --- a/src/Infrastructure/Domain/Serializer/PhpSerializer.php +++ b/src/Infrastructure/Domain/Serializer/PhpSerializer.php @@ -27,7 +27,7 @@ public function serialize($subject): string return serialize($subject); } - public function unserialize($serialized) + public function unserialize(string $serialized) { return unserialize($serialized); } diff --git a/src/Infrastructure/Domain/Testing/AggregateRoot/Scenario.php b/src/Infrastructure/Domain/Testing/AggregateRoot/Scenario.php index c9a89012..a8fd0d2e 100644 --- a/src/Infrastructure/Domain/Testing/AggregateRoot/Scenario.php +++ b/src/Infrastructure/Domain/Testing/AggregateRoot/Scenario.php @@ -27,24 +27,14 @@ */ class Scenario implements Scenario\Given, Scenario\When, Scenario\Then { - private Domain\CommandHandler $handler; - private InMemoryEventStore $store; - private Domain\AggregateRoot\Factory $factory; - private Snapshotter $snapshotter; - private UnitOfWork $uow; private ?Domain\AggregateRoot\Id $id = null; /** * @var Domain\Event\Envelope[] */ private array $events = []; - public function __construct(Domain\CommandHandler $handler, InMemoryEventStore $store, Domain\AggregateRoot\Factory $factory, Snapshotter $snapshotter, UnitOfWork $uow) + public function __construct(private Domain\CommandHandler $handler, private InMemoryEventStore $store, private Domain\AggregateRoot\Factory $factory, private Snapshotter $snapshotter, private UnitOfWork $uow) { - $this->handler = $handler; - $this->store = $store; - $this->factory = $factory; - $this->snapshotter = $snapshotter; - $this->uow = $uow; } public function for(Domain\AggregateRoot\Id $id): Given diff --git a/src/Infrastructure/Domain/Testing/AggregateRoot/Scenario/Then.php b/src/Infrastructure/Domain/Testing/AggregateRoot/Scenario/Then.php index e1c7e10d..9b7c77e0 100644 --- a/src/Infrastructure/Domain/Testing/AggregateRoot/Scenario/Then.php +++ b/src/Infrastructure/Domain/Testing/AggregateRoot/Scenario/Then.php @@ -20,5 +20,5 @@ */ interface Then { - public function then(Domain\Event ...$events): void; + public function then(Domain\Event ...$expected): void; } diff --git a/src/Infrastructure/Domain/Testing/AggregateRoot/TestCase.php b/src/Infrastructure/Domain/Testing/AggregateRoot/TestCase.php index 7b187577..71e776cf 100644 --- a/src/Infrastructure/Domain/Testing/AggregateRoot/TestCase.php +++ b/src/Infrastructure/Domain/Testing/AggregateRoot/TestCase.php @@ -59,7 +59,7 @@ protected function createSnapshotterSerializer(): Serializer return new PhpSerializer(); } - protected function createSnapshotterStorage() + protected function createSnapshotterStorage(): Snapshotter\Storage\InMemoryStorage { return new Snapshotter\Storage\InMemoryStorage(); } diff --git a/src/Infrastructure/Domain/Testing/Listener/Scenario.php b/src/Infrastructure/Domain/Testing/Listener/Scenario.php index eb07458e..f1143cf0 100644 --- a/src/Infrastructure/Domain/Testing/Listener/Scenario.php +++ b/src/Infrastructure/Domain/Testing/Listener/Scenario.php @@ -14,9 +14,9 @@ namespace Streak\Infrastructure\Domain\Testing\Listener; use PHPUnit\Framework\Assert; -use Streak\Application; use Streak\Domain; use Streak\Domain\Event; +use Streak\Infrastructure\Application\CommandBus\SynchronousCommandBus; use Streak\Infrastructure\Domain\Event\InMemoryStream; use Streak\Infrastructure\Domain\Event\Sourced\Subscription\InMemoryState; use Streak\Infrastructure\Domain\Testing\Listener\Scenario\Then; @@ -28,10 +28,6 @@ */ class Scenario implements Scenario\Given, Scenario\When, Scenario\Then, Domain\CommandHandler { - private Application\CommandBus $bus; - - private Event\Listener\Factory $factory; - /** * @var Event\Envelope[] */ @@ -56,11 +52,9 @@ class Scenario implements Scenario\Given, Scenario\When, Scenario\Then, Domain\C */ private array $expectedErrors = []; - public function __construct(Application\CommandBus $bus, Event\Listener\Factory $factory) + public function __construct(private SynchronousCommandBus $bus, private Event\Listener\Factory $factory) { - $this->bus = $bus; $this->bus->register($this); - $this->factory = $factory; } public function given(Domain\Event ...$events): Scenario\When @@ -96,6 +90,7 @@ public function assert(callable $constraint = null): void $previousState = null; if ($listener instanceof Event\Listener\Stateful) { + /** @var Event\Listener&Event\Listener\Stateful $listener */ $this->replaying = true; foreach ($this->given as $event) { $listener->on($event); @@ -110,10 +105,11 @@ public function assert(callable $constraint = null): void $previousState = $currentState; $previousListener = $listener; - $listener = $this->factory->create($previousListener->listenerId()); + /** @var Event\Listener&Event\Listener\Stateful $listener */ + $listener = $this->factory->create($previousListener->id()); $listener->fromState($currentState); - Assert::assertEquals($previousListener, $listener, sprintf('Listener "%s" that listened to %s" and generated incomplete state. Please review your Listener\Stateful::toState() and Listener\Stateful::fromState() methods.', \get_class($listener), \get_class($event))); + Assert::assertEquals($previousListener, $listener, sprintf('Listener "%s" that listened to %s" and generated incomplete state. Please review your Listener\Stateful::toState() and Listener\Stateful::fromState() methods.', $listener::class, $event::class)); } $this->replaying = false; } @@ -128,7 +124,7 @@ public function assert(callable $constraint = null): void $stream = $listener->filter($stream); $stream = iterator_to_array($stream); - Assert::assertEquals([$this->when], $stream, sprintf('Listener is not listening to %s event.', \get_class($this->when))); + Assert::assertEquals([$this->when], $stream, sprintf('Listener is not listening to %s event.', $this->when::class)); } Assert::assertNotEmpty($this->expectedCommands, 'At least one then() clause is required.'); @@ -137,7 +133,7 @@ public function assert(callable $constraint = null): void $listener->on($this->when); if (!$listener instanceof Event\Listener\Stateful) { - Assert::assertEquals($listener, $new, sprintf('State introduced when listener "%s" listened to "%s" event, but listener is not implementing "%s" interface.', \get_class($listener), \get_class($this->when), Event\Listener\Stateful::class)); + Assert::assertEquals($listener, $new, sprintf('State introduced when listener "%s" listened to "%s" event, but listener is not implementing "%s" interface.', $listener::class, $this->when::class, Event\Listener\Stateful::class)); } Assert::assertEquals($this->expectedCommands, $this->actualCommands, 'Expected commands do not match actual commands dispatched by the listener.'); diff --git a/src/Infrastructure/Domain/Testing/Listener/TestCase.php b/src/Infrastructure/Domain/Testing/Listener/TestCase.php index 903298ac..a227596e 100644 --- a/src/Infrastructure/Domain/Testing/Listener/TestCase.php +++ b/src/Infrastructure/Domain/Testing/Listener/TestCase.php @@ -38,7 +38,7 @@ public function given(Domain\Event ...$events): Scenario\When abstract public function createFactory(Application\CommandBus $bus): Domain\Event\Listener\Factory; - private function createScenario(Application\CommandBus $bus, Domain\Event\Listener\Factory $factory): Listener\Scenario + private function createScenario(SynchronousCommandBus $bus, Domain\Event\Listener\Factory $factory): Listener\Scenario { return new Listener\Scenario($bus, $factory); } diff --git a/src/Infrastructure/Domain/UnitOfWork.php b/src/Infrastructure/Domain/UnitOfWork.php index 9b32cdd0..89e28a3d 100644 --- a/src/Infrastructure/Domain/UnitOfWork.php +++ b/src/Infrastructure/Domain/UnitOfWork.php @@ -17,27 +17,37 @@ /** * @author Alan Gabriel Bem + * + * @template T of object */ interface UnitOfWork { /** + * @param T $object + * * @throws Exception\ObjectNotSupported */ public function add(object $object): void; + /** + * @param T $object + */ public function remove(object $object): void; + /** + * @param T $object + */ public function has(object $object): bool; /** - * @return object[] + * @return array */ public function uncommitted(): array; public function count(): int; /** - * @return \Generator|object[] + * @return \Generator */ public function commit(): \Generator; diff --git a/src/Infrastructure/Domain/UnitOfWork/CompositeUnitOfWork.php b/src/Infrastructure/Domain/UnitOfWork/CompositeUnitOfWork.php index 2b30b20a..83141317 100644 --- a/src/Infrastructure/Domain/UnitOfWork/CompositeUnitOfWork.php +++ b/src/Infrastructure/Domain/UnitOfWork/CompositeUnitOfWork.php @@ -18,14 +18,13 @@ /** * @author Alan Gabriel Bem * + * @template-implements UnitOfWork + * * @see \Streak\Infrastructure\Domain\UnitOfWork\CompositeUnitOfWorkTest */ class CompositeUnitOfWork implements UnitOfWork { - /** - * @var UnitOfWork[] - */ - private array $uows = []; + private array $uows; public function __construct(UnitOfWork ...$uows) { diff --git a/src/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWork.php b/src/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWork.php index 4e3579df..a954289b 100644 --- a/src/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWork.php +++ b/src/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWork.php @@ -23,6 +23,8 @@ * * @TODO: rename to EventSourcedUnitOfWork * + * @template-implements UnitOfWork + * * @see \Streak\Infrastructure\Domain\UnitOfWork\EventStoreUnitOfWorkTest */ class EventStoreUnitOfWork implements UnitOfWork @@ -38,26 +40,26 @@ public function __construct(private Domain\EventStore $store) { } - public function add(object $producer): void + public function add(object $object): void { - if (!$producer instanceof Event\Producer) { - throw new Exception\ObjectNotSupported($producer); + if (!$object instanceof Event\Producer) { + throw new Exception\ObjectNotSupported($object); } - if (!$this->has($producer)) { - $this->uncommited[] = $producer; + if (!$this->has($object)) { + $this->uncommited[] = $object; } } - public function remove(object $producer): void + public function remove(object $object): void { - if (!$producer instanceof Event\Producer) { + if (!$object instanceof Event\Producer) { return; } foreach ($this->uncommited as $key => $current) { // @var $current Event\Producer - if ($current->producerId()->equals($producer->producerId())) { + if ($current->id()->equals($object->id())) { unset($this->uncommited[$key]); return; @@ -65,15 +67,15 @@ public function remove(object $producer): void } } - public function has(object $producer): bool + public function has(object $object): bool { - if (!$producer instanceof Event\Producer) { + if (!$object instanceof Event\Producer) { return false; } foreach ($this->uncommited as $current) { // @var $current Event\Producer - if ($current->producerId()->equals($producer->producerId())) { + if ($current->id()->equals($object->id())) { return true; } } @@ -104,22 +106,22 @@ public function commit(): \Generator $this->committing = true; try { - /** @var Event\Producer $producer */ - while ($producer = array_shift($this->uncommited)) { + while ($object = array_shift($this->uncommited)) { + /** @var Event\Producer $object */ try { - $this->store->add(...$producer->events()); // maybe gather all events and send them in one single EventStore:add() call? + $this->store->add(...$object->events()); // maybe gather all events and send them in one single EventStore:add() call? - if ($producer instanceof Domain\Versionable) { - $producer->commit(); + if ($object instanceof Domain\Versionable) { + $object->commit(); } - yield $producer; + yield $object; } catch (ConcurrentWriteDetected $e) { // version must be wrong so nothing good if we retry it later on... throw $e; } catch (\Exception $e) { // something unexpected occurred, so lets leave uow in state from just before it happened - we may like to retry it later... - array_unshift($this->uncommited, $producer); + array_unshift($this->uncommited, $object); throw $e; } diff --git a/src/Infrastructure/Domain/UnitOfWork/SnapshottingUnitOfWork.php b/src/Infrastructure/Domain/UnitOfWork/SnapshottingUnitOfWork.php index 7dd2185d..47e481d4 100644 --- a/src/Infrastructure/Domain/UnitOfWork/SnapshottingUnitOfWork.php +++ b/src/Infrastructure/Domain/UnitOfWork/SnapshottingUnitOfWork.php @@ -21,6 +21,8 @@ /** * @author Alan Gabriel Bem * + * @template-implements UnitOfWork + * * @see \Streak\Infrastructure\Domain\UnitOfWork\SnapshottingUnitOfWorkTest */ class SnapshottingUnitOfWork implements UnitOfWork @@ -38,30 +40,30 @@ public function __construct(private UnitOfWork $uow, private Snapshotter $snapsh $this->interval = $interval; } - public function add(object $producer): void + public function add(object $object): void { - $this->uow->add($producer); + $this->uow->add($object); - if ($producer instanceof Event\Sourced\AggregateRoot) { - $id = $producer->producerId(); - $version = $producer->version(); + if ($object instanceof Event\Sourced\AggregateRoot) { + $id = $object->id(); + $version = $object->version(); $this->versions->attach($id, $version); } } - public function remove(object $producer): void + public function remove(object $object): void { - if ($producer instanceof Event\Sourced\AggregateRoot) { - $id = $producer->producerId(); + if ($object instanceof Event\Sourced\AggregateRoot) { + $id = $object->id(); $this->versions->offsetUnset($id); } - $this->uow->remove($producer); + $this->uow->remove($object); } - public function has(object $producer): bool + public function has(object $object): bool { - return $this->uow->has($producer); + return $this->uow->has($object); } /** @@ -90,10 +92,10 @@ public function commit(): \Generator continue; } - $versionBeforeCommit = $this->versions->offsetGet($committed->producerId()); + $versionBeforeCommit = $this->versions->offsetGet($committed->id()); $versionAfterCommit = $committed->version(); - $this->versions->offsetUnset($committed->producerId()); + $this->versions->offsetUnset($committed->id()); if (!$this->isReadyForSnapshot($versionBeforeCommit, $versionAfterCommit)) { yield $committed; diff --git a/src/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWork.php b/src/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWork.php index 8606b746..69f2b0ae 100644 --- a/src/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWork.php +++ b/src/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWork.php @@ -20,12 +20,14 @@ /** * @author Alan Gabriel Bem * + * @template-implements UnitOfWork + * * @see \Streak\Infrastructure\Domain\UnitOfWork\SubscriptionDAOUnitOfWorkTest */ class SubscriptionDAOUnitOfWork implements UnitOfWork { /** - * @var Subscription[] + * @var DAO\Subscription[] */ private array $uncommited = []; @@ -35,25 +37,25 @@ public function __construct(private DAO $dao) { } - public function add(object $subscription): void + public function add(object $object): void { - if (false === $this->supports($subscription)) { - throw new UnitOfWork\Exception\ObjectNotSupported($subscription); + if (false === $this->supports($object)) { + throw new UnitOfWork\Exception\ObjectNotSupported($object); } - if (!$this->has($subscription)) { - $this->uncommited[] = $subscription; + if (!$this->has($object)) { + $this->uncommited[] = $object; } } - public function remove(object $subscription): void + public function remove(object $object): void { - if (false === $this->supports($subscription)) { - throw new UnitOfWork\Exception\ObjectNotSupported($subscription); + if (false === $this->supports($object)) { + throw new UnitOfWork\Exception\ObjectNotSupported($object); } foreach ($this->uncommited as $key => $current) { - if ($current->subscriptionId()->equals($subscription->subscriptionId())) { + if ($current->id()->equals($object->id())) { unset($this->uncommited[$key]); return; @@ -61,14 +63,14 @@ public function remove(object $subscription): void } } - public function has(object $subscription): bool + public function has(object $object): bool { - if (false === $this->supports($subscription)) { - throw new UnitOfWork\Exception\ObjectNotSupported($subscription); + if (false === $this->supports($object)) { + throw new UnitOfWork\Exception\ObjectNotSupported($object); } foreach ($this->uncommited as $current) { - if ($current->subscriptionId()->equals($subscription->subscriptionId())) { + if ($current->id()->equals($object->id())) { return true; } } @@ -95,15 +97,15 @@ public function commit(): \Generator $this->committing = true; try { - /** @var Subscription $subscription */ - while ($subscription = array_shift($this->uncommited)) { + while ($object = array_shift($this->uncommited)) { + /** @var DAO\Subscription $object */ try { - $this->dao->save($subscription); + $this->dao->save($object); - yield $subscription; + yield $object; } catch (\Exception $e) { // something unexpected occurred, so lets leave uow in state from just before it happened - we may like to retry it later... - array_unshift($this->uncommited, $subscription); + array_unshift($this->uncommited, $object); throw $e; } @@ -123,16 +125,12 @@ public function clear(): void private function supports(object $subscription): bool { - if ($subscription instanceof DAO\Subscription) { - return true; - } - while ($subscription instanceof Subscription\Decorator) { $subscription = $subscription->subscription(); + } - if ($subscription instanceof DAO\Subscription) { - return true; - } + if ($subscription instanceof DAO\Subscription) { + return true; } return false; diff --git a/src/Infrastructure/Interfaces/RabbitMQ/CommittingSensorConsumer.php b/src/Infrastructure/Interfaces/RabbitMQ/CommittingSensorConsumer.php index 4a2a61db..e9188348 100644 --- a/src/Infrastructure/Interfaces/RabbitMQ/CommittingSensorConsumer.php +++ b/src/Infrastructure/Interfaces/RabbitMQ/CommittingSensorConsumer.php @@ -28,12 +28,12 @@ public function __construct(private ConsumerInterface $consumer, private UnitOfW { } - public function execute(AMQPMessage $message) + public function execute(AMQPMessage $msg) { $this->uow->clear(); try { - $result = $this->consumer->execute($message); + $result = $this->consumer->execute($msg); if (false !== $result) { iterator_to_array($this->uow->commit()); diff --git a/src/Infrastructure/Interfaces/RabbitMQ/SensorConsumer.php b/src/Infrastructure/Interfaces/RabbitMQ/SensorConsumer.php index 4ed501a6..73d7e59d 100644 --- a/src/Infrastructure/Interfaces/RabbitMQ/SensorConsumer.php +++ b/src/Infrastructure/Interfaces/RabbitMQ/SensorConsumer.php @@ -31,18 +31,18 @@ public function __construct(private Sensor\Factory $factory) { } - public function execute(AMQPMessage $message) + public function execute(AMQPMessage $msg) { - $original = $message->getBody(); - $message = json_decode($original, true); + $original = $msg->getBody(); + $msg = json_decode($original, true); if (\JSON_ERROR_NONE !== json_last_error()) { - $message = $original; + $msg = $original; } try { $sensor = $this->factory->create(); - $sensor->process($message); + $sensor->process($msg); } catch (\Exception) { return self::NACK; } diff --git a/tests/Application/CommandHandler/AggregateRootHandlerTest.php b/tests/Application/CommandHandler/AggregateRootHandlerTest.php index de7b8af6..68f72214 100644 --- a/tests/Application/CommandHandler/AggregateRootHandlerTest.php +++ b/tests/Application/CommandHandler/AggregateRootHandlerTest.php @@ -13,6 +13,7 @@ namespace Streak\Application\CommandHandler; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; use Streak\Domain\Command; @@ -27,12 +28,12 @@ */ class AggregateRootHandlerTest extends TestCase { - private AggregateRoot\Repository $repository; - private Command $command; - private AggregateRoot $aggregateRoot; - private AggregateRoot\Id $aggregateRootId; - private Command\AggregateRootCommand $aggregateRootCommand; - private CommandHandlingAggregateRoot $aggregateRootCommandHandler; + private AggregateRoot\Repository|MockObject $repository; + private Command|MockObject $command; + private AggregateRoot|MockObject $aggregateRoot; + private AggregateRoot\Id|MockObject $aggregateRootId; + private Command\AggregateRootCommand|MockObject $aggregateRootCommand; + private CommandHandlingAggregateRoot|MockObject $aggregateRootCommandHandler; protected function setUp(): void { diff --git a/tests/Application/QueryHandler/EventListenerHandlerTest.php b/tests/Application/QueryHandler/EventListenerHandlerTest.php index 3a76429d..60f4e6c1 100644 --- a/tests/Application/QueryHandler/EventListenerHandlerTest.php +++ b/tests/Application/QueryHandler/EventListenerHandlerTest.php @@ -13,6 +13,7 @@ namespace Streak\Application\QueryHandler; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\QueryHandler\EventListenerHandlerTest\QueryHandlingListener; use Streak\Domain\Event; @@ -28,19 +29,13 @@ */ class EventListenerHandlerTest extends TestCase { - private Repository $repository; - - private Query $query; - - private Event\Subscription $subscription; - - private Event\Listener $eventListener; - - private QueryHandlingListener $eventListenerQueryHandler; - - private Query\EventListenerQuery $eventListenerQuery; - - private Event\Listener\Id $eventListenerId; + private Repository|MockObject $repository; + private Query|MockObject $query; + private Event\Subscription|MockObject $subscription; + private Event\Listener|MockObject $eventListener; + private QueryHandlingListener|MockObject $eventListenerQueryHandler; + private Query\EventListenerQuery|MockObject $eventListenerQuery; + private Event\Listener\Id|MockObject $eventListenerId; protected function setUp(): void { diff --git a/tests/Application/Sensor/IdentificationTest.php b/tests/Application/Sensor/IdentificationTest.php index ec8c7f2f..d7ce3d21 100644 --- a/tests/Application/Sensor/IdentificationTest.php +++ b/tests/Application/Sensor/IdentificationTest.php @@ -13,6 +13,7 @@ namespace Streak\Application\Sensor; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\Sensor; @@ -23,7 +24,7 @@ */ class IdentificationTest extends TestCase { - private Sensor\Id $id; + private Sensor\Id|MockObject $id; protected function setUp(): void { @@ -32,10 +33,16 @@ protected function setUp(): void public function testObject(): void { - $identification = $this->getMockBuilder(Identification::class)->setConstructorArgs([$this->id])->getMockForTrait(); - - self::assertSame($this->id, $identification->sensorId()); - self::assertSame($this->id, $identification->producerId()); - self::assertSame($this->id, $identification->id()); + $stub = new Sensor\IdentificationTest\IdentifyingStub($this->id); + self::assertSame($this->id, $stub->id()); } } + +namespace Streak\Application\Sensor\IdentificationTest; + +use Streak\Application\Sensor; + +class IdentifyingStub +{ + use Sensor\Identification; +} diff --git a/tests/Application/Sensor/ProcessingTest.php b/tests/Application/Sensor/ProcessingTest.php index d088a8fd..022033a3 100644 --- a/tests/Application/Sensor/ProcessingTest.php +++ b/tests/Application/Sensor/ProcessingTest.php @@ -13,6 +13,7 @@ namespace Streak\Application\Sensor; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\Sensor; use Streak\Application\Sensor\ProcessingTest\AProcessed; @@ -35,7 +36,7 @@ */ class ProcessingTest extends TestCase { - private Sensor\Id $id; + private Sensor\Id|MockObject $id; protected function setUp(): void { @@ -47,8 +48,6 @@ public function testObject(): void $sensor = new SensorStub1($this->id); self::assertSame($this->id, $sensor->id()); - self::assertSame($this->id, $sensor->producerId()); - self::assertSame($this->id, $sensor->sensorId()); self::assertNull($sensor->last()); self::assertEmpty($sensor->events()); @@ -123,6 +122,16 @@ public function testTransactionalityOfProcessMethod(): void // no new assertions here please } + + public function testNoMethodFound(): void + { + $sensor = new SensorStub2($this->id); + + $this->expectExceptionObject(new \InvalidArgumentException('No method found to process message.')); + + $stdClass = new \stdClass(); + $sensor->process($stdClass); + } } namespace Streak\Application\Sensor\ProcessingTest; @@ -188,12 +197,12 @@ public function processB1(B1 $b1, $notNeededSecondArgument): void public function processOptionalB2(?B2 $optionalB1): void { - $this->addEvent(new B1Processed($optionalB1)); + $this->addEvent(new B2Processed($optionalB1)); } public function processNullableB2(B2 $nullableB1 = null): void { - $this->addEvent(new B1Processed($nullableB1)); + $this->addEvent(new B2Processed($nullableB1)); } public function processA(A $a): void @@ -219,51 +228,36 @@ public function processStringAndThrowAnException(string $string): void class ArrayProcessed implements Event { - private array $array; - - public function __construct(array $array) + public function __construct(private array $array) { - $this->array = $array; } } class IntegerProcessed implements Event { - private int $integer; - - public function __construct(int $array) + public function __construct(private int $integer) { - $this->integer = $array; } } class StringProcessed implements Event { - private string $string; - - public function __construct(string $string) + public function __construct(private string $string) { - $this->string = $string; } } class StdClassProcessed implements Event { - private \stdClass $stdClass; - - public function __construct(\stdClass $stdClass) + public function __construct(private \stdClass $stdClass) { - $this->stdClass = $stdClass; } } class BooleanProcessed implements Event { - private bool $boolean; - - public function __construct(bool $boolean) + public function __construct(private bool $boolean) { - $this->boolean = $boolean; } } @@ -281,30 +275,21 @@ class B2 extends A class AProcessed implements Event { - private A $a; - - public function __construct(A $a) + public function __construct(private A $a) { - $this->a = $a; } } class B2Processed implements Event { - private B2 $b2; - - public function __construct(B2 $b2) + public function __construct(private B2 $b2) { - $this->b2 = $b2; } } class B1Processed implements Event { - private B1 $b1; - - public function __construct(B1 $b1) + public function __construct(private B1 $b1) { - $this->b1 = $b1; } } diff --git a/tests/Domain/Aggregate/ComparisonTest.php b/tests/Domain/Aggregate/ComparisonTest.php index 6fb44237..79d6ed01 100644 --- a/tests/Domain/Aggregate/ComparisonTest.php +++ b/tests/Domain/Aggregate/ComparisonTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Aggregate; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; use Streak\Domain\Aggregate; @@ -24,9 +25,9 @@ */ class ComparisonTest extends TestCase { - private Aggregate\Id $id1; - private Aggregate\Id $id2; - private Aggregate\Id $id3; + private Aggregate\Id|MockObject $id1; + private Aggregate\Id|MockObject $id2; + private Aggregate\Id|MockObject $id3; protected function setUp(): void { @@ -81,30 +82,16 @@ public function testObject(): void use Streak\Domain; use Streak\Domain\Aggregate; -use Streak\Domain\Entity; class ComparisonStub implements Domain\Aggregate { use Aggregate\Comparison; - private Aggregate\Id $id; - - public function __construct(Aggregate\Id $id) - { - $this->id = $id; - } - - public function aggregateId(): Aggregate\Id - { - return $this->id; - } - - public function entityId(): Entity\Id + public function __construct(private Aggregate\Id $id) { - return $this->id; } - public function id(): Domain\Id + public function id(): Aggregate\Id { return $this->id; } @@ -114,19 +101,11 @@ class NonAggregateComparisonStub { use Aggregate\Comparison; - private Aggregate\Id $id; - - public function __construct(Aggregate\Id $id) + public function __construct(private Aggregate\Id $id) { - $this->id = $id; - } - - public function aggregateId(): Aggregate\Id - { - return $this->id; } - public function entityId(): Entity\Id + public function id(): Aggregate\Id { return $this->id; } diff --git a/tests/Domain/Aggregate/IdentificationTest.php b/tests/Domain/Aggregate/IdentificationTest.php index cc666325..18cc5269 100644 --- a/tests/Domain/Aggregate/IdentificationTest.php +++ b/tests/Domain/Aggregate/IdentificationTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Aggregate; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Aggregate; @@ -23,7 +24,7 @@ */ class IdentificationTest extends TestCase { - private Aggregate\Id $id; + private Aggregate\Id|MockObject $id; protected function setUp(): void { @@ -32,10 +33,16 @@ protected function setUp(): void public function testObject(): void { - $identification = $this->getMockBuilder(Identification::class)->setConstructorArgs([$this->id])->getMockForTrait(); - - self::assertSame($this->id, $identification->aggregateId()); - self::assertSame($this->id, $identification->entityId()); - self::assertSame($this->id, $identification->id()); + $stub = new Aggregate\IdentificationTest\IdentifyingStub($this->id); + self::assertSame($this->id, $stub->id()); } } + +namespace Streak\Domain\Aggregate\IdentificationTest; + +use Streak\Domain\Aggregate; + +class IdentifyingStub +{ + use Aggregate\Identification; +} diff --git a/tests/Domain/AggregateRoot/ComparisonTest.php b/tests/Domain/AggregateRoot/ComparisonTest.php index a10127a4..264efab1 100644 --- a/tests/Domain/AggregateRoot/ComparisonTest.php +++ b/tests/Domain/AggregateRoot/ComparisonTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\AggregateRoot; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; use Streak\Domain\AggregateRoot; @@ -24,9 +25,9 @@ */ class ComparisonTest extends TestCase { - private AggregateRoot\Id $id1; - private AggregateRoot\Id $id2; - private AggregateRoot\Id $id3; + private AggregateRoot\Id|MockObject $id1; + private AggregateRoot\Id|MockObject $id2; + private AggregateRoot\Id|MockObject $id3; protected function setUp(): void { @@ -80,37 +81,17 @@ public function testObject(): void namespace Streak\Domain\AggregateRoot\ComparisonTest; use Streak\Domain; -use Streak\Domain\Aggregate; use Streak\Domain\AggregateRoot; -use Streak\Domain\Entity; class ComparisonStub implements Domain\AggregateRoot { use AggregateRoot\Comparison; - private AggregateRoot\Id $id; - - public function __construct(AggregateRoot\Id $id) - { - $this->id = $id; - } - - public function aggregateRootId(): AggregateRoot\Id - { - return $this->id; - } - - public function aggregateId(): Aggregate\Id - { - return $this->id; - } - - public function entityId(): Entity\Id + public function __construct(private AggregateRoot\Id $id) { - return $this->id; } - public function id(): Domain\Id + public function id(): AggregateRoot\Id { return $this->id; } @@ -120,24 +101,11 @@ class NonAggregateRootComparisonStub { use AggregateRoot\Comparison; - private AggregateRoot\Id $id; - - public function __construct(AggregateRoot\Id $id) - { - $this->id = $id; - } - - public function aggregateRootId(): AggregateRoot\Id + public function __construct(private AggregateRoot\Id $id) { - return $this->id; - } - - public function aggregateId(): Aggregate\Id - { - return $this->id; } - public function entityId(): Entity\Id + public function id(): AggregateRoot\Id { return $this->id; } diff --git a/tests/Domain/AggregateRoot/IdentificationTest.php b/tests/Domain/AggregateRoot/IdentificationTest.php index 59bbcc56..770b4c55 100644 --- a/tests/Domain/AggregateRoot/IdentificationTest.php +++ b/tests/Domain/AggregateRoot/IdentificationTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\AggregateRoot; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; @@ -23,7 +24,7 @@ */ class IdentificationTest extends TestCase { - private AggregateRoot\Id $id; + private AggregateRoot\Id|MockObject $id; protected function setUp(): void { @@ -32,11 +33,16 @@ protected function setUp(): void public function testObject(): void { - $identification = $this->getMockBuilder(Identification::class)->setConstructorArgs([$this->id])->getMockForTrait(); - - self::assertSame($this->id, $identification->aggregateRootId()); - self::assertSame($this->id, $identification->aggregateId()); - self::assertSame($this->id, $identification->entityId()); - self::assertSame($this->id, $identification->id()); + $stub = new AggregateRoot\IdentificationTest\IdentifyingStub($this->id); + self::assertSame($this->id, $stub->id()); } } + +namespace Streak\Domain\AggregateRoot\IdentificationTest; + +use Streak\Domain\AggregateRoot; + +class IdentifyingStub +{ + use AggregateRoot\Identification; +} diff --git a/tests/Domain/Command/HandlingTest.php b/tests/Domain/Command/HandlingTest.php index aad18d21..6a0fa0e0 100644 --- a/tests/Domain/Command/HandlingTest.php +++ b/tests/Domain/Command/HandlingTest.php @@ -132,11 +132,15 @@ public function handleUnionParameter(SupportedCommand1|SupportedCommand2 $comman public function handleNonVoidReturnType(SupportedCommand1 $command1): \ArrayAccess { $this->handled[] = __METHOD__; + + return new \ArrayObject(); } public function handleUnionReturnType(SupportedCommand1 $command1): \ArrayAccess|\stdClass { $this->handled[] = __METHOD__; + + return new \ArrayObject(); } public function handled(): array diff --git a/tests/Domain/Entity/ComparisonTest.php b/tests/Domain/Entity/ComparisonTest.php index 64a86551..d9c0d8ce 100644 --- a/tests/Domain/Entity/ComparisonTest.php +++ b/tests/Domain/Entity/ComparisonTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Entity; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; use Streak\Domain\Entity; @@ -24,9 +25,9 @@ */ class ComparisonTest extends TestCase { - private Entity\Id $id1; - private Entity\Id $id2; - private Entity\Id $id3; + private Entity\Id|MockObject $id1; + private Entity\Id|MockObject $id2; + private Entity\Id|MockObject $id3; protected function setUp(): void { @@ -86,19 +87,11 @@ class ComparisonStub implements Domain\Entity { use Entity\Comparison; - private Entity\Id $id; - - public function __construct(Entity\Id $id) - { - $this->id = $id; - } - - public function entityId(): Entity\Id + public function __construct(private Entity\Id $id) { - return $this->id; } - public function id(): Domain\Id + public function id(): Entity\Id { return $this->id; } @@ -108,14 +101,11 @@ class NonEntityComparisonStub { use Entity\Comparison; - private Entity\Id $id; - - public function __construct(Entity\Id $id) + public function __construct(private Entity\Id $id) { - $this->id = $id; } - public function entityId(): Entity\Id + public function id(): Entity\Id { return $this->id; } diff --git a/tests/Domain/Entity/IdentificationTest.php b/tests/Domain/Entity/IdentificationTest.php index 434257a6..08837b07 100644 --- a/tests/Domain/Entity/IdentificationTest.php +++ b/tests/Domain/Entity/IdentificationTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Entity; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Entity; @@ -23,7 +24,7 @@ */ class IdentificationTest extends TestCase { - private Entity\Id $id; + private Entity\Id|MockObject $id; protected function setUp(): void { @@ -32,9 +33,16 @@ protected function setUp(): void public function testObject(): void { - $identification = $this->getMockBuilder(Identification::class)->setConstructorArgs([$this->id])->getMockForTrait(); - - self::assertSame($this->id, $identification->entityId()); - self::assertSame($this->id, $identification->id()); + $stub = new Entity\IdentificationTest\IdentifyingStub($this->id); + self::assertSame($this->id, $stub->id()); } } + +namespace Streak\Domain\Entity\IdentificationTest; + +use Streak\Domain\Entity; + +class IdentifyingStub +{ + use Entity\Identification; +} diff --git a/tests/Domain/Event/EnvelopeTest.php b/tests/Domain/Event/EnvelopeTest.php index a9906358..2a938761 100644 --- a/tests/Domain/Event/EnvelopeTest.php +++ b/tests/Domain/Event/EnvelopeTest.php @@ -13,7 +13,9 @@ namespace Streak\Domain\Event; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Streak\Domain\Entity; use Streak\Domain\Event; use Streak\Domain\Id\UUID; @@ -24,11 +26,16 @@ */ class EnvelopeTest extends TestCase { - private Event $event1; + private Event|MockObject $event1; + private Event|MockObject $event2; + private Entity\Id $entityId1; protected function setUp(): void { $this->event1 = $this->getMockBuilder(Event::class)->setMockClassName('dushf9fguiewhfh')->getMockForAbstractClass(); + $this->event2 = $this->getMockBuilder(Event::class)->setMockClassName('y7rb7wfe77fcw7e')->getMockForAbstractClass(); + $this->entityId1 = Event\EnvelopeTest\EntityId::random(); + $this->entityId1 = Event\EnvelopeTest\EntityId::random(); } public function testEnvelope(): void @@ -48,7 +55,7 @@ public function testEnvelope(): void self::assertSame($this->event1, $envelope1a->message()); self::assertSame(\PHP_INT_MAX, $envelope1a->version()); self::assertSame(\PHP_INT_MAX, $envelope1a->get($envelope1a::METADATA_VERSION)); - self::assertSame(['uuid' => $envelope1a->uuid()->toString(), 'name' => $envelope1a->name(), 'producer_type' => 'Streak\Domain\Id\UUID', 'producer_id' => $envelope1a->producerId()->toString(), 'version' => $envelope1a->version()], $envelope1a->metadata()); + self::assertSame(['uuid' => $envelope1a->uuid()->toString(), 'name' => $envelope1a->name(), 'producer_type' => 'Streak\Domain\Id\UUID', 'producer_id' => $envelope1a->producerId()->toString(), 'entity_type' => 'Streak\Domain\Id\UUID', 'entity_id' => $envelope1a->producerId()->toString(), 'version' => $envelope1a->version()], $envelope1a->metadata()); self::assertNull($envelope1a->get('attr-1')); $envelope1b = $envelope1a->set('attr-1', 'value-1'); @@ -56,19 +63,19 @@ public function testEnvelope(): void self::assertNotSame($envelope1a, $envelope1b); self::assertNull($envelope1a->get('attr-1')); - self::assertSame(['uuid' => $envelope1a->uuid()->toString(), 'name' => $envelope1a->name(), 'producer_type' => 'Streak\Domain\Id\UUID', 'producer_id' => $envelope1a->producerId()->toString(), 'version' => $envelope1a->version(), 'attr-1' => 'value-1'], $envelope1b->metadata()); + self::assertSame(['uuid' => $envelope1a->uuid()->toString(), 'name' => $envelope1a->name(), 'producer_type' => 'Streak\Domain\Id\UUID', 'producer_id' => $envelope1a->producerId()->toString(), 'entity_type' => 'Streak\Domain\Id\UUID', 'entity_id' => $envelope1a->producerId()->toString(), 'version' => $envelope1a->version(), 'attr-1' => 'value-1'], $envelope1b->metadata()); self::assertSame('value-1', $envelope1b->get('attr-1')); - $envelope2a = new Event\Envelope($uuid, 'dushf9fguiewhfh', $this->event1, $producerId, \PHP_INT_MAX); - $envelope2b = new Event\Envelope($uuid, 'dushf9fguiewhfh', $this->event1, $producerId, \PHP_INT_MAX); + $envelope2a = new Event\Envelope($uuid, 'dushf9fguiewhfh', $this->event1, $producerId, $producerId, \PHP_INT_MAX); + $envelope2b = new Event\Envelope($uuid, 'dushf9fguiewhfh', $this->event1, $producerId, $producerId, \PHP_INT_MAX); self::assertInstanceOf(Envelope::class, $envelope2a); - self::assertTrue($envelope2a->uuid()->equals($uuid)); + self::assertEquals($envelope2a->uuid(), $uuid); self::assertSame('dushf9fguiewhfh', $envelope2a->name()); - self::assertTrue($envelope2a->producerId()->equals($producerId)); + self::assertEquals($envelope2a->producerId(), $producerId); self::assertSame($this->event1, $envelope2a->message()); self::assertSame(\PHP_INT_MAX, $envelope2a->version()); - self::assertSame(['uuid' => $envelope2a->uuid()->toString(), 'name' => $envelope2a->name(), 'producer_type' => 'Streak\Domain\Id\UUID', 'producer_id' => $envelope2a->producerId()->toString(), 'version' => $envelope2a->version()], $envelope2a->metadata()); + self::assertSame(['uuid' => $envelope2a->uuid()->toString(), 'name' => $envelope2a->name(), 'producer_type' => 'Streak\Domain\Id\UUID', 'producer_id' => $envelope2a->producerId()->toString(), 'entity_type' => 'Streak\Domain\Id\UUID', 'entity_id' => $envelope2a->producerId()->toString(), 'version' => $envelope2a->version()], $envelope2a->metadata()); self::assertTrue($envelope1a->equals($envelope1a)); self::assertTrue($envelope2a->equals($envelope2a)); @@ -77,6 +84,38 @@ public function testEnvelope(): void self::assertTrue($envelope2a->equals($envelope2b)); self::assertFalse($envelope1a->equals(new \stdClass())); + + $envelope3 = Event\Envelope::new($this->event2, $producerId); + $envelope3 = $envelope3->defineEntityId($this->entityId1); + + self::assertNull($envelope3->version()); + self::assertSame('y7rb7wfe77fcw7e', $envelope3->name()); + self::assertEquals($envelope3->producerId(), $producerId); + self::assertEquals($envelope3->entityId(), $this->entityId1); + + $envelope4 = $envelope3->defineVersion(1); + + self::assertTrue($envelope3->equals($envelope4)); + self::assertTrue($envelope4->equals($envelope3)); + + self::assertSame(1, $envelope4->version()); + self::assertSame('y7rb7wfe77fcw7e', $envelope4->name()); + self::assertTrue($envelope4->producerId()->equals($producerId)); + self::assertTrue($envelope4->entityId()->equals($this->entityId1)); + + $envelope5 = $envelope4->defineVersion(2); + + self::assertSame(2, $envelope5->version()); + self::assertSame('y7rb7wfe77fcw7e', $envelope5->name()); + self::assertTrue($envelope5->producerId()->equals($producerId)); + self::assertTrue($envelope5->entityId()->equals($this->entityId1)); + + $envelope6 = $envelope5->defineEntityId($this->entityId1); + + self::assertSame(2, $envelope6->version()); + self::assertSame('y7rb7wfe77fcw7e', $envelope6->name()); + self::assertTrue($envelope6->producerId()->equals($producerId)); + self::assertTrue($envelope6->entityId()->equals($this->entityId1)); } public function testSettingEmptyAttributeName(): void @@ -88,27 +127,13 @@ public function testSettingEmptyAttributeName(): void $envelope->set('', 'value-1'); } +} - public function nonScalarValues() - { - return [ - [[]], - [new \stdClass()], - ]; - } - - /** - * @dataProvider nonScalarValues - * - * @param mixed $value - */ - public function testSettingNonScalarAttribute($value): void - { - $envelope = Event\Envelope::new($this->event1, UUID::random(), \PHP_INT_MAX); +namespace Streak\Domain\Event\EnvelopeTest; - $exception = new \InvalidArgumentException('Value for attribute "attr-1" is a scalar.'); - $this->expectExceptionObject($exception); +use Streak\Domain\Entity; +use Streak\Domain\Id\UUID; - $envelope->set('attr-1', $value); - } +class EntityId extends UUID implements Entity\Id +{ } diff --git a/tests/Domain/Event/Exception/AggregateAlreadyRegisteredTest.php b/tests/Domain/Event/Exception/AggregateAlreadyRegisteredTest.php index 8f787d78..ca1679ac 100644 --- a/tests/Domain/Event/Exception/AggregateAlreadyRegisteredTest.php +++ b/tests/Domain/Event/Exception/AggregateAlreadyRegisteredTest.php @@ -34,7 +34,7 @@ public function testException(): void { $exception = new AggregateAlreadyRegistered($this->aggregate); - self::assertEquals('Aggregate already registered.', $exception->getMessage()); + self::assertSame('Aggregate already registered.', $exception->getMessage()); self::assertSame($this->aggregate, $exception->aggregate()); } } diff --git a/tests/Domain/Event/Exception/EventNotSupportedTest.php b/tests/Domain/Event/Exception/EventNotSupportedTest.php index fc5abaf0..5d65ad12 100644 --- a/tests/Domain/Event/Exception/EventNotSupportedTest.php +++ b/tests/Domain/Event/Exception/EventNotSupportedTest.php @@ -30,7 +30,7 @@ class EventNotSupportedTest extends TestCase protected function setUp(): void { $producerId = $this->getMockBuilder(Domain\Id::class)->getMockForAbstractClass(); - $this->event = new Event\Envelope(UUID::random(), 'event', $this->getMockBuilder(Event::class)->getMockForAbstractClass(), $producerId, null); + $this->event = new Event\Envelope(UUID::random(), 'event', $this->getMockBuilder(Event::class)->getMockForAbstractClass(), $producerId, $producerId, null); } public function testException(): void diff --git a/tests/Domain/Event/Exception/NoEventApplyingMethodFoundTest.php b/tests/Domain/Event/Exception/NoEventApplyingMethodFoundTest.php index a83d12ee..7dba6718 100644 --- a/tests/Domain/Event/Exception/NoEventApplyingMethodFoundTest.php +++ b/tests/Domain/Event/Exception/NoEventApplyingMethodFoundTest.php @@ -24,20 +24,20 @@ */ class NoEventApplyingMethodFoundTest extends TestCase { - private Event\Consumer $consumer; + private Event\Sourced\Entity $entity; private Event\Envelope $event; protected function setUp(): void { - $this->consumer = $this->getMockBuilder(Event\Consumer::class)->getMockForAbstractClass(); - $this->event = Event\Envelope::new($this->getMockBuilder(Domain\Event::class)->getMockForAbstractClass(), Domain\Id\UUID::random()); + $this->entity = $this->getMockBuilder(Event\Sourced\Entity::class)->getMockForAbstractClass(); + $this->event = Event\Envelope::new($this->getMockBuilder(Domain\Event::class)->getMockForAbstractClass(), $producerId = Domain\Id\UUID::random()); } public function testException(): void { - $exception = new NoEventApplyingMethodFound($this->consumer, $this->event); + $exception = new NoEventApplyingMethodFound($this->entity, $this->event); - self::assertSame($this->consumer, $exception->consumer()); + self::assertSame($this->entity, $exception->object()); self::assertSame($this->event, $exception->event()); } } diff --git a/tests/Domain/Event/Exception/NotSupportedTypeTest.php b/tests/Domain/Event/Exception/NotSupportedTypeTest.php index 5d738dae..5f89f2fe 100644 --- a/tests/Domain/Event/Exception/NotSupportedTypeTest.php +++ b/tests/Domain/Event/Exception/NotSupportedTypeTest.php @@ -29,7 +29,7 @@ public function testItCreates(string $expectedMessage, $value): void { $exception = new NotSupportedType($value); self::assertEquals($value, $exception->value()); - self::assertEquals($expectedMessage, $exception->getMessage()); + self::assertSame($expectedMessage, $exception->getMessage()); } public function typesProvider(): array diff --git a/tests/Domain/Event/Exception/TooManyEventApplyingMethodsFoundTest.php b/tests/Domain/Event/Exception/TooManyEventApplyingMethodsFoundTest.php index 4f9d1daf..e9b9439c 100644 --- a/tests/Domain/Event/Exception/TooManyEventApplyingMethodsFoundTest.php +++ b/tests/Domain/Event/Exception/TooManyEventApplyingMethodsFoundTest.php @@ -24,21 +24,21 @@ */ class TooManyEventApplyingMethodsFoundTest extends TestCase { - private Event\Consumer $consumer; + private Event\Sourced\Entity $entity; private Event\Envelope $event; protected function setUp(): void { - $this->consumer = $this->getMockBuilder(Event\Consumer::class)->getMockForAbstractClass(); + $this->entity = $this->getMockBuilder(Event\Sourced\Entity::class)->getMockForAbstractClass(); $this->event = Event\Envelope::new($this->getMockBuilder(Event::class)->getMockForAbstractClass(), UUID::random()); } public function testException(): void { - $exception = new TooManyEventApplyingMethodsFound($this->consumer, $this->event); + $exception = new TooManyEventApplyingMethodsFound($this->entity, $this->event); - self::assertSame($this->consumer, $exception->consumer()); + self::assertSame($this->entity, $exception->object()); self::assertSame($this->event, $exception->event()); } } diff --git a/tests/Domain/Event/Listener/FilteringTest.php b/tests/Domain/Event/Listener/FilteringTest.php index 37790b69..424a14d4 100644 --- a/tests/Domain/Event/Listener/FilteringTest.php +++ b/tests/Domain/Event/Listener/FilteringTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Event\Listener; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; @@ -23,7 +24,7 @@ */ class FilteringTest extends TestCase { - private Event\Stream $stream; + private Event\Stream|MockObject $stream; protected function setUp(): void { diff --git a/tests/Domain/Event/Listener/IdentifyingTest.php b/tests/Domain/Event/Listener/IdentificationTest.php similarity index 57% rename from tests/Domain/Event/Listener/IdentifyingTest.php rename to tests/Domain/Event/Listener/IdentificationTest.php index 921c209b..c6582570 100644 --- a/tests/Domain/Event/Listener/IdentifyingTest.php +++ b/tests/Domain/Event/Listener/IdentificationTest.php @@ -13,17 +13,18 @@ namespace Streak\Domain\Event\Listener; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event\Listener; /** * @author Alan Gabriel Bem * - * @covers \Streak\Domain\Event\Listener\Identifying + * @covers \Streak\Domain\Event\Listener\Identification */ -class IdentifyingTest extends TestCase +class IdentificationTest extends TestCase { - private Listener\Id $id; + private Listener\Id|MockObject $id; protected function setUp(): void { @@ -32,8 +33,16 @@ protected function setUp(): void public function testObject(): void { - $identification = $this->getMockBuilder(Identifying::class)->setConstructorArgs([$this->id])->getMockForTrait(); - - self::assertSame($this->id, $identification->id()); + $stub = new Listener\IdentificationTest\IdentifyingStub($this->id); + self::assertSame($this->id, $stub->id()); } } + +namespace Streak\Domain\Event\Listener\IdentificationTest; + +use Streak\Domain\Event; + +class IdentifyingStub +{ + use Event\Listener\Identification; +} diff --git a/tests/Domain/Event/Listener/ListeningTest.php b/tests/Domain/Event/Listener/ListeningTest.php index 04edb752..287526c0 100644 --- a/tests/Domain/Event/Listener/ListeningTest.php +++ b/tests/Domain/Event/Listener/ListeningTest.php @@ -222,9 +222,11 @@ public function onObjectWhichIsUnionType(\stdClass|SupportedEvent4 $event): void $this->listenerMethodWithObjectWhichIsUnionType = true; } - public function onObjectWhenReturnTypeIsUnion(\stdClass $event): SupportedEvent1|SupportedEvent4 + public function onObjectWhenReturnTypeIsUnion(\stdClass $event): \ArrayObject|\stdClass { $this->listenerMethodWithUnionReturnTypeActivated = true; + + return new \ArrayObject(); } public function onSupportedEvent3ThatCausesException(SupportedEvent3ThatCausesException $event3): void @@ -309,11 +311,8 @@ class SupportedEvent3ThatCausesException implements Event } class SupportedEvent4 implements Event { - private $value; - - public function __construct($value) + public function __construct(private $value) { - $this->value = $value; } public function value() diff --git a/tests/Domain/Event/Sourced/Aggregate/IdentificationTest.php b/tests/Domain/Event/Sourced/Aggregate/IdentificationTest.php deleted file mode 100644 index fab96161..00000000 --- a/tests/Domain/Event/Sourced/Aggregate/IdentificationTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\Aggregate; - -use PHPUnit\Framework\TestCase; -use Streak\Domain\Event; - -/** - * @author Alan Gabriel Bem - * - * @covers \Streak\Domain\Event\Sourced\Aggregate\Identification - */ -class IdentificationTest extends TestCase -{ - private Event\Sourced\Aggregate\Id $id; - - protected function setUp(): void - { - $this->id = $this->getMockBuilder(Event\Sourced\Aggregate\Id::class)->getMockForAbstractClass(); - } - - public function testObject(): void - { - $identification = $this->getMockBuilder(Identification::class)->setConstructorArgs([$this->id])->getMockForTrait(); - - self::assertSame($this->id, $identification->producerId()); - self::assertSame($this->id, $identification->aggregateId()); - self::assertSame($this->id, $identification->entityId()); - self::assertSame($this->id, $identification->id()); - } -} diff --git a/tests/Domain/Event/Sourced/AggregateRoot/IdentificationTest.php b/tests/Domain/Event/Sourced/AggregateRoot/IdentificationTest.php deleted file mode 100644 index 52917056..00000000 --- a/tests/Domain/Event/Sourced/AggregateRoot/IdentificationTest.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\AggregateRoot; - -use PHPUnit\Framework\TestCase; -use Streak\Domain\Event; - -/** - * @author Alan Gabriel Bem - * - * @covers \Streak\Domain\Event\Sourced\AggregateRoot\Identification - */ -class IdentificationTest extends TestCase -{ - private Event\Sourced\AggregateRoot\Id $id; - - protected function setUp(): void - { - $this->id = $this->getMockBuilder(Event\Sourced\AggregateRoot\Id::class)->getMockForAbstractClass(); - } - - public function testObject(): void - { - $identification = $this->getMockBuilder(Identification::class)->setConstructorArgs([$this->id])->getMockForTrait(); - - self::assertSame($this->id, $identification->producerId()); - self::assertSame($this->id, $identification->aggregateRootId()); - self::assertSame($this->id, $identification->aggregateId()); - self::assertSame($this->id, $identification->entityId()); - self::assertSame($this->id, $identification->id()); - } -} diff --git a/tests/Domain/Event/Sourced/Entity/HelperTest.php b/tests/Domain/Event/Sourced/Entity/HelperTest.php new file mode 100644 index 00000000..eaebb930 --- /dev/null +++ b/tests/Domain/Event/Sourced/Entity/HelperTest.php @@ -0,0 +1,244 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Streak\Domain\Event\Sourced\Entity; + +use PHPUnit\Framework\TestCase; +use Streak\Domain\Event; +use Streak\Domain\Event\Sourced\Entity\HelperTest\EventSourcedEntityStub; +use Streak\Domain\Event\Sourced\Entity\HelperTest\EventSourcedEntityStubId; + +/** + * @covers \Streak\Domain\Event\Sourced\Entity\Helper + */ +class HelperTest extends TestCase +{ + public function testExtractingEventSourcedEntities(): void + { + $entity5 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db5')); + $entity4 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db4')); + $entity3 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db3')); + $entity2 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db2'), $entity3, $entity5); + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db1'), $entity2, $entity4); + + $helper = Helper::for($entity1); + + $actual = $helper->extractEventSourcedEntities(); + $actual = iterator_to_array($actual); + + $expected = [$entity2, $entity3, $entity5, $entity4]; + + self::assertSame($expected, $actual); + } + + public function testApplyingEvents(): void + { + $entity5 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db5')); + $entity4 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db4')); + $entity3 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db3')); + $entity2 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db2'), $entity3, $entity5); + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('a1880189-03a6-43aa-963f-610002a77db1'), $entity2, $entity4); + + $event1 = new Event\Sourced\Entity\HelperTest\EventSourcedEntityStubEvent1(); + $event1 = Event\Envelope::new($event1, $entity1->id()); + $event2 = new Event\Sourced\Entity\HelperTest\EventSourcedEntityStubEvent2(); + $event2 = Event\Envelope::new($event2, $entity1->id()); + $event3 = new Event\Sourced\Entity\HelperTest\EventSourcedEntityStubEvent3(); + $event3 = Event\Envelope::new($event3, $entity1->id()); + $event4 = new Event\Sourced\Entity\HelperTest\EventSourcedEntityStubEvent4(); + $event4 = Event\Envelope::new($event4, $entity1->id()); + + $helper = Helper::for($entity1); + + $helper->applyEvent($event1); + + self::assertEquals([$event1->message()], $entity1->appliedEvents()); + self::assertEquals([], $entity2->appliedEvents()); + self::assertEquals([], $entity3->appliedEvents()); + self::assertEquals([], $entity4->appliedEvents()); + self::assertEquals([], $entity5->appliedEvents()); + + $helper->applyEvent($event2); + + self::assertEquals([$event1->message(), $event2->message()], $entity1->appliedEvents()); + self::assertEquals([], $entity2->appliedEvents()); + self::assertEquals([], $entity3->appliedEvents()); + self::assertEquals([], $entity4->appliedEvents()); + self::assertEquals([], $entity5->appliedEvents()); + + try { + $helper->applyEvent($event3); + self::fail(); + } catch (Event\Exception\NoEventApplyingMethodFound $exception) { + self::assertSame($event3, $exception->event()); + self::assertSame($entity1, $exception->object()); + } + + self::assertEquals([$event1->message(), $event2->message()], $entity1->appliedEvents()); + self::assertEquals([], $entity2->appliedEvents()); + self::assertEquals([], $entity3->appliedEvents()); + self::assertEquals([], $entity4->appliedEvents()); + self::assertEquals([], $entity5->appliedEvents()); + + $this->expectExceptionObject(new Event\Exception\TooManyEventApplyingMethodsFound($entity1, $event4)); + + try { + $helper->applyEvent($event4); + self::fail(); + } catch (Event\Exception\TooManyEventApplyingMethodsFound $exception) { + self::assertSame($event4, $exception->event()); + self::assertSame($entity1, $exception->object()); + self::assertEquals([$event1->message(), $event2->message()], $entity1->appliedEvents()); + self::assertEquals([], $entity2->appliedEvents()); + self::assertEquals([], $entity3->appliedEvents()); + self::assertEquals([], $entity4->appliedEvents()); + self::assertEquals([], $entity5->appliedEvents()); + + throw $exception; + } + } +} + +namespace Streak\Domain\Event\Sourced\Entity\HelperTest; + +use Streak\Domain\Entity; +use Streak\Domain\Event; +use Streak\Domain\Id\UUID; + +final class EventSourcedEntityStubId extends UUID implements Entity\Id +{ +} + +final class EventSourcedEntityStub implements Event\Sourced\Entity +{ + use Entity\Comparison; + + private self $self; + private int $integer; + private string $string; + private object $object; + private array $arrayOfIntegers; + private array $arrayOfStrings; + private array $arrayOfObjects; + private array $arrayOfMixed; + private string $nonInitializedString; + private int $nonInitializedInteger; + private object $nonInitializedObject; + private array $nonInitializedArray; + + /** + * @var Event\Envelope[] + */ + private array $appliedEvents = []; + + public function __construct(private EventSourcedEntityStubId $id, private ?self $entity = null, ?self $entity2 = null) + { + $this->self = $this; + $this->integer = 1; + $this->string = 'string'; + $this->object = new \stdClass(); + $this->arrayOfIntegers = [-1, 0, 1]; + $this->arrayOfStrings = ['string 1', 'string 2']; + $this->arrayOfObjects = [new \stdClass(), new \stdClass()]; + $this->arrayOfMixed = [-1, 0, 1, 'string 1', 'string 2', new \stdClass(), new \stdClass(), $this, $entity, $entity2, null]; + } + + public function id(): Entity\Id + { + return $this->id; + } + + public function appliedEvents(): array + { + return $this->appliedEvents; + } + + public function applyEvent(Event\Envelope $event): void + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + public function registerAggregateRoot(Event\Sourced\AggregateRoot $aggregateRoot): void + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + public function registerAggregate(Event\Sourced\Aggregate $aggregate): void + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + public function aggregateRoot(): Event\Sourced\AggregateRoot + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + public function aggregate(): ?Event\Sourced\Aggregate + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + private function applyEventSourcedEntityStubEvent1(EventSourcedEntityStubEvent1 $event): bool + { + $this->appliedEvents[] = $event; + + return true; + } + + private function applyEventSourcedEntityStubEvent2(EventSourcedEntityStubEvent2 $event): bool + { + $this->appliedEvents[] = $event; + + return true; + } + + private function applyEventSourcedEntityStubEvent4a(EventSourcedEntityStubEvent4 $event): bool + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + private function applyEventSourcedEntityStubEvent4b(EventSourcedEntityStubEvent4 $event): bool + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + private function applyTwoArgumentsAtOnce(int $arg1, int $arg2): bool + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + private function applyNonRequiredArguments(int $arg1 = null): bool + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } + + private function applyMixedArguments($arg1): bool + { + throw new \RuntimeException(__METHOD__ . ' should not be invoked.'); + } +} + +class EventSourcedEntityStubEvent1 implements Event +{ +} + +class EventSourcedEntityStubEvent2 implements Event +{ +} + +class EventSourcedEntityStubEvent3 implements Event +{ +} +class EventSourcedEntityStubEvent4 implements Event +{ +} diff --git a/tests/Domain/Event/Sourced/Entity/IdentificationTest.php b/tests/Domain/Event/Sourced/Entity/IdentificationTest.php deleted file mode 100644 index 6fd98adf..00000000 --- a/tests/Domain/Event/Sourced/Entity/IdentificationTest.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event\Sourced\Entity; - -use PHPUnit\Framework\TestCase; -use Streak\Domain\Event; - -/** - * @author Alan Gabriel Bem - * - * @covers \Streak\Domain\Event\Sourced\Entity\Identification - */ -class IdentificationTest extends TestCase -{ - private Event\Sourced\Entity\Id $id; - - protected function setUp(): void - { - $this->id = $this->getMockBuilder(Event\Sourced\Entity\Id::class)->getMockForAbstractClass(); - } - - public function testObject(): void - { - $identification = $this->getMockBuilder(Identification::class)->setConstructorArgs([$this->id])->getMockForTrait(); - - self::assertSame($this->id, $identification->producerId()); - self::assertSame($this->id, $identification->entityId()); - self::assertSame($this->id, $identification->id()); - } -} diff --git a/tests/Domain/Event/SourcingTest.php b/tests/Domain/Event/SourcingTest.php deleted file mode 100644 index 38fdaa10..00000000 --- a/tests/Domain/Event/SourcingTest.php +++ /dev/null @@ -1,449 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Streak\Domain\Event; - -use PHPUnit\Framework\TestCase; -use Streak\Domain; -use Streak\Domain\AggregateRoot; -use Streak\Domain\Event; -use Streak\Infrastructure\Domain\Event\InMemoryStream; - -/** - * @author Alan Gabriel Bem - * - * @covers \Streak\Domain\Event\Sourcing - */ -class SourcingTest extends TestCase -{ - private AggregateRoot\Id $id1; - - private AggregateRoot\Id $id2; - - private Event\Envelope $event1; - - private Event\Envelope $event2; - - protected function setUp(): void - { - $this->id1 = new class('f5e65690-e50d-4312-a175-b004ec1bd42a') extends Domain\Id\UUID implements AggregateRoot\Id { - }; - $this->id2 = new class('f84d8230-90a8-416f-af09-5ba315214888') extends Domain\Id\UUID implements AggregateRoot\Id { - }; - $this->event1 = Event\Envelope::new($this->getMockBuilder(Event::class)->setMockClassName('event1')->getMockForAbstractClass(), $this->id1, 1); - $this->event2 = Event\Envelope::new($this->getMockBuilder(Event::class)->setMockClassName('event2')->getMockForAbstractClass(), $this->id2, 1); - } - - public function testSuccessfullyApplyingEventWithPublicHandlingMethod(): void - { - $event = new SourcingTest\EventStubForTestingPublicHandlingMethod(); - $event = Event\Envelope::new($event, $this->id1, 1); - - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - self::assertFalse($sourcing->isEventStubForTestingPublicHandlingMethodApplied()); - self::assertNull($sourcing->lastReplayed()); - self::assertNull($sourcing->lastEvent()); - self::assertEquals(0, $sourcing->version()); - self::assertEmpty($sourcing->events()); - - $sourcing->replay(new InMemoryStream($event)); - - self::assertTrue($sourcing->isEventStubForTestingPublicHandlingMethodApplied()); - self::assertSame($event, $sourcing->lastReplayed()); - self::assertEquals($event, $sourcing->lastEvent()); - self::assertEquals(1, $sourcing->version()); - self::assertEmpty($sourcing->events()); - - $sourcing->commit(); - - self::assertTrue($sourcing->isEventStubForTestingPublicHandlingMethodApplied()); - self::assertSame($event, $sourcing->lastReplayed()); - self::assertEquals($event, $sourcing->lastEvent()); - self::assertEquals(1, $sourcing->version()); - self::assertEmpty($sourcing->events()); - } - - public function testSuccessfullyApplyingEventWithNonPublicHandlingMethod(): void - { - $event = new SourcingTest\EventStubForTestingNonPublicHandlingMethod(); - $event = Event\Envelope::new($event, $this->id1, 1); - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - self::assertFalse($sourcing->isEventStubForTestingNonPublicHandlingMethodApplied()); - - $sourcing->replay(new InMemoryStream($event)); - - self::assertTrue($sourcing->isEventStubForTestingNonPublicHandlingMethodApplied()); - self::assertSame($event, $sourcing->lastReplayed()); - self::assertEquals($event, $sourcing->lastEvent()); - self::assertEquals(1, $sourcing->version()); - self::assertEmpty($sourcing->events()); - } - - public function testAggregateWithMissingHandlingMethodForGivenEvent(): void - { - $event = new SourcingTest\EventStubForTestingMissingHandlingMethod(); - $event = Event\Envelope::new($event, $this->id1, 1); - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - $exception = new Domain\Event\Exception\NoEventApplyingMethodFound($sourcing, $event); - $this->expectExceptionObject($exception); - - $sourcing->replay(new InMemoryStream($event)); - } - - public function testAggregateWithTwoOrMoreHandlingMethodsPresentForGivenEvent(): void - { - $event = new SourcingTest\EventStubForTestingTwoOrMoreHandlingMethodsPresent(); - $event = Event\Envelope::new($event, $this->id1, 1); - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - $exception = new Domain\Event\Exception\TooManyEventApplyingMethodsFound($sourcing, $event); - $this->expectExceptionObject($exception); - - $sourcing->replay(new InMemoryStream($event)); - } - - public function testAggregateWithTwoOrMoreParametersPresentOnHandlingMethod(): void - { - $event = new SourcingTest\EventStubForTestingTwoOrMoreParametersPresentOnHandlingMethod(); - $event = Event\Envelope::new($event, $this->id1, 1); - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - $exception = new Domain\Event\Exception\NoEventApplyingMethodFound($sourcing, $event); - $this->expectExceptionObject($exception); - - $sourcing->replay(new InMemoryStream($event)); - } - - public function testAggregateWithOptionalParameterOnHandlingMethodForGivenEvent(): void - { - $event = new SourcingTest\EventStubForTestingOptionalParameterOnHandlingMethod(); - $event = Event\Envelope::new($event, $this->id1, 1); - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - $exception = new Domain\Event\Exception\NoEventApplyingMethodFound($sourcing, $event); - $this->expectExceptionObject($exception); - - $sourcing->replay(new InMemoryStream($event)); - } - - public function testApplyingMethodPresentForEventsParentClassOnly(): void - { - $event1 = new SourcingTest\EventWhichIsSubclassOfEvent7(); - $event1 = Event\Envelope::new($event1, $this->id1, 1); - $event2 = new SourcingTest\AnotherEventWhichIsSubclassOfEvent7(); - $event2 = Event\Envelope::new($event2, $this->id1, 2); - - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - self::assertEquals(0, $sourcing->numberOfAppliesOfEvent7()); - - $sourcing->replay(new InMemoryStream($event1, $event2)); - - self::assertEquals(2, $sourcing->numberOfAppliesOfEvent7()); - self::assertSame($event2, $sourcing->lastReplayed()); - self::assertEquals($event2, $sourcing->lastEvent()); - self::assertEquals(2, $sourcing->version()); - self::assertEmpty($sourcing->events()); - } - -// public function testApplyingMethodPresentForEventsParentClassAndOnlyOneOfChildren() -// { -// $this->id -// ->expects(self::exactly(2)) -// ->method('equals') -// ->willReturn(true) -// ; -// -// $event1 = new SourcingTest\EventWhichIsSubclassOfEvent8($this->id); -// $event2 = new SourcingTest\AnotherEventWhichIsSubclassOfEvent8($this->id); -// -// $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id); -// -// self::assertFalse($sourcing->isEvent8Applied()); -// self::assertFalse($sourcing->isEvent8aApplied()); -// -// $sourcing->replay($event1, $event2); -// -// self::assertTrue($sourcing->isEvent8Applied()); -// self::assertTrue($sourcing->isEvent8aApplied()); -// self::assertSame($event2, $sourcing->lastReplayed()); -// self::assertEmpty($sourcing->events()); -// } - - public function testApplyingEventViaCommand(): void - { - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - self::assertEmpty($sourcing->events()); - self::assertNull($sourcing->lastEvent()); - - self::assertFalse($sourcing->isEvent9Applied()); - - $sourcing->command1($this->id1); - - self::assertTrue($sourcing->isEvent9Applied()); - - $event = new SourcingTest\EventStubForTestingApplyingViaCommand(); - - self::assertNull($sourcing->lastReplayed()); - self::assertEquals($event, $sourcing->lastEvent()->message()); - self::assertEquals(0, $sourcing->version()); - self::assertEquals([$event], $sourcing->events()); - - $sourcing->commit(); - - self::assertNull($sourcing->lastReplayed()); - self::assertEquals($event, $sourcing->lastEvent()->message()); - self::assertEquals(1, $sourcing->version()); - self::assertEquals([], $sourcing->events()); - } - - public function testApplyingEventViaCommandResultingInAnException(): void - { - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - try { - self::assertEmpty($sourcing->events()); - self::assertNull($sourcing->lastEvent()); - self::assertNull($sourcing->lastReplayed()); - - $sourcing->command2($this->id1); - - self::fail(); - } catch (\Exception $thrown) { - self::assertEquals(new \Exception('Command resulting in an exception'), $thrown); - self::assertEmpty($sourcing->events()); - self::assertNull($sourcing->lastEvent()); - self::assertNull($sourcing->lastReplayed()); - } - } - - public function testEventSourcingNonConsumer(): void - { - $sourcing = new Domain\Event\SourcingTest\EventSourcedNonConsumer($this->id1); - - $exception = new Domain\Event\Exception\SourcingObjectWithEventFailed($sourcing, $this->event1); - $this->expectExceptionObject($exception); - - $sourcing->replay(new InMemoryStream($this->event1)); - } - - public function testEventAndConsumerMismatch(): void - { - $sourcing = new SourcingTest\EventSourcedAggregateRootStub($this->id1); - - $exception = new Domain\Exception\EventAndConsumerMismatch($sourcing, $this->event2); - $this->expectExceptionObject($exception); - - $sourcing->replay(new InMemoryStream($this->event2)); - } -} - -namespace Streak\Domain\Event\SourcingTest; - -use Streak\Domain; -use Streak\Domain\AggregateRoot; -use Streak\Domain\Event; - -class EventSourcedAggregateRootStub implements Event\Consumer -{ - use Event\Sourcing; - - private \Streak\Domain\Id $id; - - private bool $eventStubForTestingPublicHandlingMethodApplied = false; - private bool $eventStubForTestingNonPublicHandlingMethodApplied = false; - private int $numberOfAppliesOfEvent7 = 0; - private bool $event8Applied = false; - private bool $event8aApplied = false; - private bool $event9Applied = false; - - public function __construct(AggregateRoot\Id $id) - { - $this->id = $id; - } - - public function producerId(): Domain\Id - { - return $this->id; - } - - public function applyEventStubForTestingPublicHandlingMethodApplied(EventStubForTestingPublicHandlingMethod $event): void - { - $this->eventStubForTestingPublicHandlingMethodApplied = true; - } - - public function applyEvent2(EventStubForTestingTwoOrMoreHandlingMethodsPresent $event2): void - { - } - - public function applyEvent2Deux(EventStubForTestingTwoOrMoreHandlingMethodsPresent $event2): void - { - } - - public function applyEvent4(EventStubForTestingTwoOrMoreParametersPresentOnHandlingMethod $event, mixed $thisParameterUnneeded): void - { - } - - public function applyEvent5(EventStubForTestingOptionalParameterOnHandlingMethod $optionalEventIsInvalid = null): void - { - } - - public function command1(AggregateRoot\Id $id): void - { - $this->apply(new EventStubForTestingApplyingViaCommand()); - } - - public function command2(AggregateRoot\Id $id): void - { - $this->apply(new EventStubForTestingApplyingViaCommandResultingInException()); - } - - public function isEventStubForTestingPublicHandlingMethodApplied(): bool - { - return $this->eventStubForTestingPublicHandlingMethodApplied; - } - - public function isEventStubForTestingNonPublicHandlingMethodApplied(): bool - { - return $this->eventStubForTestingNonPublicHandlingMethodApplied; - } - - public function isEvent8Applied(): bool - { - return $this->event8Applied; - } - - public function isEvent8aApplied(): bool - { - return $this->event8aApplied; - } - - public function isEvent9Applied(): bool - { - return $this->event9Applied; - } - - public function numberOfAppliesOfEvent7(): int - { - return $this->numberOfAppliesOfEvent7; - } - - public function id(): Domain\Id - { - return $this->id; - } - - private function applyEventStubForTestingNonPublicHandlingMethodApplied(EventStubForTestingNonPublicHandlingMethod $event): void - { - $this->eventStubForTestingNonPublicHandlingMethodApplied = true; - } - - private function applyEvent7(Event7 $event): void - { - ++$this->numberOfAppliesOfEvent7; - } - - private function applyEvent8(Event8 $event): void - { - $this->event8Applied = true; - } - - private function applyEvent8a(EventWhichIsSubclassOfEvent8 $event): void - { - $this->event8aApplied = true; - } - - private function applyEvent9(EventStubForTestingApplyingViaCommand $event): void - { - $this->event9Applied = true; - } - - private function applyEvent10(EventStubForTestingApplyingViaCommandResultingInException $event): void - { - throw new \Exception('Command resulting in an exception'); - } - - private function applyNonEvent(\stdClass $parameter): void - { - } - - private function applySomethingElse($parameters): void - { - } -} - -class EventStubForTestingPublicHandlingMethod implements Event -{ -} -class EventStubForTestingMismatching implements Event -{ -} -class EventStubForTestingTwoOrMoreHandlingMethodsPresent implements Event -{ -} -class EventStubForTestingMissingHandlingMethod implements Event -{ -} -class EventStubForTestingTwoOrMoreParametersPresentOnHandlingMethod implements Event -{ -} -class EventStubForTestingOptionalParameterOnHandlingMethod implements Event -{ -} -class EventStubForTestingNonPublicHandlingMethod implements Event -{ -} -class Event7 implements Event -{ -} -class EventWhichIsSubclassOfEvent7 extends Event7 -{ -} -class AnotherEventWhichIsSubclassOfEvent7 extends Event7 -{ -} -class Event8 implements Event -{ -} -class EventWhichIsSubclassOfEvent8 extends Event8 -{ -} -class AnotherEventWhichIsSubclassOfEvent8 extends Event8 -{ -} -class EventStubForTestingApplyingViaCommand implements Event -{ -} -class EventStubForTestingApplyingViaCommandResultingInException implements Event -{ -} - -class EventSourcedNonConsumer -{ - use Event\Sourcing; - - private \Streak\Domain\Id $id; - - public function __construct(AggregateRoot\Id $id) - { - $this->id = $id; - } - - public function producerId(): Domain\Id - { - return $this->id; - } -} diff --git a/tests/Domain/Event/Subscription/Exception/ListenerNotFoundTest.php b/tests/Domain/Event/Subscription/Exception/ListenerNotFoundTest.php index e3a03f4c..f90e98fd 100644 --- a/tests/Domain/Event/Subscription/Exception/ListenerNotFoundTest.php +++ b/tests/Domain/Event/Subscription/Exception/ListenerNotFoundTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Event\Subscription\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; @@ -23,7 +24,7 @@ */ class ListenerNotFoundTest extends TestCase { - private Event\Listener\Id $listenerId; + private Event\Listener\Id|MockObject $listenerId; protected function setUp(): void { diff --git a/tests/Domain/Event/Subscription/Exception/SubscriptionAlreadyCompletedTest.php b/tests/Domain/Event/Subscription/Exception/SubscriptionAlreadyCompletedTest.php index 12941a09..b2947228 100644 --- a/tests/Domain/Event/Subscription/Exception/SubscriptionAlreadyCompletedTest.php +++ b/tests/Domain/Event/Subscription/Exception/SubscriptionAlreadyCompletedTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Event\Subscription\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event\Listener; use Streak\Domain\Event\Subscription; @@ -24,9 +25,9 @@ */ class SubscriptionAlreadyCompletedTest extends TestCase { - private Subscription $subscription; + private Subscription|MockObject $subscription; - private Listener\Id $subscriptionId; + private Listener\Id|MockObject $subscriptionId; protected function setUp(): void { @@ -38,7 +39,7 @@ public function testException(): void { $this->subscription ->expects(self::atLeastOnce()) - ->method('subscriptionId') + ->method('id') ->willReturn($this->subscriptionId) ; diff --git a/tests/Domain/Event/Subscription/Exception/SubscriptionAlreadyStartedTest.php b/tests/Domain/Event/Subscription/Exception/SubscriptionAlreadyStartedTest.php index 7a3b953f..70795030 100644 --- a/tests/Domain/Event/Subscription/Exception/SubscriptionAlreadyStartedTest.php +++ b/tests/Domain/Event/Subscription/Exception/SubscriptionAlreadyStartedTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Event\Subscription\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event\Listener; use Streak\Domain\Event\Subscription; @@ -24,9 +25,9 @@ */ class SubscriptionAlreadyStartedTest extends TestCase { - private Subscription $subscription; + private Subscription|MockObject $subscription; - private Listener\Id $subscriptionId; + private Listener\Id|MockObject $subscriptionId; protected function setUp(): void { @@ -38,7 +39,7 @@ public function testException(): void { $this->subscription ->expects(self::atLeastOnce()) - ->method('subscriptionId') + ->method('id') ->willReturn($this->subscriptionId) ; diff --git a/tests/Domain/Event/Subscription/Exception/SubscriptionNotStartedYetTest.php b/tests/Domain/Event/Subscription/Exception/SubscriptionNotStartedYetTest.php index ac4a6305..cc86c7e4 100644 --- a/tests/Domain/Event/Subscription/Exception/SubscriptionNotStartedYetTest.php +++ b/tests/Domain/Event/Subscription/Exception/SubscriptionNotStartedYetTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Event\Subscription\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event\Listener; use Streak\Domain\Event\Subscription; @@ -24,9 +25,9 @@ */ class SubscriptionNotStartedYetTest extends TestCase { - private Subscription $subscription; + private Subscription|MockObject $subscription; - private Listener\Id $subscriptionId; + private Listener\Id|MockObject $subscriptionId; protected function setUp(): void { @@ -38,7 +39,7 @@ public function testException(): void { $this->subscription ->expects(self::atLeastOnce()) - ->method('subscriptionId') + ->method('id') ->willReturn($this->subscriptionId) ; diff --git a/tests/Domain/Event/Subscription/Exception/SubscriptionPausedTest.php b/tests/Domain/Event/Subscription/Exception/SubscriptionPausedTest.php index abeef08e..a44db4a2 100644 --- a/tests/Domain/Event/Subscription/Exception/SubscriptionPausedTest.php +++ b/tests/Domain/Event/Subscription/Exception/SubscriptionPausedTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Event\Subscription\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event\Listener; use Streak\Domain\Event\Subscription; @@ -24,8 +25,8 @@ */ class SubscriptionPausedTest extends TestCase { - private Subscription $subscription; - private Listener\Id $subscriptionId; + private Subscription|MockObject $subscription; + private Listener\Id|MockObject $subscriptionId; protected function setUp(): void { @@ -37,7 +38,7 @@ public function testException(): void { $this->subscription ->expects(self::atLeastOnce()) - ->method('subscriptionId') + ->method('id') ->willReturn($this->subscriptionId) ; diff --git a/tests/Domain/Event/Subscription/Exception/SubscriptionRestartNotPossibleTest.php b/tests/Domain/Event/Subscription/Exception/SubscriptionRestartNotPossibleTest.php index 46ab94d1..117565b1 100644 --- a/tests/Domain/Event/Subscription/Exception/SubscriptionRestartNotPossibleTest.php +++ b/tests/Domain/Event/Subscription/Exception/SubscriptionRestartNotPossibleTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Event\Subscription\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event\Listener; use Streak\Domain\Event\Subscription; @@ -24,9 +25,9 @@ */ class SubscriptionRestartNotPossibleTest extends TestCase { - private Subscription $subscription; + private Subscription|MockObject $subscription; - private Listener\Id $subscriptionId; + private Listener\Id|MockObject $subscriptionId; protected function setUp(): void { @@ -38,7 +39,7 @@ public function testException(): void { $this->subscription ->expects(self::atLeastOnce()) - ->method('subscriptionId') + ->method('id') ->willReturn($this->subscriptionId) ; diff --git a/tests/Domain/Event/Sourced/Subscription/Repository/FilterTest.php b/tests/Domain/Event/Subscription/Repository/FilterTest.php similarity index 94% rename from tests/Domain/Event/Sourced/Subscription/Repository/FilterTest.php rename to tests/Domain/Event/Subscription/Repository/FilterTest.php index 3d770f52..68db7241 100644 --- a/tests/Domain/Event/Sourced/Subscription/Repository/FilterTest.php +++ b/tests/Domain/Event/Subscription/Repository/FilterTest.php @@ -11,10 +11,9 @@ declare(strict_types=1); -namespace Streak\Domain\Event\Sourced\Subscription\Repository; +namespace Streak\Domain\Event\Subscription\Repository; use PHPUnit\Framework\TestCase; -use Streak\Domain\Event\Subscription\Repository\Filter; /** * @author Alan Gabriel Bem diff --git a/tests/Domain/EventSourcingTest.php b/tests/Domain/EventSourcingTest.php new file mode 100644 index 00000000..bbe4da6e --- /dev/null +++ b/tests/Domain/EventSourcingTest.php @@ -0,0 +1,748 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Streak\Domain; + +use PHPUnit\Framework\TestCase; +use Streak\Domain\EventSourcingTest\EventSourcedAggregateRootStub; +use Streak\Domain\EventSourcingTest\EventSourcedAggregateRootStubId; +use Streak\Domain\EventSourcingTest\EventSourcedAggregateStub; +use Streak\Domain\EventSourcingTest\EventSourcedAggregateStubId; +use Streak\Domain\EventSourcingTest\EventSourcedEntityStub; +use Streak\Domain\EventSourcingTest\EventSourcedEntityStubId; +use Streak\Domain\Exception\EventMismatched; +use Streak\Infrastructure\Domain\Event\InMemoryStream; + +/** + * @author Alan Gabriel Bem + * + * @covers \Streak\Domain\AggregateRoot\EventSourcing + * @covers \Streak\Domain\Aggregate\EventSourcing + * @covers \Streak\Domain\Entity\EventSourcing + */ +class EventSourcingTest extends TestCase +{ + public function testSuccessfullyApplyingEventOnAggregateRoot(): void + { + $aggregateRootId1 = new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'); + $aggregateRoot1 = new EventSourcedAggregateRootStub($aggregateRootId1); + + $event = new EventSourcingTest\Event1(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + + $aggregateRoot1->command($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + + $freshAggregateRoot1 = new EventSourcedAggregateRootStub($aggregateRootId1); + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testSuccessfullyApplyingEventOnAggregateRootButNotAggregate(): void + { + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852')); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + + $event = new EventSourcingTest\Event1(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + + $aggregateRoot1->command($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + + $freshAggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852')); + $freshAggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $freshAggregate1); + $freshAggregate1->registerAggregateRoot($freshAggregateRoot1); + + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testSuccessfullyApplyingEventOnAggregateRootButNotAggregateAndEntity(): void + { + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $entity1); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + $entity1->registerAggregate($aggregate1); + + $event = new EventSourcingTest\Event1(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $aggregateRoot1->command($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $freshEntity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $freshAggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $freshEntity1); + $freshAggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $freshAggregate1); + $freshAggregate1->registerAggregateRoot($freshAggregateRoot1); + $freshEntity1->registerAggregate($freshAggregate1); + + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testSuccessfullyApplyingEventOnAggregateAndAggregateRoot(): void + { + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852')); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + + $event = new EventSourcingTest\Event1(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + + $aggregateRoot1->commandOnAggregate1($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + + $freshAggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852')); + $freshAggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $freshAggregate1); + $freshAggregate1->registerAggregateRoot($freshAggregateRoot1); + + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testSuccessfullyApplyingEventOnAggregateAndAggregateRootButNotEntity(): void + { + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $entity1); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + $entity1->registerAggregate($aggregate1); + + $event = new EventSourcingTest\Event1(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $aggregateRoot1->commandOnAggregate1($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $freshEntity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $freshAggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $freshEntity1); + $freshAggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $freshAggregate1); + $freshAggregate1->registerAggregateRoot($freshAggregateRoot1); + $freshEntity1->registerAggregate($freshAggregate1); + + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testSuccessfullyApplyingEventOnAggregateButNotAggregateRoot(): void + { + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852')); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + + $event = new EventSourcingTest\Event2(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + + $aggregateRoot1->commandOnAggregate1($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + + $freshAggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852')); + $freshAggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $freshAggregate1); + $freshAggregate1->registerAggregateRoot($freshAggregateRoot1); + + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testSuccessfullyApplyingEventOnEntityAndAggregateAndAggregateRoot(): void + { + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $entity1); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + $entity1->registerAggregate($aggregate1); + + $event = new EventSourcingTest\Event1(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $aggregateRoot1->commandOnEntity1OfAggregate1($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + self::assertEquals([$event], $entity1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + self::assertEquals([$event], $entity1->appliedEvents()); + + $freshEntity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $freshAggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $freshEntity1); + $freshAggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $freshAggregate1); + $freshAggregate1->registerAggregateRoot($freshAggregateRoot1); + $freshEntity1->registerAggregate($freshAggregate1); + + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testSuccessfullyApplyingEventOnEntityAndAggregateButNotAggregateRoot(): void + { + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $entity1); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + $entity1->registerAggregate($aggregate1); + + $event = new EventSourcingTest\Event2(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $aggregateRoot1->commandOnEntity1OfAggregate1($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + self::assertEquals([$event], $entity1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEquals([$event], $aggregate1->appliedEvents()); + self::assertEquals([$event], $entity1->appliedEvents()); + + $freshEntity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $freshAggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $freshEntity1); + $freshAggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $freshAggregate1); + $freshAggregate1->registerAggregateRoot($freshAggregateRoot1); + $freshEntity1->registerAggregate($freshAggregate1); + + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testSuccessfullyApplyingEventOnEntityAndAggregateRootButNotAggregate(): void + { + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $entity1); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + $entity1->registerAggregate($aggregate1); + + $event = new EventSourcingTest\Event4(); + + self::assertNull($aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEmpty($aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEmpty($entity1->appliedEvents()); + + $aggregateRoot1->commandOnEntity1OfAggregate1($event); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(0, $aggregateRoot1->version()); + self::assertEquals([$event], $aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEquals([$event], $entity1->appliedEvents()); + + $stream = $aggregateRoot1->events(); + + $aggregateRoot1->commit(); + + self::assertEquals($event, $aggregateRoot1->lastEvent()); + self::assertSame(1, $aggregateRoot1->version()); + self::assertEmpty($aggregateRoot1->events()); + self::assertEquals([$event], $aggregateRoot1->appliedEvents()); + self::assertEmpty($aggregate1->appliedEvents()); + self::assertEquals([$event], $entity1->appliedEvents()); + + $freshEntity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $freshAggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $freshEntity1); + $freshAggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $freshAggregate1); + $freshAggregate1->registerAggregateRoot($freshAggregateRoot1); + $freshEntity1->registerAggregate($freshAggregate1); + + $freshAggregateRoot1->replay(new InMemoryStream(...$stream)); + + self::assertNotSame($aggregateRoot1, $freshAggregateRoot1); + self::assertEquals($aggregateRoot1, $freshAggregateRoot1); + } + + public function testMismatchedEventOnAggregateRoot(): void + { + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $entity1); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + $entity1->registerAggregate($aggregate1); + + $event = new EventSourcingTest\Event4(); + $event = Event\Envelope::new($event, new EventSourcedAggregateStubId('61888494-fd58-412c-86c3-03cf81aca443'), 1); + + try { + $aggregateRoot1->applyEvent($event); + self::fail(); + } catch (EventMismatched $exception) { + self::assertSame($aggregateRoot1, $exception->object()); + self::assertSame($event, $exception->event()); + } + } + + public function testMismatchedEventOnAggregate(): void + { + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $entity1); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + $entity1->registerAggregate($aggregate1); + + $event = new EventSourcingTest\Event2(); + $event = Event\Envelope::new($event, new EventSourcedAggregateStubId('61888494-fd58-412c-86c3-03cf81aca443'), 1); + + try { + $aggregate1->applyEvent($event); + self::fail(); + } catch (EventMismatched $exception) { + self::assertSame($aggregate1, $exception->object()); + self::assertSame($event, $exception->event()); + } + } + + public function testMismatchedEventOnEntity(): void + { + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852'), $entity1); + $aggregateRoot1 = new EventSourcedAggregateRootStub(new EventSourcedAggregateRootStubId('f5e65690-e50d-4312-a175-b004ec1bd42a'), $aggregate1); + $aggregate1->registerAggregateRoot($aggregateRoot1); + $entity1->registerAggregate($aggregate1); + + $event = new EventSourcingTest\Event2(); + $event = Event\Envelope::new($event, new EventSourcedAggregateStubId('61888494-fd58-412c-86c3-03cf81aca443'), 1); + + try { + $entity1->applyEvent($event); + self::fail(); + } catch (EventMismatched $exception) { + self::assertSame($entity1, $exception->object()); + self::assertSame($event, $exception->event()); + } + } + + public function testRegisteringAggregateOnItself(): void + { + $this->expectExceptionObject(new \BadMethodCallException('You can\'t register aggregate on itself.')); + + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852')); + $aggregate1->registerAggregate($aggregate1); + } + + public function testObtainingAggregateRootOnAggregateWhenItsNotRegistered(): void + { + $this->expectExceptionObject(new \BadMethodCallException('Aggregate root no registered. Did you forget to run Streak\Domain\EventSourcingTest\EventSourcedAggregateStub::registerAggregateRoot()?')); + + $aggregate1 = new EventSourcedAggregateStub(new EventSourcedAggregateStubId('51b37ad0-9e18-47fb-89ba-8d860472c852')); + + $aggregate1->aggregateRoot(); + } + + public function testObtainingAggregateRootOnEntityWhenItsNotRegistered(): void + { + $this->expectExceptionObject(new \BadMethodCallException('Aggregate root no registered. Did you forget to run Streak\Domain\EventSourcingTest\EventSourcedEntityStub::registerAggregateRoot()?')); + + $entity1 = new EventSourcedEntityStub(new EventSourcedEntityStubId('bafbcfd1-0355-42b4-bd3f-0a5379570574')); + + $entity1->aggregateRoot(); + } +} + +namespace Streak\Domain\EventSourcingTest; + +use Streak\Domain; +use Streak\Domain\Aggregate; +use Streak\Domain\AggregateRoot; +use Streak\Domain\Entity; +use Streak\Domain\Event; + +class EventSourcedAggregateRootStubId extends Domain\Id\UUID implements AggregateRoot\Id +{ +} + +class EventSourcedAggregateRootStub implements Event\Sourced\AggregateRoot +{ + use AggregateRoot\Comparison; + use AggregateRoot\EventSourcing; + use AggregateRoot\Identification; + + private array $appliedEvents = []; + + public function __construct( + EventSourcedAggregateRootStubId $id, + private ?EventSourcedAggregateStub $aggregate1 = null, + private ?EventSourcedAggregateStub $aggregate2 = null, + private ?EventSourcedEntityStub $entity1 = null, + private ?EventSourcedEntityStub $entity2 = null, + ) { + $this->identifyBy($id); + } + + public function entity1(): ?Event\Sourced\Entity + { + return $this->entity1; + } + + public function entity2(): ?Event\Sourced\Entity + { + return $this->entity2; + } + + public function command(Event $event): void + { + $this->apply($event); + } + + public function commandOnAggregate1(Event $event): void + { + $this->aggregate1->commandOnAggregate($event); + } + + public function commandOnEntity1OfAggregate1(Event $event): void + { + $this->aggregate1->commandOnEntity1($event); + } + + public function commandOnEntity2OfAggregate1(Event $event): void + { + $this->aggregate1->commandOnEntity2($event); + } + + public function commandOnEntity1(Event $event): void + { + $this->entity1->command($event); + } + + public function commandOnAggregate2(Event $event): void + { + $this->aggregate2->commandOnAggregate($event); + } + + public function commandOnEntity1OfAggregate2(Event $event): void + { + $this->aggregate2->commandOnEntity1($event); + } + + public function commandOnEntity2OfAggregate2(Event $event): void + { + $this->aggregate2->commandOnEntity2($event); + } + + public function commandOnEntity2(Event $event): void + { + $this->entity1->command($event); + } + + public function appliedEvents(): array + { + return $this->appliedEvents; + } + + private function applyEvent1(Event1 $event): void + { + $this->appliedEvents = [$event]; + } + + private function applyEvent4(Event4 $event): void + { + $this->appliedEvents[] = $event; + } +} + +class EventSourcedAggregateStubId extends Domain\Id\UUID implements Aggregate\Id +{ +} + +class EventSourcedAggregateStub implements Event\Sourced\Aggregate +{ + use Aggregate\Comparison; + use Aggregate\EventSourcing; + use Aggregate\Identification; + + /** + * @var array + */ + private array $appliedEvents = []; + + public function __construct( + EventSourcedAggregateStubId $id, + private ?EventSourcedEntityStub $entity1 = null, + private ?EventSourcedEntityStub $entity2 = null, + ) { + $this->identifyBy($id); + } + + public function commandOnAggregate(Event $event): void + { + $this->apply($event); + } + + public function commandOnEntity1(Event $event): void + { + $this->entity1->command($event); + } + + public function commandOnEntity2(Event $event): void + { + $this->entity2->command($event); + } + + public function appliedEvents(): array + { + return $this->appliedEvents; + } + + private function applyEvent1(Event1 $event): void + { + $this->appliedEvents[] = $event; + } + + private function applyEvent2(Event2 $event): void + { + $this->appliedEvents[] = $event; + } +} + +class EventSourcedEntityStubId extends Domain\Id\UUID implements Entity\Id +{ +} + +class EventSourcedEntityStub implements Event\Sourced\Entity +{ + use Entity\Comparison; + use Entity\EventSourcing; + use Entity\Identification; + + /** + * @var Event\Envelope[] + */ + private array $appliedEvents = []; + + public function __construct(EventSourcedEntityStubId $id) + { + $this->identifyBy($id); + } + + public function command(Event $event): void + { + $this->apply($event); + } + + public function appliedEvents(): array + { + return $this->appliedEvents; + } + + private function applyEvent1(Event1 $event): void + { + $this->appliedEvents[] = $event; + } + + private function applyEvent2(Event2 $event): void + { + $this->appliedEvents[] = $event; + } + + private function applyEvent3(Event3 $event): void + { + $this->appliedEvents[] = $event; + } + + private function applyEvent4(Event4 $event): void + { + $this->appliedEvents[] = $event; + } +} + +class Event1 implements Event +{ +} + +class Event2 implements Event +{ +} + +class Event3 implements Event +{ +} + +class Event4 implements Event +{ +} diff --git a/tests/Domain/EventStore/FilterTest.php b/tests/Domain/EventStore/FilterTest.php index ffac0381..490924bb 100644 --- a/tests/Domain/EventStore/FilterTest.php +++ b/tests/Domain/EventStore/FilterTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\EventStore; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Id; @@ -23,8 +24,8 @@ */ class FilterTest extends TestCase { - private Id $id1; - private Id $id2; + private Id|MockObject $id1; + private Id|MockObject $id2; protected function setUp(): void { diff --git a/tests/Domain/Exception/AggregateAlreadyExistsTest.php b/tests/Domain/Exception/AggregateAlreadyExistsTest.php index d6c72aa7..fe2c7e61 100644 --- a/tests/Domain/Exception/AggregateAlreadyExistsTest.php +++ b/tests/Domain/Exception/AggregateAlreadyExistsTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; @@ -23,7 +24,7 @@ */ class AggregateAlreadyExistsTest extends TestCase { - private Domain\AggregateRoot $aggregate; + private Domain\AggregateRoot|MockObject $aggregate; protected function setUp(): void { diff --git a/tests/Domain/Exception/AggregateNotFoundTest.php b/tests/Domain/Exception/AggregateNotFoundTest.php index 691bb092..8b5a38b9 100644 --- a/tests/Domain/Exception/AggregateNotFoundTest.php +++ b/tests/Domain/Exception/AggregateNotFoundTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; @@ -23,7 +24,7 @@ */ class AggregateNotFoundTest extends TestCase { - private AggregateRoot\Id $aggregateId; + private AggregateRoot\Id|MockObject $aggregateId; protected function setUp(): void { diff --git a/tests/Domain/Exception/CommandNotSupportedTest.php b/tests/Domain/Exception/CommandNotSupportedTest.php index 15112b3b..cf21008a 100644 --- a/tests/Domain/Exception/CommandNotSupportedTest.php +++ b/tests/Domain/Exception/CommandNotSupportedTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; @@ -23,7 +24,7 @@ */ class CommandNotSupportedTest extends TestCase { - private $command; + private Domain\Command|MockObject $command; protected function setUp(): void { diff --git a/tests/Domain/Exception/ConcurrentWriteDetectedTest.php b/tests/Domain/Exception/ConcurrentWriteDetectedTest.php index 3815ef60..02d34535 100644 --- a/tests/Domain/Exception/ConcurrentWriteDetectedTest.php +++ b/tests/Domain/Exception/ConcurrentWriteDetectedTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; @@ -23,7 +24,7 @@ */ class ConcurrentWriteDetectedTest extends TestCase { - private Domain\Id $id; + private Domain\Id|MockObject $id; protected function setUp(): void { diff --git a/tests/Domain/Exception/EventAndConsumerMismatchTest.php b/tests/Domain/Exception/EventMismatchedTest.php similarity index 65% rename from tests/Domain/Exception/EventAndConsumerMismatchTest.php rename to tests/Domain/Exception/EventMismatchedTest.php index 67da2ea5..52b6e838 100644 --- a/tests/Domain/Exception/EventAndConsumerMismatchTest.php +++ b/tests/Domain/Exception/EventMismatchedTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; use Streak\Domain\Event; @@ -21,25 +22,25 @@ /** * @author Alan Gabriel Bem * - * @covers \Streak\Domain\Exception\EventAndConsumerMismatch + * @covers \Streak\Domain\Exception\EventMismatched */ -class EventAndConsumerMismatchTest extends TestCase +class EventMismatchedTest extends TestCase { - private Event\Consumer $consumer; + private Event\Sourced\Entity|MockObject $entity; private Domain\Event\Envelope $event; protected function setUp(): void { - $this->consumer = $this->getMockBuilder(Event\Consumer::class)->getMockForAbstractClass(); + $this->entity = $this->getMockBuilder(Event\Sourced\Entity::class)->getMockForAbstractClass(); $this->event = Event\Envelope::new($this->getMockBuilder(Domain\Event::class)->getMockForAbstractClass(), UUID::random()); } public function testException(): void { - $exception = new EventAndConsumerMismatch($this->consumer, $this->event); + $exception = new EventMismatched($this->entity, $this->event); - self::assertSame($this->consumer, $exception->consumer()); + self::assertSame($this->entity, $exception->object()); self::assertSame($this->event, $exception->event()); } } diff --git a/tests/Domain/Exception/InvalidAggregateGivenTest.php b/tests/Domain/Exception/InvalidAggregateGivenTest.php index 7f1e1218..1a1bf878 100644 --- a/tests/Domain/Exception/InvalidAggregateGivenTest.php +++ b/tests/Domain/Exception/InvalidAggregateGivenTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; @@ -23,7 +24,7 @@ */ class InvalidAggregateGivenTest extends TestCase { - private AggregateRoot $aggregate; + private AggregateRoot|MockObject $aggregate; protected function setUp(): void { diff --git a/tests/Domain/Exception/InvalidAggregateIdGivenTest.php b/tests/Domain/Exception/InvalidAggregateIdGivenTest.php index 32a9725a..9df68a8d 100644 --- a/tests/Domain/Exception/InvalidAggregateIdGivenTest.php +++ b/tests/Domain/Exception/InvalidAggregateIdGivenTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; @@ -23,7 +24,7 @@ */ class InvalidAggregateIdGivenTest extends TestCase { - private Domain\AggregateRoot\Id $aggregateId; + private Domain\AggregateRoot\Id|MockObject $aggregateId; protected function setUp(): void { diff --git a/tests/Domain/Exception/InvalidIdGivenTest.php b/tests/Domain/Exception/InvalidIdGivenTest.php index 2e536b82..ec57a4c7 100644 --- a/tests/Domain/Exception/InvalidIdGivenTest.php +++ b/tests/Domain/Exception/InvalidIdGivenTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; @@ -23,7 +24,7 @@ */ class InvalidIdGivenTest extends TestCase { - private AggregateRoot\Id $id; + private AggregateRoot\Id|MockObject $id; protected function setUp(): void { diff --git a/tests/Domain/Exception/ObjectNotSupportedTest.php b/tests/Domain/Exception/ObjectNotSupportedTest.php index 66bb5c51..e3742322 100644 --- a/tests/Domain/Exception/ObjectNotSupportedTest.php +++ b/tests/Domain/Exception/ObjectNotSupportedTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; @@ -23,7 +24,7 @@ */ class ObjectNotSupportedTest extends TestCase { - private Domain\AggregateRoot $object; + private Domain\AggregateRoot|MockObject $object; protected function setUp(): void { diff --git a/tests/Domain/Exception/QueryNotSupportedTest.php b/tests/Domain/Exception/QueryNotSupportedTest.php index de96cdf9..095c9c7a 100644 --- a/tests/Domain/Exception/QueryNotSupportedTest.php +++ b/tests/Domain/Exception/QueryNotSupportedTest.php @@ -13,6 +13,7 @@ namespace Streak\Domain\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Query; @@ -23,7 +24,7 @@ */ class QueryNotSupportedTest extends TestCase { - private $query; + private Query|MockObject $query; protected function setUp(): void { diff --git a/tests/Infrastructure/Application/CommandBus/CommittingCommandBusTest.php b/tests/Infrastructure/Application/CommandBus/CommittingCommandBusTest.php index 8c475f4f..8e8e7c65 100644 --- a/tests/Infrastructure/Application/CommandBus/CommittingCommandBusTest.php +++ b/tests/Infrastructure/Application/CommandBus/CommittingCommandBusTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\CommandBus; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\CommandBus; use Streak\Domain\Command; @@ -26,15 +27,15 @@ */ class CommittingCommandBusTest extends TestCase { - private CommandBus $bus; + private CommandBus|MockObject $bus; - private Command $command1; - private Command $command2; + private Command|MockObject $command1; + private Command|MockObject $command2; - private UnitOfWork $uow; + private UnitOfWork|MockObject $uow; - private Event\Producer $producer1; - private Event\Producer $producer2; + private Event\Producer|MockObject $producer1; + private Event\Producer|MockObject $producer2; protected function setUp(): void { diff --git a/tests/Infrastructure/Application/CommandBus/DbalTransactionalCommandBusTest.php b/tests/Infrastructure/Application/CommandBus/DbalTransactionalCommandBusTest.php index 0bff1726..b8d86cee 100644 --- a/tests/Infrastructure/Application/CommandBus/DbalTransactionalCommandBusTest.php +++ b/tests/Infrastructure/Application/CommandBus/DbalTransactionalCommandBusTest.php @@ -14,6 +14,7 @@ namespace Streak\Infrastructure\Application\CommandBus; use Doctrine\DBAL\Driver\Connection; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\CommandBus; use Streak\Domain\Command; @@ -25,9 +26,9 @@ */ class DbalTransactionalCommandBusTest extends TestCase { - private CommandBus $bus; - private Connection $connection; - private Command $command; + private CommandBus|MockObject $bus; + private Connection|MockObject $connection; + private Command|MockObject $command; protected function setUp(): void { diff --git a/tests/Infrastructure/Application/CommandBus/LockableCommandBusTest.php b/tests/Infrastructure/Application/CommandBus/LockableCommandBusTest.php index ae285554..25c35198 100644 --- a/tests/Infrastructure/Application/CommandBus/LockableCommandBusTest.php +++ b/tests/Infrastructure/Application/CommandBus/LockableCommandBusTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\CommandBus; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\CommandBus; use Streak\Domain\Command; @@ -24,13 +25,13 @@ */ class LockableCommandBusTest extends TestCase { - private CommandBus $bus; + private CommandBus|MockObject $bus; - private Command $command1; - private Command $command2; - private Command $command3; - private Command $command4; - private Command $command5; + private Command|MockObject $command1; + private Command|MockObject $command2; + private Command|MockObject $command3; + private Command|MockObject $command4; + private Command|MockObject $command5; protected function setUp(): void { diff --git a/tests/Infrastructure/Application/CommandBus/RetryingCommandBusTest.php b/tests/Infrastructure/Application/CommandBus/RetryingCommandBusTest.php index 26e96c28..05fc7d82 100644 --- a/tests/Infrastructure/Application/CommandBus/RetryingCommandBusTest.php +++ b/tests/Infrastructure/Application/CommandBus/RetryingCommandBusTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\CommandBus; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\CommandBus; use Streak\Domain; @@ -26,13 +27,13 @@ */ class RetryingCommandBusTest extends TestCase { - private CommandBus $bus; + private CommandBus|MockObject $bus; - private Command $command1; - private Command $command2; - private Command $command3; + private Command|MockObject $command1; + private Command|MockObject $command2; + private Command|MockObject $command3; - private Domain\Id $id; + private Domain\Id|MockObject $id; private Exception\ConcurrentWriteDetected $exception1; private Exception\ConcurrentWriteDetected $exception2; diff --git a/tests/Infrastructure/Application/CommandBus/SynchronousCommandBusTest.php b/tests/Infrastructure/Application/CommandBus/SynchronousCommandBusTest.php index 9e0e9b58..abbdd6f0 100644 --- a/tests/Infrastructure/Application/CommandBus/SynchronousCommandBusTest.php +++ b/tests/Infrastructure/Application/CommandBus/SynchronousCommandBusTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\CommandBus; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Command; use Streak\Domain\CommandHandler; @@ -25,9 +26,9 @@ */ class SynchronousCommandBusTest extends TestCase { - private CommandHandler $handler1; - private CommandHandler $handler2; - private CommandHandler $handler3; + private CommandHandler|MockObject $handler1; + private CommandHandler|MockObject $handler2; + private CommandHandler|MockObject $handler3; private Command $command1; diff --git a/tests/Infrastructure/Application/QueryBus/SynchronousQueryBusTest.php b/tests/Infrastructure/Application/QueryBus/SynchronousQueryBusTest.php index b69c6893..45367e77 100644 --- a/tests/Infrastructure/Application/QueryBus/SynchronousQueryBusTest.php +++ b/tests/Infrastructure/Application/QueryBus/SynchronousQueryBusTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\QueryBus; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Exception\QueryNotSupported; use Streak\Domain\Query; @@ -25,11 +26,11 @@ */ class SynchronousQueryBusTest extends TestCase { - private QueryHandler $handler1; - private QueryHandler $handler2; - private QueryHandler $handler3; + private QueryHandler|MockObject $handler1; + private QueryHandler|MockObject $handler2; + private QueryHandler|MockObject $handler3; - private Query $query1; + private Query|MockObject $query1; protected function setUp(): void { diff --git a/tests/Infrastructure/Application/Sensor/CommittingSensor/FactoryTest.php b/tests/Infrastructure/Application/Sensor/CommittingSensor/FactoryTest.php index 207e255f..adc3af03 100644 --- a/tests/Infrastructure/Application/Sensor/CommittingSensor/FactoryTest.php +++ b/tests/Infrastructure/Application/Sensor/CommittingSensor/FactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\Sensor\CommittingSensor; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\Sensor; use Streak\Infrastructure\Application\Sensor\CommittingSensor; @@ -25,11 +26,11 @@ */ class FactoryTest extends TestCase { - private Sensor\Factory $factory; + private Sensor\Factory|MockObject $factory; - private UnitOfWork $uow; + private UnitOfWork|MockObject $uow; - private Sensor $sensor; + private Sensor|MockObject $sensor; protected function setUp(): void { diff --git a/tests/Infrastructure/Application/Sensor/CommittingSensorTest.php b/tests/Infrastructure/Application/Sensor/CommittingSensorTest.php index 9806bfea..d30f5f53 100644 --- a/tests/Infrastructure/Application/Sensor/CommittingSensorTest.php +++ b/tests/Infrastructure/Application/Sensor/CommittingSensorTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\Sensor; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\Sensor; use Streak\Domain\Event; @@ -25,14 +26,14 @@ */ class CommittingSensorTest extends TestCase { - private Sensor $sensor; + private Sensor|MockObject $sensor; - private UnitOfWork $uow; + private UnitOfWork|MockObject $uow; - private Sensor\Id $sensorId; + private Sensor\Id|MockObject $sensorId; - private Event $event1; - private Event $event2; + private Event|MockObject $event1; + private Event|MockObject $event2; protected function setUp(): void { @@ -49,21 +50,12 @@ public function testSensor(): void $this->sensor ->expects(self::once()) - ->method('sensorId') + ->method('id') ->with() ->willReturn($this->sensorId) ; - self::assertSame($this->sensorId, $sensor->sensorId()); - - $this->sensor - ->expects(self::once()) - ->method('producerId') - ->with() - ->willReturn($this->sensorId) - ; - - self::assertSame($this->sensorId, $sensor->producerId()); + self::assertSame($this->sensorId, $sensor->id()); $this->sensor ->expects(self::once()) diff --git a/tests/Infrastructure/Application/Sensor/Factory/CachingFactoryTest.php b/tests/Infrastructure/Application/Sensor/Factory/CachingFactoryTest.php index ed79cffe..0272646c 100644 --- a/tests/Infrastructure/Application/Sensor/Factory/CachingFactoryTest.php +++ b/tests/Infrastructure/Application/Sensor/Factory/CachingFactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\Sensor\Factory; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\Sensor; @@ -23,8 +24,8 @@ */ class CachingFactoryTest extends TestCase { - private Sensor\Factory $factory; - private Sensor $sensor; + private Sensor\Factory|MockObject $factory; + private Sensor|MockObject $sensor; protected function setUp(): void { diff --git a/tests/Infrastructure/Application/Sensor/LoggingSensor/FactoryTest.php b/tests/Infrastructure/Application/Sensor/LoggingSensor/FactoryTest.php index 2b67bea1..6a9e858c 100644 --- a/tests/Infrastructure/Application/Sensor/LoggingSensor/FactoryTest.php +++ b/tests/Infrastructure/Application/Sensor/LoggingSensor/FactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\Sensor\LoggingSensor; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Streak\Application\Sensor; @@ -25,11 +26,11 @@ */ class FactoryTest extends TestCase { - private Sensor\Factory $factory; + private Sensor\Factory|MockObject $factory; - private Sensor $sensor; + private Sensor|MockObject $sensor; - private LoggerInterface $logger; + private LoggerInterface|MockObject $logger; protected function setUp(): void { diff --git a/tests/Infrastructure/Application/Sensor/LoggingSensorTest.php b/tests/Infrastructure/Application/Sensor/LoggingSensorTest.php index 55877581..2faa4488 100644 --- a/tests/Infrastructure/Application/Sensor/LoggingSensorTest.php +++ b/tests/Infrastructure/Application/Sensor/LoggingSensorTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Application\Sensor; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Streak\Application\Sensor; @@ -25,13 +26,13 @@ */ class LoggingSensorTest extends TestCase { - private Sensor $sensor; + private Sensor|MockObject $sensor; - private LoggerInterface $logger; + private LoggerInterface|MockObject $logger; - private Sensor\Id $sensorId; + private Sensor\Id|MockObject $sensorId; - private Event $event; + private Event|MockObject $event; protected function setUp(): void { @@ -62,19 +63,11 @@ public function testObject(): void $this->sensor ->expects(self::once()) - ->method('sensorId') + ->method('id') ->willReturn($this->sensorId) ; - self::assertSame($this->sensorId, $sensor->sensorId()); - - $this->sensor - ->expects(self::once()) - ->method('producerId') - ->willReturn($this->sensorId) - ; - - self::assertSame($this->sensorId, $sensor->producerId()); + self::assertSame($this->sensorId, $sensor->id()); $this->sensor ->expects(self::once()) diff --git a/tests/Infrastructure/Domain/AggregateRoot/Factory/CompositeFactoryTest.php b/tests/Infrastructure/Domain/AggregateRoot/Factory/CompositeFactoryTest.php index 4c56a71e..8fdabd28 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Factory/CompositeFactoryTest.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Factory/CompositeFactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\AggregateRoot\Factory; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; use Streak\Domain\Exception\InvalidAggregateIdGiven; @@ -24,12 +25,12 @@ */ class CompositeFactoryTest extends TestCase { - private AggregateRoot\Id $id1; + private AggregateRoot\Id|MockObject $id1; - private AggregateRoot\Factory $factory1; - private AggregateRoot\Factory $factory2; + private AggregateRoot\Factory|MockObject $factory1; + private AggregateRoot\Factory|MockObject $factory2; - private AggregateRoot $aggregate1; + private AggregateRoot|MockObject $aggregate1; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/AggregateRoot/Repository/EventSourcedRepositoryTest.php b/tests/Infrastructure/Domain/AggregateRoot/Repository/EventSourcedRepositoryTest.php index bf63495d..e062e734 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Repository/EventSourcedRepositoryTest.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Repository/EventSourcedRepositoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\AggregateRoot\Repository; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; use Streak\Domain\Event; @@ -25,20 +26,20 @@ */ class EventSourcedRepositoryTest extends TestCase { - private Domain\AggregateRoot\Factory $factory; - private Domain\EventStore $store; + private Domain\AggregateRoot\Factory|MockObject $factory; + private Domain\EventStore|MockObject $store; - private Infrastructure\Domain\AggregateRoot\Snapshotter $snapshotter; - private Infrastructure\Domain\UnitOfWork $uow; + private Infrastructure\Domain\AggregateRoot\Snapshotter|MockObject $snapshotter; + private Infrastructure\Domain\UnitOfWork|MockObject $uow; - private Domain\AggregateRoot $nonEventSourcedAggregateRoot; + private Domain\AggregateRoot|MockObject $nonEventSourcedAggregateRoot; - private Event\Sourced\AggregateRoot $aggregateRoot; - private Event\Sourced\AggregateRoot\Id $aggregateRootId; + private Event\Sourced\AggregateRoot|MockObject $aggregateRoot; + private Domain\AggregateRoot\Id|MockObject $aggregateRootId; private Domain\Event\Envelope $event1; - private Domain\Event\Stream $stream; + private Domain\Event\Stream|MockObject $stream; protected function setUp(): void { @@ -50,7 +51,7 @@ protected function setUp(): void $this->nonEventSourcedAggregateRoot = $this->getMockBuilder(Domain\AggregateRoot::class)->getMockForAbstractClass(); $this->aggregateRoot = $this->getMockBuilder(Event\Sourced\AggregateRoot::class)->getMockForAbstractClass(); - $this->aggregateRootId = $this->getMockBuilder(Event\Sourced\AggregateRoot\Id::class)->getMockForAbstractClass(); + $this->aggregateRootId = $this->getMockBuilder(Domain\AggregateRoot\Id::class)->getMockForAbstractClass(); $this->event1 = Event\Envelope::new($this->getMockBuilder(Domain\Event::class)->getMockForAbstractClass(), $this->aggregateRootId, 1); $this->stream = $this->getMockBuilder(Event\Stream::class)->getMockForAbstractClass(); diff --git a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/NullSnapshotterTest.php b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/NullSnapshotterTest.php index 22c2bca1..6df02949 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/NullSnapshotterTest.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/NullSnapshotterTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\AggregateRoot\Snapshotter; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; @@ -23,7 +24,7 @@ */ class NullSnapshotterTest extends TestCase { - private AggregateRoot $aggregate1; + private AggregateRoot|MockObject $aggregate1; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/SnapshottableAggregatesSnapshotterTest.php b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/SnapshottableAggregatesSnapshotterTest.php index 9c52ee70..37ddcbce 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/SnapshottableAggregatesSnapshotterTest.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/SnapshottableAggregatesSnapshotterTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\AggregateRoot\Snapshotter; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; use Streak\Infrastructure\Domain\AggregateRoot\Snapshotter; @@ -27,13 +28,13 @@ */ class SnapshottableAggregatesSnapshotterTest extends TestCase { - private Serializer $serializer; + private Serializer|MockObject $serializer; - private Snapshotter\Storage $storage; + private Snapshotter\Storage|MockObject $storage; - private AggregateRoot $nonSnapshottableAggregateRoot; + private AggregateRoot|MockObject $nonSnapshottableAggregateRoot; - private SnapshottableAggregateRoot $snapshottableAggregateRoot; + private SnapshottableAggregateRoot|MockObject $snapshottableAggregateRoot; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/Exception/SnapshotNotFoundTest.php b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/Exception/SnapshotNotFoundTest.php index 180bd2f8..9de1ae09 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/Exception/SnapshotNotFoundTest.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/Exception/SnapshotNotFoundTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage\Exception; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\AggregateRoot; @@ -23,9 +24,9 @@ */ class SnapshotNotFoundTest extends TestCase { - private AggregateRoot $aggregate; + private AggregateRoot|MockObject $aggregate; - private AggregateRoot\Id $aggregateId; + private AggregateRoot\Id|MockObject $aggregateId; protected function setUp(): void { @@ -37,7 +38,7 @@ public function testException(): void { $this->aggregate ->expects(self::atLeastOnce()) - ->method('aggregateRootId') + ->method('id') ->willReturn($this->aggregateId) ; $this->aggregateId diff --git a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/InMemoryTest.php b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/InMemoryTest.php index 2188239b..fa4ac6cb 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/InMemoryTest.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/InMemoryTest.php @@ -18,8 +18,9 @@ /** * @author Alan Gabriel Bem * + * @property InMemoryStorage $storage + * * @covers \Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage\InMemoryStorage - * @covers \Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage\TestCase */ class InMemoryTest extends TestCase { diff --git a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorageTest.php b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorageTest.php index 27549ce4..055f1311 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorageTest.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/PostgresStorageTest.php @@ -15,7 +15,6 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; -use Streak\Domain; use Streak\Domain\AggregateRoot; use Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage\Exception\SnapshotNotFound; @@ -115,20 +114,20 @@ public function testItFinds(): void ]); $snapshot = $this->storage->find($this->createAggregateRootStub($id)); - self::assertEquals('snapshot', $snapshot); + self::assertSame('snapshot', $snapshot); } public function testItDoesntFindWhenTableDoesNotExists(): void { $this->givenSnapshotsTableDoesNotExists(); - self::expectException(SnapshotNotFound::class); + $this->expectException(SnapshotNotFound::class); $this->storage->find($this->createAggregateRootStub('3e7c8ffa-6bc6-4070-a6b5-30f9ae1c06fe')); } public function testItDoesntFindWhenRowDoesNotExist(): void { $this->givenSnapshotsTableExists(); - self::expectException(SnapshotNotFound::class); + $this->expectException(SnapshotNotFound::class); $this->storage->find($this->createAggregateRootStub('3e7c8ffa-6bc6-4070-a6b5-30f9ae1c06fe')); } @@ -169,18 +168,12 @@ private function createAggregateRootStub(string $id): AggregateRoot } } -class IdStub implements AggregateRoot\Id +final class IdStub implements AggregateRoot\Id { - private string $id; - - /** - * IdMock constructor. - * - * @param $id - */ - public function __construct(string $id) - { - $this->id = $id; + public function __construct( + /** @var non-empty-string $id */ + private string $id + ) { } public function equals(object $object): bool @@ -193,7 +186,7 @@ public function toString(): string return $this->id; } - public static function fromString(string $id): Domain\Id + public static function fromString(string $id): static { return new self($id); } diff --git a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisTest.php b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisStorageTest.php similarity index 72% rename from tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisTest.php rename to tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisStorageTest.php index fe36e8e6..f66a8837 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisTest.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/RedisStorageTest.php @@ -19,10 +19,11 @@ /** * @author Alan Gabriel Bem * + * @property RedisStorage $storage + * * @covers \Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage\RedisStorage - * @covers \Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage\TestCase */ -class RedisTest extends Storage\TestCase +class RedisStorageTest extends Storage\TestCase { public function testResetting(): void { @@ -39,12 +40,27 @@ public function testResetting(): void $this->storage->find($this->aggregate1); } + public function testRedisInMultiMode(): void + { + $redis = $this->newRedis(); + $storage = new RedisStorage($redis->multi()); + + $this->expectExceptionObject(new SnapshotNotFound($this->aggregate1)); + + $storage->find($this->aggregate1); + } + protected function newStorage(): Storage + { + return new RedisStorage($this->newRedis()); + } + + private function newRedis(): \Redis { $redis = new \Redis(); $redis->connect($_ENV['PHPUNIT_REDIS_HOSTNAME'], (int) $_ENV['PHPUNIT_REDIS_PORT']); $redis->select((int) $_ENV['PHPUNIT_REDIS_DATABASE']); - return new RedisStorage($redis); + return $redis; } } diff --git a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/TestCase.php b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/TestCase.php index 24bd051b..019b7f5b 100644 --- a/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/TestCase.php +++ b/tests/Infrastructure/Domain/AggregateRoot/Snapshotter/Storage/TestCase.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage; +use PHPUnit\Framework\MockObject\MockObject; use Streak\Domain\AggregateRoot; use Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage; use Streak\Infrastructure\Domain\AggregateRoot\Snapshotter\Storage\Exception\SnapshotNotFound; @@ -22,15 +23,11 @@ */ abstract class TestCase extends \PHPUnit\Framework\TestCase { - protected ?Storage $storage = null; - - protected ?AggregateRoot $aggregate1 = null; - - protected ?AggregateRoot\Id $aggregateId1 = null; - - protected ?AggregateRoot $aggregate2 = null; - - protected ?AggregateRoot\Id $aggregateId2 = null; + protected Storage $storage; + protected AggregateRoot|MockObject $aggregate1; + protected AggregateRoot\Id $aggregateId1; + protected AggregateRoot|MockObject $aggregate2; + protected AggregateRoot\Id $aggregateId2; protected function setUp(): void { @@ -38,11 +35,11 @@ protected function setUp(): void $this->aggregateId1 = new Storage\StorageTestCase\ExtendedUUID1('9bf583d5-d4ff-4cf3-bc53-8ffb6be0c67b'); $this->aggregate1 = $this->getMockBuilder(AggregateRoot::class)->setMockClassName('streak__aggregate_1')->getMockForAbstractClass(); - $this->aggregate1->method('aggregateRootId')->with()->willReturn($this->aggregateId1); + $this->aggregate1->method('id')->with()->willReturn($this->aggregateId1); $this->aggregateId2 = new Storage\StorageTestCase\ExtendedUUID2('d61546c6-cc51-4584-90f8-34203fd79b41'); $this->aggregate2 = $this->getMockBuilder(AggregateRoot::class)->setMockClassName('streak__aggregate_2')->getMockForAbstractClass(); - $this->aggregate2->method('aggregateRootId')->with()->willReturn($this->aggregateId2); + $this->aggregate2->method('id')->with()->willReturn($this->aggregateId2); } public function testObject(): void diff --git a/tests/Infrastructure/Domain/Event/Converter/CompositeConverterTest.php b/tests/Infrastructure/Domain/Event/Converter/CompositeConverterTest.php index e7fca763..9b561727 100644 --- a/tests/Infrastructure/Domain/Event/Converter/CompositeConverterTest.php +++ b/tests/Infrastructure/Domain/Event/Converter/CompositeConverterTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Converter; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; @@ -23,11 +24,11 @@ */ class CompositeConverterTest extends TestCase { - private Event\Converter $converter1; - private Event\Converter $converter2; - private Event\Converter $converter3; + private Event\Converter|MockObject $converter1; + private Event\Converter|MockObject $converter2; + private Event\Converter|MockObject $converter3; - private Event $message; + private Event|MockObject $message; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php b/tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php index 0582a35c..9997b831 100644 --- a/tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php +++ b/tests/Infrastructure/Domain/Event/Converter/NestedObjectConverterTest.php @@ -14,7 +14,6 @@ namespace Streak\Infrastructure\Domain\Event\Converter; use PHPUnit\Framework\TestCase; -use Streak\Domain; use Streak\Domain\Event; /** @@ -177,7 +176,7 @@ public function testNestedArrayToObject(): void public function testItDoesntConvertWrongNestedType(): void { - self::expectException(Event\Exception\ConversionToArrayNotPossible::class); + $this->expectException(Event\Exception\ConversionToArrayNotPossible::class); $converter = new NestedObjectConverter(); $converter->objectToArray(new NestedResource(tmpfile())); } @@ -185,147 +184,75 @@ public function testItDoesntConvertWrongNestedType(): void class NestedResource { - /** - * @var resource - */ - private $resource; - /** * @param resource $resource */ - public function __construct($resource) + public function __construct(private $resource) { - $this->resource = $resource; } } class Event1Stub implements Event { - public string $publicStringProperty; - public int $publicIntegerProperty; - public float $publicFloatProperty; - public array $publicArrayProperty; - public $publicAnyTypeProperty; public array $publicEmptyArrayProperty; - protected string $protectedStringProperty; - protected int $protectedIntegerProperty; - protected float $protectedFloatProperty; - protected array $protectedArrayProperty; - protected $protectedAnyTypeProperty; protected array $protectedEmptyArrayProperty; - private string $privateStringProperty; - private int $privateIntegerProperty; - private float $privateFloatProperty; - private array $privateArrayProperty; - private $privateAnyTypeProperty; private array $privateEmptyArrayProperty; public function __construct( - string $privateStringProperty, - string $publicStringProperty, - string $protectedStringProperty, - int $privateIntegerProperty, - int $publicIntegerProperty, - int $protectedIntegerProperty, - float $privateFloatProperty, - float $publicFloatProperty, - float $protectedFloatProperty, - array $privateArrayProperty, - array $publicArrayProperty, - array $protectedArrayProperty, - $privateAnyTypeProperty, - $publicAnyTypeProperty, - $protectedAnyTypeProperty + private string $privateStringProperty, + public string $publicStringProperty, + protected string $protectedStringProperty, + private int $privateIntegerProperty, + public int $publicIntegerProperty, + protected int $protectedIntegerProperty, + private float $privateFloatProperty, + public float $publicFloatProperty, + protected float $protectedFloatProperty, + private array $privateArrayProperty, + public array $publicArrayProperty, + protected array $protectedArrayProperty, + private $privateAnyTypeProperty, + public $publicAnyTypeProperty, + protected $protectedAnyTypeProperty ) { - $this->privateStringProperty = $privateStringProperty; - $this->publicStringProperty = $publicStringProperty; - $this->protectedStringProperty = $protectedStringProperty; - - $this->privateIntegerProperty = $privateIntegerProperty; - $this->publicIntegerProperty = $publicIntegerProperty; - $this->protectedIntegerProperty = $protectedIntegerProperty; - - $this->privateFloatProperty = $privateFloatProperty; - $this->publicFloatProperty = $publicFloatProperty; - $this->protectedFloatProperty = $protectedFloatProperty; - - $this->privateArrayProperty = $privateArrayProperty; - $this->publicArrayProperty = $publicArrayProperty; - $this->protectedArrayProperty = $protectedArrayProperty; - - $this->privateAnyTypeProperty = $privateAnyTypeProperty; - $this->publicAnyTypeProperty = $publicAnyTypeProperty; - $this->protectedAnyTypeProperty = $protectedAnyTypeProperty; - $this->privateEmptyArrayProperty = []; $this->publicEmptyArrayProperty = []; $this->protectedEmptyArrayProperty = []; } - - public function producerId(): Domain\Id - { - } } class EventA implements Event { - private string $property1; - - public function __construct(string $property1) + public function __construct(private string $property1) { - $this->property1 = $property1; } } class EventB extends EventA { - private $property2; - - public function __construct($property1, $property2) + public function __construct($property1, private $property2) { parent::__construct($property1); - $this->property2 = $property2; } } class EventC implements Event { - private Event $event; - - public function __construct(Event $event) + public function __construct(private Event $event) { - $this->event = $event; } } class ParentObject { - private object $objectProperty; - - private string $scalarProperty; - - private array $arrayProperty; - - public function __construct(string $scalarProperty, object $objectProperty, array $arrayProperty) + public function __construct(private string $scalarProperty, private object $objectProperty, private array $arrayProperty) { - $this->objectProperty = $objectProperty; - $this->scalarProperty = $scalarProperty; - $this->arrayProperty = $arrayProperty; } } class ChildObject { - private string $scalarProperty; - - private array $arrayProperty; - - private ?self $child; - - public function __construct(string $scalarProperty, array $arrayProperty, self $childObject = null) + public function __construct(private string $scalarProperty, private array $arrayProperty, private ?self $child = null) { - $this->scalarProperty = $scalarProperty; - $this->arrayProperty = $arrayProperty; - $this->child = $childObject; } } diff --git a/tests/Infrastructure/Domain/Event/Envelope/ComparatorTest.php b/tests/Infrastructure/Domain/Event/Envelope/ComparatorTest.php index eeb15f37..c8822201 100644 --- a/tests/Infrastructure/Domain/Event/Envelope/ComparatorTest.php +++ b/tests/Infrastructure/Domain/Event/Envelope/ComparatorTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Envelope; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use SebastianBergmann\Comparator\ComparisonFailure; use SebastianBergmann\Comparator\Factory; @@ -26,15 +27,15 @@ */ class ComparatorTest extends TestCase { - private Factory $factory; + private Factory|MockObject $factory; private Comparator $comparator; - private Comparator $subcomparator; + private Comparator|MockObject $subcomparator; private UUID $uuid; - private Event $event1; - private Event $event2; + private Event|MockObject $event1; + private Event|MockObject $event2; private Event\Envelope $envelope1a; private Event\Envelope $envelope1b; @@ -49,8 +50,8 @@ protected function setUp(): void $this->uuid = UUID::random(); $this->event1 = $this->getMockBuilder(Event::class)->getMockForAbstractClass(); - $this->envelope1a = new Event\Envelope($this->uuid, 'name', $this->event1, UUID::random()); - $this->envelope1b = new Event\Envelope($this->uuid, 'name', $this->event1, UUID::random()); + $this->envelope1a = new Event\Envelope($this->uuid, 'name', $this->event1, UUID::random(), UUID::random()); + $this->envelope1b = new Event\Envelope($this->uuid, 'name', $this->event1, UUID::random(), UUID::random()); $this->event2 = $this->getMockBuilder(Event::class)->getMockForAbstractClass(); $this->envelope2 = Event\Envelope::new($this->event2, UUID::random()); } @@ -117,7 +118,15 @@ public function testAccepting($expected, $actual): void public function testEqualEnvelopes(): void { - self::assertNull($this->comparator->assertEquals($this->envelope1a, $this->envelope1b)); +// $this->expectNotToPerformAssertions(); + + try { + $this->comparator->assertEquals($this->envelope1a, $this->envelope1b); + } catch (ComparisonFailure) { + self::fail(); + } + + $this->addToAssertionCount(1); // tests without assertions does not report any coverage, so this is a hack @link https://github.com/sebastianbergmann/phpunit/pull/3348 } public function testNotEqualEnvelopes(): void diff --git a/tests/Infrastructure/Domain/Event/Event/CompositeFactoryTest.php b/tests/Infrastructure/Domain/Event/Event/CompositeFactoryTest.php index d6e5c03f..647883ca 100644 --- a/tests/Infrastructure/Domain/Event/Event/CompositeFactoryTest.php +++ b/tests/Infrastructure/Domain/Event/Event/CompositeFactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Event; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Event\Listener; @@ -27,13 +28,13 @@ */ class CompositeFactoryTest extends TestCase { - private Listener\Id $id1; + private Listener\Id|MockObject $id1; - private Listener\Factory $factory1; - private Listener\Factory $factory2; - private Listener\Factory $factory3; + private Listener\Factory|MockObject $factory1; + private Listener\Factory|MockObject $factory2; + private Listener\Factory|MockObject $factory3; - private Listener $listener1; + private Listener|MockObject $listener1; private Event\Envelope $event1; diff --git a/tests/Infrastructure/Domain/Event/LoggingListener/FactoryTest.php b/tests/Infrastructure/Domain/Event/LoggingListener/FactoryTest.php index 8a8699ee..8521db76 100644 --- a/tests/Infrastructure/Domain/Event/LoggingListener/FactoryTest.php +++ b/tests/Infrastructure/Domain/Event/LoggingListener/FactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\LoggingListener; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Streak\Domain\Event; @@ -26,13 +27,13 @@ */ class FactoryTest extends TestCase { - private Listener\Factory $factory; + private Listener\Factory|MockObject $factory; - private Listener $listener; + private Listener|MockObject $listener; - private LoggerInterface $logger; + private LoggerInterface|MockObject $logger; - private Listener\Id $id; + private Listener\Id|MockObject $id; private Event\Envelope $event; diff --git a/tests/Infrastructure/Domain/Event/LoggingListenerTest.php b/tests/Infrastructure/Domain/Event/LoggingListenerTest.php index d05347a5..99957aeb 100644 --- a/tests/Infrastructure/Domain/Event/LoggingListenerTest.php +++ b/tests/Infrastructure/Domain/Event/LoggingListenerTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Streak\Domain\Event; @@ -29,23 +30,23 @@ */ class LoggingListenerTest extends TestCase { - private Event\Listener $listener1; + private Event\Listener|MockObject $listener1; - private ListenerWithAllPossibleFeatures $listener2; + private ListenerWithAllPossibleFeatures|MockObject $listener2; - private LoggerInterface $logger; + private LoggerInterface|MockObject $logger; - private Listener\Id $listenerId; + private Listener\Id|MockObject $listenerId; private Event\Envelope $event; - private Event\Stream $stream1; - private Event\Stream $stream2; + private Event\Stream|MockObject $stream1; + private Event\Stream|MockObject $stream2; - private Query $query; + private Query|MockObject $query; - private Listener\State $state1; - private Listener\State $state2; + private Listener\State|MockObject $state1; + private Listener\State|MockObject $state2; protected function setUp(): void { @@ -131,11 +132,11 @@ public function testObject(): void $this->listener2 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->listenerId) ; - self::assertSame($this->listenerId, $listener->listenerId()); + self::assertSame($this->listenerId, $listener->id()); self::assertSame($this->listenerId, $listener->id()); $listener->reset(); diff --git a/tests/Infrastructure/Domain/Event/NullListenerTest.php b/tests/Infrastructure/Domain/Event/NullListenerTest.php index 742b6807..9f2ca4f4 100644 --- a/tests/Infrastructure/Domain/Event/NullListenerTest.php +++ b/tests/Infrastructure/Domain/Event/NullListenerTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Id\UUID; @@ -24,9 +25,9 @@ */ class NullListenerTest extends TestCase { - private Event\Listener $listener; + private Event\Listener|MockObject $listener; - private Event\Listener\Id $id; + private Event\Listener\Id|MockObject $id; private Event\Envelope $event; @@ -41,14 +42,14 @@ public function testObject(): void { $this->listener ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id) ; $listener = NullListener::from($this->listener); self::assertInstanceOf(NullListener::class, $listener); - self::assertSame($this->id, $listener->listenerId()); + self::assertSame($this->id, $listener->id()); self::assertTrue($listener->on($this->event)); } diff --git a/tests/Infrastructure/Domain/Event/Sourced/Subscription/FactoryTest.php b/tests/Infrastructure/Domain/Event/Sourced/Subscription/FactoryTest.php index 57f32619..ce367d9d 100644 --- a/tests/Infrastructure/Domain/Event/Sourced/Subscription/FactoryTest.php +++ b/tests/Infrastructure/Domain/Event/Sourced/Subscription/FactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Sourced\Subscription; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Clock; use Streak\Domain\Event; @@ -24,9 +25,9 @@ */ class FactoryTest extends TestCase { - private Event\Listener $listener; + private Event\Listener|MockObject $listener; - private Clock $clock; + private Clock|MockObject $clock; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/Event/Sourced/Subscription/InMemoryStateTest.php b/tests/Infrastructure/Domain/Event/Sourced/Subscription/InMemoryStateTest.php index 537f0dc0..32da5bf8 100644 --- a/tests/Infrastructure/Domain/Event/Sourced/Subscription/InMemoryStateTest.php +++ b/tests/Infrastructure/Domain/Event/Sourced/Subscription/InMemoryStateTest.php @@ -30,7 +30,7 @@ class InMemoryStateTest extends TestCase protected function setUp(): void { - $this->stub = new class() implements State { + $this->stub = new class () implements State { public function equals(object $object): bool { throw new \BadMethodCallException('Do not call method State::equals() on this stub.'); diff --git a/tests/Infrastructure/Domain/Event/Sourced/SubscriptionTest.php b/tests/Infrastructure/Domain/Event/Sourced/SubscriptionTest.php index 5c2bcab6..ec31667f 100644 --- a/tests/Infrastructure/Domain/Event/Sourced/SubscriptionTest.php +++ b/tests/Infrastructure/Domain/Event/Sourced/SubscriptionTest.php @@ -13,11 +13,13 @@ namespace Streak\Infrastructure\Domain\Event\Sourced; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Clock; use Streak\Domain\Event; use Streak\Domain\Event\Listener; use Streak\Domain\EventStore; +use Streak\Domain\Exception\EventMismatched; use Streak\Domain\Id\UUID; use Streak\Infrastructure\Domain\Clock\FixedClock; use Streak\Infrastructure\Domain\Event\InMemoryStream; @@ -45,21 +47,21 @@ */ class SubscriptionTest extends TestCase { - private Listener $listener1; - private CompletableListener $listener3; - private ResettableListener $listener4; - private CompletableAndResettableListener $listener6; - private ResettableListenerThatCanPickStartingEvent $listener7; - private FilteringListener $listener8; - private StatefulListener $listener9; + private Listener|MockObject $listener1; + private CompletableListener|MockObject $listener3; + private ResettableListener|MockObject $listener4; + private CompletableAndResettableListener|MockObject $listener6; + private ResettableListenerThatCanPickStartingEvent|MockObject $listener7; + private FilteringListener|MockObject $listener8; + private StatefulListener|MockObject $listener9; private Listener\Id $id1; - private EventStore $store; + private EventStore|MockObject $store; - private Event\Stream $stream1; - private Event\Stream $stream2; - private Event\Stream $stream3; + private Event\Stream|MockObject $stream1; + private Event\Stream|MockObject $stream2; + private Event\Stream|MockObject $stream3; private Event\Envelope $event1; private Event\Envelope $event2; @@ -67,9 +69,9 @@ class SubscriptionTest extends TestCase private Event\Envelope $event4; private Event\Envelope $event5; - private Listener\State $state1; - private Listener\State $state2; - private Listener\State $state3; + private Listener\State|MockObject $state1; + private Listener\State|MockObject $state2; + private Listener\State|MockObject $state3; private Clock $clock; @@ -83,7 +85,7 @@ protected function setUp(): void $this->listener8 = $this->getMockBuilder(FilteringListener::class)->getMock(); $this->listener9 = $this->getMockBuilder(StatefulListener::class)->getMock(); - $this->id1 = new class('f5e65690-e50d-4312-a175-b004ec1bd42a') extends UUID implements Listener\Id { + $this->id1 = new class ('f5e65690-e50d-4312-a175-b004ec1bd42a') extends UUID implements Listener\Id { }; $this->store = $this->getMockBuilder(EventStore::class)->getMockForAbstractClass(); @@ -111,7 +113,7 @@ public function testListener(): void $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -122,9 +124,7 @@ public function testListener(): void $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -135,9 +135,7 @@ public function testListener(): void $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); @@ -146,9 +144,7 @@ public function testListener(): void $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -295,7 +291,7 @@ public function testListenerWithPicker(): void $this->listener7 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener7 @@ -310,18 +306,14 @@ public function testListenerWithPicker(): void $subscription = new Subscription($this->listener7, $this->clock); self::assertSame($subscription->listener(), $this->listener7); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event3); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event3, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event3, $now)], $subscription->events()); @@ -399,28 +391,25 @@ public function testListenerWithFilterer(): void $this->listener8 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener8, $this->clock); self::assertSame($subscription->listener(), $this->listener8); - self::assertNull($subscription->lastReplayed()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event2); - self::assertNull($subscription->lastReplayed()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event2, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event2, $now)], $subscription->events()); $subscription->commit(); - self::assertNull($subscription->lastReplayed()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event2, $now), $subscription->lastEvent()); self::assertEmpty($subscription->events()); @@ -489,7 +478,7 @@ public function testTransactionalListenerWithoutReplaying(): void $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -500,27 +489,21 @@ public function testTransactionalListenerWithoutReplaying(): void $subscription = new Subscription($this->listener3, $this->clock); self::assertSame($subscription->listener(), $this->listener3); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -612,7 +595,7 @@ public function testReplayingListener(): void $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -623,9 +606,7 @@ public function testReplayingListener(): void $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -641,9 +622,7 @@ public function testReplayingListener(): void $subscription->replay($this->stream1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertSame($event2, $subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(3, $subscription->version()); self::assertEquals($event2, $subscription->lastEvent()); self::assertEmpty($subscription->events()); @@ -706,7 +685,7 @@ public function testReplayingStatefulListenerWithExistingState(): void $this->listener9 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; @@ -714,7 +693,6 @@ public function testReplayingStatefulListenerWithExistingState(): void $subscription = new Subscription($this->listener9, $this->clock); self::assertSame($subscription->listener(), $this->listener9); - self::assertNull($subscription->lastReplayed()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -741,7 +719,6 @@ public function testReplayingStatefulListenerWithExistingState(): void $subscription->replay($this->stream1); - self::assertSame($event3, $subscription->lastReplayed()); self::assertSame(4, $subscription->version()); self::assertEquals($event3, $subscription->lastEvent()); self::assertEmpty($subscription->events()); @@ -813,14 +790,13 @@ public function testReplayingStatefulListenerWithoutExistingState(): void $this->listener9 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; $subscription = new Subscription($this->listener9, $this->clock); self::assertSame($subscription->listener(), $this->listener9); - self::assertNull($subscription->lastReplayed()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -836,7 +812,6 @@ public function testReplayingStatefulListenerWithoutExistingState(): void $subscription->replay($this->stream1); - self::assertSame($event2, $subscription->lastReplayed()); self::assertSame(3, $subscription->version()); self::assertEquals($event2, $subscription->lastEvent()); self::assertEmpty($subscription->events()); @@ -914,7 +889,7 @@ public function testReplayingListenerWithAnEmptyStream(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -925,9 +900,7 @@ public function testReplayingListenerWithAnEmptyStream(): void $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -937,9 +910,7 @@ public function testReplayingListenerWithAnEmptyStream(): void $subscription->replay($this->stream1); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -951,7 +922,7 @@ public function testCompletingListener(): void $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; @@ -960,7 +931,6 @@ public function testCompletingListener(): void self::assertSame($subscription->listener(), $this->listener3); self::assertFalse($subscription->completed()); - self::assertNull($subscription->lastReplayed()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -973,7 +943,6 @@ public function testCompletingListener(): void $subscription->replay($this->stream1); - self::assertSame($event0, $subscription->lastReplayed()); self::assertSame($event0, $subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(1, $subscription->version()); @@ -1017,7 +986,6 @@ public function testCompletingListener(): void self::assertEquals([$this->event1, $this->event2], $events); self::assertTrue($subscription->completed()); self::assertEquals([new SubscriptionListenedToEvent($this->event1, $now), new SubscriptionListenedToEvent($this->event2, $now), new SubscriptionCompleted($now)], $subscription->events()); - self::assertSame($event0, $subscription->lastReplayed()); self::assertEquals(new SubscriptionCompleted($now), $subscription->lastEvent()); self::assertSame(1, $subscription->version()); self::assertFalse($subscription->paused()); @@ -1026,7 +994,6 @@ public function testCompletingListener(): void self::assertTrue($subscription->completed()); self::assertEmpty($subscription->events()); - self::assertSame($event0, $subscription->lastReplayed()); self::assertEquals(new SubscriptionCompleted($now), $subscription->lastEvent()); self::assertSame(4, $subscription->version()); self::assertFalse($subscription->paused()); @@ -1035,7 +1002,6 @@ public function testCompletingListener(): void self::assertTrue($subscription->completed()); self::assertEmpty($subscription->events()); - self::assertSame($event0, $subscription->lastReplayed()); self::assertEquals(new SubscriptionCompleted($now), $subscription->lastEvent()); self::assertSame(4, $subscription->version()); self::assertFalse($subscription->paused()); @@ -1044,7 +1010,6 @@ public function testCompletingListener(): void self::assertTrue($subscription->completed()); self::assertEmpty($subscription->events()); - self::assertSame($event0, $subscription->lastReplayed()); self::assertEquals(new SubscriptionCompleted($now), $subscription->lastEvent()); self::assertSame(4, $subscription->version()); self::assertFalse($subscription->paused()); @@ -1053,7 +1018,6 @@ public function testCompletingListener(): void self::assertTrue($subscription->completed()); self::assertEmpty($subscription->events()); - self::assertSame($event0, $subscription->lastReplayed()); self::assertEquals(new SubscriptionCompleted($now), $subscription->lastEvent()); self::assertSame(4, $subscription->version()); self::assertFalse($subscription->paused()); @@ -1062,7 +1026,6 @@ public function testCompletingListener(): void self::assertTrue($subscription->completed()); self::assertEmpty($subscription->events()); - self::assertSame($event0, $subscription->lastReplayed()); self::assertEquals(new SubscriptionCompleted($now), $subscription->lastEvent()); self::assertSame(4, $subscription->version()); self::assertFalse($subscription->paused()); @@ -1078,16 +1041,14 @@ public function testStartingAlreadyStartedSubscription(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); @@ -1104,7 +1065,7 @@ public function testSubscribingAlreadyCompletedListener(): void $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; @@ -1126,7 +1087,6 @@ public function testSubscribingAlreadyCompletedListener(): void $subscription->replay($this->stream1); self::assertTrue($subscription->completed()); - self::assertSame($event2, $subscription->lastReplayed()); self::assertSame($event2, $subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(3, $subscription->version()); @@ -1149,7 +1109,7 @@ public function testSubscribingRestartedAndCompletedListener(): void $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; @@ -1177,7 +1137,6 @@ public function testSubscribingRestartedAndCompletedListener(): void $subscription->replay($this->stream1); self::assertTrue($subscription->completed()); - self::assertSame($event5, $subscription->lastReplayed()); self::assertSame($event5, $subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(6, $subscription->version()); @@ -1198,16 +1157,14 @@ public function testNotStartedListener(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); @@ -1232,7 +1189,7 @@ public function testRestartingSubscriptionForResettableButNonReplayableListener( { $this->listener4 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; @@ -1240,7 +1197,6 @@ public function testRestartingSubscriptionForResettableButNonReplayableListener( $subscription = new Subscription($this->listener4, $this->clock); self::assertSame($subscription->listener(), $this->listener4); - self::assertNull($subscription->lastReplayed()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -1259,21 +1215,18 @@ public function testRestartingSubscriptionForResettableButNonReplayableListener( $subscription->replay($this->stream1); - self::assertSame($event3, $subscription->lastReplayed()); self::assertSame($event3, $subscription->lastEvent()); self::assertSame([], $subscription->events()); self::assertSame(4, $subscription->version()); $subscription->restart(); - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionRestarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionRestarted($this->event1, $now)], $subscription->events()); self::assertSame(4, $subscription->version()); $subscription->commit(); - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionRestarted($this->event1, $now), $subscription->lastEvent()); self::assertSame([], $subscription->events()); self::assertSame(5, $subscription->version()); @@ -1281,7 +1234,6 @@ public function testRestartingSubscriptionForResettableButNonReplayableListener( $subscription->restart(); // nothing changed as consecutive restarts are ignored - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionRestarted($this->event1, $now), $subscription->lastEvent()); self::assertSame([], $subscription->events()); self::assertSame(5, $subscription->version()); @@ -1319,14 +1271,12 @@ public function testRestartingSubscriptionForResettableButNonReplayableListener( $events = iterator_to_array($events); self::assertSame([$this->event1, $this->event3, $this->event4, $this->event5], $events); - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionListenedToEvent($this->event5, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionListenedToEvent($this->event1, $now), new SubscriptionListenedToEvent($this->event3, $now), new SubscriptionIgnoredEvent($this->event4, $now), new SubscriptionListenedToEvent($this->event5, $now)], $subscription->events()); self::assertSame(5, $subscription->version()); $subscription->commit(); - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionListenedToEvent($this->event5, $now), $subscription->lastEvent()); self::assertSame([], $subscription->events()); self::assertSame(9, $subscription->version()); @@ -1336,16 +1286,14 @@ public function testRestartingNotStartedSubscription(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); @@ -1358,7 +1306,7 @@ public function testRestartingCompletedSubscription(): void { $this->listener6 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; @@ -1366,7 +1314,6 @@ public function testRestartingCompletedSubscription(): void $subscription = new Subscription($this->listener6, $this->clock); self::assertSame($subscription->listener(), $this->listener6); - self::assertNull($subscription->lastReplayed()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -1403,7 +1350,6 @@ public function testRestartingCompletedSubscription(): void $subscription->replay($this->stream1); - self::assertSame($event3, $subscription->lastReplayed()); self::assertSame($event3, $subscription->lastEvent()); self::assertSame([], $subscription->events()); self::assertSame(4, $subscription->version()); @@ -1411,7 +1357,6 @@ public function testRestartingCompletedSubscription(): void $subscription->restart(); - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionRestarted($this->event2, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionRestarted($this->event2, $now)], $subscription->events()); self::assertSame(4, $subscription->version()); @@ -1419,7 +1364,6 @@ public function testRestartingCompletedSubscription(): void $subscription->commit(); - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionRestarted($this->event2, $now), $subscription->lastEvent()); self::assertSame([], $subscription->events()); self::assertSame(5, $subscription->version()); @@ -1453,7 +1397,6 @@ public function testRestartingCompletedSubscription(): void $events = iterator_to_array($events); self::assertSame([$this->event2, $this->event3, $this->event4, $this->event5], $events); - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionListenedToEvent($this->event5, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionListenedToEvent($this->event2, $now), new SubscriptionListenedToEvent($this->event3, $now), new SubscriptionListenedToEvent($this->event4, $now), new SubscriptionListenedToEvent($this->event5, $now)], $subscription->events()); self::assertSame(5, $subscription->version()); @@ -1461,7 +1404,6 @@ public function testRestartingCompletedSubscription(): void $subscription->commit(); - self::assertSame($event3, $subscription->lastReplayed()); self::assertEquals(new SubscriptionListenedToEvent($this->event5, $now), $subscription->lastEvent()); self::assertSame([], $subscription->events()); self::assertSame(9, $subscription->version()); @@ -1472,7 +1414,7 @@ public function testRestartingNonResettableListener(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; @@ -1481,7 +1423,6 @@ public function testRestartingNonResettableListener(): void self::assertSame($subscription->listener(), $this->listener1); self::assertFalse($subscription->completed()); - self::assertNull($subscription->lastReplayed()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); @@ -1499,7 +1440,6 @@ public function testRestartingNonResettableListener(): void $subscription->replay($this->stream1); - self::assertSame($event2, $subscription->lastReplayed()); self::assertSame($event2, $subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(3, $subscription->version()); @@ -1528,13 +1468,13 @@ public function testEquals(): void $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($id1) ; $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($id2) ; @@ -1563,33 +1503,28 @@ public function testStartingSubscriptionWithResettableListenerWithFirstEventIgno $this->listener4 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener4, $this->clock); self::assertSame($subscription->listener(), $this->listener4); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); + self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -1633,33 +1568,27 @@ public function testStartingSubscriptionWithResettableListenerWithFirstEventNotI $this->listener4 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener4, $this->clock); self::assertSame($subscription->listener(), $this->listener4); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -1703,33 +1632,27 @@ public function testRestartingFreshlyStartedSubscription(): void $this->listener4 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener4, $this->clock); self::assertSame($subscription->listener(), $this->listener4); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -1737,9 +1660,7 @@ public function testRestartingFreshlyStartedSubscription(): void $subscription->restart(); // nothing changed as consecutive restarts are ignored - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -1766,6 +1687,7 @@ public function testNonPositiveLimitGivenWhileSubscribingToTheEventStoreBeforeSt $this->expectExceptionObject(new \InvalidArgumentException('$limit must be a positive integer, but 0 was given.')); $events = $subscription->subscribeTo($this->store, 0); + $events = new \IteratorIterator($events); $events->rewind(); } @@ -1773,7 +1695,7 @@ public function testNonPositiveLimitGivenWhileSubscribingToTheEventStoreAfterSta { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; @@ -1799,6 +1721,7 @@ public function testNonPositiveLimitGivenWhileSubscribingToTheEventStoreAfterSta $this->expectExceptionObject(new \InvalidArgumentException('$limit must be a positive integer, but -1 was given.')); $events = $subscription->subscribeTo($this->store, -1); + $events = new \IteratorIterator($events); $events->rewind(); } @@ -1808,7 +1731,7 @@ public function testContinuousListeningWithNumberOfEventsBeingExactlyImposedLimi $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -1819,27 +1742,21 @@ public function testContinuousListeningWithNumberOfEventsBeingExactlyImposedLimi $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -1900,7 +1817,7 @@ public function testContinuousListeningWithNumberOfEventsBeingMoreThanImposedLim $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -1911,27 +1828,21 @@ public function testContinuousListeningWithNumberOfEventsBeingMoreThanImposedLim $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -1988,7 +1899,7 @@ public function testContinuousListeningWithNumberOfEventsBeingMoreThanImposedLim $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -1999,27 +1910,21 @@ public function testContinuousListeningWithNumberOfEventsBeingMoreThanImposedLim $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -2076,7 +1981,7 @@ public function testContinuousListeningWithNumberOfEventsBeingLessThanImposedLim $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -2087,27 +1992,21 @@ public function testContinuousListeningWithNumberOfEventsBeingLessThanImposedLim $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -2168,34 +2067,28 @@ public function testCompletingListenerWhileContinuousListening(): void $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener3, $this->clock); self::assertSame($subscription->listener(), $this->listener3); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertNull($subscription->lastEvent()); self::assertEmpty($subscription->events()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([new SubscriptionStarted($this->event1, $now)], $subscription->events()); $subscription->commit(); - self::assertSame($this->id1, $subscription->subscriptionId()); - self::assertSame($this->id1, $subscription->producerId()); - self::assertNull($subscription->lastReplayed()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertEquals(new SubscriptionStarted($this->event1, $now), $subscription->lastEvent()); self::assertEquals([], $subscription->events()); @@ -2256,6 +2149,51 @@ public function testCompletingListenerWhileContinuousListening(): void self::assertEquals([], $subscription->events()); self::assertSame(7, $subscription->version()); } + + public function testReplayingMismatchedEvent(): void + { + $now = new \DateTime('2018-09-28 19:12:32.763188 +00:00'); + + $this->listener1 + ->expects(self::atLeastOnce()) + ->method('id') + ->willReturn($this->id1) + ; + $this->listener1 + ->expects(self::never()) + ->method('replay') + ; + + $subscription = new Subscription($this->listener1, $this->clock); + + self::assertSame($subscription->listener(), $this->listener1); + self::assertSame($this->id1, $subscription->id()); + self::assertNull($subscription->lastEvent()); + self::assertEmpty($subscription->events()); + self::assertSame(0, $subscription->version()); + + $event0 = new SubscriptionStarted($this->event1, $now); + $event0 = Event\Envelope::new($event0, $this->id1, 1); + $event1 = new SubscriptionListenedToEvent($this->event1, $now); + $event1 = Event\Envelope::new($event1, $this->id1, 2); + $event2 = new SubscriptionListenedToEvent($this->event2, $now); + $event2 = Event\Envelope::new($event2, UUID::random(), 3); + + $this->stream1 = new InMemoryStream($event0, $event1, $event2); + + try { + $subscription->replay($this->stream1); + self::fail(); + } catch (EventMismatched $exception) { + self::assertSame($event2, $exception->event()); + self::assertSame($subscription, $exception->object()); + + self::assertSame($this->id1, $subscription->id()); + self::assertSame(1, $subscription->version()); + self::assertEquals($event0, $subscription->lastEvent()); + self::assertEmpty($subscription->events()); + } + } } namespace Streak\Infrastructure\Domain\Event\Sourced\SubscriptionTest; @@ -2290,3 +2228,7 @@ abstract class StatefulListener implements Listener, Listener\Stateful abstract class IterableStream implements Event\Stream, \IteratorAggregate { } + +class UnsupportedEvent implements Event +{ +} diff --git a/tests/Infrastructure/Domain/Event/SubscriberTest.php b/tests/Infrastructure/Domain/Event/SubscriberTest.php index af3ccb8e..cd3ac5d4 100644 --- a/tests/Infrastructure/Domain/Event/SubscriberTest.php +++ b/tests/Infrastructure/Domain/Event/SubscriberTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Event\Exception; @@ -29,17 +30,17 @@ */ class SubscriberTest extends TestCase { - private EventBus $bus; + private EventBus|MockObject $bus; - private Event\Listener\Factory $listenerFactory; + private Event\Listener\Factory|MockObject $listenerFactory; - private Event\Subscription\Factory $subscriptionFactory; + private Event\Subscription\Factory|MockObject $subscriptionFactory; - private Event\Subscription\Repository $subscriptionsRepository; + private Event\Subscription\Repository|MockObject $subscriptionsRepository; - private Event\Listener $listener1; + private Event\Listener|MockObject $listener1; - private Event\Subscription $subscription1; + private Event\Subscription|MockObject $subscription1; private Event\Envelope $event1; diff --git a/tests/Infrastructure/Domain/Event/Subscription/CommittingSubscription/FactoryTest.php b/tests/Infrastructure/Domain/Event/Subscription/CommittingSubscription/FactoryTest.php index 9fc742c7..155c1c52 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/CommittingSubscription/FactoryTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/CommittingSubscription/FactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription\CommittingSubscription; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Clock; use Streak\Domain\Event; @@ -27,11 +28,11 @@ */ class FactoryTest extends TestCase { - private Event\Listener $listener; + private Event\Listener|MockObject $listener; - private Clock $clock; + private Clock|MockObject $clock; - private UnitOfWork $uow; + private UnitOfWork|MockObject $uow; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/Event/Subscription/CommittingSubscriptionTest.php b/tests/Infrastructure/Domain/Event/Subscription/CommittingSubscriptionTest.php index 8fc294af..7f73212f 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/CommittingSubscriptionTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/CommittingSubscriptionTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Event\Listener; @@ -27,23 +28,23 @@ */ class CommittingSubscriptionTest extends TestCase { - private Event\Subscription $subscription; + private Event\Subscription|MockObject $subscription; - private Listener $listener; + private Listener|MockObject $listener; private Listener\Id $id1; - private EventStore $store; + private EventStore|MockObject $store; private Event\Envelope $event1; - private UnitOfWork $uow; + private UnitOfWork|MockObject $uow; protected function setUp(): void { $this->listener = $this->getMockBuilder(Listener::class)->addMethods(['replay', 'reset', 'completed'])->getMockForAbstractClass(); - $this->id1 = new class('f5e65690-e50d-4312-a175-b004ec1bd42a') extends UUID implements Listener\Id { + $this->id1 = new class ('f5e65690-e50d-4312-a175-b004ec1bd42a') extends UUID implements Listener\Id { }; $this->store = $this->getMockBuilder(EventStore::class)->getMockForAbstractClass(); @@ -68,7 +69,7 @@ public function testListener(): void ; $this->subscription ->expects(self::atLeastOnce()) - ->method('subscriptionId') + ->method('id') ->willReturn($this->id1) ; $this->subscription @@ -98,7 +99,7 @@ public function testListener(): void ; self::assertSame($this->listener, $subscription->listener()); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(\PHP_INT_MAX, $subscription->version()); self::assertTrue($subscription->starting()); self::assertFalse($subscription->starting()); diff --git a/tests/Infrastructure/Domain/Event/Subscription/DAO/DAORepositoryTest.php b/tests/Infrastructure/Domain/Event/Subscription/DAO/DAORepositoryTest.php index 55b0e4f5..e2a6f53f 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DAO/DAORepositoryTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DAO/DAORepositoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription\DAO; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event\Listener\Id; use Streak\Domain\Event\Subscription; @@ -27,9 +28,9 @@ class DAORepositoryTest extends TestCase { private DAORepository $daoRepository; - private DAO $dao; + private DAO|MockObject $dao; - private UnitOfWork $uow; + private UnitOfWork|MockObject $uow; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/Event/Subscription/DAO/DAOTestCase.php b/tests/Infrastructure/Domain/Event/Subscription/DAO/DAOTestCase.php index a5eb61a7..70c6c944 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DAO/DAOTestCase.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DAO/DAOTestCase.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription\DAO; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Id\UUID; @@ -30,24 +31,24 @@ abstract class DAOTestCase extends TestCase { protected ?DAO $dao = null; - protected Event\Subscription\Factory $subscriptions; + protected Event\Subscription\Factory|MockObject $subscriptions; - protected Event\Listener\Factory $listeners; + protected Event\Listener\Factory|MockObject $listeners; - protected Event\Listener $listener1; + protected Event\Listener|MockObject $listener1; - protected Event\Listener $listener2; + protected Event\Listener|MockObject $listener2; protected ?Event\Envelope $event = null; - protected ?FixedClock $clock = null; + protected FixedClock|MockObject $clock; protected function setUp(): void { $this->subscriptions = $this->getMockBuilder(Event\Subscription\Factory::class)->getMockForAbstractClass(); $this->listeners = $this->getMockBuilder(Event\Listener\Factory::class)->getMockForAbstractClass(); - $this->listener1 = $this->getMockBuilder(CompletableListener::class)->setMockClassName('listener1')->getMock(); - $this->listener2 = $this->getMockBuilder(CompletableListener::class)->setMockClassName('listener2')->getMock(); + $this->listener1 = $this->getMockBuilder(CompletableListener::class)->setMockClassName('listener1_sydteu')->getMockForAbstractClass(); + $this->listener2 = $this->getMockBuilder(CompletableListener::class)->setMockClassName('listener2_dhafg6')->getMockForAbstractClass(); $this->event = Event\Envelope::new(new EventStub(), UUID::random()); $this->clock = new FixedClock(new \DateTime('2018-09-28 19:12:32.763188 +00:00')); $this->dao = $this->newDAO(new Subscription\Factory($this->clock), $this->listeners); @@ -70,22 +71,23 @@ public function testDAO(): void $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($listenerId1) ; $this->listener2 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($listenerId2) ; $this->listener1 + ->expects(self::atLeastOnce()) ->method('completed') ->willReturnOnConsecutiveCalls(false, true) ; $this->listener2 + ->expects(self::never()) ->method('completed') - ->willReturnOnConsecutiveCalls(false, false) ; $all = $this->dao->all(); diff --git a/tests/Infrastructure/Domain/Event/Subscription/DAO/DbalPostgresDAOTest.php b/tests/Infrastructure/Domain/Event/Subscription/DAO/DbalPostgresDAOTest.php index 44385979..4b561c72 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DAO/DbalPostgresDAOTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DAO/DbalPostgresDAOTest.php @@ -22,6 +22,8 @@ /** * @author Alan Gabriel Bem * + * @property DbalPostgresDAO $dao + * * @covers \Streak\Infrastructure\Domain\Event\Subscription\DAO\DbalPostgresDAO */ class DbalPostgresDAOTest extends DAOTestCase @@ -59,7 +61,7 @@ public function testDAO(): void $listener3 = $this->getMockBuilder(DAO\DbalPostgresDAOTest\CompletableListener::class)->setMockClassName('listener3')->getMock(); $listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($listenerId3) ; $subscription3 = new Subscription($listener3, $this->clock); diff --git a/tests/Infrastructure/Domain/Event/Subscription/DAO/IdentityMappingDaoTest.php b/tests/Infrastructure/Domain/Event/Subscription/DAO/IdentityMappingDaoTest.php index 714714b0..660f055b 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DAO/IdentityMappingDaoTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DAO/IdentityMappingDaoTest.php @@ -15,10 +15,7 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Streak\Domain\Event; -use Streak\Domain\Event\Envelope; use Streak\Domain\Event\Listener\Id; -use Streak\Domain\Id\UUID; use Streak\Infrastructure\Domain\Event\Subscription\DAO; /** @@ -26,7 +23,7 @@ */ class IdentityMappingDaoTest extends TestCase { - private DAO $dao; + private DAO|MockObject $dao; protected function setUp(): void { @@ -159,7 +156,7 @@ public function testItReturnsOne(): void $subscription = $this->createSubscriptionStub('eea81580-4e00-4680-8f87-e96054d3c41b', 'SubscriptionId', 100); $this->dao->expects(self::once())->method('one')->willReturn($subscription); $dao = new IdentityMappingDao($this->dao); - self::assertSame($subscription, $dao->one($subscription->subscriptionId())); + self::assertSame($subscription, $dao->one($subscription->id())); } public function testItExists(): void @@ -169,25 +166,15 @@ public function testItExists(): void $dao->exists($this->createSubscriptionIdStub('Id', 'be0e34c3-d53b-4463-b316-4a210971e64d')); } - /** - * @return MockObject|Subscription - */ - private function createSubscriptionStub(string $subscriptionId, string $subscriptionIdClassName, int $version): Subscription + private function createSubscriptionStub(string $subscriptionId, string $subscriptionIdClassName, int $version): MockObject|Subscription { $result = $this->getMockBuilder(Subscription::class)->disableOriginalConstructor()->getMock(); - $result->method('subscriptionId')->willReturn($this->createSubscriptionIdStub($subscriptionIdClassName, $subscriptionId)); + $result->method('id')->willReturn($this->createSubscriptionIdStub($subscriptionIdClassName, $subscriptionId)); $result->method('version')->willReturn($version); return $result; } - private function createEnvelopeStub(string $id): Envelope - { - $event = $this->getMockBuilder(Event::class)->getMock(); - - return new Envelope(new UUID($id), 'test', $event, new UUID($id)); - } - private function createSubscriptionIdStub(string $className, string $id): Id { $result = $this->getMockBuilder(Id::class)->setMockClassName($className)->getMock(); diff --git a/tests/Infrastructure/Domain/Event/Subscription/DAO/InMemoryDAOTest.php b/tests/Infrastructure/Domain/Event/Subscription/DAO/InMemoryDAOTest.php index efdab26e..d57be5fb 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DAO/InMemoryDAOTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DAO/InMemoryDAOTest.php @@ -19,6 +19,8 @@ /** * @author Alan Gabriel Bem * + * @property InMemoryDAO $dao + * * @covers \Streak\Infrastructure\Domain\Event\Subscription\DAO\InMemoryDAO */ class InMemoryDAOTest extends DAOTestCase diff --git a/tests/Infrastructure/Domain/Event/Subscription/DAO/Subscription/FactoryTest.php b/tests/Infrastructure/Domain/Event/Subscription/DAO/Subscription/FactoryTest.php index 1c1fb9a9..b822410b 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DAO/Subscription/FactoryTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DAO/Subscription/FactoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription\DAO\Subscription; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Clock; use Streak\Domain\Event; @@ -25,9 +26,9 @@ */ class FactoryTest extends TestCase { - private Event\Listener $listener; + private Event\Listener|MockObject $listener; - private Clock $clock; + private Clock|MockObject $clock; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/Event/Subscription/DAO/SubscriptionTest.php b/tests/Infrastructure/Domain/Event/Subscription/DAO/SubscriptionTest.php index bc81e8ac..0e430eaf 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DAO/SubscriptionTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DAO/SubscriptionTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription\DAO; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Clock; use Streak\Domain\Event; @@ -36,20 +37,20 @@ */ class SubscriptionTest extends TestCase { - private Listener $listener1; - private CompletableListener $listener3; - private ResettableListener $listener4; - private ResettableListenerThatCanPickStartingEvent $listener7; - private FilteringListener $listener8; - private StatefulListener $listener9; + private Listener|MockObject $listener1; + private CompletableListener|MockObject $listener3; + private ResettableListener|MockObject $listener4; + private ResettableListenerThatCanPickStartingEvent|MockObject $listener7; + private FilteringListener|MockObject $listener8; + private StatefulListener|MockObject $listener9; private Listener\Id $id1; - private EventStore $store; + private EventStore|MockObject $store; - private Event\Stream $stream1; - private Event\Stream $stream2; - private Event\Stream $stream3; + private Event\Stream|MockObject $stream1; + private Event\Stream|MockObject $stream2; + private Event\Stream|MockObject $stream3; private Event\Envelope $event1; private Event\Envelope $event2; @@ -57,7 +58,7 @@ class SubscriptionTest extends TestCase private Event\Envelope $event4; private Event\Envelope $event5; - private Clock $clock; + private Clock|MockObject $clock; protected function setUp(): void { @@ -68,7 +69,7 @@ protected function setUp(): void $this->listener8 = $this->getMockBuilder(FilteringListener::class)->getMock(); $this->listener9 = $this->getMockBuilder(StatefulListener::class)->getMock(); - $this->id1 = new class('f5e65690-e50d-4312-a175-b004ec1bd42a') extends UUID implements Listener\Id { + $this->id1 = new class ('f5e65690-e50d-4312-a175-b004ec1bd42a') extends UUID implements Listener\Id { }; $this->store = $this->getMockBuilder(EventStore::class)->getMockForAbstractClass(); @@ -90,7 +91,7 @@ public function testListener(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -101,7 +102,7 @@ public function testListener(): void $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertFalse($subscription->starting()); self::assertFalse($subscription->paused()); @@ -111,7 +112,7 @@ public function testListener(): void $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertTrue($subscription->starting()); self::assertFalse($subscription->paused()); @@ -202,7 +203,7 @@ public function testStatefulListener(): void { $this->listener9 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; @@ -242,13 +243,13 @@ public function testStatefulListener(): void $subscription = new Subscription($this->listener9, $this->clock); self::assertSame($subscription->listener(), $this->listener9); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertFalse($subscription->starting()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertTrue($subscription->starting()); @@ -312,7 +313,7 @@ public function testListenerWithPicker(): void { $this->listener7 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener7 @@ -327,12 +328,12 @@ public function testListenerWithPicker(): void $subscription = new Subscription($this->listener7, $this->clock); self::assertSame($subscription->listener(), $this->listener7); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event3); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2, $this->event3); @@ -386,14 +387,14 @@ public function testListenerWithFilterer(): void $this->listener8 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener8, $this->clock); self::assertSame($subscription->listener(), $this->listener8); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event2); @@ -450,7 +451,7 @@ public function testTransactionalListenerWithoutReplaying(): void { $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -461,12 +462,12 @@ public function testTransactionalListenerWithoutReplaying(): void $subscription = new Subscription($this->listener3, $this->clock); self::assertSame($subscription->listener(), $this->listener3); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); @@ -536,21 +537,21 @@ public function testCompletingListener(): void { $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener3, $this->clock); self::assertSame($subscription->listener(), $this->listener3); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); self::assertFalse($subscription->completed()); self::assertFalse($subscription->paused()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); self::assertFalse($subscription->completed()); self::assertFalse($subscription->paused()); @@ -647,14 +648,14 @@ public function testStartingAlreadyStartedSubscription(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); $subscription->startFor($this->event1); @@ -667,7 +668,7 @@ public function testStartingStatefulSubscription(): void { $this->listener9 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener9 @@ -679,7 +680,7 @@ public function testStartingStatefulSubscription(): void $subscription = new Subscription($this->listener9, $this->clock); self::assertSame($subscription->listener(), $this->listener9); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); $subscription->startFor($this->event1); } @@ -688,14 +689,14 @@ public function testNotStartedListener(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); $this->store ->expects(self::never()) @@ -718,7 +719,7 @@ public function testRestartingSubscription(): void { $this->listener4 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener4 @@ -729,12 +730,12 @@ public function testRestartingSubscription(): void $subscription = new Subscription($this->listener4, $this->clock); self::assertSame($subscription->listener(), $this->listener4); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); @@ -783,14 +784,14 @@ public function testRestartingNotStartedSubscription(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); $this->expectExceptionObject(new Event\Subscription\Exception\SubscriptionNotStartedYet($subscription)); @@ -801,19 +802,19 @@ public function testRestartingCompletedSubscription(): void { $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener3, $this->clock); self::assertSame($subscription->listener(), $this->listener3); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); @@ -888,19 +889,19 @@ public function testRestartingNonResettableListener(): void { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); @@ -962,6 +963,7 @@ public function testNonPositiveLimitGivenWhileSubscribingToTheEventStoreBeforeSt $this->expectExceptionObject(new \InvalidArgumentException('$limit must be a positive integer, but 0 was given.')); $events = $subscription->subscribeTo($this->store, 0); + $events = new \IteratorIterator($events); $events->rewind(); } @@ -969,13 +971,13 @@ public function testNonPositiveLimitGivenWhileSubscribingToTheEventStoreAfterSta { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->with() ->willReturn($this->id1) ; $subscription = new Subscription($this->listener1, $this->clock); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); $subscription->startFor($this->event1); $this->store @@ -995,6 +997,7 @@ public function testNonPositiveLimitGivenWhileSubscribingToTheEventStoreAfterSta $this->expectExceptionObject(new \InvalidArgumentException('$limit must be a positive integer, but -1 was given.')); $events = $subscription->subscribeTo($this->store, -1); + $events = new \IteratorIterator($events); $events->rewind(); } @@ -1002,7 +1005,7 @@ public function testContinuousListeningWithNumberOfEventsBeingExactlyImposedLimi { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -1013,12 +1016,12 @@ public function testContinuousListeningWithNumberOfEventsBeingExactlyImposedLimi $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); @@ -1069,7 +1072,7 @@ public function testContinuousListeningWithNumberOfEventsBeingMoreThanImposedLim { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -1080,12 +1083,12 @@ public function testContinuousListeningWithNumberOfEventsBeingMoreThanImposedLim $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); @@ -1132,7 +1135,7 @@ public function testContinuousListeningWithNumberOfEventsBeingMoreThanImposedLim { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -1143,12 +1146,12 @@ public function testContinuousListeningWithNumberOfEventsBeingMoreThanImposedLim $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); @@ -1195,7 +1198,7 @@ public function testContinuousListeningWithNumberOfEventsBeingLessThanImposedLim { $this->listener1 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $this->listener1 @@ -1206,12 +1209,12 @@ public function testContinuousListeningWithNumberOfEventsBeingLessThanImposedLim $subscription = new Subscription($this->listener1, $this->clock); self::assertSame($subscription->listener(), $this->listener1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); @@ -1262,19 +1265,19 @@ public function testCompletingListenerWhileContinuousListening(): void { $this->listener3 ->expects(self::atLeastOnce()) - ->method('listenerId') + ->method('id') ->willReturn($this->id1) ; $subscription = new Subscription($this->listener3, $this->clock); self::assertSame($subscription->listener(), $this->listener3); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(0, $subscription->version()); $subscription->startFor($this->event1); - self::assertSame($this->id1, $subscription->subscriptionId()); + self::assertSame($this->id1, $subscription->id()); self::assertSame(1, $subscription->version()); $this->stream1 = new InMemoryStream($this->event1, $this->event2); diff --git a/tests/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription/FactoryTest.php b/tests/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription/FactoryTest.php index eeb6fc5c..d22d10a4 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription/FactoryTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscription/FactoryTest.php @@ -14,6 +14,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription\DbalTransactionalSubscription; use Doctrine\DBAL\Driver\Connection; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event\Listener; use Streak\Domain\Event\Subscription; @@ -26,13 +27,13 @@ */ class FactoryTest extends TestCase { - private Subscription\Factory $factory; + private Subscription\Factory|MockObject $factory; - private Connection $connection; + private Connection|MockObject $connection; - private Listener $listener; + private Listener|MockObject $listener; - private Subscription $subscription; + private Subscription|MockObject $subscription; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscriptionTest.php b/tests/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscriptionTest.php index ae48c7cd..ef125b2a 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscriptionTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/DbalTransactionalSubscriptionTest.php @@ -13,8 +13,9 @@ namespace Streak\Infrastructure\Domain\Event\Subscription; -use Doctrine\DBAL\Driver\Connection; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Event\Listener; @@ -35,14 +36,14 @@ */ class DbalTransactionalSubscriptionTest extends TestCase { - private Subscription $subscription; + private Subscription|MockObject $subscription; - private Listener $listener; + private Listener|MockObject $listener; private EventStore $store1; private EventStore $store2; - private Listener\Id $subscriptionId; + private Listener\Id|MockObject $subscriptionId; private UUID $producerId1; @@ -50,7 +51,7 @@ class DbalTransactionalSubscriptionTest extends TestCase private Event\Envelope $event2; private Event\Envelope $event3; - private Connection $connection; + private Connection|MockObject $connection; private static Connection $connection1; private static Connection $connection2; @@ -83,7 +84,7 @@ protected function setUp(): void $this->subscription = $this->getMockBuilder(Subscription::class)->getMockForAbstractClass(); $this->listener = $this->getMockBuilder(Listener::class)->getMockForAbstractClass(); $this->subscriptionId = $this->getMockBuilder(Listener\Id::class)->getMockForAbstractClass(); - $this->connection = $this->getMockBuilder(Connection::class)->getMockForAbstractClass(); + $this->connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); $this->producerId1 = ProducerId1::random(); $this->event1 = Event\Envelope::new(new Event1(), $this->producerId1); $this->event2 = Event\Envelope::new(new Event2(), $this->producerId1); @@ -128,12 +129,12 @@ public function testObject(): void $this->subscription ->expects(self::once()) - ->method('subscriptionId') + ->method('id') ->with() ->willReturn($this->subscriptionId) ; - self::assertSame($this->subscriptionId, $subscription->subscriptionId()); + self::assertSame($this->subscriptionId, $subscription->id()); $this->subscription ->expects(self::once()) @@ -533,6 +534,7 @@ public function testSubscriberForErrorDuringTransaction1(): void try { $events = $subscription->subscribeTo($this->store1); + $events = new \IteratorIterator($events); $events->rewind(); $event1 = $events->current(); self::assertEquals($this->event1, $event1); @@ -613,6 +615,7 @@ public function testSubscriberForErrorDuringTransaction2(): void try { $events = $subscription->subscribeTo($this->store1); + $events = new \IteratorIterator($events); $events->rewind(); $event1 = $events->current(); self::assertEquals($this->event1, $event1); @@ -688,6 +691,7 @@ public function testSubscriberForErrorDuringTransaction3(): void try { $events = $subscription->subscribeTo($this->store1); + $events = new \IteratorIterator($events); $events->rewind(); $event1 = $events->current(); self::assertEquals($this->event1, $event1); @@ -765,6 +769,7 @@ public function testSubscriberForErrorDuringTransaction4(): void try { $events = $subscription->subscribeTo($this->store1); + $events = new \IteratorIterator($events); $events->rewind(); } finally { self::assertTrue($this->store1->stream()->empty()); diff --git a/tests/Infrastructure/Domain/Event/Subscription/EventSourcedRepositoryTest.php b/tests/Infrastructure/Domain/Event/Subscription/EventSourcedRepositoryTest.php index d5dcd4f5..ad5cda86 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/EventSourcedRepositoryTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/EventSourcedRepositoryTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; use Streak\Domain\Event; @@ -35,23 +36,23 @@ */ class EventSourcedRepositoryTest extends TestCase { - private Event\Subscription\Factory $subscriptions; + private Event\Subscription\Factory|MockObject $subscriptions; - private Event\Listener\Factory $listeners; + private Event\Listener\Factory|MockObject $listeners; private InMemoryEventStore $store; private UnitOfWork\EventStoreUnitOfWork $uow; - private Event\Listener $listener1; + private Event\Listener|MockObject $listener1; - private EventSourcedSubscription $eventSourcedSubscription1; - private DecoratedSubscription $eventSourcedSubscription2; - private DecoratedSubscription $eventSourcedSubscription3; + private EventSourcedSubscription|MockObject $eventSourcedSubscription1; + private DecoratedSubscription|MockObject $eventSourcedSubscription2; + private DecoratedSubscription|MockObject $eventSourcedSubscription3; - private Event\Subscription $nonEventSourcedSubscription1; - private DecoratedSubscription $nonEventSourcedSubscription2; - private DecoratedSubscription $nonEventSourcedSubscription3; + private Event\Subscription|MockObject $nonEventSourcedSubscription1; + private DecoratedSubscription|MockObject $nonEventSourcedSubscription2; + private DecoratedSubscription|MockObject $nonEventSourcedSubscription3; private Listener\Id $id1; private Listener\Id $id2; @@ -84,13 +85,13 @@ protected function setUp(): void $this->nonEventSourcedSubscription3 = $this->getMockBuilder(DecoratedSubscription::class)->setMockClassName('nonEventSourcedSubscription3')->getMock(); $this->nonEventSourcedSubscription3->method('subscription')->willReturn($this->nonEventSourcedSubscription2); - $this->id1 = new class('f5e65690-e50d-4312-a175-b004ec1bd42a') extends Domain\Id\UUID implements Listener\Id { + $this->id1 = new class ('f5e65690-e50d-4312-a175-b004ec1bd42a') extends Domain\Id\UUID implements Listener\Id { }; - $this->id2 = new class('d01286b0-7dd6-4520-b714-0e9903ab39af') extends Domain\Id\UUID implements Listener\Id { + $this->id2 = new class ('d01286b0-7dd6-4520-b714-0e9903ab39af') extends Domain\Id\UUID implements Listener\Id { }; - $this->id3 = new class('39ab6175-7cd7-4c94-95c1-03d05c2e2fa2') extends Domain\Id\UUID implements Listener\Id { + $this->id3 = new class ('39ab6175-7cd7-4c94-95c1-03d05c2e2fa2') extends Domain\Id\UUID implements Listener\Id { }; - $this->id4 = new class('2d40c01d-7aa9-4757-ac28-de3733431cc5') extends Domain\Id\UUID implements Listener\Id { + $this->id4 = new class ('2d40c01d-7aa9-4757-ac28-de3733431cc5') extends Domain\Id\UUID implements Listener\Id { }; $this->event1 = Event\Envelope::new($this->getMockBuilder(Event::class)->setMockClassName('event1')->getMockForAbstractClass(), UUID::random()); @@ -153,7 +154,7 @@ public function testFindingNotExistingSubscription(): void $this->eventSourcedSubscription1 ->expects(self::once()) - ->method('producerId') + ->method('id') ->willReturn($this->id1) ; @@ -177,7 +178,7 @@ public function testCheckingForExistingSubscription(): void $this->eventSourcedSubscription1 ->expects(self::once()) - ->method('producerId') + ->method('id') ->willReturn($this->id1) ; @@ -192,7 +193,7 @@ public function testCheckingForNotExistingSubscription(): void $this->eventSourcedSubscription1 ->expects(self::once()) - ->method('producerId') + ->method('id') ->willReturn($this->id1) ; @@ -232,7 +233,7 @@ public function testFindingSubscription(): void $this->eventSourcedSubscription1 ->expects(self::once()) - ->method('producerId') + ->method('id') ->willReturn($this->id1) ; @@ -242,7 +243,9 @@ public function testFindingSubscription(): void ->with(self::callback(function (Event\Stream $stream) use ($event1, $event2, $event3) { $stream = iterator_to_array($stream); - return self::equalTo([$event1, $event2, $event3])->evaluate($stream); + self::equalTo([$event1, $event2, $event3])->evaluate($stream); + + return true; })) ; @@ -288,7 +291,7 @@ public function testFindingPreviouslyRestartedSubscription(): void $this->eventSourcedSubscription1 ->expects(self::once()) - ->method('producerId') + ->method('id') ->willReturn($this->id1) ; @@ -299,7 +302,9 @@ public function testFindingPreviouslyRestartedSubscription(): void $stream = iterator_to_array($stream); // streaming from SubscriptionRestarted event - return self::equalTo([$event1, $event2, $event3, $event4, $event5, $event6])->evaluate($stream); + self::equalTo([$event1, $event2, $event3, $event4, $event5, $event6])->evaluate($stream); + + return true; })) ; @@ -324,7 +329,7 @@ public function testAddingEventSourcedSubscription(): void $this->eventSourcedSubscription1 ->expects(self::atLeastOnce()) - ->method('producerId') + ->method('id') ->willReturn($this->id1) ; @@ -339,7 +344,7 @@ public function testAddingDecoratedEventSourcedSubscription(): void $this->eventSourcedSubscription1 ->expects(self::atLeastOnce()) - ->method('producerId') + ->method('id') ->willReturn($this->id1) ; @@ -413,7 +418,7 @@ public function testFindingSubscriptions(): void use Streak\Domain\Event; -abstract class EventSourcedSubscription implements Event\Subscription, Event\Sourced +abstract class EventSourcedSubscription implements Event\Sourced\Subscription { } diff --git a/tests/Infrastructure/Domain/Event/Subscription/LazyLoadedSubscriptionTest.php b/tests/Infrastructure/Domain/Event/Subscription/LazyLoadedSubscriptionTest.php index 65a0cacc..495bbe94 100644 --- a/tests/Infrastructure/Domain/Event/Subscription/LazyLoadedSubscriptionTest.php +++ b/tests/Infrastructure/Domain/Event/Subscription/LazyLoadedSubscriptionTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\Event\Subscription; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Event\Listener; @@ -27,19 +28,19 @@ */ class LazyLoadedSubscriptionTest extends TestCase { - private Listener\Id $id; + private Listener\Id|MockObject $id; - private Listener $listener; + private Listener|MockObject $listener; - private Subscription $subscription; + private Subscription|MockObject $subscription; - private Subscription\Repository $repository; + private Subscription\Repository|MockObject $repository; private Event\Envelope $event1; private Event\Envelope $event2; private Event\Envelope $event3; - private EventStore $store; + private EventStore|MockObject $store; protected function setUp(): void { @@ -64,7 +65,7 @@ public function testObject(): void ->willReturn($this->subscription) ; - self::assertSame($this->id, $subscription->subscriptionId()); + self::assertSame($this->id, $subscription->id()); $this->subscription ->expects(self::once()) diff --git a/tests/Infrastructure/Domain/EventBus/InMemoryEventBusTest.php b/tests/Infrastructure/Domain/EventBus/InMemoryEventBusTest.php index 703a67c0..3dc34e3b 100644 --- a/tests/Infrastructure/Domain/EventBus/InMemoryEventBusTest.php +++ b/tests/Infrastructure/Domain/EventBus/InMemoryEventBusTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\EventBus; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Id\UUID; @@ -24,9 +25,13 @@ */ class InMemoryEventBusTest extends TestCase { - private Event\Listener $listener1; - private Event\Listener $listener2; - private Event\Listener $listener3; + private Event\Listener|MockObject $listener1; + private Event\Listener|MockObject $listener2; + private Event\Listener|MockObject $listener3; + + private Event\Listener\Id $listenerId1; + private Event\Listener\Id $listenerId2; + private Event\Listener\Id $listenerId3; private Event\Envelope $event1; private Event\Envelope $event2; @@ -34,13 +39,20 @@ class InMemoryEventBusTest extends TestCase protected function setUp(): void { - $this->listener1 = $this->getMockBuilder(Event\Listener::class)->setMockClassName('listener1')->getMockForAbstractClass(); - $this->listener2 = $this->getMockBuilder(Event\Listener::class)->setMockClassName('listener2')->getMockForAbstractClass(); - $this->listener3 = $this->getMockBuilder(Event\Listener::class)->setMockClassName('listener3')->getMockForAbstractClass(); - - $this->event1 = Event\Envelope::new($this->getMockBuilder(Event::class)->setMockClassName('event1')->getMockForAbstractClass(), UUID::random()); - $this->event2 = Event\Envelope::new($this->getMockBuilder(Event::class)->setMockClassName('event2')->getMockForAbstractClass(), UUID::random()); - $this->event3 = Event\Envelope::new($this->getMockBuilder(Event::class)->setMockClassName('event3')->getMockForAbstractClass(), UUID::random()); + $this->listenerId1 = new class ('98f94b04-e5e9-4032-aaa4-b3a89cfa69a8') extends UUID implements Event\Listener\Id {}; + $this->listenerId2 = new class ('90b13520-4ce0-4105-a054-b033748a56cc') extends UUID implements Event\Listener\Id {}; + $this->listenerId3 = new class ('8a7bbab7-8e41-4741-972a-f4413a3cb49f') extends UUID implements Event\Listener\Id {}; + + $this->listener1 = $this->getMockBuilder(Event\Listener::class)->setMockClassName('listener1_2783trn')->getMockForAbstractClass(); + $this->listener1->expects(self::any())->method('id')->willReturn($this->listenerId1); + $this->listener2 = $this->getMockBuilder(Event\Listener::class)->setMockClassName('listener2_qw6rh33')->getMockForAbstractClass(); + $this->listener2->expects(self::any())->method('id')->willReturn($this->listenerId2); + $this->listener3 = $this->getMockBuilder(Event\Listener::class)->setMockClassName('listener3_jasge7b')->getMockForAbstractClass(); + $this->listener3->expects(self::any())->method('id')->willReturn($this->listenerId3); + + $this->event1 = new Event\Envelope(UUID::fromString('e7dd3e20-d3bc-4722-a601-57c73c4f5452'), 'event1', $this->getMockBuilder(Event::class)->setMockClassName('event1_yuwgrt2r')->getMockForAbstractClass(), $id = UUID::random(), $id); + $this->event2 = new Event\Envelope(UUID::fromString('4a2d2323-9841-4e8d-a9e5-224beb6f36d7'), 'event2', $this->getMockBuilder(Event::class)->setMockClassName('event2_237trxbq')->getMockForAbstractClass(), $id = UUID::random(), $id); + $this->event3 = new Event\Envelope(UUID::fromString('e4339858-831a-40fa-a35b-4690329890f7'), 'event3', $this->getMockBuilder(Event::class)->setMockClassName('event3_fhsyrt23')->getMockForAbstractClass(), $id = UUID::random(), $id); } public function testBus(): void @@ -57,45 +69,32 @@ public function testBus(): void [$this->event1], [$this->event2] ) - ->willReturnOnConsecutiveCalls( - true, - true - ) ; $bus->publish($this->event1); - $this->listener3 - ->expects(self::exactly(2)) + $this->listener2 ->method('on') ->withConsecutive( [$this->event2], - [$this->event3] - ) - ->willReturnOnConsecutiveCalls( + [$this->event3], + )->willReturnOnConsecutiveCalls( + self::returnCallback(function () use ($bus) { + $bus->remove($this->listener1); + $bus->add($this->listener3); + $bus->publish($this->event3); + + return true; + }), true, - true - ) - ; + ); - $this->listener2 - ->expects(self::at(0)) - ->method('on') - ->with($this->event2) - ->willReturnCallback(function () use ($bus) { - $bus->remove($this->listener1); - $bus->add($this->listener3); - $bus->publish($this->event3); - - return true; - }) - ; - - $this->listener2 - ->expects(self::at(1)) + $this->listener3 ->method('on') - ->with($this->event3) - ->willReturn(true) + ->withConsecutive( + [$this->event2], + [$this->event3] + ) ; $bus->add($this->listener2); diff --git a/tests/Infrastructure/Domain/EventBus/NullEventBusTest.php b/tests/Infrastructure/Domain/EventBus/NullEventBusTest.php index 5d87d788..be8d84b4 100644 --- a/tests/Infrastructure/Domain/EventBus/NullEventBusTest.php +++ b/tests/Infrastructure/Domain/EventBus/NullEventBusTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\EventBus; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\Id\UUID; @@ -24,9 +25,9 @@ */ class NullEventBusTest extends TestCase { - private Event\Listener $listener1; - private Event\Listener $listener2; - private Event\Listener $listener3; + private Event\Listener|MockObject $listener1; + private Event\Listener|MockObject $listener2; + private Event\Listener|MockObject $listener3; private Event\Envelope $event1; private Event\Envelope $event2; diff --git a/tests/Infrastructure/Domain/EventStore/DbalPostgresEventStoreTest.php b/tests/Infrastructure/Domain/EventStore/DbalPostgresEventStoreTest.php index 9388c0b9..de76907e 100644 --- a/tests/Infrastructure/Domain/EventStore/DbalPostgresEventStoreTest.php +++ b/tests/Infrastructure/Domain/EventStore/DbalPostgresEventStoreTest.php @@ -17,6 +17,7 @@ use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Platforms\MySqlPlatform; +use PHPUnit\Framework\MockObject\MockObject; use Streak\Domain\Event; use Streak\Domain\EventStore; use Streak\Domain\Exception\ConcurrentWriteDetected; @@ -33,7 +34,7 @@ class DbalPostgresEventStoreTest extends EventStoreTestCase private static Connection $connection2; - private Connection $mysql; + private Connection|MockObject $mysql; private MySqlPlatform $mysqlPlatform; diff --git a/tests/Infrastructure/Domain/EventStore/EventStoreTestCase.php b/tests/Infrastructure/Domain/EventStore/EventStoreTestCase.php index 7fdfee20..a4e1ecb0 100644 --- a/tests/Infrastructure/Domain/EventStore/EventStoreTestCase.php +++ b/tests/Infrastructure/Domain/EventStore/EventStoreTestCase.php @@ -247,6 +247,38 @@ public function testObject(): void self::assertEquals($event214, $stream->last()); } + public function testFilteringWithEventsNotInStore(): void + { + $producerId11 = new EventStoreTestCase\ProducerId1('producer1'); + + $event111 = new EventStoreTestCase\Event1(); + $event111 = Event\Envelope::new($event111, $producerId11, 1); + $event112 = new EventStoreTestCase\Event2(); + $event112 = Event\Envelope::new($event112, $producerId11, 2); + $event113 = new EventStoreTestCase\Event3(); + $event113 = Event\Envelope::new($event113, $producerId11, 3); + + $this->store->add($event111); + + $stream = $this->store->stream(); + self::assertFalse($stream->empty()); + self::assertEquals([$event111], iterator_to_array($stream)); + self::assertEquals($event111, $stream->first()); + self::assertEquals($event111, $stream->last()); + + $stream = $stream->from($event112); + self::assertFalse($stream->empty()); + self::assertEquals([$event111], iterator_to_array($stream)); + self::assertEquals($event111, $stream->first()); + self::assertEquals($event111, $stream->last()); + + $stream = $stream->to($event113); + self::assertFalse($stream->empty()); + self::assertEquals([$event111], iterator_to_array($stream)); + self::assertEquals($event111, $stream->first()); + self::assertEquals($event111, $stream->last()); + } + public function testConcurrentWriting(): void { $producerId1 = new EventStoreTestCase\ProducerId1('producer1'); @@ -317,7 +349,7 @@ public function testItGetsEvent(): void $uuid2 = new Id\UUID('5e04364e-4590-403b-9f8f-3ae14f6dcce6'); $event = new EventStoreTestCase\Event1(); - $event = new Event\Envelope($uuid1, 'event1', $event, new EventStoreTestCase\ProducerId1('producer1'), 1); + $event = new Event\Envelope($uuid1, EventStoreTestCase\Event1::class, $event, new EventStoreTestCase\ProducerId1('producer1'), new EventStoreTestCase\ProducerId1('producer1'), 1); $this->store->add($event); @@ -334,11 +366,10 @@ abstract protected function newEventStore(): EventStore; abstract class ValueId implements Domain\Id { - private string $value; - - public function __construct(string $value) - { - $this->value = $value; + final public function __construct( + /** @var non-empty-string $value */ + private string $value + ) { } public function equals(object $id): bool @@ -355,7 +386,7 @@ public function toString(): string return $this->value; } - public static function fromString(string $id): Domain\Id + public static function fromString(string $id): static { return new static($id); } diff --git a/tests/Infrastructure/Domain/EventStore/PublishingEventStoreTest.php b/tests/Infrastructure/Domain/EventStore/PublishingEventStoreTest.php index 10ef8f73..42673c6b 100644 --- a/tests/Infrastructure/Domain/EventStore/PublishingEventStoreTest.php +++ b/tests/Infrastructure/Domain/EventStore/PublishingEventStoreTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\EventStore; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain; use Streak\Domain\Event; @@ -28,22 +29,22 @@ */ class PublishingEventStoreTest extends TestCase { - private EventStore $store; + private EventStore|MockObject $store; - private EventStoreWithSchema $schemableStore; + private EventStoreWithSchema|MockObject $schemableStore; - private EventBus $bus; + private EventBus|MockObject $bus; - private Domain\Id $id; + private Domain\Id|MockObject $id; private Event\Envelope $event1; private Event\Envelope $event2; private Event\Envelope $event3; - private Event\Stream $stream1; - private Event\Stream $stream2; + private Event\Stream|MockObject $stream1; + private Event\Stream|MockObject $stream2; - private Schema $schema; + private Schema|MockObject $schema; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/UnitOfWork/CompositeUnitOfWorkTest.php b/tests/Infrastructure/Domain/UnitOfWork/CompositeUnitOfWorkTest.php index b1133d34..cff5d0f1 100644 --- a/tests/Infrastructure/Domain/UnitOfWork/CompositeUnitOfWorkTest.php +++ b/tests/Infrastructure/Domain/UnitOfWork/CompositeUnitOfWorkTest.php @@ -13,6 +13,7 @@ namespace Streak\Infrastructure\Domain\UnitOfWork; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Infrastructure\Domain\UnitOfWork; @@ -23,9 +24,9 @@ */ class CompositeUnitOfWorkTest extends TestCase { - private UnitOfWork $uow1; - private UnitOfWork $uow2; - private UnitOfWork $uow3; + private UnitOfWork|MockObject $uow1; + private UnitOfWork|MockObject $uow2; + private UnitOfWork|MockObject $uow3; protected function setUp(): void { diff --git a/tests/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWorkTest.php b/tests/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWorkTest.php index 82cb5091..93088a64 100644 --- a/tests/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWorkTest.php +++ b/tests/Infrastructure/Domain/UnitOfWork/EventStoreUnitOfWorkTest.php @@ -13,14 +13,15 @@ namespace Streak\Infrastructure\Domain\UnitOfWork; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Domain\Event; use Streak\Domain\EventStore; use Streak\Domain\Exception\ConcurrentWriteDetected; use Streak\Domain\Id\UUID; +use Streak\Infrastructure\Domain\EventStoreUnitOfWorkTest\NonVersionableEventSourcedStub; +use Streak\Infrastructure\Domain\EventStoreUnitOfWorkTest\VersionableEventSourcedStub; use Streak\Infrastructure\Domain\UnitOfWork\Exception\ObjectNotSupported; -use Streak\Infrastructure\Domain\UnitOfWorkTest\NonVersionableEventSourcedStub; -use Streak\Infrastructure\Domain\UnitOfWorkTest\VersionableEventSourcedStub; /** * @author Alan Gabriel Bem @@ -29,13 +30,13 @@ */ class EventStoreUnitOfWorkTest extends TestCase { - private EventStore $store; + private EventStore|MockObject $store; - private Event $event1; - private Event $event2; - private Event $event3; - private Event $event4; - private Event $event5; + private Event|MockObject $event1; + private Event|MockObject $event2; + private Event|MockObject $event3; + private Event|MockObject $event4; + private Event|MockObject $event5; protected function setUp(): void { @@ -69,7 +70,7 @@ public function testObject(): void $uow = new EventStoreUnitOfWork($this->store); self::assertEmpty($uow->uncommitted()); - self::assertEquals(0, $uow->count()); + self::assertSame(0, $uow->count()); self::assertFalse($uow->has($object1)); self::assertFalse($uow->has($object2)); self::assertFalse($uow->has($object3)); @@ -78,7 +79,7 @@ public function testObject(): void $uow->remove($object1); self::assertEmpty($uow->uncommitted()); - self::assertEquals(0, $uow->count()); + self::assertSame(0, $uow->count()); self::assertFalse($uow->has($object1)); self::assertFalse($uow->has($object2)); self::assertFalse($uow->has($object3)); @@ -87,7 +88,7 @@ public function testObject(): void $uow->add($object1); self::assertSame([$object1], $uow->uncommitted()); - self::assertEquals(1, $uow->count()); + self::assertSame(1, $uow->count()); self::assertTrue($uow->has($object1)); self::assertFalse($uow->has($object2)); self::assertFalse($uow->has($object3)); @@ -96,7 +97,7 @@ public function testObject(): void $uow->add($object2); self::assertSame([$object1, $object2], $uow->uncommitted()); - self::assertEquals(2, $uow->count()); + self::assertSame(2, $uow->count()); self::assertTrue($uow->has($object1)); self::assertTrue($uow->has($object2)); self::assertFalse($uow->has($object3)); @@ -105,7 +106,7 @@ public function testObject(): void $uow->remove($object2); self::assertSame([$object1], $uow->uncommitted()); - self::assertEquals(1, $uow->count()); + self::assertSame(1, $uow->count()); self::assertTrue($uow->has($object1)); self::assertFalse($uow->has($object2)); self::assertFalse($uow->has($object3)); @@ -114,7 +115,7 @@ public function testObject(): void $uow->add($object3); self::assertSame([$object1, $object3], $uow->uncommitted()); - self::assertEquals(2, $uow->count()); + self::assertSame(2, $uow->count()); self::assertTrue($uow->has($object1)); self::assertFalse($uow->has($object2)); self::assertTrue($uow->has($object3)); @@ -123,7 +124,7 @@ public function testObject(): void $uow->add($object4); self::assertSame([$object1, $object3, $object4], $uow->uncommitted()); - self::assertEquals(3, $uow->count()); + self::assertSame(3, $uow->count()); self::assertTrue($uow->has($object1)); self::assertFalse($uow->has($object2)); self::assertTrue($uow->has($object3)); @@ -159,7 +160,7 @@ public function testObject(): void self::assertTrue($object1->commited()); self::assertFalse($object2->commited()); self::assertTrue($object3->commited()); - self::assertEquals(0, $uow->count()); + self::assertSame(0, $uow->count()); self::assertFalse($uow->has($object1)); self::assertFalse($uow->has($object2)); self::assertFalse($uow->has($object3)); @@ -246,7 +247,7 @@ public function testError(): void // retry try { iterator_to_array($uow->commit()); - } catch (\RuntimeException $exception3) { + } catch (\RuntimeException) { self::fail(); } finally { self::assertSame(0, $uow->count()); @@ -259,7 +260,7 @@ public function testError(): void try { iterator_to_array($uow->commit()); self::fail(); - } catch (ConcurrentWriteDetected $exception4) { + } catch (ConcurrentWriteDetected) { self::assertSame(0, $uow->count()); self::assertFalse($uow->has($object1)); self::assertFalse($uow->has($object2)); @@ -282,23 +283,19 @@ public function testWrongObject(): void } } -namespace Streak\Infrastructure\Domain\UnitOfWorkTest; +namespace Streak\Infrastructure\Domain\EventStoreUnitOfWorkTest; use Streak\Domain; use Streak\Domain\Event; use Streak\Domain\Versionable; -class VersionableEventSourcedStub implements Event\Sourced, Versionable +class VersionableEventSourcedStub implements Event\Producer, Event\Consumer, Event\Replayable, Versionable { - private Domain\Id $id; - private int $version; private array $events; private bool $commited = false; - public function __construct(Domain\Id $id, int $version, Event\Envelope ...$events) + public function __construct(private Domain\Id $id, private int $version, Event\Envelope ...$events) { - $this->id = $id; - $this->version = $version; $this->events = $events; } @@ -307,12 +304,7 @@ public function equals(object $object): bool throw new \BadMethodCallException(); } - public function lastReplayed(): ?Event\Envelope - { - throw new \BadMethodCallException(); - } - - public function producerId(): Domain\Id + public function id(): Domain\Id { return $this->id; } @@ -322,7 +314,17 @@ public function events(): array return $this->events; } - public function replay(Event\Stream $events): void + public function replay(Event\Stream $stream): void + { + throw new \BadMethodCallException(); + } + + public function lastEvent(): ?Event\Envelope + { + throw new \BadMethodCallException(); + } + + public function applyEvent(Event\Envelope $event): void { throw new \BadMethodCallException(); } @@ -343,14 +345,12 @@ public function commited(): bool } } -class NonVersionableEventSourcedStub implements Event\Sourced +class NonVersionableEventSourcedStub implements Event\Producer, Event\Consumer, Event\Replayable { - private Domain\Id $id; private array $events; - public function __construct(Domain\Id $id, Event\Envelope ...$events) + public function __construct(private Domain\Id $id, Event\Envelope ...$events) { - $this->id = $id; $this->events = $events; } @@ -359,14 +359,14 @@ public function equals(object $object): bool throw new \BadMethodCallException(); } - public function lastReplayed(): ?Event\Envelope + public function id(): Domain\Id { - throw new \BadMethodCallException(); + return $this->id; } - public function producerId(): Domain\Id + public function applyEvent(Event\Envelope $event): void { - return $this->id; + throw new \BadMethodCallException(); } public function events(): array @@ -374,7 +374,7 @@ public function events(): array return $this->events; } - public function replay(Event\Stream $events): void + public function replay(Event\Stream $stream): void { throw new \BadMethodCallException(); } diff --git a/tests/Infrastructure/Domain/UnitOfWork/Exception/ObjectNotSupportedTest.php b/tests/Infrastructure/Domain/UnitOfWork/Exception/ObjectNotSupportedTest.php index 866cb0b5..65d0a1e3 100644 --- a/tests/Infrastructure/Domain/UnitOfWork/Exception/ObjectNotSupportedTest.php +++ b/tests/Infrastructure/Domain/UnitOfWork/Exception/ObjectNotSupportedTest.php @@ -27,6 +27,6 @@ public function testIt(): void $exception = new ObjectNotSupported($object, $previous); self::assertSame($object, $exception->object()); self::assertSame($previous, $exception->getPrevious()); - self::assertEquals('Object is not supported.', $exception->getMessage()); + self::assertSame('Object is not supported.', $exception->getMessage()); } } diff --git a/tests/Infrastructure/Domain/UnitOfWork/SnapshottingUnitOfWorkTest.php b/tests/Infrastructure/Domain/UnitOfWork/SnapshottingUnitOfWorkTest.php index 2e8d4830..de2928f5 100644 --- a/tests/Infrastructure/Domain/UnitOfWork/SnapshottingUnitOfWorkTest.php +++ b/tests/Infrastructure/Domain/UnitOfWork/SnapshottingUnitOfWorkTest.php @@ -14,7 +14,9 @@ namespace Streak\Infrastructure\Domain\UnitOfWork; use InvalidArgumentException; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Streak\Domain\AggregateRoot; use Streak\Domain\Event; use Streak\Infrastructure\Domain\AggregateRoot\Snapshotter; use Streak\Infrastructure\Domain\UnitOfWork; @@ -26,19 +28,19 @@ */ class SnapshottingUnitOfWorkTest extends TestCase { - private UnitOfWork $uow; + private UnitOfWork|MockObject $uow; - private Snapshotter $snapshotter; + private Snapshotter|MockObject $snapshotter; - private Event\Producer $producer; + private Event\Producer|MockObject $producer; - private Event\Sourced\AggregateRoot $aggregateRoot1; + private Event\Sourced\AggregateRoot|MockObject $aggregateRoot1; - private Event\Sourced\AggregateRoot\Id $aggregateRootId1; + private AggregateRoot\Id|MockObject $aggregateRootId1; - private Event\Sourced\AggregateRoot $aggregateRoot2; + private Event\Sourced\AggregateRoot|MockObject $aggregateRoot2; - private Event\Sourced\AggregateRoot\Id $aggregateRootId2; + private AggregateRoot\Id|MockObject $aggregateRootId2; protected function setUp(): void { @@ -46,9 +48,9 @@ protected function setUp(): void $this->snapshotter = $this->getMockBuilder(Snapshotter::class)->getMockForAbstractClass(); $this->producer = $this->getMockBuilder(Event\Producer::class)->setMockClassName('s__producer')->getMockForAbstractClass(); $this->aggregateRoot1 = $this->getMockBuilder(Event\Sourced\AggregateRoot::class)->setMockClassName('s__ar1')->getMockForAbstractClass(); - $this->aggregateRootId1 = $this->getMockBuilder(Event\Sourced\AggregateRoot\Id::class)->getMockForAbstractClass(); + $this->aggregateRootId1 = $this->getMockBuilder(AggregateRoot\Id::class)->getMockForAbstractClass(); $this->aggregateRoot2 = $this->getMockBuilder(Event\Sourced\AggregateRoot::class)->setMockClassName('s__ar2')->getMockForAbstractClass(); - $this->aggregateRootId2 = $this->getMockBuilder(Event\Sourced\AggregateRoot\Id::class)->getMockForAbstractClass(); + $this->aggregateRootId2 = $this->getMockBuilder(AggregateRoot\Id::class)->getMockForAbstractClass(); } public function testObject(): void @@ -57,12 +59,12 @@ public function testObject(): void $this->producer ->expects(self::never()) // we do not handle this type of object - ->method('producerId') + ->method('id') ; $this->aggregateRoot1 ->expects(self::atLeastOnce()) - ->method('producerId') + ->method('id') ->willReturn($this->aggregateRootId1) ; @@ -78,7 +80,7 @@ public function testObject(): void $this->aggregateRoot2 ->expects(self::atLeastOnce()) - ->method('producerId') + ->method('id') ->willReturn($this->aggregateRootId2) ; @@ -237,7 +239,7 @@ public function testCommitInterval(int $beforeVersion, int $afterVersion, int $s $this->aggregateRoot1 ->expects(self::atLeastOnce()) - ->method('producerId') + ->method('id') ->willReturn($this->aggregateRootId1) ; @@ -276,7 +278,7 @@ public function commitIntervalProvider(): array */ public function testItDoesNotCreateWithWrongInterval(int $interval): void { - self::expectException(InvalidArgumentException::class); + $this->expectException(InvalidArgumentException::class); new SnapshottingUnitOfWork($this->uow, $this->snapshotter, 0); } diff --git a/tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php b/tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php index f310a5d1..37abde5b 100644 --- a/tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php +++ b/tests/Infrastructure/Domain/UnitOfWork/SubscriptionDAOUnitOfWorkTest.php @@ -26,7 +26,7 @@ */ class SubscriptionDAOUnitOfWorkTest extends TestCase { - private DAO $dao; + private DAO|MockObject $dao; private SubscriptionDAOUnitOfWork $uow; @@ -54,14 +54,14 @@ public function testItAddsDecorator(): void public function testItDoesNotAddsNotSupportedSubscription(): void { $subscription = $this->getMockBuilder(Subscription::class)->getMock(); - self::expectException(ObjectNotSupported::class); + $this->expectException(ObjectNotSupported::class); $this->uow->add($subscription); } public function testHasOnNotSupportedObject(): void { $subscription = $this->getMockBuilder(Subscription::class)->getMock(); - self::expectException(ObjectNotSupported::class); + $this->expectException(ObjectNotSupported::class); $this->uow->has($subscription); } @@ -69,11 +69,11 @@ public function testItRemoves(): void { $subscription = $this->createSubscriptionStub('1'); $this->uow->add($subscription); - self::assertEquals(1, $this->uow->count()); + self::assertSame(1, $this->uow->count()); $this->uow->remove($subscription); self::assertFalse($this->uow->has($subscription)); self::assertEmpty($this->uow->uncommitted()); - self::assertEquals(0, $this->uow->count()); + self::assertSame(0, $this->uow->count()); } public function testItRemovesNonExistedSubscription(): void @@ -87,7 +87,7 @@ public function testItRemovesNonExistedSubscription(): void public function testItDoesNotRemoveNotSupportedSubscription(): void { $subscription = $this->getMockBuilder(Subscription::class)->getMock(); - self::expectException(ObjectNotSupported::class); + $this->expectException(ObjectNotSupported::class); $this->uow->remove($subscription); } @@ -106,30 +106,24 @@ public function testItCommitsWithException(): void $subscription = $this->createSubscriptionStub('1'); $this->uow->add($subscription); $this->dao->expects(self::once())->method('save')->with($subscription)->willThrowException(new \Exception()); - self::expectException(\Exception::class); + $this->expectException(\Exception::class); iterator_to_array($this->uow->commit()); self::assertEquals([$subscription], $this->uow->uncommitted()); } - /** - * @return MockObject|Subscription\Decorator - */ - private function createSubscriptionDecoratorStub(string $id): Subscription\Decorator + private function createSubscriptionDecoratorStub(string $id): MockObject|Subscription\Decorator { $result = $this->getMockBuilder(DecoratedSubscription::class)->getMock(); $result->method('subscription')->willReturn($this->createSubscriptionStub($id)); - $result->method('subscriptionId')->willReturn($this->createIdStub($id)); + $result->method('id')->willReturn($this->createIdStub($id)); return $result; } - /** - * @return DAO\Subscription|MockObject - */ - private function createSubscriptionStub(string $id): DAO\Subscription + private function createSubscriptionStub(string $id): MockObject|DAO\Subscription { $result = $this->getMockBuilder(DAO\Subscription::class)->disableOriginalConstructor()->getMock(); - $result->method('subscriptionId')->willReturn($this->createIdStub($id)); + $result->method('id')->willReturn($this->createIdStub($id)); return $result; } diff --git a/tests/Infrastructure/Interfaces/RabbitMQ/CommittingSensorConsumerTest.php b/tests/Infrastructure/Interfaces/RabbitMQ/CommittingSensorConsumerTest.php index 3a5139cd..ec571756 100644 --- a/tests/Infrastructure/Interfaces/RabbitMQ/CommittingSensorConsumerTest.php +++ b/tests/Infrastructure/Interfaces/RabbitMQ/CommittingSensorConsumerTest.php @@ -15,6 +15,7 @@ use OldSound\RabbitMqBundle\RabbitMq\ConsumerInterface; use PhpAmqpLib\Message\AMQPMessage; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Infrastructure\Domain\UnitOfWork; @@ -28,9 +29,9 @@ class CommittingSensorConsumerTest extends TestCase private const ACK = true; private const NACK = false; - private ConsumerInterface $consumer; + private ConsumerInterface|MockObject $consumer; - private UnitOfWork $uow; + private UnitOfWork|MockObject $uow; protected function setUp(): void { diff --git a/tests/Infrastructure/Interfaces/RabbitMQ/SensorConsumerTest.php b/tests/Infrastructure/Interfaces/RabbitMQ/SensorConsumerTest.php index 2d4b9695..fa762780 100644 --- a/tests/Infrastructure/Interfaces/RabbitMQ/SensorConsumerTest.php +++ b/tests/Infrastructure/Interfaces/RabbitMQ/SensorConsumerTest.php @@ -14,6 +14,7 @@ namespace Streak\Infrastructure\Interfaces\RabbitMQ; use PhpAmqpLib\Message\AMQPMessage; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Streak\Application\Sensor; @@ -27,9 +28,9 @@ class SensorConsumerTest extends TestCase private const ACK = true; private const NACK = false; - private Sensor\Factory $factory; + private Sensor\Factory|MockObject $factory; - private Sensor $sensor; + private Sensor|MockObject $sensor; protected function setUp(): void { diff --git a/tests/Infrastructure/Serializer/PhpSerializerTest.php b/tests/Infrastructure/Serializer/PhpSerializerTest.php index 300c447e..26ef4acb 100644 --- a/tests/Infrastructure/Serializer/PhpSerializerTest.php +++ b/tests/Infrastructure/Serializer/PhpSerializerTest.php @@ -34,7 +34,7 @@ public function testSerialize($value): void $serialized = $serializer->serialize($value); $unserialized = $serializer->unserialize($serialized); - self::assertEquals(serialize($value), $serialized); + self::assertSame(serialize($value), $serialized); self::assertEquals(unserialize($serialized), $unserialized); self::assertEquals($value, $unserialized); }