Skip to content

Commit 06c345d

Browse files
committed
test: print Workflow History on test failure
1 parent 0a2bc21 commit 06c345d

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

tests/Acceptance/App/TestCase.php

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
namespace Temporal\Tests\Acceptance\App;
66

7+
use Google\Protobuf\Timestamp;
78
use Psr\Log\LoggerInterface;
89
use Spiral\Core\Container;
910
use Spiral\Core\Scope;
11+
use Temporal\Api\Enums\V1\EventType;
12+
use Temporal\Api\Failure\V1\Failure;
13+
use Temporal\Client\WorkflowClientInterface;
1014
use Temporal\Client\WorkflowStubInterface;
1115
use Temporal\Tests\Acceptance\App\Logger\ClientLogger;
1216
use Temporal\Tests\Acceptance\App\Logger\LoggerFactory;
@@ -59,6 +63,8 @@ function (Container $container): mixed {
5963
$runner->stop();
6064
$runner->start();
6165

66+
$this->printWorkflowException($container->get(WorkflowClientInterface::class), $args);
67+
6268
throw $e;
6369
} finally {
6470
// Cleanup: terminate injected workflow if any
@@ -75,4 +81,74 @@ function (Container $container): mixed {
7581
},
7682
);
7783
}
84+
85+
private function printWorkflowException(WorkflowClientInterface $workflowClient, array $args): ?\Throwable
86+
{
87+
foreach ($args as $arg) {
88+
if (!$arg instanceof WorkflowStubInterface) {
89+
continue;
90+
}
91+
92+
$fnTime = static fn(?Timestamp $ts): float => $ts === null
93+
? 0
94+
: $ts->getSeconds() + \round($ts->getNanos() / 1_000_000_000, 6);
95+
96+
foreach ($workflowClient->getWorkflowHistory(
97+
$arg->getExecution(),
98+
) as $event) {
99+
$start ??= $fnTime($event->getEventTime());
100+
echo "\n" . \str_pad((string) $event->getEventId(), 3, ' ', STR_PAD_LEFT) . ' ';
101+
# Calculate delta time
102+
$deltaMs = \round(1_000 * ($fnTime($event->getEventTime()) - $start));
103+
echo \str_pad(\number_format($deltaMs, 0, '.', "'"), 6, ' ', STR_PAD_LEFT) . 'ms ';
104+
echo \str_pad(EventType::name($event->getEventType()), 40, ' ', STR_PAD_RIGHT) . ' ';
105+
106+
$cause = $event->getStartChildWorkflowExecutionFailedEventAttributes()?->getCause()
107+
?? $event->getSignalExternalWorkflowExecutionFailedEventAttributes()?->getCause()
108+
?? $event->getRequestCancelExternalWorkflowExecutionFailedEventAttributes()?->getCause();
109+
if ($cause !== null) {
110+
echo "Cause: $cause";
111+
continue;
112+
}
113+
114+
$failure = $event->getActivityTaskFailedEventAttributes()?->getFailure()
115+
?? $event->getWorkflowTaskFailedEventAttributes()?->getFailure()
116+
?? $event->getNexusOperationFailedEventAttributes()?->getFailure()
117+
?? $event->getWorkflowExecutionFailedEventAttributes()?->getFailure()
118+
?? $event->getChildWorkflowExecutionFailedEventAttributes()?->getFailure()
119+
?? $event->getNexusOperationCancelRequestFailedEventAttributes()?->getFailure();
120+
121+
if ($failure === null) {
122+
continue;
123+
}
124+
125+
# Render failure
126+
echo "Failure:\n";
127+
echo "========== BEGIN ===========\n";
128+
$this->renderFailure($failure, 1);
129+
echo "=========== END ============\n";
130+
}
131+
}
132+
133+
return null;
134+
}
135+
136+
private function renderFailure(Failure $failure, int $level): void
137+
{
138+
$fnPad = static function (string $str) use ($level): string {
139+
$pad = \str_repeat(' ', $level);
140+
return $pad . \str_replace("\n", "\n$pad", $str);
141+
};
142+
echo $fnPad('Source: ' . $failure->getSource()) . "\n";
143+
echo $fnPad('Info: ' . $failure->getFailureInfo()) . "\n";
144+
echo $fnPad('Message: ' . $failure->getMessage()) . "\n";
145+
echo $fnPad("Stack trace:") . "\n";
146+
echo $fnPad($failure->getStackTrace()) . "\n";
147+
$previous = $failure->getCause();
148+
if ($previous !== null) {
149+
echo $fnPad('————————————————————————————') . "\n";
150+
echo $fnPad('Caused by:') . "\n";
151+
$this->renderFailure($previous, $level + 1);
152+
}
153+
}
78154
}

0 commit comments

Comments
 (0)