Files
Gnuboard7/tests/Feature/DevTools/DevtoolsDebugGateTest.php
T
HeuJung 4744e7bf85 fix(core): 라우트 캐시 상태에서 DevTools 덤프·브라우저 로그 수집 복구
route:cache 가 걸리면 RouteServiceProvider 가 캐시 로드로 분기해 라우트 파일이
실행되지 않는다. routes/devtools.php 는 전역 함수 5개를 정의하고 핸들러가 호출했고,
boost 의 browser-logs 는 프로바이더 boot 등록분이라 setCompiledRoutes 교체로
폐기됐다. 7.0.6 의 RouteCacheHelper 가 12개 라이프사이클 지점에서 캐시를 자동
생성하면서, 확장을 한 번이라도 건드린 사이트에서 항상 재현됐다.

로직을 오토로드되는 App\Support\DevTools\* 로 옮기고 browser-logs URI 를 G7 가
직접 소유해 캐시에 함께 구워지게 했다. 게이트가 참조하던 App\Models\Setting 은
저장소에 없는 유물이라 ConfigRepositoryInterface 로 교체했다.

같은 부류의 재발은 정적 검사(route-file-local-function)로 차단하고, 재현이
in-process 로 불가능하므로 서브프로세스 하네스로 회귀를 고정했다.
2026-08-07 10:13:52 +09:00

117 lines
4.1 KiB
PHP

<?php
namespace Tests\Feature\DevTools;
use App\Contracts\Repositories\ConfigRepositoryInterface;
use App\Support\DevTools\DebugGate;
use Mockery;
use Tests\TestCase;
/**
* DevTools 엔드포인트의 디버그 모드 게이트 회귀 테스트.
*
* 배경:
* 게이트는 원래 `config('app.debug') || \App\Models\Setting::getValue('debug.mode', false)`
* 였는데 `App\Models\Setting` 은 저장소에 존재하지 않는 유물이었다. `||` 단축평가 덕에
* `APP_DEBUG=true` 인 동안에는 두 번째 항이 평가되지 않아 드러나지 않았을 뿐이고,
* `APP_DEBUG=false` + settings JSON 의 `debug` 카테고리 미동기화가 겹치면
* **403 이어야 할 응답이 `Class "App\Models\Setting" not found` 500 이 됐다.**
*
* 검증 축:
* 1. app.debug=false + debug.mode=true → 200 (두 번째 항이 실제로 평가되어야 한다)
* 2. app.debug=false + debug.mode=false → 403 (500 이 아니어야 한다)
* 3. app.debug=true → 200 (환경설정 조회 없이 통과)
*/
class DevtoolsDebugGateTest extends TestCase
{
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
/**
* `debug.mode` 환경설정만 켜져 있어도 게이트를 통과해야 한다.
*
* 수정 전: HTTP 500 `Class "App\Models\Setting" not found`
*/
public function test_dump_state_passes_gate_via_settings_debug_mode(): void
{
config(['app.debug' => false]);
$this->mockConfigRepositoryDebugMode(true);
$response = $this->postJson('/_boost/g7-debug/dump-state', ['test' => true]);
$response->assertStatus(200);
$response->assertJson(['status' => 'success']);
}
/**
* 양쪽 모두 꺼져 있으면 403 이어야 한다 (500 이 아니라).
*/
public function test_dump_state_returns_403_when_debug_disabled(): void
{
config(['app.debug' => false]);
$this->mockConfigRepositoryDebugMode(false);
$response = $this->postJson('/_boost/g7-debug/dump-state', ['test' => true]);
$response->assertStatus(403);
$response->assertJson(['status' => 'error']);
// 번역 키가 해석되지 않으면 Laravel 은 키 문자열을 그대로 돌려준다 — 오류 없이
// 사용자에게 `devtools.debug_disabled` 가 노출되므로 해석 여부를 단언한다.
$this->assertNotSame(
'devtools.debug_disabled',
$response->json('message'),
'번역 키가 해석되지 않았습니다 (lang/{ko,en}/devtools.php 누락).'
);
}
/**
* `browser-logs` 도 동일 게이트를 사용한다.
*/
public function test_browser_logs_returns_403_when_debug_disabled(): void
{
config(['app.debug' => false]);
$this->mockConfigRepositoryDebugMode(false);
$response = $this->postJson('/_boost/browser-logs', ['logs' => []]);
$response->assertStatus(403);
}
/**
* `.env` 의 `APP_DEBUG=true` 만으로도 통과한다 (환경설정 조회 불필요).
*/
public function test_gate_passes_on_app_debug_without_settings_lookup(): void
{
config(['app.debug' => true]);
$repository = Mockery::mock(ConfigRepositoryInterface::class);
$repository->shouldNotReceive('get');
$this->app->instance(ConfigRepositoryInterface::class, $repository);
$this->assertTrue(DebugGate::isEnabled());
}
/**
* `ConfigRepositoryInterface` 를 `debug.mode` 고정값으로 대체한다.
*
* @param bool $enabled debug.mode 값
* @return void
*/
private function mockConfigRepositoryDebugMode(bool $enabled): void
{
$repository = Mockery::mock(ConfigRepositoryInterface::class);
$repository->shouldReceive('get')
->with('debug.mode', false)
->andReturn($enabled);
$repository->shouldReceive('get')->andReturnUsing(
static fn (string $key, mixed $default = null): mixed => $default
);
$this->app->instance(ConfigRepositoryInterface::class, $repository);
}
}