test(core): 개발 환경 파일을 건드리는 테스트 격리
테스트가 개발자의 `.env` 를 삭제한 사고 이후 부트스트랩에 복원 안전망을 넣었지만, 그것은 프로세스 종료 시점 복원이라 같은 실행 안에서 뒤 테스트가 훼손된 파일을 읽는 구간이 남아 있었다. 복원이 아니라 애초에 건드리지 않는 구조로 바꾼다. 앱 루트를 임시 디렉토리로 돌리면 `base_path` 를 쓰는 제품 코드는 한 줄도 바뀌지 않은 채 격리된 파일만 다룬다. 공용 트레이트로 묶어 세 클래스가 같은 방식을 쓰게 했다. 격리 자체를 증명하기 위해 안전망을 임시로 끄고 돌렸다. 안전망 없이도 `.env` 가 바이트 단위로 그대로였다 — "green 이니 됐다" 로는 안전망이 뒤에서 복원해 준 것과 구분되지 않는다. 이 과정에서 격리로는 막을 수 없는 유형을 하나 더 찾았다. 별도 프로세스를 띄워 업그레이드 커맨드를 실행하는 테스트가 자식 쪽에서 `.env` 의 버전 값을 덮어쓰고 있었다. 부모의 앱 루트 전환도, 테스트 부트스트랩의 안전망도 자식에는 닿지 않는다. 테스트 환경 지정은 읽는 파일만 바꿀 뿐 쓰기 대상은 언제나 프로젝트 루트의 `.env` 다. 그 테스트가 검증하는 것은 자식이 방금 쓴 클래스를 읽어들이는지 뿐이므로, 커맨드가 이미 제공하는 부수효과 차단 옵션을 붙였다. 같은 구조의 문제가 업그레이드 스텝 임시 파일에도 있었다 — 실제 `upgrades/` 에 쓰고 정리를 tearDown 에 의존하므로 중단되면 개발 체크아웃에 정체불명의 스텝이 남는다. 실제로 두 번 발견해 지웠고, 부트스트랩 셧다운 훅이 그 패턴을 쓸어내도록 했다. 검증: 세 클래스 개별 green, 안전망을 끈 통합 실행 28건 green + `.env` 불변, 자식 프로세스 테스트 green, 전 구간 `.env` 해시 불변, audit 위반 0. 알려진 잔여 문제: 인스톨러와 업그레이드 스위트를 한 프로세스로 합쳐 돌리면 모듈 클래스 중복 선언 fatal 로 중단된다. 각각 따로 돌리면 297 / 301 건 모두 통과하며, 이번 변경 이전에도 같은 증상이었다. 별도 조사가 필요해 이번 범위에서 다루지 않았다.
This commit is contained in:
1 parent
072b3f50d9
commit
7e569efe4c
6 files changed
+184
-103
No files matched your search
@@ -4,6 +4,7 @@ namespace Tests\Unit\Providers;
|
||||
|
||||
use App\Providers\InstallerRuntimeServiceProvider;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Tests\Concerns\IsolatesInstallerBasePath;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
@@ -16,16 +17,14 @@ use Tests\TestCase;
|
||||
*/
|
||||
class InstallerRuntimeServiceProviderTest extends TestCase
|
||||
{
|
||||
use IsolatesInstallerBasePath;
|
||||
|
||||
private string $runtimePath;
|
||||
|
||||
private ?string $originalEnv = null;
|
||||
|
||||
private string $envPath;
|
||||
|
||||
private ?string $originalEnvContent = null;
|
||||
|
||||
private bool $originalEnvExisted = false;
|
||||
|
||||
/** @var array<string, string|null> */
|
||||
private array $originalEnvSnapshot = [];
|
||||
|
||||
@@ -39,20 +38,14 @@ class InstallerRuntimeServiceProviderTest extends TestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// 앱 루트를 임시 디렉토리로 돌린다. 본 테스트는 `.env` 와 runtime.php 를 직접
|
||||
// 쓰고 지우므로, 실제 프로젝트 루트에서 돌면 개발자의 `.env` 를 파괴한다.
|
||||
// tearDown 복원에 기대지 않고 애초에 실제 파일을 건드리지 않는다.
|
||||
$this->isolateInstallerBasePath();
|
||||
|
||||
$this->runtimePath = base_path('storage/installer/runtime.php');
|
||||
$this->envPath = base_path('.env');
|
||||
|
||||
// 테스트 시작 시 runtime.php 정리 (이전 테스트의 잔재 제거)
|
||||
if (is_file($this->runtimePath)) {
|
||||
@unlink($this->runtimePath);
|
||||
}
|
||||
|
||||
// .env 원본 보존
|
||||
if (is_file($this->envPath)) {
|
||||
$this->originalEnvExisted = true;
|
||||
$this->originalEnvContent = file_get_contents($this->envPath);
|
||||
}
|
||||
|
||||
// process ENV 스냅샷 (stale ENV 보정 테스트가 갱신하므로 다음 테스트 격리)
|
||||
foreach (self::ENV_KEYS_FOR_SNAPSHOT as $key) {
|
||||
$value = getenv($key);
|
||||
@@ -77,13 +70,6 @@ class InstallerRuntimeServiceProviderTest extends TestCase
|
||||
$this->originalEnv = null;
|
||||
}
|
||||
|
||||
// .env 복원
|
||||
if ($this->originalEnvExisted && $this->originalEnvContent !== null) {
|
||||
file_put_contents($this->envPath, $this->originalEnvContent);
|
||||
} elseif (! $this->originalEnvExisted && is_file($this->envPath)) {
|
||||
@unlink($this->envPath);
|
||||
}
|
||||
|
||||
// process ENV 복원
|
||||
foreach ($this->originalEnvSnapshot as $key => $value) {
|
||||
if ($value === null) {
|
||||
@@ -96,6 +82,9 @@ class InstallerRuntimeServiceProviderTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
// 임시 앱 루트 해제 및 제거 (실제 프로젝트 파일은 처음부터 건드리지 않았다)
|
||||
$this->releaseInstallerBasePath();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user