diff --git a/src/Plugins/Shard.php b/src/Plugins/Shard.php index abd835ea..0a660780 100644 --- a/src/Plugins/Shard.php +++ b/src/Plugins/Shard.php @@ -34,7 +34,8 @@ final class Shard implements AddsOutput, HandlesArguments, Terminable * index: int, * total: int, * testsRan: int, - * testsCount: int + * testsCount: int, + * estimatedTime: float|null * }|null */ private static ?array $shard = null; @@ -122,11 +123,16 @@ final class Shard implements AddsOutput, HandlesArguments, Terminable $testsToRun = (array_chunk($tests, max(1, (int) ceil(count($tests) / $total))))[$index - 1] ?? []; } + $estimatedTime = self::$timeBalanced && $timings !== null + ? array_sum(array_map(fn (string $test): float => $timings[$test] ?? 0.0, $testsToRun)) + : null; + self::$shard = [ 'index' => $index, 'total' => $total, 'testsRan' => count($testsToRun), 'testsCount' => count($tests), + 'estimatedTime' => $estimatedTime, ]; return [...$arguments, '--filter', $this->buildFilterArgument($testsToRun)]; @@ -174,7 +180,7 @@ final class Shard implements AddsOutput, HandlesArguments, Terminable 'php', ...$this->removeParallelArguments($arguments), '--list-tests', - ]))->mustRun()->getOutput(); + ]))->setTimeout(120)->mustRun()->getOutput(); preg_match_all('/ - (?:P\\\\)?(Tests\\\\[^:]+)::/', $output, $matches); @@ -226,8 +232,14 @@ final class Shard implements AddsOutput, HandlesArguments, Terminable 'total' => $total, 'testsRan' => $testsRan, 'testsCount' => $testsCount, + 'estimatedTime' => $estimatedTime, ] = self::$shard; + $suffix = ''; + if (self::$timeBalanced && is_float($estimatedTime)) { + $suffix = sprintf(' (time-balanced, ~%.1fs)', $estimatedTime); + } + $this->output->writeln(sprintf( ' Shard: %d of %d — %d file%s ran, out of %d%s.', $index, @@ -235,7 +247,7 @@ final class Shard implements AddsOutput, HandlesArguments, Terminable $testsRan, $testsRan === 1 ? '' : 's', $testsCount, - self::$timeBalanced ? ' (time-balanced)' : '', + $suffix, )); return $exitCode; @@ -364,13 +376,13 @@ final class Shard implements AddsOutput, HandlesArguments, Terminable $contents = file_get_contents($path); if ($contents === false) { - return null; + throw new InvalidOption('The [tests/.pest/shards.json] file could not be read. Delete it or run [--update-shards] to regenerate.'); } $data = json_decode($contents, true); if (! is_array($data) || ! isset($data['timings']) || ! is_array($data['timings'])) { - return null; + throw new InvalidOption('The [tests/.pest/shards.json] file is corrupted. Delete it or run [--update-shards] to regenerate.'); } /** @var array */