fix(core,basic): 검색 봇 화면 렌더러 패리티 결손 일괄 수정
일반 화면(React)과 봇 화면(PHP)은 같은 레이아웃을 각각 렌더하는데 봇 화면 쪽 지원 범위가 뒤처져, 확장이 교체한 본문이 통째로 빈 채 나갔다 (공개 이슈 ). 같은 결손 계열을 전수 조사해 함께 닫는다. - 확장 주입 props 를 렌더 진입 시점에 해석해 자손 전체에 상속 → 게시글·답글 원글·댓글·페이지·상품 설명 5개 지점 복구 - 사용자 작성 HTML 정화기 신설 — isHtml 판정에 따라 이스케이프/정화. 미정화 상태에서 봇 경로로 저장형 스크립트가 실제 실행됐다 - 노드 키 패리티: conditions / type:iterator / responsive 매칭 규칙 / children 문자열 / text 우선순위 / $t:defer / 레이아웃 초기 상태 - 표현식: 단일 바인딩 판정 교체, ||·&& 를 값 반환(JS 시맨틱)으로, 비교식이 raw 경로에서 null 이 되던 문제 - 데이터소스: 엔드포인트 표현식 전면 해석 + 레이아웃 8곳 선언 보강 - 봇 페이지 캐시 1회 전량 무효화 업그레이드 스텝 지원 범위 SSoT 표를 문서에 고정하고, 한쪽만 고치는 것을 막는 검사 룰과 레이아웃 전수 순회 테스트로 잠갔다.
This commit is contained in:
1 parent
b505ac7ba7
commit
0dfb45951b
34 files changed
+5244
-172
No files matched your search
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Upgrades;
|
||||
|
||||
require_once __DIR__.'/../../../upgrades/data/7.0.6/migrations/02_ClearSeoPageCacheAfterRendererParityFix.php';
|
||||
|
||||
use App\Extension\Cache\CoreCacheDriver;
|
||||
use App\Extension\UpgradeContext;
|
||||
use App\Upgrades\Data\V7_0_6\Migrations\ClearSeoPageCacheAfterRendererParityFix;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* 7.0.6 업그레이드 스텝 — 봇 페이지 캐시 1회 무효화
|
||||
*
|
||||
* 7.0.6 이전 렌더러가 빈 본문으로 저장한 캐시가 남아 있으면, 렌더러를 고쳐도
|
||||
* 캐시 수명 동안 검색 봇이 계속 빈 페이지를 받는다. 업그레이드 시 한 번 비운다.
|
||||
*/
|
||||
class ClearSeoPageCacheAfterRendererParityFixTest extends TestCase
|
||||
{
|
||||
private ClearSeoPageCacheAfterRendererParityFix $migration;
|
||||
|
||||
private CoreCacheDriver $cache;
|
||||
|
||||
/**
|
||||
* 테스트 초기화 - 배열 캐시 스토어와 마이그레이션을 준비합니다.
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config()->set('cache.default', 'array');
|
||||
$this->cache = new CoreCacheDriver('array');
|
||||
$this->cache->flush();
|
||||
$this->migration = new ClearSeoPageCacheAfterRendererParityFix;
|
||||
}
|
||||
|
||||
/**
|
||||
* 업그레이드 컨텍스트를 만듭니다.
|
||||
*
|
||||
* @return UpgradeContext 컨텍스트
|
||||
*/
|
||||
private function context(): UpgradeContext
|
||||
{
|
||||
return new UpgradeContext('7.0.5', '7.0.6', '7.0.6');
|
||||
}
|
||||
|
||||
/**
|
||||
* 인덱스에 등록된 캐시 항목과 인덱스 자체가 모두 삭제됩니다.
|
||||
*
|
||||
* @effects stale_page_cache_is_cleared_on_upgrade, cache_index_is_cleared_on_upgrade
|
||||
*/
|
||||
public function test_clears_indexed_page_cache_entries_and_index(): void
|
||||
{
|
||||
$this->cache->put('seo.page.abc', '<html>빈 본문</html>', 3600);
|
||||
$this->cache->put('seo.page.def', '<html>빈 본문2</html>', 3600);
|
||||
$this->cache->put('seo.cached_urls', [
|
||||
['key' => 'seo.page.abc', 'url' => '/board/free/1'],
|
||||
['key' => 'seo.page.def', 'url' => '/page/about'],
|
||||
], 3600);
|
||||
|
||||
$this->migration->run($this->context());
|
||||
|
||||
$this->assertNull($this->cache->get('seo.page.abc'));
|
||||
$this->assertNull($this->cache->get('seo.page.def'));
|
||||
$this->assertNull($this->cache->get('seo.cached_urls'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 인덱스가 없으면 아무 것도 하지 않습니다 (no-op).
|
||||
*
|
||||
* @effects invalidation_is_idempotent, unrelated_cache_namespaces_are_preserved
|
||||
*/
|
||||
public function test_no_index_is_noop(): void
|
||||
{
|
||||
$this->cache->put('unrelated.key', 'keep', 3600);
|
||||
|
||||
$this->migration->run($this->context());
|
||||
|
||||
$this->assertSame('keep', $this->cache->get('unrelated.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 재실행해도 부작용이 없습니다 (멱등).
|
||||
*
|
||||
* @effects invalidation_is_idempotent
|
||||
*/
|
||||
public function test_is_idempotent(): void
|
||||
{
|
||||
$this->cache->put('seo.page.abc', '<html></html>', 3600);
|
||||
$this->cache->put('seo.cached_urls', [['key' => 'seo.page.abc', 'url' => '/']], 3600);
|
||||
|
||||
$this->migration->run($this->context());
|
||||
$this->migration->run($this->context());
|
||||
|
||||
$this->assertNull($this->cache->get('seo.page.abc'));
|
||||
$this->assertNull($this->cache->get('seo.cached_urls'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 인덱스 항목이 손상되어 있어도 나머지를 삭제하고 인덱스를 비웁니다.
|
||||
*
|
||||
* @effects stale_page_cache_is_cleared_on_upgrade, cache_index_is_cleared_on_upgrade
|
||||
*/
|
||||
public function test_malformed_index_entries_are_skipped(): void
|
||||
{
|
||||
$this->cache->put('seo.page.ok', '<html></html>', 3600);
|
||||
$this->cache->put('seo.cached_urls', [
|
||||
'not-an-array',
|
||||
['url' => '/키없음'],
|
||||
['key' => '', 'url' => '/빈키'],
|
||||
['key' => 'seo.page.ok', 'url' => '/정상'],
|
||||
], 3600);
|
||||
|
||||
$this->migration->run($this->context());
|
||||
|
||||
$this->assertNull($this->cache->get('seo.page.ok'));
|
||||
$this->assertNull($this->cache->get('seo.cached_urls'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 봇 페이지 캐시 외의 캐시는 건드리지 않습니다.
|
||||
*
|
||||
* @effects unrelated_cache_namespaces_are_preserved
|
||||
*/
|
||||
public function test_unrelated_cache_keys_are_preserved(): void
|
||||
{
|
||||
$this->cache->put('extension.middleware_index', ['a'], 3600);
|
||||
$this->cache->put('seo.page.abc', '<html></html>', 3600);
|
||||
$this->cache->put('seo.cached_urls', [['key' => 'seo.page.abc', 'url' => '/']], 3600);
|
||||
|
||||
$this->migration->run($this->context());
|
||||
|
||||
$this->assertSame(['a'], $this->cache->get('extension.middleware_index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 인덱스가 손상되어 다른 네임스페이스 키를 가리켜도 그 키는 지우지 않습니다.
|
||||
*
|
||||
* 삭제 대상을 봇 페이지 캐시 프리픽스(`seo.page.`)로 한정해, 오염된 인덱스가
|
||||
* 무관한 캐시를 함께 날리는 사고를 막습니다.
|
||||
*
|
||||
* @effects unrelated_cache_namespaces_are_preserved, stale_page_cache_is_cleared_on_upgrade
|
||||
*/
|
||||
public function test_index_entries_outside_page_cache_namespace_are_not_forgotten(): void
|
||||
{
|
||||
$this->cache->put('extension.middleware_index', ['a'], 3600);
|
||||
$this->cache->put('seo.page.abc', '<html></html>', 3600);
|
||||
$this->cache->put('seo.cached_urls', [
|
||||
['key' => 'seo.page.abc', 'url' => '/'],
|
||||
// 오염된 엔트리 — 봇 페이지 캐시가 아닌 키를 가리킨다
|
||||
['key' => 'extension.middleware_index', 'url' => '/'],
|
||||
], 3600);
|
||||
|
||||
$this->migration->run($this->context());
|
||||
|
||||
$this->assertSame(['a'], $this->cache->get('extension.middleware_index'), '무관한 캐시가 삭제되었습니다.');
|
||||
$this->assertNull($this->cache->get('seo.page.abc'), '봇 페이지 캐시는 삭제되어야 합니다.');
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user