domovoy/tests/Jobs/ScanJobRunnerTest.php

161 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Domovoy\Tests\Jobs;
use Domovoy\Models\NetworkRange;
use Domovoy\Models\ScanJob;
use Domovoy\Repositories\NetworkRangeRepository;
use Domovoy\Repositories\ScanJobRepository;
use Domovoy\Services\Discovery\NetworkScanner;
use Domovoy\Services\Jobs\ScanJobRunner;
use PHPUnit\Framework\TestCase;
final class ScanJobRunnerTest extends TestCase
{
public function testNetworkDiscoveryJobScansItsNetworkRange(): void
{
$job = new ScanJob();
$job->id = 77;
$job->type = 'network_discovery';
$job->status = 'pending';
$job->networkRangeId = 5;
$range = new NetworkRange();
$range->id = 5;
$range->cidr = '192.168.1.1/32';
$jobs = new InMemoryScanJobRepository([$job]);
$ranges = new InMemoryNetworkRangeLookup([5 => $range]);
$scanner = new RecordingNetworkScanner();
$runner = new ScanJobRunner($jobs, $scanner, $ranges);
$runner->runNext();
self::assertSame('done', $job->status);
self::assertSame($range, $scanner->scannedRange);
self::assertSame(77, $scanner->scanJobId);
}
public function testPausedDiscoveryJobKeepsProgressAndDoesNotBecomeDone(): void
{
$job = new ScanJob();
$job->id = 88;
$job->type = 'network_discovery';
$job->status = 'pending';
$job->networkRangeId = 5;
$job->resultJson = json_encode([
'next_ip_index' => 1,
'hosts_found' => 2,
]);
$range = new NetworkRange();
$range->id = 5;
$range->cidr = '192.168.1.0/30';
$jobs = new InMemoryScanJobRepository([$job]);
$ranges = new InMemoryNetworkRangeLookup([5 => $range]);
$scanner = new RecordingNetworkScanner();
$scanner->result = [
'hosts' => [],
'completed' => false,
'next_ip_index' => 2,
'total_ips' => 2,
'scanned_count' => 1,
'hosts_found' => 2,
];
$jobs->statusAfterFirstProgressCheck = 'paused';
$runner = new ScanJobRunner($jobs, $scanner, $ranges);
$runner->runNext();
self::assertSame('paused', $job->status);
self::assertNull($job->finishedAt);
self::assertSame(1, $scanner->startIndex);
self::assertSame(2, json_decode($job->resultJson ?? '{}', true)['next_ip_index']);
}
}
final class InMemoryScanJobRepository extends ScanJobRepository
{
public ?string $statusAfterFirstProgressCheck = null;
private int $findByIdCalls = 0;
/** @param ScanJob[] $pending */
public function __construct(private array $pending)
{
}
public function findPending(): array
{
return $this->pending;
}
public function save(ScanJob $job): void
{
}
public function findById(int $id): ?ScanJob
{
$this->findByIdCalls++;
if ($this->statusAfterFirstProgressCheck !== null && $this->findByIdCalls > 1) {
$this->pending[0]->status = $this->statusAfterFirstProgressCheck;
}
return $this->pending[0] ?? null;
}
}
final class InMemoryNetworkRangeLookup extends NetworkRangeRepository
{
/** @param array<int, NetworkRange> $ranges */
public function __construct(private array $ranges)
{
}
public function findById(int $id): ?NetworkRange
{
return $this->ranges[$id] ?? null;
}
}
final class RecordingNetworkScanner extends NetworkScanner
{
public ?NetworkRange $scannedRange = null;
public ?int $scanJobId = null;
public ?int $startIndex = null;
public array $result = [
'hosts' => [],
'completed' => true,
'next_ip_index' => 1,
'total_ips' => 1,
'scanned_count' => 1,
'hosts_found' => 0,
];
public function __construct()
{
}
public function scan(NetworkRange $range, ?int $scanJobId = null): array
{
$this->scannedRange = $range;
$this->scanJobId = $scanJobId;
return [];
}
public function scanResumable(
NetworkRange $range,
int $scanJobId,
int $startIndex,
callable $shouldStop,
callable $onProgress
): array {
$this->scannedRange = $range;
$this->scanJobId = $scanJobId;
$this->startIndex = $startIndex;
$onProgress($this->result);
return $this->result;
}
}