diff --git a/mailpoet/tests/integration/Automation/Engine/Control/StepRunLoggerTest.php b/mailpoet/tests/integration/Automation/Engine/Control/StepRunLoggerTest.php new file mode 100644 index 0000000000..e6bc6a64f3 --- /dev/null +++ b/mailpoet/tests/integration/Automation/Engine/Control/StepRunLoggerTest.php @@ -0,0 +1,193 @@ +storage = $this->diContainer->get(AutomationRunLogStorage::class); + $this->hooks = $this->diContainer->get(Hooks::class); + } + + public function testItLogsStart(): void { + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 1); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(0, $logs); + + $logger->logStart(); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(1, $logs); + $this->assertLogData($logs[0]); + } + + public function testItLogsStepData(): void { + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 1); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(0, $logs); + + $logger->logStart(); + $logger->logStepData(new Step('step-id', 'action', 'step-key', [], [])); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(1, $logs); + $this->assertLogData($logs[0], ['step_key' => 'step-key']); + } + + public function testItLogsSuccess(): void { + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 1); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(0, $logs); + + $logger->logStart(); + $logger->logSuccess(); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(1, $logs); + $this->assertLogData($logs[0], ['status' => 'complete']); + } + + public function testItLogsProgress(): void { + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 1); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(0, $logs); + + $logger->logStart(); + $logger->logProgress(); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(1, $logs); + $this->assertLogData($logs[0], ['status' => 'running']); + } + + public function testItLogsFailure(): void { + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 1); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(0, $logs); + + $error = new Exception('test error'); + $logger->logStart(); + $logger->logFailure($error); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(1, $logs); + $this->assertLogData($logs[0], ['status' => 'failed', 'error' => $error]); + } + + public function testItLogsRunNumber(): void { + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 1); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(0, $logs); + + $logger->logStart(); + $logger->logProgress(); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(1, $logs); + $this->assertLogData($logs[0], ['run_number' => 1]); + + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 2); + $logger->logStart(); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(1, $logs); + $this->assertLogData($logs[0], ['status' => 'running', 'run_number' => 2]); + } + + public function testItTriggersAfterRunHook(): void { + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 1); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(0, $logs); + + $runs = 0; + $lastLog = null; + + $wp = $this->diContainer->get(WordPress::class); + $wp->addAction(Hooks::AUTOMATION_RUN_LOG_AFTER_STEP_RUN, function (AutomationRunLog $log) use (&$runs, &$lastLog) { + $log->setData('test', 'value'); + $runs += 1; + $lastLog = $log; + }); + + $logger->logStart(); + $logger->logStepData(new Step('step-id', 'action', 'step-key', [], [])); + $logger->logProgress(); + $this->assertSame(0, $runs); + + $logger->logSuccess(); + + /** @var int $runs PHPStan thinks $runs === 0 from the previous assert */ + $this->assertSame(1, $runs); + $this->assertNotNull($lastLog); + $this->assertLogData($lastLog, ['step_key' => 'step-key', 'status' => 'complete', 'data' => '{"test":"value"}']); + + $error = new Exception('test error'); + $logger->logFailure($error); + + /** @var int $runs PHPStan thinks $runs === 1 from the previous assert */ + $this->assertSame(2, $runs); + $this->assertNotNull($lastLog); + $this->assertLogData($lastLog, ['step_key' => 'step-key', 'status' => 'failed', 'data' => '{"test":"value"}', 'error' => $error]); + } + + public function testItCatchesAfterRunHookErrors(): void { + $logger = new StepRunLogger($this->storage, $this->hooks, 1, 'step-id', AutomationRunLog::TYPE_ACTION, 1); + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(0, $logs); + + $runs = 0; + $wp = $this->diContainer->get(WordPress::class); + $wp->addAction(Hooks::AUTOMATION_RUN_LOG_AFTER_STEP_RUN, function (AutomationRunLog $log) use (&$runs) { + $runs += 1; + throw new Exception('test error'); + }); + + $logger->logStart(); + $logger->logStepData(new Step('step-id', 'action', 'step-key', [], [])); + $logger->logProgress(); + $this->assertSame(0, $runs); + + $logger->logSuccess(); + + /** @var int $runs PHPStan thinks $runs === 0 from the previous assert */ + $this->assertSame(1, $runs); + + $logs = $this->storage->getLogsForAutomationRun(1); + $this->assertCount(1, $logs); + $this->assertLogData($logs[0], ['step_key' => 'step-key', 'status' => 'complete']); + } + + private function assertLogData(AutomationRunLog $log, array $data = []): void { + $error = isset($data['error']) ? [ + 'message' => $data['error']->getMessage(), + 'errorClass' => get_class($data['error']), + 'code' => $data['error']->getCode(), + 'trace' => Json::decode(Json::encode($data['error']->getTrace())), // normalize objects to arrays + ] : []; + + $expected = [ + 'id' => $data['id'] ?? $log->getId(), + 'automation_run_id' => $data['automation_run_id'] ?? 1, + 'step_id' => $data['step_id'] ?? 'step-id', + 'step_type' => $data['step_type'] ?? 'action', + 'step_key' => $data['step_key'] ?? 'unknown', + 'status' => $data['status'] ?? 'running', + 'started_at' => $data['started_at'] ?? $log->getStartedAt()->format(DateTimeImmutable::W3C), + 'updated_at' => $data['updated_at'] ?? $log->getUpdatedAt()->format(DateTimeImmutable::W3C), + 'run_number' => $data['row_number'] ?? 1, + 'data' => $data['data'] ?? '{}', + 'error' => Json::encode($error), + ]; + $this->assertSame($expected, $log->toArray()); + } +} diff --git a/mailpoet/tests/integration/Automation/Engine/Data/AutomationRunLogTest.php b/mailpoet/tests/integration/Automation/Engine/Data/AutomationRunLogTest.php index 3978e4ef16..6fc8961c9a 100644 --- a/mailpoet/tests/integration/Automation/Engine/Data/AutomationRunLogTest.php +++ b/mailpoet/tests/integration/Automation/Engine/Data/AutomationRunLogTest.php @@ -130,26 +130,6 @@ class AutomationRunLogTest extends \MailPoetTest { expect($log->getData())->count(0); } - public function testItGetsExposedViaAction(): void { - $this->wp->addAction(Hooks::AUTOMATION_RUN_LOG_AFTER_STEP_RUN, function(AutomationRunLog $log) { - $log->setData('test', 'value'); - }); - $automationRunLogs = $this->getLogsForAction(); - expect($automationRunLogs)->count(1); - $log = $automationRunLogs[0]; - expect($log->getData()['test'])->equals('value'); - } - - public function testBadActionIntegrationsCannotDerailStepFromRunning() { - $this->wp->addAction(Hooks::AUTOMATION_RUN_LOG_AFTER_STEP_RUN, function(AutomationRunLog $log) { - throw new \Exception('bad integration'); - }); - $automationRunLogs = $this->getLogsForAction(); - expect($automationRunLogs)->count(1); - $log = $automationRunLogs[0]; - expect($log->getStatus())->equals(AutomationRunLog::STATUS_COMPLETE); - } - public function testItStoresAutomationRunAndStepIdsCorrectly() { $testAction = $this->getRegisteredTestAction(); $actionStep = new Step('action-step-id', Step::TYPE_ACTION, $testAction->getKey(), [], []); @@ -197,29 +177,6 @@ class AutomationRunLogTest extends \MailPoetTest { expect($log->getUpdatedAt())->isInstanceOf(\DateTimeImmutable::class); } - public function testItLogsFailedStatusCorrectly(): void { - $automationRunLogs = $this->getLogsForAction(function() { - throw new \Exception('error'); - }); - expect($automationRunLogs)->count(1); - $log = $automationRunLogs[0]; - expect($log->getStatus())->equals('failed'); - } - - public function testItIncludesErrorOnFailure(): void { - $automationRunLogs = $this->getLogsForAction(function() { - throw new \Exception('error', 12345); - }); - expect($automationRunLogs)->count(1); - $log = $automationRunLogs[0]; - $error = $log->getError(); - expect($error['message'])->equals('error'); - expect($error['code'])->equals(12345); - expect($error['errorClass'])->equals('Exception'); - expect($error['trace'])->array(); - expect(count($error['trace']))->greaterThan(0); - } - private function getLogsForAction($callback = null) { if ($callback === null) { $callback = function() {