Files
compras/tests/Feature/OperationalHealthTest.php
T
nala 63d20b10fc
tests / ci (push) Canceled after 0s
commit de armazens
2026-11-04 09:40:26 +02:00

89 lines
4.9 KiB
PHP

<?php
use App\Services\OperationalHealth;
use App\Services\ReceiptDocumentHealth;
use App\Services\ReplenishmentHeartbeat;
use App\Services\ReplenishmentQueue;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\HttpException;
require_once __DIR__.'/../Support/ReceiptFixture.php';
beforeEach(function () {
$this->f = receiptFixture();
auth()->logout();
$this->originalStorage = app()->storagePath();
$this->temporaryStorage = $this->originalStorage.'/framework/testing/operations-'.Str::uuid();
File::ensureDirectoryExists($this->temporaryStorage.'/framework');
File::ensureDirectoryExists($this->temporaryStorage.'/documents');
app()->useStoragePath($this->temporaryStorage);
Storage::set('receipt_documents', Storage::build(['driver' => 'local', 'root' => $this->temporaryStorage.'/documents', 'throw' => true]));
app(ReplenishmentHeartbeat::class)->record(now()->toIso8601String(), 0);
});
afterEach(function () {
app()->useStoragePath($this->originalStorage);
File::deleteDirectory($this->temporaryStorage);
});
test('operational health integrates native inspections without changing facts or heartbeat', function () {
$before = [];
foreach (['requisitions', 'stock_movements', 'audit_logs', 'replenishment_work', 'receipt_documents', 'approval_steps'] as $table) {
$before[$table] = DB::table($table)->orderBy('id')->get()->toArray();
}
$heartbeat = File::get(storage_path('framework/replenishment-command-status.json'));
expect(Artisan::call('sgc:operations-check', ['--json' => true]))->toBe(0);
$output = Artisan::output();
$result = json_decode($output, true, 32, JSON_THROW_ON_ERROR);
expect($result['schema_version'])->toBe(1)->and($result['ok'])->toBeTrue()->and($result['complete'])->toBeTrue()
->and($result['checks']['replenishment']['result']['work']['total'])->toBe(0)
->and($result['checks']['receipt_documents']['result']['documents_checked'])->toBe(0);
expect($output)->not->toContain($this->temporaryStorage, 'tenant_id', 'password');
expect(File::get(storage_path('framework/replenishment-command-status.json')))->toBe($heartbeat);
foreach ($before as $table => $rows) {
expect(DB::table($table)->orderBy('id')->get()->toArray())->toEqual($rows);
}
});
test('operational health continues the other inspection after a private failure', function () {
$this->mock(ReplenishmentQueue::class)->shouldReceive('health')->once()->andThrow(new RuntimeException('PRIVATE database password and path'));
expect(Artisan::call('sgc:operations-check', ['--json' => true]))->toBe(1);
$output = Artisan::output();
$result = json_decode($output, true, 32, JSON_THROW_ON_ERROR);
expect($result['ok'])->toBeFalse()->and($result['complete'])->toBeFalse()
->and($result['checks']['replenishment']['status'])->toBe('unavailable')
->and($result['checks']['receipt_documents']['status'])->toBe('passed');
expect($output)->not->toContain('PRIVATE', 'password', $this->temporaryStorage);
});
test('operational health reports incomplete document coverage and preserves files', function () {
Storage::disk('receipt_documents')->put('one.bin', 'one');
Storage::disk('receipt_documents')->put('two.bin', 'two');
expect(Artisan::call('sgc:operations-check', ['--json' => true, '--document-limit' => '1']))->toBe(1);
$result = json_decode(Artisan::output(), true, 32, JSON_THROW_ON_ERROR);
expect($result['complete'])->toBeFalse()->and($result['checks']['receipt_documents']['status'])->toBe('incomplete')
->and($result['checks']['receipt_documents']['result']['reasons'])->toContain('limit_reached');
expect(Storage::disk('receipt_documents')->allFiles())->toHaveCount(2);
});
test('operational health distinguishes complete attention from successful operation', function () {
File::delete(storage_path('framework/replenishment-command-status.json'));
$result = app(OperationalHealth::class)->inspect();
expect($result['ok'])->toBeFalse()->and($result['complete'])->toBeTrue()
->and($result['checks']['replenishment']['status'])->toBe('attention')
->and($result['checks']['receipt_documents']['status'])->toBe('passed');
$this->artisan('sgc:operations-check')->expectsOutput('Operação: verificações requerem atenção.')->assertExitCode(1);
});
test('operational health rejects invalid limits and interactive identities before inspection', function () {
$this->mock(ReceiptDocumentHealth::class)->shouldNotReceive('inspect');
expect(Artisan::call('sgc:operations-check', ['--document-limit' => '10001']))->toBe(2);
expect(fn () => app(OperationalHealth::class)->inspect(0))->toThrow(LogicException::class);
$this->actingAs($this->f['receiver']);
expect(fn () => app(OperationalHealth::class)->inspect())->toThrow(HttpException::class);
});