run($context); } /** * @scenario backfill=legacy_row * * @effects backfill_fills_legacy_rows */ #[Test] public function legacy_rows_are_backfilled_with_first_internal_image(): void { // createTestPost 는 DB 직접 insert — 모델 saving 이벤트를 타지 않아 // 업그레이드 전 작성 글(캐시 null)과 동일한 상태다 $legacy = $this->createTestPost([ 'content_mode' => 'html', 'content' => '
글

',
]);
$this->runBackfill();
$this->assertSame(
'/storage/uploads/legacy.jpg',
DB::table('board_posts')->where('id', $legacy)->value('content_thumbnail_url'),
'첫 외부 후보는 건너뛰고 첫 내부 이미지가 백필되어야 합니다.'
);
}
/**
* @scenario backfill=already_filled
*
* @effects backfill_fills_legacy_rows
*/
#[Test]
public function already_filled_rows_are_untouched(): void
{
$filled = $this->createTestPost([
'content' => '
',
'content_thumbnail_url' => '/storage/uploads/kept.jpg',
]);
$this->runBackfill();
$this->assertSame(
'/storage/uploads/kept.jpg',
DB::table('board_posts')->where('id', $filled)->value('content_thumbnail_url'),
'이미 값이 있는 행은 백필 대상이 아니어야 합니다.'
);
}
/**
* @scenario backfill=external_only
*
* @effects backfill_keeps_external_only_null
*/
#[Test]
public function external_only_rows_stay_null(): void
{
$external = $this->createTestPost([
'content_mode' => 'html',
'content' => '
',
]);
$noImage = $this->createTestPost(['content_mode' => 'html', 'content' => '이미지 없음
']); $this->runBackfill(); $this->assertNull(DB::table('board_posts')->where('id', $external)->value('content_thumbnail_url')); $this->assertNull(DB::table('board_posts')->where('id', $noImage)->value('content_thumbnail_url')); } /** * text 모드 레거시 행은 리터럴 img 마크업이 있어도 백필되지 않아야 합니다. * * text 모드 본문은 이스케이프 렌더라 상세에 이미지가 표시되지 않는다 — * 목록 썸네일만 뜨면 상세와 어긋난다 (content_mode 기본값이 text 라 모집단이 크다). * * @scenario backfill=text_mode * * @effects text_mode_content_never_caches */ #[Test] public function text_mode_rows_are_not_backfilled(): void { $textMode = $this->createTestPost([ 'content_mode' => 'text', 'content' => '텍스트 본문의
마크업',
]);
$this->runBackfill();
$this->assertNull(
DB::table('board_posts')->where('id', $textMode)->value('content_thumbnail_url'),
'text 모드 글은 백필 대상이 아니어야 합니다.'
);
}
/**
* @scenario backfill=idempotent
*
* @effects backfill_idempotent_second_run
*/
#[Test]
public function second_run_is_idempotent(): void
{
$this->createTestPost(['content_mode' => 'html', 'content' => '
']);
$this->createTestPost(['content_mode' => 'html', 'content' => '
']);
$this->createTestPost(['content_mode' => 'html', 'content' => '이미지 없음
']); $this->runBackfill(); $first = $this->snapshot(); $this->runBackfill(); $second = $this->snapshot(); $this->assertSame($first, $second, '재실행 결과가 동일해야 합니다.'); } /** * 이 게시판 게시글의 (id, content_thumbnail_url) 스냅샷을 반환합니다. * * @return array