Files
Gnuboard7/tests/Unit/ActivityLog/MonologIntegrationTest.php
T
2026-04-01 10:30:52 +09:00

204 lines
6.7 KiB
PHP

<?php
namespace Tests\Unit\ActivityLog;
use App\Enums\ActivityLogType;
use App\Models\ActivityLog;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Log;
use Tests\TestCase;
/**
* Monolog 통합 테스트
*
* Log::channel('activity')를 통한 전체 파이프라인이
* 올바르게 동작하는지 End-to-End로 검증합니다.
* ActivityLogChannel → ActivityLogProcessor → ActivityLogHandler 전체 흐름을 테스트합니다.
*/
class MonologIntegrationTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
config(['activity_log.enabled' => true]);
}
/**
* Log::channel('activity')->info()가 ActivityLog 레코드를 생성하는지 확인
*/
public function test_log_channel_creates_activity_log_record(): void
{
Log::channel('activity')->info('user.login', [
'log_type' => ActivityLogType::User,
'description_key' => 'activity_log.description.user_login',
'user_id' => null,
'ip_address' => '10.0.0.1',
'user_agent' => 'TestBrowser/1.0',
]);
$this->assertDatabaseCount('activity_logs', 1);
$log = ActivityLog::first();
$this->assertEquals('user.login', $log->action);
$this->assertEquals(ActivityLogType::User, $log->log_type);
$this->assertEquals('activity_log.description.user_login', $log->description_key);
}
/**
* ActivityLogProcessor가 인증된 사용자 정보를 자동 주입하는지 확인
*/
public function test_processor_auto_injects_authenticated_user(): void
{
$user = User::factory()->create();
$this->actingAs($user);
Log::channel('activity')->info('user.profile_update', [
'log_type' => ActivityLogType::User,
]);
$log = ActivityLog::first();
$this->assertEquals($user->id, $log->user_id);
}
/**
* ActivityLogProcessor가 IP 주소를 자동 주입하는지 확인
*/
public function test_processor_auto_injects_ip_address(): void
{
Log::channel('activity')->info('system.test', [
'log_type' => ActivityLogType::System,
]);
$log = ActivityLog::first();
// IP 주소가 자동 주입됨 (테스트 환경에서는 127.0.0.1 또는 null)
$this->assertArrayHasKey('ip_address', $log->toArray());
}
/**
* 전체 context(description_key, description_params, changes, loggable)가 올바르게 저장되는지 확인
*/
public function test_full_context_passes_through_pipeline(): void
{
$user = User::factory()->create();
$changes = [
[
'field' => 'name',
'label_key' => 'user.name',
'old' => '이전 이름',
'new' => '새 이름',
'type' => 'text',
],
];
$descriptionParams = ['user_name' => $user->name];
Log::channel('activity')->info('user.update', [
'log_type' => ActivityLogType::Admin,
'description_key' => 'activity_log.description.user_updated',
'description_params' => $descriptionParams,
'changes' => $changes,
'properties' => ['section' => 'profile'],
'loggable' => $user,
'user_id' => $user->id,
'ip_address' => '192.168.0.1',
'user_agent' => 'AdminPanel/2.0',
]);
$this->assertDatabaseCount('activity_logs', 1);
$log = ActivityLog::first();
// 기본 필드
$this->assertEquals('user.update', $log->action);
$this->assertEquals(ActivityLogType::Admin, $log->log_type);
$this->assertEquals($user->id, $log->user_id);
$this->assertEquals('192.168.0.1', $log->ip_address);
$this->assertEquals('AdminPanel/2.0', $log->user_agent);
// description_key, description_params
$this->assertEquals('activity_log.description.user_updated', $log->description_key);
$this->assertEquals($descriptionParams, $log->description_params);
// changes
$this->assertIsArray($log->changes);
$this->assertCount(1, $log->changes);
$this->assertEquals('name', $log->changes[0]['field']);
$this->assertEquals('이전 이름', $log->changes[0]['old']);
$this->assertEquals('새 이름', $log->changes[0]['new']);
// properties
$this->assertEquals(['section' => 'profile'], $log->properties);
// loggable (polymorphic)
$this->assertEquals($user->getMorphClass(), $log->loggable_type);
$this->assertEquals($user->getKey(), $log->loggable_id);
}
/**
* config disabled 시 Log::channel('activity')가 레코드를 생성하지 않는지 확인
*/
public function test_disabled_config_prevents_logging(): void
{
config(['activity_log.enabled' => false]);
Log::channel('activity')->info('user.create', [
'log_type' => ActivityLogType::Admin,
]);
$this->assertDatabaseCount('activity_logs', 0);
}
/**
* 여러 로그를 연속 기록할 수 있는지 확인
*/
public function test_multiple_logs_can_be_recorded_sequentially(): void
{
Log::channel('activity')->info('user.login', [
'log_type' => ActivityLogType::User,
'user_id' => null,
'ip_address' => '10.0.0.1',
'user_agent' => 'Browser/1.0',
]);
Log::channel('activity')->info('admin.settings_update', [
'log_type' => ActivityLogType::Admin,
'user_id' => null,
'ip_address' => '10.0.0.2',
'user_agent' => 'Browser/2.0',
]);
$this->assertDatabaseCount('activity_logs', 2);
$logs = ActivityLog::orderBy('id')->get();
$this->assertEquals('user.login', $logs[0]->action);
$this->assertEquals('admin.settings_update', $logs[1]->action);
}
/**
* 명시적으로 전달한 user_id가 Processor에 의해 덮어쓰이지 않는지 확인
*/
public function test_explicit_context_not_overwritten_by_processor(): void
{
$authUser = User::factory()->create();
$this->actingAs($authUser);
$explicitUserId = 99999;
Log::channel('activity')->info('system.impersonate', [
'log_type' => ActivityLogType::System,
'user_id' => $explicitUserId,
'ip_address' => '172.16.0.1',
'user_agent' => 'CLI/1.0',
]);
$log = ActivityLog::first();
$this->assertEquals($explicitUserId, $log->user_id);
$this->assertEquals('172.16.0.1', $log->ip_address);
$this->assertEquals('CLI/1.0', $log->user_agent);
}
}