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); });