Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['8.2', '8.4']
php: ['8.2', '8.3', '8.4', '8.5']

steps:
- name: Checkout code
Expand Down Expand Up @@ -45,5 +45,8 @@ jobs:
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest

- name: Lint package source and entry points
run: php scripts/lint.php

- name: Run tests
run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php tests/isolated
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,14 @@ This project is licensed under the MIT License.

## Offline verification checks

Run `php scripts/lint.php` to parse all package source, entry points, scripts, and tests.
CI checks PHP 8.2, 8.3, 8.4, and 8.5.

Run `php vendor/bin/phpunit --bootstrap vendor/autoload.php tests/isolated`.
These contract tests inject storage that never writes files or opens databases;
they do not load `.env`, start the server, or contact verification services.
they do not load `.env`, bind a listening socket, or contact verification services.
A server loading test constructs the server and routes a synthetic request without
initializing its network listener.
The older tests outside this directory use configured storage and are not run by CI.

Run `php -d xdebug.mode=off scripts/benchmark_lookups.php` for a synthetic
Expand Down
26 changes: 26 additions & 0 deletions scripts/lint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types=1);

// Parse every source file without executing configuration or opening sockets.
$root = dirname(__DIR__);
$paths = [$root . '/run.php', $root . '/runtests.php'];
foreach (['src', 'scripts', 'tests'] as $directory) {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root . '/' . $directory, FilesystemIterator::SKIP_DOTS));
foreach ($files as $file) {
if ($file->isFile() && $file->getExtension() === 'php') $paths[] = $file->getPathname();
}
}
sort($paths);
foreach ($paths as $path) {
$process = proc_open([PHP_BINARY, '-l', $path], [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
if (!is_resource($process)) throw new RuntimeException('Could not start PHP lint');
$output = stream_get_contents($pipes[1]);
$error = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$status = proc_close($process);
if ($status !== 0) {
fwrite(STDERR, $output . $error);
exit($status);
}
}
printf("Parsed %d PHP files with PHP %s.\n", count($paths), PHP_VERSION);
4 changes: 2 additions & 2 deletions src/VerifierServer/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,12 @@ private function __initStreamSocketServer(): void
*/
private function __initReactHttpServer(?LoopInterface $loop = null): void
{
$this->server = new HttpServer(
$this->server = (new HttpServer(
$this->loop = $loop instanceof LoopInterface
? $loop
: Loop::get(),
fn($request) => $this->handleReact($request)
)->on('error', fn(Throwable $e) => $this->logError($e, true));
))->on('error', fn(Throwable $e) => $this->logError($e, true));
$this->socket = new SocketServer(
"{$this->addr}:{$this->port}",
[
Expand Down
26 changes: 26 additions & 0 deletions tests/isolated/ServerLoadingTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types=1);

use PHPUnit\Framework\TestCase;
use React\Http\Message\ServerRequest;
use VerifierServer\PersistentState;
use VerifierServer\Server;

final class ServerLoadingTest extends TestCase
{
public function testServerLoadsAndRoutesWithoutBindingSocket(): void
{
$server = new Server('127.0.0.1', 16261);
$state = new PersistentState('test-only-token');
$list = [['discord' => '123', 'ss13' => 'alice']];
$state->setVerifyList($list, false);
$server->setState($state);
$handler = new ReflectionMethod(Server::class, 'handleReact');
$response = $handler->invoke($server, new ServerRequest('GET', '/verified'));
self::assertSame(200, $response->getStatusCode());
self::assertSame($list, json_decode((string) $response->getBody(), true));
self::assertSame('application/json', $response->getHeaderLine('Content-Type'));
self::assertNull($server->getServer());
self::assertNull($server->getSocketServer());
$server->close();
}
}
Loading