126 lines
3.9 KiB
PHP
126 lines
3.9 KiB
PHP
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace Tests\Support;
|
|
|
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
use QdbHttpResponse;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* In-process API tests via qdb_dispatch_api_request().
|
|
|
|
*
|
|
|
|
* Error envelopes:
|
|
|
|
* - Handlers: { ok: false, error: { code, message } } — use assertError()
|
|
|
|
* - Auth middleware (require_valid_token, require_role): { error: "message" } — use assertLegacyAuthError()
|
|
|
|
*/
|
|
|
|
abstract class ApiTestCase extends TestCase
|
|
|
|
{
|
|
|
|
protected ?string $bearerToken = null;
|
|
|
|
|
|
|
|
protected function setUp(): void
|
|
|
|
{
|
|
|
|
parent::setUp();
|
|
|
|
DatabaseFixture::forTests()->reset();
|
|
|
|
$this->bearerToken = null;
|
|
|
|
unset($GLOBALS['__TEST_JSON_BODY']);
|
|
|
|
$_GET = [];
|
|
|
|
$_POST = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array{status: int, body: array<string, mixed>, raw: string}
|
|
|
|
*/
|
|
|
|
protected function api(
|
|
|
|
string $method,
|
|
|
|
string $route,
|
|
|
|
?array $jsonBody = null,
|
|
|
|
?string $token = null,
|
|
|
|
array $query = [],
|
|
|
|
): array {
|
|
|
|
$_GET = $query;
|
|
|
|
$_POST = [];
|
|
|
|
$_SERVER['REQUEST_METHOD'] = strtoupper($method);
|
|
|
|
$_SERVER['REQUEST_URI'] = '/api/' . ltrim($route, '/');
|
|
|
|
$_SERVER['SCRIPT_NAME'] = '/api/index.php';
|
|
|
|
$_SERVER['HTTP_AUTHORIZATION'] = ($token ?? $this->bearerToken)
|
|
|
|
? 'Bearer ' . ($token ?? $this->bearerToken)
|
|
|
|
: '';
|
|
|
|
|
|
|
|
if ($jsonBody !== null) {
|
|
|
|
$GLOBALS['__TEST_JSON_BODY'] = json_encode($jsonBody, JSON_THROW_ON_ERROR);
|
|
|
|
} else {
|
|
|
|
unset($GLOBALS['__TEST_JSON_BODY']);
|
|
|
|
}
|
|
|
|
|
|
|
|
ob_start();
|
|
|
|
$status = 200;
|
|
|
|
$body = [];
|
|
|
|
|
|
|
|
try {
|
|
|
|
require_once dirname(__DIR__, 2) . '/api/dispatch.php';
|
|
|
|
qdb_dispatch_api_request();
|
|
|
|
} catch (QdbHttpResponse $e) {
|
|
|
|
$status = $e->status;
|
|
|
|
$body = $e->body;
|
|
|
|
}
|
|
|
|
|
|
|
|
$raw = (string) ob_get_clean();
|
|
|
|
|
|
|
|
if ($raw !== '' && $body === []) {
|
|
|
|
$decoded = json_decode($raw, true);
|
|
|
|
if (is_array($decoded)) {
|
|
|
|
$body = $decoded;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($body === [] && $raw !== '') {
|
|
|
|
$body = ['_raw' => $raw];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isset($body['ok']) && isset($body['error'])) {
|
|
|
|
// legacy auth envelope — body kept as-is
|
|
|
|
} elseif ($status === 200 && !isset($body['ok']) && $raw === '') {
|
|
|
|
$status = http_response_code() ?: 200;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ['status' => $status, 'body' => $body, 'raw' => $raw];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array{status: int, body: array<string, mixed>, raw: string}
|
|
|
|
*/
|
|
|
|
protected function loginAs(string $username, string $password = DatabaseFixture::PASSWORD): array
|
|
|
|
{
|
|
|
|
$res = $this->api('POST', 'auth/login', [
|
|
|
|
'username' => $username,
|
|
|
|
'password' => $password,
|
|
|
|
]);
|
|
|
|
|
|
|
|
if (($res['body']['ok'] ?? false) === true) {
|
|
|
|
$this->bearerToken = $res['body']['data']['token'] ?? null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $res;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function assertOk(array $response): void
|
|
|
|
{
|
|
|
|
$this->assertTrue($response['body']['ok'] ?? false, $response['raw'] ?: json_encode($response['body']));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function assertError(array $response, ?string $code = null): void
|
|
|
|
{
|
|
|
|
$this->assertFalse($response['body']['ok'] ?? true);
|
|
|
|
if ($code !== null) {
|
|
|
|
$this->assertSame($code, $response['body']['error']['code'] ?? null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function assertLegacyAuthError(array $response, int $status, string $message): void
|
|
|
|
{
|
|
|
|
$this->assertSame($status, $response['status']);
|
|
|
|
$this->assertSame($message, $response['body']['error'] ?? null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|