Stabilize discovery workflow
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user