TenantAtlas/apps/platform/tests/Unit/Support/OpsUx/OperationRunProgressContractTest.php
Ahmed Darrazi 4256e642ed
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m39s
chore: commit all changes (automated)
2026-05-05 12:38:55 +02:00

221 lines
7.4 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\OperationRun;
use App\Support\OpsUx\OperationRunProgressContract;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('returns counted progress for running runs with trustworthy processed totals', function (): void {
$run = OperationRun::factory()->create([
'status' => 'running',
'outcome' => 'pending',
'summary_counts' => [
'total' => 10,
'processed' => 4,
],
'started_at' => now()->subMinute(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('counted')
->and($progress['display'])->toBe('counted')
->and($progress['processed'])->toBe(4)
->and($progress['total'])->toBe(10)
->and($progress['percent'])->toBe(40)
->and($progress['label'])->toBe('4 / 10 processed (40%)');
});
it('clamps counted progress into a truthful visible range', function (): void {
$run = OperationRun::factory()->create([
'status' => 'running',
'outcome' => 'pending',
'summary_counts' => [
'total' => 10,
'processed' => 15,
],
'started_at' => now()->subMinute(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('counted')
->and($progress['processed'])->toBe(10)
->and($progress['total'])->toBe(10)
->and($progress['percent'])->toBe(100)
->and($progress['label'])->toBe('10 / 10 processed (100%)');
});
it('keeps queued runs activity only even when planned totals exist', function (): void {
$run = OperationRun::factory()->create([
'status' => 'queued',
'outcome' => 'pending',
'summary_counts' => [
'total' => 10,
'processed' => 0,
],
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('activity')
->and($progress['display'])->toBe('indeterminate')
->and($progress['label'])->toBe('Waiting for worker.')
->and($progress['percent'])->toBeNull();
});
it('returns no progress for terminal runs even when retained counts exist', function (): void {
$run = OperationRun::factory()->create([
'status' => 'completed',
'outcome' => 'succeeded',
'summary_counts' => [
'total' => 10,
'processed' => 10,
],
'started_at' => now()->subMinutes(2),
'completed_at' => now()->subSecond(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('none')
->and($progress['display'])->toBe('none')
->and($progress['label'])->toBeNull()
->and($progress['percent'])->toBeNull();
});
it('does not let outcome counters masquerade as counted progress', function (): void {
$run = OperationRun::factory()->create([
'status' => 'running',
'outcome' => 'pending',
'summary_counts' => [
'succeeded' => 4,
'failed' => 1,
'skipped' => 2,
],
'started_at' => now()->subMinute(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('activity')
->and($progress['display'])->toBe('indeterminate')
->and($progress['label'])->toBe('Progress details pending.')
->and($progress['percent'])->toBeNull();
});
it('classifies repo-real baseline evidence capture runs as phased fallback', function (): void {
$run = OperationRun::factory()->create([
'type' => 'baseline_capture',
'status' => 'running',
'outcome' => 'pending',
'context' => [
'baseline_capture' => [
'evidence_capture' => [
'requested' => 10,
'succeeded' => 3,
'skipped' => 1,
],
'resume_token' => 'resume-123',
],
],
'started_at' => now()->subMinute(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('phased')
->and($progress['display'])->toBe('indeterminate')
->and($progress['label'])->toBe('Capturing evidence.')
->and($progress['percent'])->toBeNull();
});
it('uses canonical phase metadata when present for phased runs', function (): void {
$run = OperationRun::factory()->create([
'type' => 'baseline_compare',
'status' => 'running',
'outcome' => 'pending',
'context' => [
'progress' => [
'phase' => [
'key' => 'persisting',
'label' => 'Saving comparison results.',
],
],
],
'started_at' => now()->subMinute(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('phased')
->and($progress['display'])->toBe('indeterminate')
->and($progress['label'])->toBe('Saving comparison results.')
->and($progress['percent'])->toBeNull();
});
it('classifies aggregate multi-run work as composite fallback', function (): void {
$run = OperationRun::factory()->create([
'status' => 'running',
'outcome' => 'pending',
'summary_counts' => [
'operation_count' => 3,
],
'started_at' => now()->subMinute(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('composite')
->and($progress['display'])->toBe('indeterminate')
->and($progress['label'])->toBe('Composite progress pending.')
->and($progress['percent'])->toBeNull();
});
it('derives a tenant review composite label from aggregate operation truth', function (): void {
$run = OperationRun::factory()->create([
'type' => 'tenant.review.compose',
'status' => 'running',
'outcome' => 'pending',
'summary_counts' => [
'operation_count' => 3,
],
'started_at' => now()->subMinute(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('composite')
->and($progress['display'])->toBe('indeterminate')
->and($progress['label'])->toBe('Review composition is aggregating 3 operations.')
->and($progress['percent'])->toBeNull();
});
it('uses explicit composite attention hints when present', function (): void {
$run = OperationRun::factory()->create([
'type' => 'tenant.review.compose',
'status' => 'running',
'outcome' => 'pending',
'summary_counts' => [
'operation_count' => 4,
],
'context' => [
'progress' => [
'composite' => [
'label' => 'Review composition is aggregating 4 operations. 1 failed operation currently needs review.',
],
],
],
'started_at' => now()->subMinute(),
]);
$progress = OperationRunProgressContract::forRun($run);
expect($progress['capability'])->toBe('composite')
->and($progress['display'])->toBe('indeterminate')
->and($progress['label'])->toBe('Review composition is aggregating 4 operations. 1 failed operation currently needs review.')
->and($progress['percent'])->toBeNull();
});