Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,21 @@ clean:
.PHONY: regenerate-fixture-results
regenerate-fixture-results: vendor
$(DOCKER_PHP_EXEC) vendor/bin/phpunit \
--log-junit test/fixtures/special_chars/data-provider-with-special-chars.xml \
--log-junit test/fixtures/special_chars/junit-data-provider-with-special-chars.xml \
--log-otr test/fixtures/special_chars/otr-data-provider-with-special-chars.xml \
--no-configuration \
test/fixtures/special_chars/UnitTestWithDataProviderSpecialCharsTest.php \
> /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/ErrorTest.php --log-junit test/fixtures/common_results/junit/ErrorTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/FailureTest.php --log-junit test/fixtures/common_results/junit/FailureTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/IncompleteTest.php --log-junit test/fixtures/common_results/junit/IncompleteTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/RiskyTest.php --log-junit test/fixtures/common_results/junit/RiskyTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/SkippedTest.php --log-junit test/fixtures/common_results/junit/SkippedTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/SuccessTest.php --log-junit test/fixtures/common_results/junit/SuccessTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/WarningTest.php --log-junit test/fixtures/common_results/junit/WarningTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/ --log-junit test/fixtures/common_results/combined.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/ErrorTest.php --log-junit test/fixtures/common_results/junit/ErrorTest.xml --log-otr test/fixtures/common_results/otr/ErrorTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/FailureTest.php --log-junit test/fixtures/common_results/junit/FailureTest.xml --log-otr test/fixtures/common_results/otr/FailureTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/IncompleteTest.php --log-junit test/fixtures/common_results/junit/IncompleteTest.xml --log-otr test/fixtures/common_results/otr/IncompleteTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/RiskyTest.php --log-junit test/fixtures/common_results/junit/RiskyTest.xml --log-otr test/fixtures/common_results/otr/RiskyTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/SkippedTest.php --log-junit test/fixtures/common_results/junit/SkippedTest.xml --log-otr test/fixtures/common_results/otr/SkippedTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/SuccessTest.php --log-junit test/fixtures/common_results/junit/SuccessTest.xml --log-otr test/fixtures/common_results/otr/SuccessTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/WarningTest.php --log-junit test/fixtures/common_results/junit/WarningTest.xml --log-otr test/fixtures/common_results/otr/WarningTest.xml > /dev/null || true
$(DOCKER_PHP_EXEC) vendor/bin/phpunit --no-configuration test/fixtures/common_results/ --log-junit test/fixtures/common_results/junit-combined.xml --log-otr test/fixtures/common_results/otr-combined.xml > /dev/null || true
find test/fixtures/ -type f -name "*.xml" -print0 | xargs -0 sed -i 's#$(PWD)#.#g'
find test/fixtures/ -type f -name "*.xml" -print0 | xargs -0 sed -i 's#time="........"#time="1.234567"#g'
sed -i 's#name="./test/fixtures/common_results"#name=""#g' test/fixtures/common_results/combined.xml
sed -i 's#name="CLI Arguments"#name=""#g' test/fixtures/common_results/combined.xml
find test/fixtures/ -type f -name "*.xml" -print0 | xargs -0 sed -i 's#time="..........................."#time="2026-02-01T12:13:14.567890Z"#g'
sed -i 's#name="./test/fixtures/common_results"#name=""#g' test/fixtures/common_results/junit-combined.xml test/fixtures/common_results/otr-combined.xml
sed -i 's#name="CLI Arguments"#name=""#g' test/fixtures/common_results/junit-combined.xml test/fixtures/common_results/otr-combined.xml
8 changes: 8 additions & 0 deletions src/Otr/Event.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace ParaTest\Otr;

final readonly class Event
{

}
28 changes: 28 additions & 0 deletions src/Otr/Events.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

Check failure on line 1 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Missing declare(strict_types=1).

namespace ParaTest\Otr;

use SimpleXMLElement;
use SplFileInfo;

final readonly class Events
{
public static function fromFile(SplFileInfo $logFile): self
{
assert($logFile->isFile() && 0 < (int) $logFile->getSize());

Check failure on line 12 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Function assert() should not be referenced via a fallback global name, but via a use statement.

$logFileContents = file_get_contents($logFile->getPathname());

Check failure on line 14 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Function file_get_contents() should not be referenced via a fallback global name, but via a use statement.
assert($logFileContents !== false);

Check failure on line 15 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Function assert() should not be referenced via a fallback global name, but via a use statement.
$xml = new SimpleXMLElement($logFileContents);

Check failure on line 16 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Line indented incorrectly; expected at least 8 spaces, found 0
var_dump($xml->children('e', true));

Check failure on line 17 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Function var_dump() should not be referenced via a fallback global name, but via a use statement.

Check failure on line 17 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Line indented incorrectly; expected at least 8 spaces, found 0
foreach ($xml->children('e', true) as $event) {

Check failure on line 18 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Expected 1 line after "foreach", found 0.

Check failure on line 18 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Line indented incorrectly; expected 8 spaces, found 0
var_dump($event);exit();

Check failure on line 19 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Line indented incorrectly; expected at least 12 spaces, found 4
}
var_dump('end');exit;
print_r($xml);exit;

Check failure on line 22 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Unreachable statement - code above always terminates.

Check warning on line 22 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Code after the EXIT statement on line 21 cannot be executed
return self::parseTestSuite(

Check warning on line 23 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Code after the EXIT statement on line 22 cannot be executed

Check warning on line 23 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Code after the EXIT statement on line 21 cannot be executed
new SimpleXMLElement($logFileContents),

Check warning on line 24 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Code after the EXIT statement on line 22 cannot be executed

Check warning on line 24 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Code after the EXIT statement on line 21 cannot be executed
true,

Check warning on line 25 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Code after the EXIT statement on line 22 cannot be executed

Check warning on line 25 in src/Otr/Events.php

View workflow job for this annotation

GitHub Actions / Coding Standards (8.3)

Code after the EXIT statement on line 21 cannot be executed
);
}
}
68 changes: 68 additions & 0 deletions src/Otr/LogMerger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace ParaTest\Otr;

use SplFileInfo;

/**
* @internal
*
* @immutable
*/
final readonly class LogMerger
{
/** @param list<SplFileInfo> $otrFiles */
public function merge(array $otrFiles)

Check failure on line 17 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Method ParaTest\Otr\LogMerger::merge() has no return type specified.
{
$mainSuite = null;
foreach ($otrFiles as $otrFile) {
if (! $otrFile->isFile()) {
continue;
}

$otherSuite = Events::fromFile($otrFile);
if ($mainSuite === null) {
$mainSuite = $otherSuite;
continue;
}

if ($mainSuite->name !== $otherSuite->name) {

Check failure on line 31 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Cannot access property $name on mixed.

Check failure on line 31 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Access to an undefined property ParaTest\Otr\Events::$name.
if ($mainSuite->name !== '') {

Check failure on line 32 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Cannot access property $name on mixed.
$mainSuite = new TestSuite(

Check failure on line 33 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Instantiated class ParaTest\Otr\TestSuite not found.
'',
$mainSuite->tests,

Check failure on line 35 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Cannot access property $tests on mixed.
$mainSuite->assertions,

Check failure on line 36 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Cannot access property $assertions on mixed.
$mainSuite->failures,

Check failure on line 37 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Cannot access property $failures on mixed.
$mainSuite->errors,

Check failure on line 38 in src/Otr/LogMerger.php

View workflow job for this annotation

GitHub Actions / Static Analysis (8.3)

Cannot access property $errors on mixed.
$mainSuite->skipped,
$mainSuite->time,
'',
[$mainSuite->name => $mainSuite],
[],
);
}

if ($otherSuite->name !== '') {
$otherSuite = new TestSuite(
'',
$otherSuite->tests,
$otherSuite->assertions,
$otherSuite->failures,
$otherSuite->errors,
$otherSuite->skipped,
$otherSuite->time,
'',
[$otherSuite->name => $otherSuite],
[],
);
}
}

$mainSuite = $mainSuite->mergeWith($otherSuite);
}

return $mainSuite;
}
}
4 changes: 2 additions & 2 deletions test/Unit/JUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ public function testMergeJunitLogs(): void
$xml = str_replace('time="8.641969"', 'time="1.234567"', $xml);
file_put_contents($outputFile, $xml);

self::assertXmlFileEqualsXmlFile(FIXTURES . '/common_results/combined.xml', $outputFile);
self::assertXmlFileEqualsXmlFile(FIXTURES . '/common_results/junit-combined.xml', $outputFile);
}

public function testHandleSpecialChars(): void
{
$tmpDir = (new TmpDirCreator())->create();

$junitLog = FIXTURES . '/special_chars/data-provider-with-special-chars.xml';
$junitLog = FIXTURES . '/special_chars/junit-data-provider-with-special-chars.xml';
$testSuite = (new LogMerger())->merge([new SplFileInfo($junitLog)]);
self::assertNotNull($testSuite);

Expand Down
50 changes: 50 additions & 0 deletions test/Unit/OtrTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace ParaTest\Tests\Unit;

use ParaTest\Otr\LogMerger;
use ParaTest\Otr\Writer;
use ParaTest\Tests\TmpDirCreator;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use SplFileInfo;

use function file_get_contents;
use function file_put_contents;
use function glob;
use function str_replace;

/** @internal */
#[CoversClass(LogMerger::class)]
final class OtrTest extends TestCase
{
public function testMergeOtrLogs(): void
{
$tmpDir = (new TmpDirCreator())->create();

$otrFiles = [];
$glob = glob(FIXTURES . '/common_results/otr/*');
self::assertNotFalse($glob);
foreach ($glob as $file) {
$otrFiles[] = new SplFileInfo($file);
}

self::assertNotSame([], $otrFiles);
$testSuite = (new LogMerger())->merge($otrFiles);
self::assertNotNull($testSuite);

$outputFile = $tmpDir . '/result.xml';
(new Writer())->write(
$testSuite,
$outputFile,
);

$xml = file_get_contents($outputFile);
self::assertNotFalse($xml);
file_put_contents($outputFile, $xml);

self::assertXmlFileEqualsXmlFile(FIXTURES . '/common_results/otr-combined.xml', $outputFile);
}
}
2 changes: 1 addition & 1 deletion test/Unit/WrapperRunner/WrapperRunnerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ public function testWritesLogWithEmptyNameWhenPathIsNotProvided(): void
$xml = preg_replace('/time="[^"]+"/', 'time="1.234567"', $xml);
file_put_contents($outputFile, $xml);

self::assertXmlFileEqualsXmlFile(FIXTURES . '/common_results/combined.xml', $outputFile);
self::assertXmlFileEqualsXmlFile(FIXTURES . '/common_results/junit-combined.xml', $outputFile);
}

public function testRunnerReversed(): void
Expand Down
171 changes: 171 additions & 0 deletions test/fixtures/common_results/otr-combined.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
<?xml version="1.0"?>
<e:events xmlns="https://schemas.opentest4j.org/reporting/core/0.2.0" xmlns:e="https://schemas.opentest4j.org/reporting/events/0.2.0" xmlns:php="https://schema.phpunit.de/otr/php/0.0.1" xmlns:phpunit="https://schema.phpunit.de/otr/phpunit/0.0.1">
<infrastructure>
<hostName>398c61687e1b</hostName>
<userName>code</userName>
<operatingSystem>Linux 398c61687e1b 6.17.0-14-generic #14~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Jan 15 15:52:10 UTC 2 x86_64</operatingSystem>
<php:phpVersion>8.3.30</php:phpVersion>
<php:threadModel>NTS</php:threadModel>
</infrastructure>
<e:started id="1" name="" time="2026-02-01T12:13:14.567890Z"/>
<e:started id="2" parentId="1" name="ParaTest\Tests\fixtures\common_results\ErrorTest" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/ErrorTest.php">
<filePosition line="11"/>
</fileSource>
<phpunit:classSource className="ParaTest\Tests\fixtures\common_results\ErrorTest"/>
</sources>
</e:started>
<e:started id="3" parentId="2" name="testError" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/ErrorTest.php">
<filePosition line="13"/>
</fileSource>
<phpunit:methodSource className="ParaTest\Tests\fixtures\common_results\ErrorTest" methodName="testError"/>
</sources>
</e:started>
<e:finished id="3" time="2026-02-01T12:13:14.567890Z">
<result status="ERRORED">
<reason>Error here!</reason>
<phpunit:throwable type="RuntimeException" assertionError="false"><![CDATA[RuntimeException: Error here!

./test/fixtures/common_results/ErrorTest.php:15
]]></phpunit:throwable>
</result>
</e:finished>
<e:finished id="2" time="2026-02-01T12:13:14.567890Z"/>
<e:started id="4" parentId="1" name="ParaTest\Tests\fixtures\common_results\FailureTest" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/FailureTest.php">
<filePosition line="10"/>
</fileSource>
<phpunit:classSource className="ParaTest\Tests\fixtures\common_results\FailureTest"/>
</sources>
</e:started>
<e:started id="5" parentId="4" name="testFailure" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/FailureTest.php">
<filePosition line="12"/>
</fileSource>
<phpunit:methodSource className="ParaTest\Tests\fixtures\common_results\FailureTest" methodName="testFailure"/>
</sources>
</e:started>
<e:finished id="5" time="2026-02-01T12:13:14.567890Z">
<result status="FAILED">
<reason>Failed asserting that false is true.</reason>
<phpunit:throwable type="PHPUnit\Framework\ExpectationFailedException" assertionError="true"><![CDATA[Failed asserting that false is true.

./test/fixtures/common_results/FailureTest.php:14
]]></phpunit:throwable>
</result>
</e:finished>
<e:finished id="4" time="2026-02-01T12:13:14.567890Z"/>
<e:started id="6" parentId="1" name="ParaTest\Tests\fixtures\common_results\IncompleteTest" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/IncompleteTest.php">
<filePosition line="10"/>
</fileSource>
<phpunit:classSource className="ParaTest\Tests\fixtures\common_results\IncompleteTest"/>
</sources>
</e:started>
<e:started id="7" parentId="6" name="testIncomplete" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/IncompleteTest.php">
<filePosition line="12"/>
</fileSource>
<phpunit:methodSource className="ParaTest\Tests\fixtures\common_results\IncompleteTest" methodName="testIncomplete"/>
</sources>
</e:started>
<e:finished id="7" time="2026-02-01T12:13:14.567890Z">
<result status="ABORTED">
<reason></reason>
<phpunit:throwable type="PHPUnit\Framework\IncompleteTestError" assertionError="false"><![CDATA[
./test/fixtures/common_results/IncompleteTest.php:14
]]></phpunit:throwable>
</result>
</e:finished>
<e:finished id="6" time="2026-02-01T12:13:14.567890Z"/>
<e:started id="8" parentId="1" name="ParaTest\Tests\fixtures\common_results\RiskyTest" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/RiskyTest.php">
<filePosition line="10"/>
</fileSource>
<phpunit:classSource className="ParaTest\Tests\fixtures\common_results\RiskyTest"/>
</sources>
</e:started>
<e:started id="9" parentId="8" name="testRisky" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/RiskyTest.php">
<filePosition line="12"/>
</fileSource>
<phpunit:methodSource className="ParaTest\Tests\fixtures\common_results\RiskyTest" methodName="testRisky"/>
</sources>
</e:started>
<e:finished id="9" time="2026-02-01T12:13:14.567890Z">
<result status="SUCCESSFUL"/>
</e:finished>
<e:finished id="8" time="2026-02-01T12:13:14.567890Z"/>
<e:started id="10" parentId="1" name="ParaTest\Tests\fixtures\common_results\SkippedTest" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/SkippedTest.php">
<filePosition line="10"/>
</fileSource>
<phpunit:classSource className="ParaTest\Tests\fixtures\common_results\SkippedTest"/>
</sources>
</e:started>
<e:started id="11" parentId="10" name="testSkipped" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/SkippedTest.php">
<filePosition line="12"/>
</fileSource>
<phpunit:methodSource className="ParaTest\Tests\fixtures\common_results\SkippedTest" methodName="testSkipped"/>
</sources>
</e:started>
<e:finished id="11" time="2026-02-01T12:13:14.567890Z">
<result status="SKIPPED">
<reason></reason>
</result>
</e:finished>
<e:finished id="10" time="2026-02-01T12:13:14.567890Z"/>
<e:started id="12" parentId="1" name="ParaTest\Tests\fixtures\common_results\SuccessTest" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/SuccessTest.php">
<filePosition line="10"/>
</fileSource>
<phpunit:classSource className="ParaTest\Tests\fixtures\common_results\SuccessTest"/>
</sources>
</e:started>
<e:started id="13" parentId="12" name="testSuccess" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/SuccessTest.php">
<filePosition line="12"/>
</fileSource>
<phpunit:methodSource className="ParaTest\Tests\fixtures\common_results\SuccessTest" methodName="testSuccess"/>
</sources>
</e:started>
<e:finished id="13" time="2026-02-01T12:13:14.567890Z">
<result status="SUCCESSFUL"/>
</e:finished>
<e:finished id="12" time="2026-02-01T12:13:14.567890Z"/>
<e:started id="14" parentId="1" name="ParaTest\Tests\fixtures\common_results\WarningTest" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/WarningTest.php">
<filePosition line="14"/>
</fileSource>
<phpunit:classSource className="ParaTest\Tests\fixtures\common_results\WarningTest"/>
</sources>
</e:started>
<e:started id="15" parentId="14" name="testWarning" time="2026-02-01T12:13:14.567890Z">
<sources>
<fileSource path="./test/fixtures/common_results/WarningTest.php">
<filePosition line="16"/>
</fileSource>
<phpunit:methodSource className="ParaTest\Tests\fixtures\common_results\WarningTest" methodName="testWarning"/>
</sources>
</e:started>
<e:finished id="15" time="2026-02-01T12:13:14.567890Z">
<result status="SUCCESSFUL"/>
</e:finished>
<e:finished id="14" time="2026-02-01T12:13:14.567890Z"/>
<e:finished id="1" time="2026-02-01T12:13:14.567890Z"/>
</e:events>
Loading
Loading