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 → 현재 버전으로 교정
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
<?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}() 본문 끝을 찾지 못했습니다.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user