domovoy/tests/Repositories/DiscoveredHostRepositoryTes...

130 lines
3.9 KiB
PHP

<?php
declare(strict_types=1);
namespace Domovoy\Tests\Repositories;
use Domovoy\Models\DiscoveredHost;
use Domovoy\Repositories\DiscoveredHostRepository;
use PDO;
use PDOStatement;
use PHPUnit\Framework\TestCase;
final class DiscoveredHostRepositoryTest extends TestCase
{
public function testSaveUpdatesExistingNewHostByMacInsteadOfCreatingDuplicate(): void
{
$pdo = new FakeDiscoveredHostPdo();
$repository = new DiscoveredHostRepository($pdo);
$first = new DiscoveredHost();
$first->scanJobId = 1;
$first->ipAddress = '192.168.1.10';
$first->macAddress = 'AA:BB:CC:DD:EE:FF';
$first->hostname = 'old-host';
$first->openPorts = [22];
$repository->save($first);
$second = new DiscoveredHost();
$second->scanJobId = 2;
$second->ipAddress = '192.168.1.20';
$second->macAddress = 'aa:bb:cc:dd:ee:ff';
$second->hostname = 'new-host';
$second->openPorts = [22, 80];
$repository->save($second);
self::assertCount(1, $pdo->rows);
self::assertSame(1, $first->id);
self::assertSame(1, $second->id);
self::assertSame(2, $pdo->rows[1]['scan_job_id']);
self::assertSame('192.168.1.20', $pdo->rows[1]['ip_address']);
self::assertSame('new-host', $pdo->rows[1]['hostname']);
self::assertSame('[22,80]', $pdo->rows[1]['open_ports_json']);
}
}
final class FakeDiscoveredHostPdo extends PDO
{
/** @var array<int, array<string, mixed>> */
public array $rows = [];
public int $lastId = 0;
public function __construct()
{
}
public function prepare(string $query, array $options = []): PDOStatement|false
{
return new FakeDiscoveredHostStatement($this, $query);
}
public function lastInsertId(?string $name = null): string|false
{
return (string)$this->lastId;
}
}
final class FakeDiscoveredHostStatement extends PDOStatement
{
/** @var array<string, mixed>|false */
private array|false $result = false;
public function __construct(
private FakeDiscoveredHostPdo $pdo,
private string $query
) {
}
public function execute(?array $params = null): bool
{
$params ??= [];
if (str_contains($this->query, 'SELECT * FROM discovered_hosts WHERE id = :id')) {
$this->result = $this->pdo->rows[(int)$params['id']] ?? false;
return true;
}
if (str_contains($this->query, 'WHERE mac_address = :mac_address')) {
$this->result = false;
foreach ($this->pdo->rows as $row) {
if ($row['mac_address'] === $params['mac_address'] && $row['status'] === 'new') {
$this->result = $row;
break;
}
}
return true;
}
if (str_contains($this->query, 'WHERE ip_address = :ip_address')) {
$this->result = false;
foreach ($this->pdo->rows as $row) {
if ($row['ip_address'] === $params['ip_address'] && $row['status'] === 'new') {
$this->result = $row;
break;
}
}
return true;
}
if (str_contains($this->query, 'INSERT INTO discovered_hosts')) {
$this->pdo->lastId++;
$params['id'] = $this->pdo->lastId;
$this->pdo->rows[$this->pdo->lastId] = $params;
return true;
}
if (str_contains($this->query, 'UPDATE discovered_hosts SET')) {
$id = (int)$params['id'];
$this->pdo->rows[$id] = array_replace($this->pdo->rows[$id], $params);
return true;
}
throw new \RuntimeException('Unexpected query: ' . $this->query);
}
public function fetch(int $mode = PDO::FETCH_DEFAULT, int $cursorOrientation = PDO::FETCH_ORI_NEXT, int $cursorOffset = 0): mixed
{
return $this->result;
}
}