diff --git a/composer.json b/composer.json index 9751450..7b9e021 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,6 @@ "test-coverage" : "phpunit --log-junit tmp/coverage/unitreport.xml --coverage-html tmp/coverage --coverage-clover tmp/coverage/coverage.xml", "phpstan": "vendor/bin/phpstan.phar analyse -c tests/phpstan.neon -l 7 src/", "cs-check": "vendor/bin/phpcs --colors --standard=config/ruleset.xml -s -p --ignore=/config/Migrations/,/src/Dto/ src/ tests/ config/", - "cs-fix": "vendor/bin/phpcbf --colors --standard=config/ruleset.xml -v --ignore=/config/Migrations/,/src/Dto/ src/ tests/ config/" + "cs-fix": "vendor/bin/phpcbf --colors --standard=config/ruleset.xml --ignore=/config/Migrations/,/src/Dto/ src/ tests/ config/" } } diff --git a/src/Business/Logger/TransitionLog.php b/src/Business/Logger/TransitionLog.php index 7d13cfc..0ba6259 100644 --- a/src/Business/Logger/TransitionLog.php +++ b/src/Business/Logger/TransitionLog.php @@ -47,11 +47,24 @@ public function __construct( */ public function setEvent(EventInterface $event): void { - $nameEvent = $event->getName(); - $nameEvent .= $event->getEventTypeLabel(); + $eventName = $event->getName(); + $eventName .= $event->getEventTypeLabel(); foreach ($this->logEntities as $logEntity) { - $logEntity->event = $nameEvent; + $logEntity->event = $eventName; + } + } + + /** + * @param \StateMachine\Dto\StateMachine\ItemDto $itemDto + * @param string $eventName + * + * @return void + */ + public function setEventName(ItemDto $itemDto, string $eventName): void + { + foreach ($this->logEntities as $logEntity) { + $logEntity->event = $eventName; } } diff --git a/src/Business/Logger/TransitionLogInterface.php b/src/Business/Logger/TransitionLogInterface.php index a836792..69049b6 100644 --- a/src/Business/Logger/TransitionLogInterface.php +++ b/src/Business/Logger/TransitionLogInterface.php @@ -21,6 +21,14 @@ interface TransitionLogInterface */ public function setEvent(EventInterface $event): void; + /** + * @param \StateMachine\Dto\StateMachine\ItemDto $itemDto + * @param string $eventName + * + * @return void + */ + public function setEventName(ItemDto $itemDto, string $eventName): void; + /** * @param \StateMachine\Dto\StateMachine\ItemDto[] $stateMachineItems * diff --git a/src/Business/StateMachine/Trigger.php b/src/Business/StateMachine/Trigger.php index e138854..c73111b 100644 --- a/src/Business/StateMachine/Trigger.php +++ b/src/Business/StateMachine/Trigger.php @@ -136,6 +136,7 @@ public function triggerEvent(string $eventName, array $stateMachineItems): int $this->transitionLog->init($stateMachineItems); $this->logSourceState($stateMachineItems); + $this->logEventName($stateMachineItems, $eventName); $this->runCommand($eventName, $stateMachineItems, $processes); @@ -384,6 +385,19 @@ protected function logSourceState(array $stateMachineItems): void } } + /** + * @param \StateMachine\Dto\StateMachine\ItemDto[] $stateMachineItems + * @param string $eventName + * + * @return void + */ + protected function logEventName(array $stateMachineItems, string $eventName): void + { + foreach ($stateMachineItems as $itemDto) { + $this->transitionLog->setEventName($itemDto, $eventName); + } + } + /** * @param string $commandString * @param string $stateMachineName diff --git a/src/Model/Table/StateMachineTransitionLogsTable.php b/src/Model/Table/StateMachineTransitionLogsTable.php index a79ff98..492cb6e 100644 --- a/src/Model/Table/StateMachineTransitionLogsTable.php +++ b/src/Model/Table/StateMachineTransitionLogsTable.php @@ -170,7 +170,7 @@ public function afterSave(EventInterface $event, EntityInterface $entity, ArrayO /** * @param int $stateMachineItemId * - * @return array + * @return \StateMachine\Model\Entity\StateMachineTransitionLog[] */ public function getLogs(int $stateMachineItemId): array { diff --git a/tests/TestCase/Business/StateMachineFacadeTest.php b/tests/TestCase/Business/StateMachineFacadeTest.php index 103054f..4781d04 100644 --- a/tests/TestCase/Business/StateMachineFacadeTest.php +++ b/tests/TestCase/Business/StateMachineFacadeTest.php @@ -12,21 +12,26 @@ use Cake\I18n\FrozenTime; use Cake\ORM\TableRegistry; use Cake\TestSuite\TestCase; +use InvalidArgumentException; use StateMachine\Business\StateMachineFacade; use StateMachine\Business\StateMachineFacadeInterface; use StateMachine\Dependency\StateMachineHandlerInterface; use StateMachine\Dto\StateMachine\ItemDto; use StateMachine\Dto\StateMachine\ProcessDto; +use StateMachine\Model\Table\StateMachineItemsTable; use StateMachine\Model\Table\StateMachineItemStateHistoryTable; use StateMachine\Model\Table\StateMachineItemStatesTable; use StateMachine\Model\Table\StateMachineProcessesTable; use StateMachine\Model\Table\StateMachineTimeoutsTable; +use StateMachine\Model\Table\StateMachineTransitionLogsTable; class StateMachineFacadeTest extends TestCase { protected const TESTING_SM = 'TestingSm'; protected const TEST_PROCESS_NAME = 'TestProcess'; protected const TEST_PROCESS_WITH_LOOP_NAME = 'TestProcessWithLoop'; + protected const TEST_PROCESS_WITH_ERROR_NAME = 'TestProcessWithError'; + protected const TEST_PROCESS_WITH_COMMAND_ERROR_NAME = 'TestProcessWithCommandError'; /** * @var \StateMachine\Model\Table\StateMachineItemStateHistoryTable @@ -48,6 +53,11 @@ class StateMachineFacadeTest extends TestCase */ protected $StateMachineTimeouts; + /** + * @var \StateMachine\Model\Table\StateMachineTransitionLogsTable + */ + protected $StateMachineTransitionLogs; + /** * @var array */ @@ -81,6 +91,12 @@ public function setUp(): void $config = TableRegistry::getTableLocator()->exists('StateMachineTimeouts') ? [] : ['className' => StateMachineTimeoutsTable::class]; $this->StateMachineTimeouts = TableRegistry::getTableLocator()->get('StateMachineTimeouts', $config); + + $config = TableRegistry::getTableLocator()->exists('StateMachineTransitionLogs') ? [] : ['className' => StateMachineTransitionLogsTable::class]; + $this->StateMachineTransitionLogs = TableRegistry::getTableLocator()->get('StateMachineTransitionLogs', $config); + + $config = TableRegistry::getTableLocator()->exists('StateMachineItems') ? [] : ['className' => StateMachineItemsTable::class]; + $this->StateMachineItems = TableRegistry::getTableLocator()->get('StateMachineItems', $config); } /** @@ -211,6 +227,86 @@ public function testTriggerEventForItemWithManualEventShouldMoveToNextStateWithM $this->assertSame($identifier, $itemDto->getIdentifier()); } + /** + * @return void + */ + public function testTriggerEventConditionFailureLogsTransition(): void + { + $processName = static::TEST_PROCESS_WITH_ERROR_NAME; + $identifier = 1985; + + $processDto = new ProcessDto(); + $processDto->setProcessName($processName); + $processDto->setStateMachineName(static::TESTING_SM); + + $stateMachineHandler = $this->createTestStateMachineHandler(); + $stateMachineFacade = $this->createStateMachineFacade($stateMachineHandler); + + $failed = false; + try { + $stateMachineFacade->triggerForNewStateMachineItem($processDto, $identifier); + } catch (InvalidArgumentException $exception) { + $failed = true; + } + $this->assertTrue($failed, 'Should have thrown exception'); + + $itemDto = $stateMachineHandler->getItemStateUpdated(); + $this->assertSame('invoice sent', $itemDto->getStateName()); + $this->assertSame($identifier, $itemDto->getIdentifier()); + + $stateMachineItem = $this->StateMachineItems->find()->where(['state_machine' => static::TESTING_SM, 'identifier' => $identifier])->firstOrFail(); + + $logs = $this->StateMachineTransitionLogs->getLogs($stateMachineItem->id); + $this->assertCount(3, $logs); + + $lastLog = array_shift($logs); + $this->assertSame('export order (on enter)', $lastLog->event); + $this->assertSame('invoice sent', $lastLog->source_state); + $this->assertNull($lastLog->target_state); + $this->assertTrue($lastLog->is_error); + $this->assertContains('Test exception for identity', $lastLog->error_message); + } + + /** + * @return void + */ + public function testTriggerEventCommandFailureLogsTransition(): void + { + $processName = static::TEST_PROCESS_WITH_COMMAND_ERROR_NAME; + $identifier = 1985; + + $processDto = new ProcessDto(); + $processDto->setProcessName($processName); + $processDto->setStateMachineName(static::TESTING_SM); + + $stateMachineHandler = $this->createTestStateMachineHandler(); + $stateMachineFacade = $this->createStateMachineFacade($stateMachineHandler); + + $failed = false; + try { + $stateMachineFacade->triggerForNewStateMachineItem($processDto, $identifier); + } catch (InvalidArgumentException $exception) { + $failed = true; + } + $this->assertTrue($failed, 'Should have thrown exception'); + + $itemDto = $stateMachineHandler->getItemStateUpdated(); + $this->assertSame('invoice created', $itemDto->getStateName()); + $this->assertSame($identifier, $itemDto->getIdentifier()); + + $stateMachineItem = $this->StateMachineItems->find()->where(['state_machine' => static::TESTING_SM, 'identifier' => $identifier])->firstOrFail(); + + $logs = $this->StateMachineTransitionLogs->getLogs($stateMachineItem->id); + $this->assertCount(2, $logs); + + $lastLog = array_shift($logs); + $this->assertSame('send invoice', $lastLog->event); + $this->assertSame('invoice created', $lastLog->source_state); + $this->assertNull($lastLog->target_state); + $this->assertTrue($lastLog->is_error); + $this->assertContains('Test exception for identity', $lastLog->error_message); + } + /** * @return void */ diff --git a/tests/test_app/src/StateMachine/Command/TestErrorCommand.php b/tests/test_app/src/StateMachine/Command/TestErrorCommand.php new file mode 100644 index 0000000..2a94787 --- /dev/null +++ b/tests/test_app/src/StateMachine/Command/TestErrorCommand.php @@ -0,0 +1,29 @@ +getIdentifierOrFail()); + } +} diff --git a/tests/test_app/src/StateMachine/Condition/TestErrorCondition.php b/tests/test_app/src/StateMachine/Condition/TestErrorCondition.php new file mode 100644 index 0000000..aed9c8f --- /dev/null +++ b/tests/test_app/src/StateMachine/Condition/TestErrorCondition.php @@ -0,0 +1,30 @@ +getIdentifierOrFail()); + } +} diff --git a/tests/test_app/src/StateMachine/TestStateMachineHandler.php b/tests/test_app/src/StateMachine/TestStateMachineHandler.php index 0adf7a2..eec31b0 100644 --- a/tests/test_app/src/StateMachine/TestStateMachineHandler.php +++ b/tests/test_app/src/StateMachine/TestStateMachineHandler.php @@ -8,6 +8,8 @@ namespace App\StateMachine; use App\StateMachine\Command\TestCommand; +use App\StateMachine\Command\TestErrorCommand; +use App\StateMachine\Condition\TestErrorCondition; use App\StateMachine\Condition\TestTrueCondition; use StateMachine\Dependency\StateMachineHandlerInterface; use StateMachine\Dto\StateMachine\ItemDto; @@ -34,6 +36,7 @@ public function getCommands(): array { return [ 'Test/Command' => TestCommand::class, + 'Test/ErrorCommand' => TestErrorCommand::class, ]; } @@ -44,6 +47,7 @@ public function getConditions(): array { return [ 'Test/Condition' => TestTrueCondition::class, + 'Test/ErrorCondition' => TestErrorCondition::class, ]; } diff --git a/tests/test_files/TestingSm/TestProcessWithCommandError.xml b/tests/test_files/TestingSm/TestProcessWithCommandError.xml new file mode 100644 index 0000000..bb95bf5 --- /dev/null +++ b/tests/test_files/TestingSm/TestProcessWithCommandError.xml @@ -0,0 +1,38 @@ + + + + + + + + Flag1 + + + Flag1 + Flag2 + + + + + + new + invoice created + create invoice + + + + invoice created + invoice sent + send invoice + + + + + + + + + diff --git a/tests/test_files/TestingSm/TestProcessWithError.xml b/tests/test_files/TestingSm/TestProcessWithError.xml new file mode 100644 index 0000000..3e1612e --- /dev/null +++ b/tests/test_files/TestingSm/TestProcessWithError.xml @@ -0,0 +1,46 @@ + + + + + + + + Flag1 + + + Flag1 + Flag2 + + + + + + + new + invoice created + create invoice + + + + invoice created + invoice sent + send invoice + + + + invoice sent + order exported + export order + + + + + + + + + +