Files
Gnuboard7/tests/Feature/Console/ExtStaticStatusCommandTest.php
HeuJung de18159986 fix(core,admin_basic): 정적 게시 재게시 누락 3건 수정 + 관리자 수동 복구 UI + sudo core:update 소유권 정합
- 템플릿 update 는 레이아웃 변경 여부와 무관하게 캐시 버전을 올리고(실패 복원 뒤에도), 자산 주소 방식 전환 3경로도 bump 한다
- config:cache 가 컨테이너 인스턴스를 덮어 이후 terminating 재게시가 사라지던 결함을 복원 헬퍼로 차단
- custom/ 변경 감지와 게시가 같은 열거자(재귀·크기 포함)를 쓰고, 서명은 호스트별로 저장
- 캐시 버전·서명 키를 만료시키지 않는다(기본 TTL 24h 로 매일 전체 재생성되던 문제)
- 관리자 > 환경설정 > 일반 「초기 화면 정적 파일」 카드: 상태 조회 + 지금 다시 만들기(확인 모달), 대시보드 알림 버튼 연결, CLI 와 같은 statusReport 소비
- sudo core:update 경로의 root 소유 잔존(설정 디렉토리·임시 폴더·로그·업그레이드 마이그레이션 산출물) 상속·정합화, ext-static 명령 root 경고와 sudo -u 힌트
- 안내·문서·트러블슈팅 4건·audit 룰 ext-cache-version-raw-read·ja 언어팩 동기
2026-09-06 15:22:52 +09:00

149 lines
6.1 KiB
PHP

<?php
namespace Tests\Feature\Console;
use App\Extension\Helpers\FilePermissionHelper;
use App\Extension\Traits\ClearsTemplateCaches;
use App\Services\ExtensionStaticCacheService;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
use Tests\TestCase;
/**
* `ext-static:status` / `ext-static:publish` 의 root 실행 안내 + 상태 보고서 소비 테스트 (#651 C1·D3).
*
* 상태 명령은 종전에 "즉시 게시하려면 `php artisan ext-static:publish`" 를 실행 계정과 무관하게
* 권했다. 운영자가 그 안내를 sudo 셸에서 그대로 따르면 캐시 락 샤드가 root 소유가 되어 이후 웹
* 요청이 500 이 된다. 이제 root 이면 경고와 `sudo -u {웹계정}` 형태의 힌트를 함께 낸다 — 중단은
* 하지 않는다(D3).
*/
class ExtStaticStatusCommandTest extends TestCase
{
private string $isolatedPublicPath;
protected function setUp(): void
{
parent::setUp();
$this->isolatedPublicPath = storage_path('framework/testing/public-cmd-'.getmypid());
File::ensureDirectoryExists($this->isolatedPublicPath);
$this->app->usePublicPath($this->isolatedPublicPath);
ClearsTemplateCaches::resetExtensionCacheStoreMemo();
Cache::put('g7:core:ext.cache_version', 987600000);
Cache::forget('g7:core:ext.static.publish_failure');
ExtensionStaticCacheService::resetPublishScheduleForTesting();
}
protected function tearDown(): void
{
FilePermissionHelper::fakeWebServerAccountForTesting(null);
File::deleteDirectory($this->isolatedPublicPath);
ExtensionStaticCacheService::resetPublishScheduleForTesting();
parent::tearDown();
}
/**
* root 가 아니면 경고 없이 종전 문구 그대로다 (미게시 → 비-0 종료).
*
* @effects status_command_warns_root_and_hints_web_account
*/
public function test_non_root_status_prints_plain_publish_hint_without_root_warning(): void
{
FilePermissionHelper::fakeWebServerAccountForTesting(['mode' => 'non_root', 'name' => null]);
$this->artisan('ext-static:status')
->expectsOutputToContain('부트스트랩 리소스 정적 게시 상태')
->expectsOutputToContain('현재 캐시 버전 : 987600000')
->expectsOutputToContain('게시 상태 : 미게시')
->expectsOutputToContain('php artisan ext-static:publish')
->doesntExpectOutputToContain('root 로 실행 중')
->doesntExpectOutputToContain('sudo -u')
->assertExitCode(1);
}
/**
* root + 웹 계정 식별 → 경고 + `sudo -u {계정}` 힌트. 종료 코드는 종전과 같다.
*
* @effects status_command_warns_root_and_hints_web_account
*/
public function test_root_status_warns_and_hints_sudo_with_web_account(): void
{
FilePermissionHelper::fakeWebServerAccountForTesting(['mode' => 'root_web_known', 'name' => 'www-data']);
$this->artisan('ext-static:status')
->expectsOutputToContain('root 로 실행 중')
->expectsOutputToContain('sudo -u www-data php artisan ext-static:publish')
->assertExitCode(1);
}
/**
* root + 웹 계정 미상 → placeholder 와 확인 방법.
*
* @effects status_command_warns_root_and_hints_web_account
*/
public function test_root_status_with_unknown_web_account_uses_placeholder(): void
{
FilePermissionHelper::fakeWebServerAccountForTesting(['mode' => 'root_web_unknown', 'name' => null]);
// 한 줄에 두 부분 문자열을 따로 기대하면 Mockery 가 첫 기대만 소비한다 — 한 문자열로 잠근다
$this->artisan('ext-static:status')
->expectsOutputToContain('sudo -u <웹서버계정> php artisan ext-static:publish (웹서버 계정은 storage 디렉토리 소유자로 확인)')
->assertExitCode(1);
}
/**
* root 서비스 구성(웹 계정도 root)은 sudo 접두 없이 안내한다 — 재실행도 root 로 무해.
*
* @effects status_command_warns_root_and_hints_web_account
*/
public function test_root_symmetric_hint_has_no_sudo_prefix(): void
{
FilePermissionHelper::fakeWebServerAccountForTesting(['mode' => 'root_web_symmetric', 'name' => null]);
$this->artisan('ext-static:status')
->expectsOutputToContain('root 로 실행 중')
->doesntExpectOutputToContain('sudo -u')
->assertExitCode(1);
}
/**
* 게시 명령은 root 여도 **중단하지 않고** 경고 뒤 계속 실행한다 (D3 — 명시적 명령은 운영자 책임).
*
* @effects publish_command_warns_root_but_continues
*/
public function test_publish_warns_root_but_still_publishes(): void
{
FilePermissionHelper::fakeWebServerAccountForTesting(['mode' => 'root_web_known', 'name' => 'www-data']);
Cache::lock('ext-static.publish.987600000', 300)->forceRelease();
$this->artisan('ext-static:publish')
->expectsOutputToContain('root 로 실행 중')
->expectsOutputToContain('sudo -u www-data php artisan ext-static:publish')
->expectsOutputToContain('정적 게시가 완료되었습니다')
->assertExitCode(0);
$this->assertFileExists(public_path('build/ext/987600000/manifest.json'));
}
/**
* 상태 명령은 서비스 보고서를 소비한다 — 게시 뒤에는 완료·파일 수·게시 시각을 그대로 보인다.
*
* @effects status_command_consumes_service_report
*/
public function test_status_reflects_published_report(): void
{
FilePermissionHelper::fakeWebServerAccountForTesting(['mode' => 'non_root', 'name' => null]);
Cache::lock('ext-static.publish.987600000', 300)->forceRelease();
$this->assertTrue(app(ExtensionStaticCacheService::class)->publishCurrent());
$this->artisan('ext-static:status')
->expectsOutputToContain('게시 상태 : 완료')
->expectsOutputToContain('manifest 파일 : 1건')
->expectsOutputToContain('이상 없음.')
->assertExitCode(0);
}
}