initial prototype based on nat-as-server
Some checks failed
PHPUnit / test (push) Has been cancelled

This commit is contained in:
tom.hempel
2026-06-29 12:39:55 +02:00
commit f1caa9e681
148 changed files with 34905 additions and 0 deletions

109
tests/Unit/ApiLogTest.php Normal file
View File

@ -0,0 +1,109 @@
<?php
declare(strict_types=1);
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
final class ApiLogTest extends TestCase
{
private string $logDir;
protected function setUp(): void
{
require_once dirname(__DIR__, 2) . '/lib/api_log.php';
$this->logDir = $_ENV['QDB_API_LOG_DIR'] ?? (QDB_TEST_UPLOADS . '/logs/api');
if (!is_dir($this->logDir)) {
mkdir($this->logDir, 0775, true);
}
$this->clearLogFiles();
unset($GLOBALS['qdb_api_log_ctx']);
}
protected function tearDown(): void
{
$this->clearLogFiles();
unset($GLOBALS['qdb_api_log_ctx']);
}
public function testClassifyActivity(): void
{
$this->assertNull(qdb_api_log_classify_activity('OPTIONS', 'web', 'users'));
$this->assertSame('web_change', qdb_api_log_classify_activity('POST', 'web', 'users'));
$this->assertSame('app_change', qdb_api_log_classify_activity('POST', '', 'app_questionnaires'));
$this->assertSame('app_sync', qdb_api_log_classify_activity('GET', '', 'app_questionnaires'));
$this->assertSame('web_export', qdb_api_log_classify_activity('GET', 'web', 'export'));
$this->assertSame('web_change', qdb_api_log_classify_activity('POST', 'web', 'backup'));
$this->assertTrue(qdb_api_log_is_website_download('backup'));
}
public function testRedactSensitiveFields(): void
{
$redacted = qdb_api_log_redact_value([
'username' => 'coach1',
'password' => 'secret',
'encrypted' => str_repeat('x', 40),
]);
$this->assertSame('coach1', $redacted['username']);
$this->assertSame('[REDACTED]', $redacted['password']);
$this->assertSame('[ENCRYPTED:40 chars]', $redacted['encrypted']);
}
public function testRedactQueryString(): void
{
$qs = qdb_api_log_redact_query_string('questionnaireID=qn1&token=abc&password=pw');
parse_str((string)$qs, $params);
$this->assertSame('qn1', $params['questionnaireID'] ?? null);
$this->assertSame('[REDACTED]', $params['token'] ?? null);
$this->assertSame('[REDACTED]', $params['password'] ?? null);
}
public function testTokenHintMasksMiddle(): void
{
$hint = qdb_api_log_token_hint('0123456789abcdef');
$this->assertStringContainsString('…', $hint);
$this->assertStringNotContainsString('56789', $hint);
}
public function testClientIpUsesForwardedFor(): void
{
$_SERVER['HTTP_X_FORWARDED_FOR'] = '203.0.113.50, 198.51.100.1';
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$this->assertSame('203.0.113.50', qdb_api_log_client_ip());
unset($_SERVER['HTTP_X_FORWARDED_FOR']);
}
public function testBeginFinishWritesWebChangeEntry(): void
{
$_SERVER['HTTP_X_QDB_CLIENT'] = 'web';
$_SERVER['REQUEST_URI'] = '/api/users';
$_SERVER['QUERY_STRING'] = '';
qdb_test_set_request_body(json_encode(['username' => 'new_coach'], JSON_THROW_ON_ERROR));
http_response_code(200);
qdb_api_log_begin('POST', 'users');
qdb_api_log_finish();
$date = date('Y-m-d');
$read = qdb_api_log_read_entries($date, 'web_change', 10);
$entries = $read['entries'];
$this->assertNotEmpty($entries);
$last = $entries[0];
$this->assertSame('web_change', $last['activity']);
$this->assertSame('POST', $last['method']);
$this->assertSame('users', $last['route']);
$changes = $last['changes'] ?? [];
$fields = array_column($changes, 'field');
$this->assertContains('username', $fields);
qdb_test_reset_http_state();
}
private function clearLogFiles(): void
{
foreach (glob($this->logDir . '/api-*.log') ?: [] as $path) {
@unlink($path);
}
}
}