Adopt PHPUnit for plugin unit tests

This commit is contained in:
ms2k 2026-08-07 01:01:58 +09:00
commit 5a16298c22
3 changed files with 2038 additions and 190 deletions

View file

@ -0,0 +1,89 @@
<?php
use OPNsense\NordVPN\NordApi;
use PHPUnit\Framework\TestCase;
final class NordApiTest extends TestCase
{
private string $key;
protected function setUp(): void
{
$this->key = base64_encode(str_repeat("\0", 32));
}
public function testCredentialsUseNordVpnAccessTokenAuthorization(): void
{
$api = new NordApi(function ($path, $query, $authorization): array {
$this->assertSame('/v1/users/services/credentials', $path);
$this->assertSame([], $query);
$this->assertSame('Bearer token:synthetic-token', $authorization);
return ['nordlynx_private_key' => $this->key];
});
$this->assertSame($this->key, $api->credentials('synthetic-token'));
}
public function testRecommendationsApplyCountryAllowlist(): void
{
$requests = [];
$api = new NordApi(function ($path, $query) use (&$requests): array {
$requests[] = [$path, $query];
if ($path === '/v1/servers/countries') {
return [['id' => 99, 'code' => 'nl', 'name' => 'Netherlands']];
}
return [[
'hostname' => 'nl.example.invalid',
'station' => '198.51.100.10',
'locations' => [['country' => ['code' => 'nl']]],
'technologies' => [[
'id' => 35,
'pivot' => ['status' => 'online'],
'metadata' => [['name' => 'public_key', 'value' => $this->key]],
]],
]];
});
$servers = $api->recommendations(['NL']);
$this->assertCount(1, $servers);
$this->assertSame('NL', $servers[0]['country']);
$this->assertSame(99, $requests[1][1]['filters[country_id]']);
$this->assertSame(35, $requests[1][1]['filters[servers_technologies]']);
}
public function testEmptyCountryAllowlistQueriesRecommendationsDirectly(): void
{
$api = new NordApi(static function ($path): array {
if ($path === '/v1/servers/countries') {
throw new RuntimeException('countries should not be queried');
}
return [];
});
$this->assertSame([], $api->recommendations([]));
}
public function testEndpointDiscoveryPaginatesCompleteNordLynxAddressSet(): void
{
$requests = [];
$api = new NordApi(static function ($path, $query) use (&$requests): array {
$requests[] = [$path, $query];
if ($query['offset'] === 0) {
return array_map(
static fn($index) => ['station' => sprintf('198.51.%d.%d', intdiv($index, 250), $index % 250 + 1)],
range(0, 499)
);
}
return [['station' => '203.0.113.10'], ['station' => 'invalid']];
});
$addresses = $api->endpointAddresses();
$this->assertCount(501, $addresses);
$this->assertSame('/v1/servers', $requests[0][0]);
$this->assertSame(500, $requests[0][1]['limit']);
$this->assertSame(500, $requests[1][1]['offset']);
$this->assertSame(35, $requests[0][1]['filters[servers_technologies]']);
}
}

View file

@ -0,0 +1,61 @@
<?php
use OPNsense\NordVPN\EndpointStore;
use OPNsense\NordVPN\EnrollmentInspector;
use OPNsense\NordVPN\NordApi;
use OPNsense\NordVPN\StatusStore;
use PHPUnit\Framework\TestCase;
final class StoreAndInspectorTest extends TestCase
{
public function testEndpointRefreshWritesAtomicReusableTable(): void
{
$directory = sys_get_temp_dir() . '/nordvpn-endpoints-' . bin2hex(random_bytes(8));
$path = $directory . '/endpoints.txt';
$requests = 0;
$api = new NordApi(static function () use (&$requests): array {
$requests++;
return [['station' => '203.0.113.10']];
});
$store = new EndpointStore($path);
$this->assertTrue($store->refreshIfStale($api));
$this->assertTrue($store->available());
$this->assertSame("203.0.113.10\n", file_get_contents($path));
$this->assertFalse($store->refreshIfStale($api));
$this->assertSame(1, $requests);
unlink($path);
rmdir($directory);
}
public function testRfc1918WarningFollowsDestinationSelectorSemantics(): void
{
$inspector = new EnrollmentInspector([
'private' => ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'],
'public' => ['203.0.113.0/24'],
'nested' => ['private'],
]);
$this->assertTrue($inspector->includesPrivateDestinations('any', false));
$this->assertTrue($inspector->includesPrivateDestinations('nested', false));
$this->assertFalse($inspector->includesPrivateDestinations('public', false));
$this->assertFalse($inspector->includesPrivateDestinations('2001:db8::/32', false));
$this->assertFalse($inspector->includesPrivateDestinations('private', true));
$this->assertTrue($inspector->includesPrivateDestinations('10.0.0.0/8', true));
}
public function testStatusWritesAtomicallyAndRetainsDefaults(): void
{
$path = sys_get_temp_dir() . '/nordvpn-status-' . bin2hex(random_bytes(8)) . '.json';
$store = new StatusStore($path);
$this->assertFalse($store->read()['available']);
$store->write(['available' => true, 'state' => 'available']);
$status = $store->read();
$this->assertTrue($status['available']);
$this->assertGreaterThan(0, $status['updated_at']);
unlink($path);
}
}

View file

@ -0,0 +1,52 @@
<?php
use OPNsense\NordVPN\SystemRunner;
use OPNsense\NordVPN\TunnelHealth;
use PHPUnit\Framework\TestCase;
final class SystemRunnerAndHealthTest extends TestCase
{
public function testTunnelHealthRequiresRecentHandshake(): void
{
$runner = new SystemRunner(static fn() => "public-key\t900\n");
$recent = new TunnelHealth($runner, 180, static fn() => 1000);
$stale = new TunnelHealth($runner, 50, static fn() => 1000);
$this->assertTrue($recent->check('wg0')['available']);
$this->assertFalse($stale->check('wg0')['available']);
$this->assertFalse($recent->check('invalid')['available']);
}
public function testWireGuardApplyFollowsRegistrationSequence(): void
{
$commands = [];
$runner = new SystemRunner(static function ($command) use (&$commands): string {
$commands[] = $command;
return '';
});
$runner->applyWireGuard();
$this->assertSame([
['/usr/local/sbin/configctl', 'interface', 'invoke', 'registration'],
['/usr/local/sbin/configctl', 'template', 'reload', 'OPNsense/Wireguard'],
['/usr/local/opnsense/scripts/wireguard/wg-service-control.php', '-a', 'configure'],
], $commands);
}
public function testFirewallApplyReloadsRulesBeforeEvictingPluginStates(): void
{
$commands = [];
$runner = new SystemRunner(static function ($command) use (&$commands): string {
$commands[] = $command;
return '';
});
$runner->applyFirewall();
$this->assertSame([
['/usr/local/etc/rc.filter_configure'],
['/sbin/pfctl', '-k', 'label', '-k', SystemRunner::FIREWALL_LABEL],
], $commands);
}
}