Files
Gnuboard7/tests/Unit/Extension/TemplateUpdateConfigCacheInvalidationTest.php
T
HeuJung e819db9d42 fix(core): 공개 템플릿 config 캐시 무효화 누락과 확장 캐시 삭제 경로 동종 결함 정비
공개 config.json 의 고정 캐시 키(template.config.{identifier})가 어떤 갱신
경로에서도 forget 되지 않아 template:update/cache-clear/비활성화/삭제 후에도
최대 1시간(TTL) 이전 manifest 로 응답되던 결함(공개 )을 수정한다.

- TemplateManager::clearTemplateCache 공개화 — config/components_manifest(두
 변종)/현재 버전 routes·language 키 능동 forget, updateTemplate cleanup 호출
- forgetLayoutCacheKeys 가 편집기용 .with_source_meta 변종까지 삭제
- ext.cache_version 쓰기를 incrementExtensionCacheVersion 단일 지점으로 통일
- module/plugin:cache-clear 의 유령 키 forget 을 실재 캐시(레이아웃 서빙/해석
 캐시, 상태 키, 미들웨어 인덱스, 버전 bump) 무효화로 교체
- 공개 routes/language/layout API 의 ?v 생략 폴백을 0 → 현재 버전으로 교정
2026-08-17 13:22:48 +09:00

87 lines
3.3 KiB
PHP

<?php
namespace Tests\Unit\Extension;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
/**
* 템플릿 업데이트 성공 cleanup 의 config 캐시 무효화 구조 테스트 (#588, 공개 #119)
*
* `template.config.{identifier}` 는 버전 접미사 없는 고정 키라 캐시 버전 bump 로
* 무효화되지 않는다. updateTemplate() 성공 cleanup 이 clearTemplateCache() 를
* 직접 호출하지 않으면, 비활성 업데이트·레이아웃 무변경 업데이트 경로에서 공개
* config.json 이 TTL(1시간) 동안 이전 manifest 를 계속 서빙한다.
*
* 실제 updateTemplate() 통합 실행은 업데이트 소스(_pending/신버전) 픽스처가 필요해
* 비용이 크므로, clearTemplateCache() 의 키 삭제는 TemplateCacheManagementTest 가
* 동작으로 검증하고 본 테스트는 호출 존재를 소스 구조로 고정한다
* (선례: ExtensionUpdateStatusCacheSymmetryTest).
*/
class TemplateUpdateConfigCacheInvalidationTest extends TestCase
{
/**
* @scenario cache_state=warm_current,lifecycle_trigger=template_update,template_type=user
*
* @effects template_update_invalidates_public_config_cache
*/
#[Test]
public function update_template_cleanup_calls_clear_template_cache(): void
{
$body = $this->methodSource(
base_path('app/Extension/TemplateManager.php'),
'updateTemplate'
);
$this->assertStringContainsString(
'$this->clearTemplateCache(',
$body,
'updateTemplate() 성공 cleanup 이 clearTemplateCache() 를 호출해야 합니다 — '
.'누락 시 공개 config.json 이 캐시 TTL 동안 이전 manifest 로 응답됩니다.'
);
}
/**
* 대상 메서드 본문을 주석 제거 후 반환합니다.
*
* 주석을 남겨 두면 설명 문장에 들어 있는 호출 표기가 검사를 통과시킨다.
*
* @param string $path 대상 파일 절대 경로
* @param string $method 대상 메서드명
* @return string 주석이 제거된 메서드 본문
*/
private function methodSource(string $path, string $method): string
{
$this->assertFileExists($path);
$stripped = '';
foreach (token_get_all(file_get_contents($path)) as $token) {
if (is_array($token) && in_array($token[0], [T_COMMENT, T_DOC_COMMENT], true)) {
continue;
}
$stripped .= is_array($token) ? $token[1] : $token;
}
$start = strpos($stripped, "public function {$method}(");
$this->assertNotFalse($start, "{$path} 에서 {$method}() 메서드를 찾지 못했습니다.");
// 중괄호 균형으로 메서드 본문 끝을 찾는다
$open = strpos($stripped, '{', $start);
$depth = 0;
$length = strlen($stripped);
for ($i = $open; $i < $length; $i++) {
if ($stripped[$i] === '{') {
$depth++;
} elseif ($stripped[$i] === '}') {
$depth--;
if ($depth === 0) {
return substr($stripped, $open, $i - $open + 1);
}
}
}
$this->fail("{$path} 의 {$method}() 본문 끝을 찾지 못했습니다.");
}
}