up(); } private function findFeed(int $id): stdClass { $feed = DB::table('feeds')->find($id); $this->assertInstanceOf(stdClass::class, $feed); return $feed; } private function targetUrl(): string { $url = config('feed.providers.belga.languages.en.url'); $this->assertIsString($url); return $url; } private function seedFeed(string $url, string $type, bool $isActive = true, string $provider = 'belga'): int { return DB::table('feeds')->insertGetId([ 'name' => 'Belga', 'provider' => $provider, 'type' => $type, 'url' => $url, 'is_active' => $isActive, 'created_at' => now(), 'updated_at' => now(), ]); } public function test_converts_a_feed_still_on_the_dead_rss_url(): void { DB::table('feeds')->delete(); $id = $this->seedFeed(self::DEAD_RSS_URL, 'rss'); $this->runMigration(); $feed = $this->findFeed($id); $this->assertSame('website', $feed->type); $this->assertSame($this->targetUrl(), $feed->url); $this->assertTrue((bool) $feed->is_active); } public function test_is_idempotent_when_the_feed_is_already_migrated(): void { DB::table('feeds')->delete(); $id = $this->seedFeed($this->targetUrl(), 'website'); $this->runMigration(); $this->runMigration(); $this->assertSame(1, DB::table('feeds')->where('provider', 'belga')->count()); $feed = $this->findFeed($id); $this->assertSame('website', $feed->type); $this->assertSame($this->targetUrl(), $feed->url); } public function test_deactivates_superseded_rows_instead_of_colliding_on_the_unique_url(): void { DB::table('feeds')->delete(); $staleId = $this->seedFeed(self::DEAD_RSS_URL, 'rss'); $currentId = $this->seedFeed($this->targetUrl(), 'website'); $this->runMigration(); // Both rows survive: routes.feed_id cascades on delete, so a superseded // feed is deactivated rather than removed. $this->assertSame(2, DB::table('feeds')->where('provider', 'belga')->count()); $current = $this->findFeed($currentId); $this->assertTrue((bool) $current->is_active); $this->assertSame($this->targetUrl(), $current->url); $this->assertSame('website', $current->type); $stale = $this->findFeed($staleId); $this->assertFalse((bool) $stale->is_active); } public function test_adopts_the_oldest_row_when_none_is_on_the_target_url(): void { DB::table('feeds')->delete(); $oldestId = $this->seedFeed(self::DEAD_RSS_URL, 'rss'); $newerId = $this->seedFeed('https://capi.belga.press/belgapress/api/public/pressreleases?count=6', 'website'); $this->runMigration(); // Neither row matches config, so the migration falls back to the lowest // id — the oldest row, which is the one routes are most likely tied to. $oldest = $this->findFeed($oldestId); $this->assertSame($this->targetUrl(), $oldest->url); $this->assertSame('website', $oldest->type); $this->assertTrue((bool) $oldest->is_active); $this->assertFalse((bool) $this->findFeed($newerId)->is_active); } public function test_leaves_other_providers_untouched(): void { DB::table('feeds')->delete(); $vrtId = $this->seedFeed('https://www.vrt.be/vrtnws/nl/', 'website', true, 'vrt'); // Seed a belga row too, so the migration actually runs its updates // rather than bailing out at the "no belga feed" guard. $this->seedFeed(self::DEAD_RSS_URL, 'rss'); $this->runMigration(); $vrt = $this->findFeed($vrtId); $this->assertSame('https://www.vrt.be/vrtnws/nl/', $vrt->url); $this->assertSame('website', $vrt->type); $this->assertTrue((bool) $vrt->is_active); } public function test_down_is_a_deliberate_no_op(): void { DB::table('feeds')->delete(); $id = $this->seedFeed($this->targetUrl(), 'website'); $migration = require database_path('migrations/2024_01_01_000012_sync_belga_feed_to_website_discovery.php'); $migration->down(); // Rolling back must not restore the retired RSS url. $feed = $this->findFeed($id); $this->assertSame($this->targetUrl(), $feed->url); $this->assertSame('website', $feed->type); } public function test_does_nothing_when_no_belga_feed_exists(): void { DB::table('feeds')->delete(); $this->runMigration(); $this->assertSame(0, DB::table('feeds')->count()); } public function test_does_nothing_when_the_configured_url_is_missing(): void { DB::table('feeds')->delete(); config(['feed.providers.belga.languages.en.url' => '']); $id = $this->seedFeed(self::DEAD_RSS_URL, 'rss'); $this->runMigration(); $feed = $this->findFeed($id); $this->assertSame('rss', $feed->type); $this->assertSame(self::DEAD_RSS_URL, $feed->url); } }