layoutRepository = app(LayoutRepositoryInterface::class); } /** protected 메서드 노출 */ public function invalidate(int $templateId, string $identifier): void { $this->invalidateTemplateLayoutCache($templateId, $identifier); } }; } private function coreCache(): CoreCacheDriver { return new CoreCacheDriver(config('cache.default', 'array')); } #[Test] public function 레이아웃_캐시_무효화는_일반키와_편집기meta키를_모두_삭제한다(): void { $template = Template::factory()->create([ 'identifier' => 'sirsoft-basic', 'type' => 'user', 'status' => ExtensionStatus::Active->value, ]); TemplateLayout::create([ 'template_id' => $template->id, 'name' => 'home', 'content' => ['meta' => ['title' => 'Home'], 'components' => []], ]); $cache = $this->coreCache(); // 트레이트 게터와 같은 근거 — 원시 키 읽기는 키 부재 시 0 을 돌려주어 실제 무효화 키(`.v{time}`)와 // 어긋난 `.v0` 키를 만든다(트레이트는 부재 시 재생성). 무효화 대상 키는 게터가 SSoT 다. $version = ExtensionStaticCacheService::getExtensionCacheVersion(); // PublicLayoutController::serve() 가 쓰는 두 캐시 키 — 일반 + 편집기(.meta) $generalKey = "layout.sirsoft-basic.home.v{$version}"; $metaKey = "layout.sirsoft-basic.home.v{$version}.meta"; $cache->put($generalKey, ['cached' => 'general'], 3600); $cache->put($metaKey, ['cached' => 'meta'], 3600); // 사전 조건: 두 키 모두 캐시에 존재 $this->assertNotNull($cache->get($generalKey), '사전: 일반 키 캐시 존재'); $this->assertNotNull($cache->get($metaKey), '사전: 편집기 .meta 키 캐시 존재'); // 상태 변화 공통 지점 — 레이아웃 캐시 무효화 $this->makeInvalidator()->invalidate($template->id, 'sirsoft-basic'); // 두 키 모두 무효화되어야 함 (.meta 누락이면 편집기 stale 회귀) $this->assertNull($cache->get($generalKey), '일반 키가 무효화됨'); $this->assertNull($cache->get($metaKey), '편집기.meta 키도 무효화됨'); } #[Test] public function 템플릿_레이아웃_refresh_후_편집기meta_캐시가_stale로_남지_않는다(): void { $template = Template::factory()->create([ 'identifier' => 'sirsoft-basic', 'type' => 'user', 'status' => ExtensionStatus::Active->value, ]); TemplateLayout::create([ 'template_id' => $template->id, 'name' => 'home', 'content' => ['meta' => ['title' => 'Home'], 'components' => []], ]); $cache = $this->coreCache(); // 트레이트 게터와 같은 근거 — 원시 키 읽기는 키 부재 시 0 을 돌려주어 실제 무효화 키(`.v{time}`)와 // 어긋난 `.v0` 키를 만든다(트레이트는 부재 시 재생성). 무효화 대상 키는 게터가 SSoT 다. $version = ExtensionStaticCacheService::getExtensionCacheVersion(); $metaKey = "layout.sirsoft-basic.home.v{$version}.meta"; $cache->put($metaKey, ['stale' => 'editor-old-content'], 3600); // 상태 변화 공통 지점 호출 → 편집기 .meta 키가 stale 로 남으면 실패 $this->makeInvalidator()->invalidate($template->id, 'sirsoft-basic'); $this->assertNull( $cache->get($metaKey), 'refresh/상태변화 후 편집기 .meta 캐시가 stale 로 잔존하면 편집기 캔버스가 옛 레이아웃을 표시한다', ); } }