Files
datahub/backend/test/Cases/Unit/Service/OperationLogServiceTest.php
T
2026-03-17 15:55:13 +08:00

117 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
namespace HyperfTest\Cases\Unit\Service;
use App\Model\OperationLog;
use App\Service\OperationLogService;
use HyperfTest\TestCase;
use HyperfTest\Traits\AuthenticatedTestTrait;
/**
* OperationLogService 单元测试
*
* 验证操作日志的异步写入和辅助方法
*
* @internal
* @coversNothing
*/
class OperationLogServiceTest extends TestCase
{
use AuthenticatedTestTrait;
/**
* 在子协程中执行回调,等待其退出(含 defer 执行)
*
* co-phpunit 下所有测试共享同一顶层协程,
* Coroutine::defer 的回调要到协程退出才执行。
* 此方法创建子协程并 join 等待,确保 defer 回调完成后再继续。
*/
protected function runInChildCoroutineAndWait(callable $callback): void
{
$cid = \Swoole\Coroutine::create($callback);
if ($cid !== false) {
\Swoole\Coroutine::join([$cid]);
}
}
public function test_log_creates_record_in_coroutine(): void
{
$action = 'test.unit_' . uniqid();
$this->runInChildCoroutineAndWait(static function () use ($action): void {
OperationLogService::log(
user_id: 1,
action: $action,
target_type: 'user',
target_id: 99,
description: '单元测试操作日志',
detail: ['key' => 'value'],
ip: '127.0.0.1',
);
});
// join 等待子协程退出后 defer 已执行,记录已写入
$record = OperationLog::query()->where('action', $action)->first();
$this->assertNotNull($record);
$this->assertSame(1, $record->user_id);
$this->assertSame($action, $record->action);
$this->assertSame('user', $record->target_type);
$this->assertSame(99, $record->target_id);
$this->assertSame('单元测试操作日志', $record->description);
$this->assertSame(['key' => 'value'], $record->detail);
$this->assertSame('127.0.0.1', $record->ip);
// 清理测试数据
OperationLog::query()->where('id', $record->id)->delete();
}
public function test_log_with_null_detail_and_ip(): void
{
$action = 'test.null_detail_' . uniqid();
$this->runInChildCoroutineAndWait(static function () use ($action): void {
OperationLogService::log(
user_id: 2,
action: $action,
target_type: 'auth',
target_id: null,
description: '测试空 detail 和 ip',
);
});
$record = OperationLog::query()->where('action', $action)->first();
$this->assertNotNull($record);
$this->assertSame(2, $record->user_id);
$this->assertNull($record->target_id);
$this->assertNull($record->detail);
$this->assertNull($record->ip);
// 清理
OperationLog::query()->where('id', $record->id)->delete();
}
public function test_log_does_not_throw_on_failure(): void
{
// 验证 log 方法在写入失败时不抛异常(仅记录错误日志)
// 使用超长 action 触发数据库约束失败
$long_action = str_repeat('a', 100); // 超过 VARCHAR(50) 限制
$this->runInChildCoroutineAndWait(static function () use ($long_action): void {
OperationLogService::log(
user_id: 1,
action: $long_action,
target_type: 'test',
target_id: null,
description: '不应抛异常',
);
});
// 如果到达这里说明没有抛异常
$this->assertTrue(true);
}
}