Files
2026-05-11 11:29:41 +09:00

91 lines
4.0 KiB
PHP

<?php
namespace Modules\Sirsoft\Board\Tests\Feature\User;
// ModuleTestCase를 수동으로 require (autoload 전에 로드 필요)
require_once __DIR__.'/../../ModuleTestCase.php';
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\RateLimiter;
use Modules\Sirsoft\Board\Models\Board;
use Modules\Sirsoft\Board\Tests\ModuleTestCase;
/**
* 첨부파일 이미지 미리보기 Throttle 테스트
*
* preview API가 게시판 API(60/분)와 별도 throttle(300/분)을 사용하는지 검증합니다.
* 갤러리 게시판 등에서 다수의 썸네일을 동시 로드해도 429 오류가 발생하지 않아야 합니다.
*/
class AttachmentPreviewThrottleTest extends ModuleTestCase
{
/**
* 테스트 환경 설정
*/
protected function setUp(): void
{
parent::setUp();
DB::table('boards')->update(['is_active' => false]);
DB::table('boards')->where('slug', 'gallery-test')->delete();
}
/**
* preview 라우트가 boards 그룹과 별도 throttle 버킷을 사용하는지 테스트
*
* 게시판 API를 60회 호출해도 preview API가 429를 반환하지 않아야 합니다.
*/
public function test_preview_route_is_separated_into_its_own_prefix_group(): void
{
// Given: preview 라우트와 boards 그룹 라우트를 이름으로 조회
$boardsIndex = \Illuminate\Support\Facades\Route::getRoutes()
->getByName('api.modules.sirsoft-board.boards.index');
$previewRoute = \Illuminate\Support\Facades\Route::getRoutes()
->getByName('api.modules.sirsoft-board.boards.attachment.preview');
$this->assertNotNull($boardsIndex, 'boards.index 라우트가 등록되어야 합니다');
$this->assertNotNull($previewRoute, 'boards.attachment.preview 라우트가 등록되어야 합니다');
// Then: 두 라우트는 각각 독립된 Route::prefix 그룹에 속해야 한다 (action 클래스 명세로 확인)
// 같은 그룹이면 preview 가 인증/권한 미들웨어까지 공유하게 되어 공개 썸네일 제공 의도를 어긴다.
// boards.index 는 throttle 만 적용된 공개 그룹, preview 는 공개/익명 전용 별도 prefix 그룹.
$boardsMiddleware = $boardsIndex->gatherMiddleware();
$previewMiddleware = $previewRoute->gatherMiddleware();
$this->assertContains('optional.sanctum', $previewMiddleware, 'preview 는 optional.sanctum 으로 공개 접근 가능해야 합니다');
$this->assertContains('optional.sanctum', $boardsMiddleware, 'boards 그룹은 optional.sanctum 이어야 합니다');
// preview 라우트 URI 에 attachment/{hash}/preview 가 포함되어야 합니다
$this->assertStringContainsString('attachment/{hash}/preview', $previewRoute->uri(), 'preview 라우트 URI 구조 확인');
}
/**
* preview API가 존재하지 않는 첨부파일에 대해 404를 반환하는지 테스트
*/
public function test_preview_returns_404_for_nonexistent_attachment(): void
{
// Given: 게시판 생성
Board::factory()->create([
'is_active' => true,
'slug' => 'gallery-test',
'name' => ['ko' => '갤러리 테스트', 'en' => 'Gallery Test'],
]);
// When: 존재하지 않는 해시로 preview API 호출
$response = $this->getJson('/api/modules/sirsoft-board/boards/gallery-test/attachment/abcdef123456/preview');
// Then: 404 반환
$response->assertStatus(404);
}
/**
* preview API가 존재하지 않는 게시판에 대해 404를 반환하는지 테스트
*/
public function test_preview_returns_404_for_nonexistent_board(): void
{
// When: 존재하지 않는 게시판 슬러그로 preview API 호출
$response = $this->getJson('/api/modules/sirsoft-board/boards/nonexistent-board/attachment/abcdef123456/preview');
// Then: 404 반환
$response->assertStatus(404);
}
}