An event bus is capable of dispatching a message to multiple listeners.
Автор: Alexander Miertsch (kontakt@codeliner.ws)
Наследование: extends MessageBus
 /**
  * @param ActionEvent $actionEvent
  */
 public function onEventStoreCommitPost(ActionEvent $actionEvent)
 {
     $this->queuedActionEvents[] = $actionEvent;
     if (!$this->inConfirmSelectMode) {
         $this->inConfirmSelectMode = true;
         while ($actionEvent = array_shift($this->queuedActionEvents)) {
             $fallback = new \ArrayIterator();
             $recordedEvents = $actionEvent->getParam('recordedEvents', $fallback);
             if ($fallback !== $recordedEvents) {
                 $this->producer->confirmSelect();
             }
             $countRecordedEvents = 0;
             foreach ($recordedEvents as $recordedEvent) {
                 $this->eventBus->dispatch($recordedEvent);
                 $countRecordedEvents++;
             }
             if ($fallback !== $recordedEvents) {
                 $this->producer->setConfirmCallback(function (int $deliveryTag, bool $multiple) use($countRecordedEvents) {
                     return $deliveryTag !== $countRecordedEvents;
                 }, function (int $deliveryTag, bool $multiple, bool $requeue) use(&$result) {
                     throw new RuntimeException('Could not publish all events');
                 });
                 $this->producer->waitForConfirm($this->timeout);
             }
         }
         $this->inConfirmSelectMode = false;
     }
 }
 protected function setUp()
 {
     parent::setUp();
     $eventBus = new EventBus();
     $commandBus = new CommandBus();
     $commandRouter = new CommandRouter();
     $commandRouter->route(StartSubProcess::MSG_NAME)->to(function (StartSubProcess $command) {
         $this->receivedMessage = $command;
     });
     $commandRouter->route('processing-message-proophprocessingtestmockuserdictionary-collect-data')->to(function (WorkflowMessage $message) {
         $this->receivedMessage = $message;
     });
     $commandBus->utilize($commandRouter);
     $commandBus->utilize(new ToProcessingMessageTranslator());
     $commandBus->utilize(new CallbackStrategy());
     $eventRouter = new EventRouter();
     $eventRouter->route('processing-message-proophprocessingtestmockuserdictionary-data-collected')->to(function (WorkflowMessage $workflowMessage) {
         $this->receivedMessage = $workflowMessage;
     });
     $eventRouter->route('processing-log-message')->to(function (LogMessage $logMessage) {
         $this->receivedMessage = $logMessage;
     });
     $eventRouter->route(SubProcessFinished::MSG_NAME)->to(function (SubProcessFinished $event) {
         $this->receivedMessage = $event;
     });
     $eventBus->utilize($eventRouter);
     $eventBus->utilize(new ToProcessingMessageTranslator());
     $eventBus->utilize(new CallbackStrategy());
     $this->workflowEngine = new RegistryWorkflowEngine();
     $this->workflowEngine->registerCommandBus($commandBus, [NodeName::defaultName()->toString(), 'test-target', 'sub-processor']);
     $this->workflowEngine->registerEventBus($eventBus, [NodeName::defaultName()->toString()]);
 }
 /**
  * Publish recorded events on the event bus
  *
  * @param ActionEvent $actionEvent
  */
 public function onEventStoreCommitPost(ActionEvent $actionEvent)
 {
     $recordedEvents = $actionEvent->getParam('recordedEvents', new \ArrayIterator());
     foreach ($recordedEvents as $recordedEvent) {
         $this->eventBus->dispatch($recordedEvent);
     }
 }
 /**
  * @param BernardMessage $message
  */
 public function routeMessage(BernardMessage $message)
 {
     $proophMessage = $message->getProophMessage();
     if ($proophMessage->messageType() === Message::TYPE_COMMAND) {
         $this->commandBus->dispatch($proophMessage);
     } else {
         $this->eventBus->dispatch($proophMessage);
     }
 }
 /**
  * @test
  */
 public function it_invokes_processing_event_on_workflow_message_handler()
 {
     $userData = array('id' => 1, 'name' => 'Alex', 'address' => array('street' => 'Main Street', 'streetNumber' => 10, 'zip' => '12345', 'city' => 'Test City'));
     $user = UserDictionary::fromNativeValue($userData);
     $wfEvent = WorkflowMessage::newDataCollected($user, 'test-case', NodeName::defaultName());
     $eventBus = new EventBus();
     $eventRouter = new EventRouter();
     $eventRouter->route($wfEvent->messageName())->to($this->workflowMessageHandler);
     $eventBus->utilize($eventRouter);
     $eventBus->utilize(new HandleWorkflowMessageInvokeStrategy());
     $eventBus->dispatch($wfEvent);
     $this->assertSame($wfEvent, $this->workflowMessageHandler->lastWorkflowMessage());
 }
Пример #6
0
 /**
  * @interitdoc
  */
 public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
 {
     $eventName = $request->getAttribute(self::NAME_ATTRIBUTE);
     if (null === $eventName) {
         return $next($request, $response, new RuntimeException(sprintf('Event name attribute ("%s") was not found in request.', self::NAME_ATTRIBUTE), Middleware::STATUS_CODE_BAD_REQUEST));
     }
     try {
         $event = $this->eventFactory->createMessageFromArray($eventName, ['payload' => $request->getParsedBody(), 'metadata' => $this->metadataGatherer->getFromRequest($request)]);
         $this->eventBus->dispatch($event);
         return $response->withStatus(Middleware::STATUS_CODE_ACCEPTED);
     } catch (\Exception $e) {
         return $next($request, $response, new RuntimeException(sprintf('An error occurred during dispatching of event "%s"', $eventName), Middleware::STATUS_CODE_INTERNAL_SERVER_ERROR, $e));
     }
 }
 protected function setUp()
 {
     $this->workflowMessageHandler = new AbstractWorkflowMessageHandlerMock();
     $eventBus = new EventBus();
     $eventRouter = new EventRouter();
     $eventRouter->route(MessageNameUtils::LOG_MESSAGE_NAME)->to(function (LogMessage $logMessage) {
         $this->lastProcessingMessage = $logMessage;
     });
     $eventBus->utilize($eventRouter);
     $eventBus->utilize(new CallbackStrategy());
     $workflowEngine = new RegistryWorkflowEngine();
     $workflowEngine->registerEventBus($eventBus, [AbstractWorkflowEngine::LOCAL_CHANNEL, NodeName::defaultName()->toString()]);
     $this->workflowMessageHandler->useWorkflowEngine($workflowEngine);
 }
 /**
  * @test
  */
 public function it_confirms_select_one_action_event_after_the_other()
 {
     $actionEvent = $this->prophesize(ActionEvent::class);
     $iterator = new \ArrayIterator(['foo', 'bar']);
     $actionEvent->getParam('recordedEvents', new \ArrayIterator())->willReturn($iterator)->shouldBeCalled();
     $producer = $this->prophesize(Producer::class);
     $producer->startTransaction()->shouldBeCalledTimes(2);
     $producer->commitTransaction()->shouldBeCalledTimes(2);
     $eventBus = new EventBus();
     $plugin = new TransactionalEventPublisher($eventBus, $producer->reveal());
     $eventBusCalls = [];
     $eventRouter = new EventRouter();
     $eventRouter->route('foo')->to(function ($event) use($plugin, &$eventBusCalls) {
         $eventBusCalls[] = $event;
         $actionEvent = new DefaultActionEvent($event, null, ['recordedEvents' => new \ArrayIterator(['baz', 'bam', 'bat'])]);
         $plugin->onEventStoreCommitPost($actionEvent);
     });
     $eventRouter->route('bar')->to(function ($event) use(&$eventBusCalls) {
         $eventBusCalls[] = $event;
     });
     $eventRouter->route('baz')->to(function ($event) use(&$eventBusCalls) {
         $eventBusCalls[] = $event;
     });
     $eventRouter->route('bam')->to(function ($event) use(&$eventBusCalls) {
         $eventBusCalls[] = $event;
     });
     $eventRouter->route('bat')->to(function ($event) use(&$eventBusCalls) {
         $eventBusCalls[] = $event;
     });
     $eventBus->utilize($eventRouter);
     $plugin->onEventStoreCommitPost($actionEvent->reveal());
     $this->assertEquals(['foo', 'bar', 'baz', 'bam', 'bat'], $eventBusCalls);
 }
 protected function setUp()
 {
     UsersFixture::createTableAndInsertUsers($this->getDbalConnection());
     $this->messageReceiver = new StupidWorkflowProcessorMock();
     $this->commandBus = new CommandBus();
     $this->commandBus->utilize(new SingleTargetMessageRouter($this->messageReceiver));
     $this->commandBus->utilize(new WorkflowProcessorInvokeStrategy());
     $this->eventBus = new EventBus();
     $this->eventBus->utilize(new SingleTargetMessageRouter($this->messageReceiver));
     $this->eventBus->utilize(new WorkflowProcessorInvokeStrategy());
     $this->tableGateway = new DoctrineTableGateway($this->getDbalConnection(), self::TEST_TABLE);
     $this->workflowEngine = new RegistryWorkflowEngine();
     $this->workflowEngine->registerCommandBus($this->commandBus, [NodeName::defaultName()->toString(), 'test-case']);
     $this->workflowEngine->registerEventBus($this->eventBus, [NodeName::defaultName()->toString(), 'test-case']);
     $this->tableGateway->useWorkflowEngine($this->workflowEngine);
 }
Пример #10
0
 /**
  * @interitdoc
  */
 public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
 {
     $payload = null;
     $messageName = 'UNKNOWN';
     try {
         $payload = $request->getParsedBody();
         if (is_array($payload) && isset($payload['message_name'])) {
             $messageName = $payload['message_name'];
         }
         MessageDataAssertion::assert($payload);
         $message = $this->messageFactory->createMessageFromArray($payload['message_name'], $payload);
         switch ($message->messageType()) {
             case Message::TYPE_COMMAND:
                 $this->commandBus->dispatch($message);
                 return $response->withStatus(Middleware::STATUS_CODE_ACCEPTED);
             case Message::TYPE_EVENT:
                 $this->eventBus->dispatch($message);
                 return $response->withStatus(Middleware::STATUS_CODE_ACCEPTED);
             case Message::TYPE_QUERY:
                 return $this->responseStrategy->fromPromise($this->queryBus->dispatch($message));
             default:
                 return $next($request, $response, new RuntimeException(sprintf('Invalid message type "%s" for message "%s".', $message->messageType(), $messageName), Middleware::STATUS_CODE_BAD_REQUEST));
         }
     } catch (\Assert\InvalidArgumentException $e) {
         return $next($request, $response, new RuntimeException($e->getMessage(), Middleware::STATUS_CODE_BAD_REQUEST, $e));
     } catch (\Exception $e) {
         return $next($request, $response, new RuntimeException(sprintf('An error occurred during dispatching of message "%s"', $messageName), Middleware::STATUS_CODE_INTERNAL_SERVER_ERROR, $e));
     }
 }
Пример #11
0
 protected function setUp()
 {
     $this->messageReceiver = new StupidWorkflowProcessorMock();
     $this->commandBus = new CommandBus();
     $this->commandBus->utilize(new SingleTargetMessageRouter($this->messageReceiver));
     $this->commandBus->utilize(new WorkflowProcessorInvokeStrategy());
     $this->eventBus = new EventBus();
     $this->eventBus->utilize(new SingleTargetMessageRouter($this->messageReceiver));
     $this->eventBus->utilize(new WorkflowProcessorInvokeStrategy());
     $locationTranslator = new LocationTranslator(['temp' => sys_get_temp_dir(), 'testdata' => $this->getTestDataPath()]);
     $this->fileGateway = new FileGateway(Bootstrap::getServiceManager()->get('prooph.link.fileconnector.file_type_adapter_manager'), Bootstrap::getServiceManager()->get('prooph.link.fileconnector.filename_renderer'), $locationTranslator);
     $workflowEngine = new RegistryWorkflowEngine();
     $workflowEngine->registerCommandBus($this->commandBus, [NodeName::defaultName()->toString(), 'file-connector']);
     $workflowEngine->registerEventBus($this->eventBus, [NodeName::defaultName()->toString(), 'file-connector']);
     $this->fileGateway->useWorkflowEngine($workflowEngine);
     $this->tempPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR;
 }
 /**
  * Perform a message
  */
 public function perform()
 {
     $messageClass = $this->args['message_class'];
     /* @var $message \Prooph\Common\Messaging\RemoteMessage*/
     $message = $messageClass::fromArray($this->args['message_data']);
     if ($message->header()->type() === MessageHeader::TYPE_COMMAND) {
         try {
             $this->commandBus->dispatch($message);
         } catch (CommandDispatchException $ex) {
             throw $ex->getPrevious();
         }
     } else {
         try {
             $this->eventBus->dispatch($message);
         } catch (EventDispatchException $ex) {
             throw $ex->getPrevious();
         }
     }
 }
 /**
  * @param ActionEvent $actionEvent
  */
 public function onEventStoreCommitPost(ActionEvent $actionEvent)
 {
     $this->queuedActionEvents[] = $actionEvent;
     if (!$this->inTransaction) {
         $this->inTransaction = true;
         while ($actionEvent = array_shift($this->queuedActionEvents)) {
             $fallback = new \ArrayIterator();
             $recordedEvents = $actionEvent->getParam('recordedEvents', $fallback);
             if ($fallback !== $recordedEvents) {
                 $this->producer->startTransaction();
             }
             foreach ($recordedEvents as $recordedEvent) {
                 $this->eventBus->dispatch($recordedEvent);
             }
             if ($fallback !== $recordedEvents) {
                 $this->producer->commitTransaction();
             }
         }
         $this->inTransaction = false;
     }
 }
Пример #14
0
 /**
  * @test
  */
 public function it_invokes_all_listeners()
 {
     $handler = new MessageHandler();
     $this->eventBus->getActionEventEmitter()->attachListener(MessageBus::EVENT_ROUTE, function (ActionEvent $e) use($handler) {
         if ($e->getParam(MessageBus::EVENT_PARAM_MESSAGE_NAME) === CustomMessage::class) {
             $e->setParam(EventBus::EVENT_PARAM_EVENT_LISTENERS, [$handler, $handler]);
         }
     });
     $customMessage = new CustomMessage("foo");
     $this->eventBus->dispatch($customMessage);
     $this->assertSame($customMessage, $handler->getLastMessage());
     $this->assertEquals(2, $handler->getInvokeCounter());
 }
 /**
  * @param Envelope $envelope
  * @param Queue $queue
  * @return DeliveryResult
  */
 public function __invoke(Envelope $envelope, Queue $queue) : DeliveryResult
 {
     $data = json_decode($envelope->getBody(), true);
     if (!isset($data['created_at'])) {
         return DeliveryResult::MSG_REJECT();
     }
     $data['created_at'] = DateTimeImmutable::createFromFormat('Y-m-d\\TH:i:s.u', $data['created_at'], new DateTimeZone('UTC'));
     if (false === $data['created_at']) {
         return DeliveryResult::MSG_REJECT();
     }
     try {
         $event = $this->messageFactory->createMessageFromArray($envelope->getType(), $data);
         $this->eventBus->dispatch($event);
     } catch (\Throwable $e) {
         while ($e = $e->getPrevious()) {
             if ($e instanceof ConcurrencyException) {
                 return DeliveryResult::MSG_REJECT_REQUEUE();
             }
         }
         return DeliveryResult::MSG_REJECT();
     }
     return DeliveryResult::MSG_ACK();
 }
 /**
  * @test
  */
 public function it_sends_an_event_to_queue_pulls_it_with_consumer_and_forwards_it_to_event_bus()
 {
     $event = new SomethingDone(['data' => 'test event']);
     //The message dispatcher works with a ready-to-use bernard producer and one queue
     $messageProducer = new BernardMessageProducer($this->bernardProducer, 'test-queue');
     //Normally you would send the event on a event bus. We skip this step here cause we are only
     //interested in the function of the message dispatcher
     $messageProducer($event);
     //Set up event bus which will receive the event message from the bernard consumer
     $consumerEventBus = new EventBus();
     $somethingDoneListener = new MessageHandler();
     $consumerEventBus->utilize(new EventRouter([$event->messageName() => [$somethingDoneListener]]));
     //We use a special bernard router which forwards all messages to a command bus or event bus depending on the
     //Prooph\ServiceBus\Message\MessageHeader::TYPE
     $bernardRouter = new BernardRouter(new CommandBus(), $consumerEventBus);
     $bernardConsumer = new Consumer($bernardRouter, new EventDispatcher());
     //We use the same queue name here as we've defined for the message dispatcher above
     $bernardConsumer->tick($this->persistentFactory->create('test-queue'));
     $this->assertNotNull($somethingDoneListener->getLastMessage());
     $this->assertEquals($event->payload(), $somethingDoneListener->getLastMessage()->payload());
 }
 public function publishChangesOf(ProcessingConfig $processingConfig)
 {
     foreach ($processingConfig->popRecordedEvents() as $recordedEvent) {
         $this->eventBus->dispatch($recordedEvent);
     }
 }
Пример #18
0
 protected function setUpOtherMachine()
 {
     $this->otherMachineWorkflowMessageHandler = new TestWorkflowMessageHandler();
     $commandBus = new CommandBus();
     $this->otherMachineCommandRouter = new CommandRouter();
     $this->otherMachineCommandRouter->route(MessageNameUtils::getCollectDataCommandName('Prooph\\ProcessingTest\\Mock\\UserDictionaryS2'))->to($this->otherMachineWorkflowMessageHandler);
     $this->otherMachineCommandRouter->route(MessageNameUtils::getProcessDataCommandName('Prooph\\ProcessingTest\\Mock\\TargetUserDictionary'))->to($this->otherMachineWorkflowMessageHandler);
     $commandBus->utilize($this->otherMachineCommandRouter);
     $commandBus->utilize(new HandleWorkflowMessageInvokeStrategy());
     $commandBus->utilize(new WorkflowProcessorInvokeStrategy());
     $commandBus->utilize(new ToProcessingMessageTranslator());
     $this->otherMachineWorkflowEngine = new RegistryWorkflowEngine();
     $this->otherMachineWorkflowEngine->registerCommandBus($commandBus, ['test-case', 'test-target', 'other_machine']);
     //Add second command bus to local workflow engine to forward StartSubProcess command to message dispatcher
     $this->otherMachineMessageDispatcher = new InMemoryRemoteMessageDispatcher($commandBus, new EventBus());
     $parentNodeCommandBus = new CommandBus();
     $parentCommandRouter = new CommandRouter();
     $parentCommandRouter->route(StartSubProcess::MSG_NAME)->to($this->otherMachineMessageDispatcher);
     $parentNodeCommandBus->utilize($parentCommandRouter);
     $parentNodeCommandBus->utilize(new ForwardToRemoteMessageDispatcherStrategy(new FromProcessingMessageTranslator()));
     $this->workflowEngine->registerCommandBus($parentNodeCommandBus, ['other_machine']);
     $this->getOtherMachineWorkflowProcessor();
     //Add event buses to handle SubProcessFinished event
     $parentNodeEventBus = new EventBus();
     $parentNodeEventRouter = new EventRouter();
     $parentNodeEventBus->utilize(new SingleTargetMessageRouter($this->getTestWorkflowProcessor()));
     $parentNodeEventBus->utilize(new ToProcessingMessageTranslator());
     $parentNodeEventBus->utilize(new WorkflowProcessorInvokeStrategy());
     $otherMachineEventBus = new EventBus();
     $toParentNodeMessageDispatcher = new InMemoryRemoteMessageDispatcher(new CommandBus(), $parentNodeEventBus);
     $otherMachineEventBus->utilize(new SingleTargetMessageRouter($toParentNodeMessageDispatcher));
     $otherMachineEventBus->utilize(new ForwardToRemoteMessageDispatcherStrategy(new FromProcessingMessageTranslator()));
     $this->otherMachineWorkflowEngine->registerEventBus($otherMachineEventBus, [Definition::DEFAULT_NODE_NAME]);
 }
Пример #19
0
 /**
  * @test
  */
 public function it_performs_next_task_after_receiving_answer_for_previous_task()
 {
     $task1 = CollectData::from('test-case', UserDictionary::prototype());
     $task2 = ProcessData::address('test-target', ['Prooph\\ProcessingTest\\Mock\\UserDictionary']);
     $process = LinearProcess::setUp(NodeName::defaultName(), [$task1, $task2]);
     $wfm = WorkflowMessage::collectDataOf(UserDictionary::prototype(), NodeName::defaultName(), 'test-case');
     $answer1 = $wfm->answerWith(UserDictionary::fromNativeValue(['id' => 1, 'name' => 'John Doe', 'address' => ['street' => 'Main Street', 'streetNumber' => 10, 'zip' => '12345', 'city' => 'Test City']]));
     $this->workflowMessageHandler->setNextAnswer($answer1);
     $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 2);
     //Fake follow up task execution
     $processDataMessage = $answer1->prepareDataProcessing($taskListPosition, 'test-handler');
     //Remove TaskListPosition again
     $ref = new \ReflectionClass($processDataMessage);
     $taskListPositionProp = $ref->getProperty('processTaskListPosition');
     $taskListPositionProp->setAccessible(true);
     $taskListPositionProp->setValue($processDataMessage, null);
     $this->commandRouter->route($processDataMessage->messageName())->to($this->workflowMessageHandler);
     $answer2 = $processDataMessage->answerWithDataProcessingCompleted();
     $eventBus = new EventBus();
     $eventRouter = new EventRouter([$answer1->messageName() => [function (WorkflowMessage $answer) use($process, $answer2) {
         $this->workflowMessageHandler->setNextAnswer($answer2);
         $process->receiveMessage($answer, $this->workflowEngine);
     }], $answer2->messageName() => [function (WorkflowMessage $answer) use($process) {
         $process->receiveMessage($answer, $this->workflowEngine);
     }]]);
     $eventBus->utilize($eventRouter)->utilize(new CallbackStrategy());
     $workflowEngine = new RegistryWorkflowEngine();
     $workflowEngine->registerEventBus($eventBus, [NodeName::defaultName()->toString()]);
     $this->workflowMessageHandler->useWorkflowEngine($workflowEngine);
     $process->perform($this->workflowEngine);
     $this->assertTrue($process->isFinished());
     $this->assertTrue($process->isSuccessfulDone());
 }
 /**
  * @test
  */
 public function it_sends_a_sub_process_finished_event_via_message_dispatcher_to_a_handler()
 {
     $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1);
     $wfMessage = $this->getUserDataCollectedTestMessage();
     $wfMessage->connectToProcessTask($taskListPosition);
     $logMessage = LogMessage::logDebugMsg("Just a fake event", $wfMessage);
     $subProcessFinished = SubProcessFinished::record(NodeName::defaultName(), $taskListPosition->taskListId()->processId(), true, $logMessage, $taskListPosition);
     $eventBus = new EventBus();
     $eventRouter = new EventRouter();
     $eventRouter->route(SubProcessFinished::MSG_NAME)->to($this->messageDispatcher);
     $eventBus->utilize($eventRouter);
     $eventBus->utilize(new ForwardToRemoteMessageDispatcherStrategy(new FromProcessingMessageTranslator()));
     $eventBus->dispatch($subProcessFinished);
     /** @var $receivedMessage SubProcessFinished */
     $receivedMessage = $this->receivedMessage;
     $this->assertInstanceOf(get_class($subProcessFinished), $receivedMessage);
     $this->assertTrue($taskListPosition->taskListId()->processId()->equals($receivedMessage->subProcessId()));
     $this->assertTrue($taskListPosition->equals($receivedMessage->parentTaskListPosition()));
     $this->assertTrue($subProcessFinished->uuid()->equals($receivedMessage->uuid()));
     $this->assertTrue($logMessage->uuid()->equals($receivedMessage->lastMessage()->uuid()));
     $this->assertEquals($logMessage->technicalMsg(), $receivedMessage->lastMessage()->technicalMsg());
     $this->assertEquals($subProcessFinished->createdAt()->format('Y-m-d H:i:s'), $receivedMessage->createdAt()->format('Y-m-d H:i:s'));
 }
Пример #21
0
 /**
  * Dispatch a tick event
  *
  * @return array
  */
 public function tickAction()
 {
     $this->eventBus->dispatch(TickOccurred::record());
     return new JsonModel(['success' => true]);
 }
Пример #22
0
 /**
  * @test
  */
 public function it_queues_incoming_messages_during_active_transaction_to_avoid_nested_transactions()
 {
     $wfMessage = $this->getUserDataCollectedTestMessage();
     $eventBus = new EventBus();
     $eventBus->utilize(new SingleTargetMessageRouter($this->getTestWorkflowProcessor()));
     $eventBus->utilize(new WorkflowProcessorInvokeStrategy());
     $workflowEngine = new RegistryWorkflowEngine();
     $workflowEngine->registerEventBus($eventBus, [NodeName::defaultName()->toString()]);
     $this->workflowMessageHandler->useWorkflowEngine($workflowEngine);
     $nextAnswer = $wfMessage->prepareDataProcessing(TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1), NodeName::defaultName())->answerWithDataProcessingCompleted();
     $ref = new \ReflectionClass($nextAnswer);
     $refProp = $ref->getProperty('processTaskListPosition');
     $refProp->setAccessible(true);
     $refProp->setValue($nextAnswer, null);
     $this->workflowMessageHandler->setNextAnswer($nextAnswer);
     //Without queueing incoming messages an exception will be thrown, cause the WorkflowMessageHandler answers
     //during active transaction and the WorkflowProcessor would try to load the not yet persisted process.
     $this->getTestWorkflowProcessor()->receiveMessage($wfMessage);
     $this->assertNotNull($this->lastPostCommitEvent);
     $recordedEvents = $this->lastPostCommitEvent->getRecordedEvents();
     $eventNames = [];
     foreach ($recordedEvents as $recordedEvent) {
         $eventNames[] = $recordedEvent->messageName();
     }
     $expectedEventNames = ['Prooph\\Processing\\Processor\\Task\\Event\\TaskEntryMarkedAsDone'];
     $this->assertEquals($expectedEventNames, $eventNames);
 }