'ko']); } protected function tearDown(): void { DB::table('pages')->where('slug', 'like', 'backfill-%')->delete(); parent::tearDown(); } /** * 모델 이벤트를 우회해 레거시 상태 페이지 행을 만듭니다. * * @param array $attributes 덮어쓸 속성 * @return int 페이지 ID */ private function createLegacyRow(array $attributes = []): int { return DB::table('pages')->insertGetId(array_merge([ 'slug' => 'backfill-'.uniqid(), 'title' => json_encode(['ko' => '레거시 페이지'], JSON_UNESCAPED_UNICODE), 'content' => json_encode(['ko' => '

본문

'], JSON_UNESCAPED_UNICODE), 'content_mode' => 'html', 'content_thumbnail_url' => null, 'published' => 1, 'published_at' => now(), 'current_version' => 1, 'created_at' => now(), 'updated_at' => now(), ], $attributes)); } private function runBackfill(): void { $context = new UpgradeContext('1.0.3', '1.1.0', '1.1.0', 'extension-upgrade'); (new Upgrade_1_1_0)->run($context); } /** * @scenario backfill=legacy_row * * @effects backfill_fills_legacy_pages */ #[Test] public function legacy_rows_are_backfilled_and_gated(): void { $legacy = $this->createLegacyRow([ 'content' => json_encode([ 'ko' => '', ], JSON_UNESCAPED_UNICODE), ]); $textMode = $this->createLegacyRow([ 'content_mode' => 'text', 'content' => json_encode(['ko' => '텍스트 '], JSON_UNESCAPED_UNICODE), ]); $filled = $this->createLegacyRow([ 'content' => json_encode(['ko' => ''], JSON_UNESCAPED_UNICODE), 'content_thumbnail_url' => '/storage/pages/kept.jpg', ]); $this->runBackfill(); $this->assertSame('/storage/pages/legacy.jpg', DB::table('pages')->where('id', $legacy)->value('content_thumbnail_url')); $this->assertNull(DB::table('pages')->where('id', $textMode)->value('content_thumbnail_url')); $this->assertSame('/storage/pages/kept.jpg', DB::table('pages')->where('id', $filled)->value('content_thumbnail_url')); } /** * @scenario backfill=idempotent * * @effects backfill_idempotent_second_run */ #[Test] public function second_run_is_idempotent(): void { $this->createLegacyRow([ 'content' => json_encode(['ko' => ''], JSON_UNESCAPED_UNICODE), ]); $this->createLegacyRow([ 'content' => json_encode(['ko' => '

이미지 없음

'], JSON_UNESCAPED_UNICODE), ]); $this->runBackfill(); $first = $this->snapshot(); $this->runBackfill(); $second = $this->snapshot(); $this->assertSame($first, $second, '재실행 결과가 동일해야 합니다.'); } /** * @return array 스냅샷 */ private function snapshot(): array { return DB::table('pages') ->where('slug', 'like', 'backfill-%') ->orderBy('id') ->get(['id', 'content_thumbnail_url']) ->map(fn ($row) => ['id' => (int) $row->id, 'content_thumbnail_url' => $row->content_thumbnail_url]) ->all(); } }