netgescon-day0/tests/Feature/ControlTowerPollCommandTest.php

229 lines
7.1 KiB
PHP

<?php
use Illuminate\Support\Facades\Http;
use Illuminate\Console\Command;
beforeEach(function () {
Http::preventStrayRequests();
});
it('fetches real task via GET 200 and passes description, metadata, and expectedReport to wrapper', function () {
$taskId = 'task-test-real-200';
Http::fake([
'http://192.168.0.53:4174/api/tasks/task-test-real-200*' => Http::response([
'task' => [
'id' => $taskId,
'title' => 'Real Title 200',
'description' => 'Real Description 200 Content',
'target_machine_id' => 'machine-205-dev',
'metadata' => [
'opId' => 'op-123',
'expectedReport' => [
'consolidated_unit_id' => 'UNIT-200',
'note_contains' => 'NOTE_200_OK'
]
]
]
], 200),
'http://192.168.0.53:4174/api/reports' => Http::response(['id' => 'rep-200'], 201),
'http://192.168.0.53:4174/api/tasks/status' => Http::response(['status' => 'done'], 200),
'http://192.168.0.53:4174/api/machines/heartbeat' => Http::response(['status' => 'online'], 200),
]);
$mockScript = tempnam(sys_get_temp_dir(), 'mock_wrapper_real_') . '.sh';
$scriptContent = <<<'BASH'
#!/usr/bin/env bash
INPUT="$(cat -)"
if [[ "$INPUT" != *"Real Description 200 Content"* ]]; then
echo "ERROR: description missing from stdin" >&2
exit 1
fi
if [[ "$INPUT" != *"EXPECTED_REPORT:"* ]]; then
echo "ERROR: expectedReport missing from stdin" >&2
exit 1
fi
if [[ "$INPUT" != *"UNIT-200"* ]]; then
echo "ERROR: UNIT-200 missing from stdin" >&2
exit 1
fi
cat << JSON
{
"ok": true,
"parsed": {
"task_id": "task-test-real-200",
"esito_205": "riuscito",
"repository": "ssh://git@192.168.0.53:2222/michele/netgescon-day0.git",
"branch": "stabilization/205-zero",
"commit": "0ac85f8c8502d9bb4e015ee6b15a452ef3fd1422",
"consolidated_unit_id": "UNIT-200",
"blocco_dati": "no",
"dates_used": ["2026-08-10"],
"test_eseguiti": ["real task test"],
"note": ["NOTE_200_OK"],
"absorbed_legacy_fragments": ["frag-200"],
"open_legacy_fragments": [],
"raw_text": "NOTE_200_OK"
}
}
JSON
exit 0
BASH;
file_put_contents($mockScript, $scriptContent);
chmod($mockScript, 0755);
$exitCode = $this->artisan('netgescon:control-tower-poll', [
'--task-id' => $taskId,
'--wrapper-script' => $mockScript,
])->run();
@unlink($mockScript);
expect($exitCode)->toBe(Command::SUCCESS);
Http::assertSent(function ($request) use ($taskId) {
return str_contains($request->url(), '/api/tasks/' . $taskId);
});
Http::assertSent(function ($request) use ($taskId) {
return str_contains($request->url(), '/api/reports') &&
($request['task_id'] ?? null) === $taskId &&
str_contains($request['raw_text'] ?? '', 'NOTE_200_OK');
});
});
it('fails and does not execute wrapper or publish report when task GET returns 403', function () {
$taskId = 'task-test-403';
Http::fake([
'http://192.168.0.53:4174/api/tasks/task-test-403*' => Http::response(['error' => 'Forbidden'], 403),
]);
$mockScript = tempnam(sys_get_temp_dir(), 'mock_wrapper_403_') . '.sh';
file_put_contents($mockScript, "#!/usr/bin/env bash\necho 'Should not execute' >&2\nexit 1\n");
chmod($mockScript, 0755);
$exitCode = $this->artisan('netgescon:control-tower-poll', [
'--task-id' => $taskId,
'--wrapper-script' => $mockScript,
])->run();
@unlink($mockScript);
expect($exitCode)->toBe(Command::FAILURE);
Http::assertNotSent(function ($request) {
return str_contains($request->url(), '/api/reports');
});
});
it('fails and does not execute wrapper or publish report when task GET returns 404', function () {
$taskId = 'task-test-404';
Http::fake([
'http://192.168.0.53:4174/api/tasks/task-test-404*' => Http::response(['error' => 'Not Found'], 404),
]);
$mockScript = tempnam(sys_get_temp_dir(), 'mock_wrapper_404_') . '.sh';
file_put_contents($mockScript, "#!/usr/bin/env bash\necho 'Should not execute' >&2\nexit 1\n");
chmod($mockScript, 0755);
$exitCode = $this->artisan('netgescon:control-tower-poll', [
'--task-id' => $taskId,
'--wrapper-script' => $mockScript,
])->run();
@unlink($mockScript);
expect($exitCode)->toBe(Command::FAILURE);
Http::assertNotSent(function ($request) {
return str_contains($request->url(), '/api/reports');
});
});
it('fails when returned task ID differs from requested task ID', function () {
$taskId = 'task-test-mismatch';
Http::fake([
'http://192.168.0.53:4174/api/tasks/task-test-mismatch*' => Http::response([
'task' => [
'id' => 'different-id-999',
'title' => 'Title',
'description' => 'Desc',
'target_machine_id' => 'machine-205-dev',
'metadata' => []
]
], 200),
]);
$mockScript = tempnam(sys_get_temp_dir(), 'mock_wrapper_mismatch_') . '.sh';
file_put_contents($mockScript, "#!/usr/bin/env bash\necho 'Should not execute' >&2\nexit 1\n");
chmod($mockScript, 0755);
$exitCode = $this->artisan('netgescon:control-tower-poll', [
'--task-id' => $taskId,
'--wrapper-script' => $mockScript,
])->run();
@unlink($mockScript);
expect($exitCode)->toBe(Command::FAILURE);
Http::assertNotSent(function ($request) {
return str_contains($request->url(), '/api/reports');
});
});
it('does not publish report when wrapper exit code is non-zero and displays stdout and stderr', function () {
$taskId = 'task-test-err-001';
Http::fake([
'http://192.168.0.53:4174/api/tasks/task-test-err-001*' => Http::response([
'task' => [
'id' => $taskId,
'title' => 'Title Err',
'description' => 'Desc Err',
'target_machine_id' => 'machine-205-dev',
'metadata' => []
]
], 200),
]);
$mockScript = tempnam(sys_get_temp_dir(), 'mock_wrapper_err_') . '.sh';
$jsonErrorOutput = json_encode(['ok' => false, 'missing' => ['task_id']], JSON_PRETTY_PRINT);
$scriptContent = <<<BASH
#!/usr/bin/env bash
echo 'Standard error log message' >&2
cat << JSON
{$jsonErrorOutput}
JSON
exit 1
BASH;
file_put_contents($mockScript, $scriptContent);
chmod($mockScript, 0755);
$this->artisan('netgescon:control-tower-poll', [
'--task-id' => $taskId,
'--wrapper-script' => $mockScript,
])
->expectsOutputToContain('WRAPPER AGY FALLITO')
->expectsOutputToContain('EXIT_CODE: 1')
->expectsOutputToContain('STDOUT:')
->expectsOutputToContain('"ok": false')
->expectsOutputToContain('STDERR:')
->expectsOutputToContain('Standard error log message')
->assertExitCode(Command::FAILURE);
@unlink($mockScript);
Http::assertNotSent(function ($request) {
return str_contains($request->url(), '/api/reports');
});
});