/** * @test */ public function it_creates_linear_messaging_process_as_sub_process_if_parent_process_id_is_given() { $processDefinition = ["process_type" => Definition::PROCESS_LINEAR_MESSAGING, "tasks" => [["task_type" => Definition::TASK_COLLECT_DATA, "source" => 'test-case', "processing_type" => 'Prooph\\ProcessingTest\\Mock\\UserDictionary']]]; $parentTaskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $processFactory = new ProcessFactory(); $process = $processFactory->createProcessFromDefinition($processDefinition, NodeName::defaultName(), $parentTaskListPosition); $this->assertInstanceOf('Prooph\\Processing\\Processor\\LinearProcess', $process); $this->assertTrue($process->isSubProcess()); $this->assertTrue($parentTaskListPosition->equals($process->parentTaskListPosition())); }
/** * @test */ public function it_handles_a_process_data_message() { $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 2); $wfMessage = WorkflowMessage::newDataCollected(UserDictionary::fromNativeValue(['id' => 1, 'name' => 'John Doe', 'address' => ['street' => 'Main Street', 'streetNumber' => 10, 'zip' => '12345', 'city' => 'Test City']]), 'test-case', NodeName::defaultName()); $wfMessage->connectToProcessTask($taskListPosition); $wfMessage = $wfMessage->prepareDataProcessing($taskListPosition, 'message-handler'); $this->workflowMessageHandler->handleWorkflowMessage($wfMessage); $this->assertSame($wfMessage, $this->workflowMessageHandler->lastProcessDataMessage()); $this->assertInstanceOf('Prooph\\Processing\\Message\\LogMessage', $this->lastProcessingMessage); }
/** * @test */ public function it_returns_start_sub_process_command_including_previous_message() { $subProcessDefinition = ["process_type" => Definition::PROCESS_LINEAR_MESSAGING, "tasks" => [["task_type" => Definition::TASK_COLLECT_DATA, "source" => 'test-case', "processing_type" => 'Prooph\\ProcessingTest\\Mock\\UserDictionary']]]; $task = RunSubProcess::setUp(NodeName::defaultName(), $subProcessDefinition); $parentTaskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $previousMessage = WorkflowMessage::newDataCollected(UserDictionary::fromNativeValue(['id' => 1, 'name' => 'John Doe', 'address' => ['street' => 'Main Street', 'streetNumber' => 10, 'zip' => '12345', 'city' => 'Test City']]), 'test-case', NodeName::defaultName()); $startSubProcess = $task->generateStartCommandForSubProcess($parentTaskListPosition, $previousMessage); $this->assertTrue($parentTaskListPosition->equals($startSubProcess->parentTaskListPosition())); $this->assertEquals($subProcessDefinition, $startSubProcess->subProcessDefinition()); $this->assertEquals($previousMessage->messageName(), $startSubProcess->previousWorkflowMessage()->messageName()); }
/** * @test */ public function it_translates_to_service_bus_message_and_back() { $subProcessDefinition = ["process_type" => Definition::PROCESS_LINEAR_MESSAGING, "tasks" => [["task_type" => Definition::TASK_COLLECT_DATA, "source" => 'test-case', "processing_type" => 'Prooph\\ProcessingTest\\Mock\\UserDictionary']]]; $parentTaskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $command = StartSubProcess::at($parentTaskListPosition, $subProcessDefinition, false, 'sub-processor'); $sbMessage = $command->toServiceBusMessage(); $this->assertInstanceOf('Prooph\\Common\\Messaging\\RemoteMessage', $sbMessage); $copyOfCommand = StartSubProcess::fromServiceBusMessage($sbMessage); $this->assertInstanceOf('Prooph\\Processing\\Processor\\Command\\StartSubProcess', $copyOfCommand); $this->assertTrue($parentTaskListPosition->equals($copyOfCommand->parentTaskListPosition())); $this->assertEquals($subProcessDefinition, $copyOfCommand->subProcessDefinition()); $this->assertFalse($copyOfCommand->syncLogMessages()); $this->assertEquals(NodeName::defaultName()->toString(), $copyOfCommand->origin()); $this->assertEquals('sub-processor', $copyOfCommand->target()); }
/** * @test */ public function it_translates_to_service_bus_message_and_back() { $nodeName = NodeName::fromString('other_machine'); $subProcessId = ProcessId::generate(); $parentTaskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $wfMessage = $this->getUserDataCollectedTestMessage(); $wfMessage->connectToProcessTask(TaskListPosition::at(TaskListId::linkWith($nodeName, $subProcessId), 1)); $message = LogMessage::logDebugMsg("Processing finished", $wfMessage); $event = SubProcessFinished::record($nodeName, $subProcessId, true, $message, $parentTaskListPosition); $sbMessage = $event->toServiceBusMessage(); $this->assertInstanceOf('Prooph\\Common\\Messaging\\RemoteMessage', $sbMessage); $copyOfEvent = SubProcessFinished::fromServiceBusMessage($sbMessage); $this->assertInstanceOf('Prooph\\Processing\\Processor\\Event\\SubProcessFinished', $copyOfEvent); $this->assertTrue($nodeName->equals($copyOfEvent->processorNodeName())); $this->assertTrue($parentTaskListPosition->equals($copyOfEvent->parentTaskListPosition())); $this->assertEquals($parentTaskListPosition->taskListId()->nodeName()->toString(), $copyOfEvent->target()); $this->assertTrue($subProcessId->equals($copyOfEvent->subProcessId())); $this->assertTrue($copyOfEvent->succeed()); $this->assertEquals($message->technicalMsg(), $copyOfEvent->lastMessage()->technicalMsg()); }
/** * @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')); }
/** * @return array */ public function provideEntries() { $wfStartMessage = WorkflowMessage::collectDataOf(TestUser::prototype(), 'test-case', 'localhost'); $startMessageLogEntry = MessageLogEntry::logMessage($wfStartMessage); $startMessageLogEntryWithAssignedProcessId = MessageLogEntry::logMessage($wfStartMessage); $startMessageLogEntryWithAssignedProcessId->assignIdOfStartedProcess(ProcessId::generate()); $startMessageLogEntryWithAssignedProcessIdSucceed = MessageLogEntry::logMessage($wfStartMessage); $startMessageLogEntryWithAssignedProcessIdSucceed->assignIdOfStartedProcess(ProcessId::generate()); $startMessageLogEntryWithAssignedProcessIdFailed = MessageLogEntry::logMessage($wfStartMessage); $startMessageLogEntryWithAssignedProcessIdFailed->markAsFailed("Starting process failed"); $wfMessage = WorkflowMessage::collectDataOf(TestUser::prototype(), 'test-case', 'localhost'); $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $wfMessage->connectToProcessTask($taskListPosition); $normalMessageLogEntryPending = MessageLogEntry::logMessage($wfMessage); $normalMessageLogEntrySucceed = MessageLogEntry::logMessage($wfMessage); $normalMessageLogEntrySucceed->markAsSucceed(); $normalMessageLogEntryFailed = MessageLogEntry::logMessage($wfMessage); $normalMessageLogEntryFailed->markAsFailed("Processing failed"); return [[$startMessageLogEntry], [$startMessageLogEntryWithAssignedProcessId], [$startMessageLogEntryWithAssignedProcessIdSucceed], [$startMessageLogEntryWithAssignedProcessIdFailed], [$normalMessageLogEntryPending], [$normalMessageLogEntrySucceed], [$normalMessageLogEntryFailed]]; }
/** * @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); }
/** * @test */ public function it_writes_each_string_of_the_collection_to_a_separate_file_and_the_value_is_available_in_the_filename_template_to_create_unique_file_names() { $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $strings = StringCollection::fromNativeValue(["first", "second", "third"]); $metadata = [FileGateway::META_FILE_TYPE => 'json', FileGateway::META_PATH => $this->tempPath, FileGateway::META_FILENAME_TEMPLATE => 'string-{{value}}.json', FileGateway::META_WRITE_MULTI_FILES => true]; $this->tempFiles[] = 'string-first.json'; $this->tempFiles[] = 'string-second.json'; $this->tempFiles[] = 'string-third.json'; $workflowMessage = WorkflowMessage::newDataCollected($strings, NodeName::defaultName()->toString(), 'file-connector'); $workflowMessage->connectToProcessTask($taskListPosition); $workflowMessage = $workflowMessage->prepareDataProcessing($taskListPosition, NodeName::defaultName()->toString(), $metadata); $this->fileGateway->handleWorkflowMessage($workflowMessage); $this->assertInstanceOf('Prooph\\Processing\\Message\\WorkflowMessage', $this->messageReceiver->getLastReceivedMessage()); $this->assertTrue(file_exists($this->tempPath . $this->tempFiles[0])); $this->assertTrue(file_exists($this->tempPath . $this->tempFiles[1])); $this->assertTrue(file_exists($this->tempPath . $this->tempFiles[2])); $second = json_decode(file_get_contents($this->tempPath . $this->tempFiles[1])); $this->assertEquals('second', $second); }
/** * @test */ public function it_transforms_a_process_data_command_to_a_data_processed_event() { $userData = array('id' => 1, 'name' => 'Alex', 'address' => array('street' => 'Main Street', 'streetNumber' => 10, 'zip' => '12345', 'city' => 'Test City')); $user = UserDictionary::fromNativeValue($userData); $wfMessage = WorkflowMessage::newDataCollected($user, 'test-case', NodeName::defaultName()->toString(), array('metadata' => true)); $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $wfCommand = $wfMessage->prepareDataProcessing($taskListPosition, 'user-data-processor', array('prepared' => true)); $wfAnswer = $wfCommand->answerWithDataProcessingCompleted(array('processed' => true)); $this->assertEquals(MessageNameUtils::MESSAGE_NAME_PREFIX . 'proophprocessingtestmockuserdictionary-data-processed', $wfAnswer->messageName()); $this->assertEquals($userData, $wfAnswer->payload()->extractTypeData()); $this->assertFalse($wfCommand->uuid()->equals($wfAnswer->uuid())); $this->assertEquals(1, $wfMessage->version()); $this->assertEquals(2, $wfCommand->version()); $this->assertEquals(3, $wfAnswer->version()); $this->assertTrue($taskListPosition->equals($wfCommand->processTaskListPosition())); $this->assertTrue($wfCommand->processTaskListPosition()->equals($wfAnswer->processTaskListPosition())); $this->assertEquals(array('metadata' => true, 'prepared' => true, 'processed' => true), $wfAnswer->metadata()); //Target of the new-data-collected event, should also be the target of the answer of the process-data command $this->assertEquals(NodeName::defaultName()->toString(), $wfAnswer->target()); //Origin of the answer should be the addressed message handler $this->assertEquals('user-data-processor', $wfAnswer->origin()); }
/** * @param TaskListPosition $parentTaskListPosition * @param NodeName $nodeName * @param Task[] $tasks * @param array $config * @param bool $syncLogMessages * @throws \InvalidArgumentException * @return static */ public static function setUpAsSubProcess(TaskListPosition $parentTaskListPosition, NodeName $nodeName, array $tasks, array $config = array(), $syncLogMessages = true) { /** @var $instance Process */ $instance = new static(); $instance->assertConfig($config); $processId = ProcessId::generate(); $taskList = TaskList::scheduleTasks(TaskListId::linkWith($nodeName, $processId), $tasks); if (!is_bool($syncLogMessages)) { throw new \InvalidArgumentException("Argument syncLogMessages must be of type boolean"); } $instance->recordThat(ProcessWasSetUp::asSubProcess($processId, $parentTaskListPosition, $taskList, $config, $syncLogMessages)); return $instance; }
protected function getTestTaskListEntry() { $processId = ProcessId::generate(); $taskListId = TaskListId::linkWith(NodeName::defaultName(), $processId); $taskListPosition = TaskListPosition::at($taskListId, 1); $task = CollectData::from('test-crm', UserDictionary::prototype()); return TaskListEntry::newEntryAt($taskListPosition, $task); }
/** * @return WorkflowMessage */ private function getTestWorkflowMessage() { $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $wfMessage = WorkflowMessage::collectDataOf(UserDictionary::prototype(), 'test-case', 'message-handler'); $wfMessage->connectToProcessTask($taskListPosition); return $wfMessage; }
/** * @test */ function it_does_not_perform_the_delete_query_when_no_listener_adds_a_condition() { $taskListPosition = TaskListPosition::at(TaskListId::linkWith(NodeName::defaultName(), ProcessId::generate()), 1); $metadata = [DoctrineTableGateway::META_TRY_UPDATE => true]; $users = TestUserCollection::fromNativeValue([['id' => null, 'name' => 'John Doe', 'age' => 29], ['id' => null, 'name' => 'Maxi Mustermann', 'age' => 41]]); $message = WorkflowMessage::newDataCollected($users, 'test-case', 'localhost'); $message->connectToProcessTask($taskListPosition); $message = $message->prepareDataProcessing($taskListPosition, 'localhost', $metadata); $this->tableGateway->handleWorkflowMessage($message); $this->assertInstanceOf('Prooph\\Processing\\Message\\WorkflowMessage', $this->messageReceiver->getLastReceivedMessage()); /** @var $message WorkflowMessage */ $message = $this->messageReceiver->getLastReceivedMessage(); $metadata = $message->metadata(); $this->assertTrue(isset($metadata[MessageMetadata::SUCCESSFUL_ITEMS])); $this->assertEquals(2, $metadata[MessageMetadata::SUCCESSFUL_ITEMS]); $this->assertTrue(isset($metadata[MessageMetadata::FAILED_ITEMS])); $this->assertEquals(0, $metadata[MessageMetadata::FAILED_ITEMS]); $this->assertTrue(isset($metadata[MessageMetadata::FAILED_MESSAGES])); $this->assertEmpty($metadata[MessageMetadata::FAILED_MESSAGES]); $query = $this->getDbalConnection()->createQueryBuilder(); $userResultSet = $query->select('*')->from(self::TEST_TABLE)->execute()->fetchAll(); $this->assertEquals(5, count($userResultSet)); $expectedUsers = [['id' => '1', 'name' => 'John Doe', 'age' => '34'], ['id' => '2', 'name' => 'Max Mustermann', 'age' => '41'], ['id' => '3', 'name' => 'Donald Duck', 'age' => '57'], ['id' => '4', 'name' => 'John Doe', 'age' => '29'], ['id' => '5', 'name' => 'Maxi Mustermann', 'age' => '41']]; $this->assertEquals($expectedUsers, $userResultSet); }
/** * @test */ public function it_dispatches_a_sub_process_finished_event() { $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); $this->workflowEngine->dispatch($subProcessFinished); $this->assertSame($subProcessFinished, $this->receivedMessage); }
/** * @return TaskList */ protected function getTestTaskList() { $task1 = CollectData::from('crm', UserDictionary::prototype()); $task2 = CollectData::from('online-shop', UserDictionary::prototype()); $task3 = CollectData::from('address-book', UserDictionary::prototype()); $processId = ProcessId::generate(); $taskListId = TaskListId::linkWith(NodeName::defaultName(), $processId); return TaskList::scheduleTasks($taskListId, [$task1, $task2, $task3]); }