2025-08-05 21:53:49 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Tests\Feature\Http\Controllers\Api\V1;
|
|
|
|
|
|
2025-08-15 16:39:18 +02:00
|
|
|
use Domains\Logging\Enums\LogLevelEnum;
|
|
|
|
|
use Domains\Logging\Models\Log;
|
2025-08-05 21:53:49 +02:00
|
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
|
use Tests\TestCase;
|
|
|
|
|
|
|
|
|
|
class LogsControllerTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
use RefreshDatabase;
|
|
|
|
|
|
2025-08-14 22:01:15 +02:00
|
|
|
protected function setUp(): void
|
|
|
|
|
{
|
|
|
|
|
parent::setUp();
|
|
|
|
|
// Clear any logs that may have been created during application startup
|
|
|
|
|
Log::query()->delete();
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-05 21:53:49 +02:00
|
|
|
public function test_index_returns_successful_response(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->count(5)->create();
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200)
|
|
|
|
|
->assertJsonStructure([
|
|
|
|
|
'success',
|
|
|
|
|
'message',
|
|
|
|
|
'data' => [
|
|
|
|
|
'logs' => [
|
|
|
|
|
'*' => [
|
|
|
|
|
'id',
|
|
|
|
|
'level',
|
|
|
|
|
'message',
|
|
|
|
|
'context',
|
|
|
|
|
'created_at',
|
|
|
|
|
'updated_at',
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
'pagination' => [
|
|
|
|
|
'current_page',
|
|
|
|
|
'last_page',
|
|
|
|
|
'per_page',
|
|
|
|
|
'total',
|
|
|
|
|
'from',
|
|
|
|
|
'to',
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
])
|
|
|
|
|
->assertJson([
|
|
|
|
|
'success' => true,
|
|
|
|
|
'message' => 'Logs retrieved successfully.'
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_orders_logs_by_created_at_desc(): void
|
|
|
|
|
{
|
|
|
|
|
$oldLog = Log::factory()->create(['created_at' => now()->subDays(2)]);
|
|
|
|
|
$newLog = Log::factory()->create(['created_at' => now()->subDay()]);
|
|
|
|
|
$newestLog = Log::factory()->create(['created_at' => now()]);
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$logs = $response->json('data.logs');
|
|
|
|
|
|
|
|
|
|
$this->assertEquals($newestLog->id, $logs[0]['id']);
|
|
|
|
|
$this->assertEquals($newLog->id, $logs[1]['id']);
|
|
|
|
|
$this->assertEquals($oldLog->id, $logs[2]['id']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_filters_by_level(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->create(['level' => LogLevelEnum::ERROR]);
|
|
|
|
|
Log::factory()->create(['level' => LogLevelEnum::WARNING]);
|
|
|
|
|
Log::factory()->create(['level' => LogLevelEnum::INFO]);
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs?level=error');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$logs = $response->json('data.logs');
|
|
|
|
|
|
|
|
|
|
$this->assertCount(1, $logs);
|
|
|
|
|
$this->assertEquals('error', $logs[0]['level']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_respects_per_page_parameter(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->count(15)->create();
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs?per_page=5');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$logs = $response->json('data.logs');
|
|
|
|
|
$pagination = $response->json('data.pagination');
|
|
|
|
|
|
|
|
|
|
$this->assertCount(5, $logs);
|
|
|
|
|
$this->assertEquals(5, $pagination['per_page']);
|
|
|
|
|
$this->assertEquals(15, $pagination['total']);
|
|
|
|
|
$this->assertEquals(3, $pagination['last_page']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_limits_per_page_to_maximum(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->count(10)->create();
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs?per_page=150');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$pagination = $response->json('data.pagination');
|
|
|
|
|
|
|
|
|
|
// Should be limited to 100 as per controller logic
|
|
|
|
|
$this->assertEquals(100, $pagination['per_page']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_uses_default_per_page_when_not_specified(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->count(25)->create();
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$pagination = $response->json('data.pagination');
|
|
|
|
|
|
|
|
|
|
// Should use default of 20
|
|
|
|
|
$this->assertEquals(20, $pagination['per_page']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_handles_empty_logs(): void
|
|
|
|
|
{
|
|
|
|
|
$response = $this->getJson('/api/v1/logs');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200)
|
|
|
|
|
->assertJson([
|
|
|
|
|
'success' => true,
|
|
|
|
|
'message' => 'Logs retrieved successfully.',
|
|
|
|
|
'data' => [
|
|
|
|
|
'logs' => [],
|
|
|
|
|
'pagination' => [
|
|
|
|
|
'total' => 0,
|
|
|
|
|
'current_page' => 1,
|
|
|
|
|
'last_page' => 1,
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_pagination_works_correctly(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->count(25)->create();
|
|
|
|
|
|
|
|
|
|
// Test first page
|
|
|
|
|
$response = $this->getJson('/api/v1/logs?per_page=10&page=1');
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$pagination = $response->json('data.pagination');
|
|
|
|
|
$this->assertEquals(1, $pagination['current_page']);
|
|
|
|
|
$this->assertEquals(3, $pagination['last_page']);
|
|
|
|
|
$this->assertEquals(1, $pagination['from']);
|
|
|
|
|
$this->assertEquals(10, $pagination['to']);
|
|
|
|
|
|
|
|
|
|
// Test second page
|
|
|
|
|
$response = $this->getJson('/api/v1/logs?per_page=10&page=2');
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$pagination = $response->json('data.pagination');
|
|
|
|
|
$this->assertEquals(2, $pagination['current_page']);
|
|
|
|
|
$this->assertEquals(11, $pagination['from']);
|
|
|
|
|
$this->assertEquals(20, $pagination['to']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_with_multiple_log_levels(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->create(['level' => LogLevelEnum::ERROR, 'message' => 'Error message']);
|
|
|
|
|
Log::factory()->create(['level' => LogLevelEnum::WARNING, 'message' => 'Warning message']);
|
|
|
|
|
Log::factory()->create(['level' => LogLevelEnum::INFO, 'message' => 'Info message']);
|
|
|
|
|
Log::factory()->create(['level' => LogLevelEnum::DEBUG, 'message' => 'Debug message']);
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$logs = $response->json('data.logs');
|
|
|
|
|
|
|
|
|
|
$this->assertCount(4, $logs);
|
|
|
|
|
|
|
|
|
|
$levels = array_column($logs, 'level');
|
|
|
|
|
$this->assertContains('error', $levels);
|
|
|
|
|
$this->assertContains('warning', $levels);
|
|
|
|
|
$this->assertContains('info', $levels);
|
|
|
|
|
$this->assertContains('debug', $levels);
|
|
|
|
|
}
|
2025-08-16 09:00:46 +02:00
|
|
|
|
|
|
|
|
public function test_index_handles_negative_per_page(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->count(5)->create();
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs?per_page=-5');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$pagination = $response->json('data.pagination');
|
|
|
|
|
|
|
|
|
|
// Should use default of 20 when negative value provided
|
|
|
|
|
$this->assertEquals(20, $pagination['per_page']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_handles_zero_per_page(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->count(5)->create();
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs?per_page=0');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$pagination = $response->json('data.pagination');
|
|
|
|
|
|
|
|
|
|
// Should use default of 20 when zero provided
|
|
|
|
|
$this->assertEquals(20, $pagination['per_page']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_excludes_system_noise_messages(): void
|
|
|
|
|
{
|
|
|
|
|
// Create a log with system noise message that should be excluded
|
|
|
|
|
Log::factory()->create(['message' => 'No active feeds found. Article discovery skipped.']);
|
|
|
|
|
Log::factory()->create(['message' => 'Regular log message']);
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$logs = $response->json('data.logs');
|
|
|
|
|
|
|
|
|
|
// Should only get the regular log, not the system noise
|
|
|
|
|
$this->assertCount(1, $logs);
|
|
|
|
|
$this->assertEquals('Regular log message', $logs[0]['message']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_index_handles_non_numeric_per_page(): void
|
|
|
|
|
{
|
|
|
|
|
Log::factory()->count(5)->create();
|
|
|
|
|
|
|
|
|
|
$response = $this->getJson('/api/v1/logs?per_page=invalid');
|
|
|
|
|
|
|
|
|
|
$response->assertStatus(200);
|
|
|
|
|
|
|
|
|
|
$pagination = $response->json('data.pagination');
|
|
|
|
|
|
|
|
|
|
// Should use default of 20 when invalid value provided
|
|
|
|
|
$this->assertEquals(20, $pagination['per_page']);
|
|
|
|
|
}
|
2025-08-05 21:53:49 +02:00
|
|
|
}
|