From 0beef7767aae498de4cc725547e8269d281c5fec Mon Sep 17 00:00:00 2001 From: nanaya Date: Thu, 15 Jun 2023 21:56:31 +0900 Subject: [PATCH] Ensure db connections are reset --- .../BeatmapsControllerSoloScoresTest.php | 274 +++++++++--------- tests/Models/Solo/ScoreEsIndexTest.php | 146 +++++----- tests/TestCase.php | 31 +- 3 files changed, 235 insertions(+), 216 deletions(-) diff --git a/tests/Controllers/BeatmapsControllerSoloScoresTest.php b/tests/Controllers/BeatmapsControllerSoloScoresTest.php index 145001e5677..2886fa10f40 100644 --- a/tests/Controllers/BeatmapsControllerSoloScoresTest.php +++ b/tests/Controllers/BeatmapsControllerSoloScoresTest.php @@ -33,147 +33,151 @@ class BeatmapsControllerSoloScoresTest extends TestCase public static function setUpBeforeClass(): void { - (new static())->refreshApplication(); - static::$user = User::factory()->create(['osu_subscriber' => true]); - static::$otherUser = User::factory()->create(['country_acronym' => Country::factory()]); - $friend = User::factory()->create(['country_acronym' => Country::factory()]); - static::$beatmap = Beatmap::factory()->qualified()->create(); - - $countryAcronym = static::$user->country_acronym; - - static::$scores = []; - $scoreFactory = SoloScore::factory(); - foreach (['solo' => 0, 'legacy' => null] as $type => $buildId) { - $defaultData = ['build_id' => $buildId]; - - static::$scores = array_merge(static::$scores, [ - "{$type}:user" => $scoreFactory->withData($defaultData, ['total_score' => 1100])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$user, - ]), - "{$type}:userMods" => $scoreFactory->withData($defaultData, [ - 'total_score' => 1050, - 'mods' => static::defaultMods(['DT', 'HD']), - ])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$user, - ]), - "{$type}:userModsNC" => $scoreFactory->withData($defaultData, [ - 'total_score' => 1050, - 'mods' => static::defaultMods(['NC']), - ])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$user, - ]), - "{$type}:otherUserModsNCPFHigherScore" => $scoreFactory->withData($defaultData, [ - 'total_score' => 1010, - 'mods' => static::defaultMods(['NC', 'PF']), - ])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$otherUser, - ]), - "{$type}:userModsLowerScore" => $scoreFactory->withData($defaultData, [ - 'total_score' => 1000, - 'mods' => static::defaultMods(['DT', 'HD']), - ])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$user, - ]), - "{$type}:friend" => $scoreFactory->withData($defaultData, ['total_score' => 1000])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => $friend, - ]), - // With preference mods - "{$type}:otherUser" => $scoreFactory->withData($defaultData, [ - 'total_score' => 1000, - 'mods' => static::defaultMods(['PF']), - ])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$otherUser, - ]), - "{$type}:otherUserMods" => $scoreFactory->withData($defaultData, [ - 'total_score' => 1000, - 'mods' => static::defaultMods(['HD', 'PF', 'NC']), - ])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$otherUser, - ]), - "{$type}:otherUserModsExtraNonPreferences" => $scoreFactory->withData($defaultData, [ - 'total_score' => 1000, - 'mods' => static::defaultMods(['DT', 'HD', 'HR']), - ])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$otherUser, - ]), - "{$type}:otherUserModsUnrelated" => $scoreFactory->withData($defaultData, [ - 'total_score' => 1000, - 'mods' => static::defaultMods(['FL']), - ])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => static::$otherUser, - ]), - // Same total score but achieved later so it should come up after earlier score - "{$type}:otherUser2Later" => $scoreFactory->withData($defaultData, ['total_score' => 1000])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => User::factory()->state(['country_acronym' => Country::factory()]), - ]), - "{$type}:otherUser3SameCountry" => $scoreFactory->withData($defaultData, ['total_score' => 1000])->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => true, - 'user_id' => User::factory()->state(['country_acronym' => $countryAcronym]), - ]), - // Non-preserved score should be filtered out - "{$type}:nonPreserved" => $scoreFactory->withData($defaultData)->create([ - 'beatmap_id' => static::$beatmap, - 'preserve' => false, - 'user_id' => User::factory()->state(['country_acronym' => Country::factory()]), - ]), - // Unrelated score - "{$type}:unrelated" => $scoreFactory->withData($defaultData)->create([ - 'user_id' => User::factory()->state(['country_acronym' => Country::factory()]), - ]), + static::withDbAccess(function () { + static::$user = User::factory()->create(['osu_subscriber' => true]); + static::$otherUser = User::factory()->create(['country_acronym' => Country::factory()]); + $friend = User::factory()->create(['country_acronym' => Country::factory()]); + static::$beatmap = Beatmap::factory()->qualified()->create(); + + $countryAcronym = static::$user->country_acronym; + + static::$scores = []; + $scoreFactory = SoloScore::factory(); + foreach (['solo' => 0, 'legacy' => null] as $type => $buildId) { + $defaultData = ['build_id' => $buildId]; + + static::$scores = array_merge(static::$scores, [ + "{$type}:user" => $scoreFactory->withData($defaultData, ['total_score' => 1100])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$user, + ]), + "{$type}:userMods" => $scoreFactory->withData($defaultData, [ + 'total_score' => 1050, + 'mods' => static::defaultMods(['DT', 'HD']), + ])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$user, + ]), + "{$type}:userModsNC" => $scoreFactory->withData($defaultData, [ + 'total_score' => 1050, + 'mods' => static::defaultMods(['NC']), + ])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$user, + ]), + "{$type}:otherUserModsNCPFHigherScore" => $scoreFactory->withData($defaultData, [ + 'total_score' => 1010, + 'mods' => static::defaultMods(['NC', 'PF']), + ])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$otherUser, + ]), + "{$type}:userModsLowerScore" => $scoreFactory->withData($defaultData, [ + 'total_score' => 1000, + 'mods' => static::defaultMods(['DT', 'HD']), + ])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$user, + ]), + "{$type}:friend" => $scoreFactory->withData($defaultData, ['total_score' => 1000])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => $friend, + ]), + // With preference mods + "{$type}:otherUser" => $scoreFactory->withData($defaultData, [ + 'total_score' => 1000, + 'mods' => static::defaultMods(['PF']), + ])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$otherUser, + ]), + "{$type}:otherUserMods" => $scoreFactory->withData($defaultData, [ + 'total_score' => 1000, + 'mods' => static::defaultMods(['HD', 'PF', 'NC']), + ])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$otherUser, + ]), + "{$type}:otherUserModsExtraNonPreferences" => $scoreFactory->withData($defaultData, [ + 'total_score' => 1000, + 'mods' => static::defaultMods(['DT', 'HD', 'HR']), + ])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$otherUser, + ]), + "{$type}:otherUserModsUnrelated" => $scoreFactory->withData($defaultData, [ + 'total_score' => 1000, + 'mods' => static::defaultMods(['FL']), + ])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => static::$otherUser, + ]), + // Same total score but achieved later so it should come up after earlier score + "{$type}:otherUser2Later" => $scoreFactory->withData($defaultData, ['total_score' => 1000])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => User::factory()->state(['country_acronym' => Country::factory()]), + ]), + "{$type}:otherUser3SameCountry" => $scoreFactory->withData($defaultData, ['total_score' => 1000])->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => true, + 'user_id' => User::factory()->state(['country_acronym' => $countryAcronym]), + ]), + // Non-preserved score should be filtered out + "{$type}:nonPreserved" => $scoreFactory->withData($defaultData)->create([ + 'beatmap_id' => static::$beatmap, + 'preserve' => false, + 'user_id' => User::factory()->state(['country_acronym' => Country::factory()]), + ]), + // Unrelated score + "{$type}:unrelated" => $scoreFactory->withData($defaultData)->create([ + 'user_id' => User::factory()->state(['country_acronym' => Country::factory()]), + ]), + ]); + } + + UserRelation::create([ + 'friend' => true, + 'user_id' => static::$user->getKey(), + 'zebra_id' => $friend->getKey(), ]); - } - UserRelation::create([ - 'friend' => true, - 'user_id' => static::$user->getKey(), - 'zebra_id' => $friend->getKey(), - ]); - - Artisan::call('es:index-scores:queue', [ - '--all' => true, - '--no-interaction' => true, - ]); - (new ScoreSearch())->indexWait(); + Artisan::call('es:index-scores:queue', [ + '--all' => true, + '--no-interaction' => true, + ]); + (new ScoreSearch())->indexWait(); + }); } public static function tearDownAfterClass(): void { - (new static())->refreshApplication(); - Beatmap::truncate(); - Beatmapset::truncate(); - Country::truncate(); - Genre::truncate(); - Group::truncate(); - Language::truncate(); - SoloScore::truncate(); - User::truncate(); - UserGroup::truncate(); - UserGroupEvent::truncate(); - UserRelation::truncate(); - (new ScoreSearch())->deleteAll(); + parent::tearDownAfterClass(); + + static::withDbAccess(function () { + Beatmap::truncate(); + Beatmapset::truncate(); + Country::truncate(); + Genre::truncate(); + Group::truncate(); + Language::truncate(); + SoloScore::truncate(); + User::truncate(); + UserGroup::truncate(); + UserGroupEvent::truncate(); + UserRelation::truncate(); + (new ScoreSearch())->deleteAll(); + }); } private static function defaultMods(array $modNames): array diff --git a/tests/Models/Solo/ScoreEsIndexTest.php b/tests/Models/Solo/ScoreEsIndexTest.php index b3e4aa8b162..ba42e4fe3c5 100644 --- a/tests/Models/Solo/ScoreEsIndexTest.php +++ b/tests/Models/Solo/ScoreEsIndexTest.php @@ -34,84 +34,86 @@ class ScoreEsIndexTest extends TestCase public static function setUpBeforeClass(): void { - (new static())->refreshApplication(); - static::$user = User::factory()->create(['osu_subscriber' => true]); - $otherUser = User::factory()->create(['country_acronym' => Country::factory()]); - static::$beatmap = Beatmap::factory()->qualified()->create(); - - $scoreFactory = Score::factory()->state(['preserve' => true]); - $defaultData = ['build_id' => 1]; - - $mods = [ - ['acronym' => 'DT', 'settings' => []], - ['acronym' => 'HD', 'settings' => []], - ]; - $unrelatedMods = [ - ['acronym' => 'NC', 'settings' => []], - ]; - - static::$scores = [ - 'otherUser' => $scoreFactory->withData($defaultData, [ - 'total_score' => 1150, - 'mods' => $unrelatedMods, - ])->create([ - 'beatmap_id' => static::$beatmap, - 'user_id' => $otherUser, - ]), - 'otherUserMods' => $scoreFactory->withData($defaultData, [ - 'total_score' => 1140, - 'mods' => $mods, - ])->create([ - 'beatmap_id' => static::$beatmap, - 'user_id' => $otherUser, - ]), - 'otherUser2' => $scoreFactory->withData($defaultData, [ - 'total_score' => 1150, - 'mods' => $mods, - ])->create([ - 'beatmap_id' => static::$beatmap, - 'user_id' => User::factory()->state(['country_acronym' => Country::factory()]), - ]), - 'otherUser3SameCountry' => $scoreFactory->withData($defaultData, [ - 'total_score' => 1130, - 'mods' => $unrelatedMods, - ])->create([ - 'beatmap_id' => static::$beatmap, - 'user_id' => User::factory()->state(['country_acronym' => static::$user->country_acronym]), - ]), - 'user' => $scoreFactory->withData($defaultData, ['total_score' => 1100])->create([ - 'beatmap_id' => static::$beatmap, - 'user_id' => static::$user, - ]), - 'userMods' => $scoreFactory->withData($defaultData, [ - 'total_score' => 1050, - 'mods' => $mods, - ])->create([ - 'beatmap_id' => static::$beatmap, - 'user_id' => static::$user, - ]), - ]; - - static::reindexScores(); + static::withDbAccess(function () { + static::$user = User::factory()->create(['osu_subscriber' => true]); + $otherUser = User::factory()->create(['country_acronym' => Country::factory()]); + static::$beatmap = Beatmap::factory()->qualified()->create(); + + $scoreFactory = Score::factory()->state(['preserve' => true]); + $defaultData = ['build_id' => 1]; + + $mods = [ + ['acronym' => 'DT', 'settings' => []], + ['acronym' => 'HD', 'settings' => []], + ]; + $unrelatedMods = [ + ['acronym' => 'NC', 'settings' => []], + ]; + + static::$scores = [ + 'otherUser' => $scoreFactory->withData($defaultData, [ + 'total_score' => 1150, + 'mods' => $unrelatedMods, + ])->create([ + 'beatmap_id' => static::$beatmap, + 'user_id' => $otherUser, + ]), + 'otherUserMods' => $scoreFactory->withData($defaultData, [ + 'total_score' => 1140, + 'mods' => $mods, + ])->create([ + 'beatmap_id' => static::$beatmap, + 'user_id' => $otherUser, + ]), + 'otherUser2' => $scoreFactory->withData($defaultData, [ + 'total_score' => 1150, + 'mods' => $mods, + ])->create([ + 'beatmap_id' => static::$beatmap, + 'user_id' => User::factory()->state(['country_acronym' => Country::factory()]), + ]), + 'otherUser3SameCountry' => $scoreFactory->withData($defaultData, [ + 'total_score' => 1130, + 'mods' => $unrelatedMods, + ])->create([ + 'beatmap_id' => static::$beatmap, + 'user_id' => User::factory()->state(['country_acronym' => static::$user->country_acronym]), + ]), + 'user' => $scoreFactory->withData($defaultData, ['total_score' => 1100])->create([ + 'beatmap_id' => static::$beatmap, + 'user_id' => static::$user, + ]), + 'userMods' => $scoreFactory->withData($defaultData, [ + 'total_score' => 1050, + 'mods' => $mods, + ])->create([ + 'beatmap_id' => static::$beatmap, + 'user_id' => static::$user, + ]), + ]; + + static::reindexScores(); + }); } public static function tearDownAfterClass(): void { parent::tearDownAfterClass(); - (new static())->refreshApplication(); - Beatmap::truncate(); - Beatmapset::truncate(); - Country::truncate(); - Genre::truncate(); - Group::truncate(); - Language::truncate(); - Score::truncate(); - User::truncate(); - UserGroup::truncate(); - UserGroupEvent::truncate(); - UserRelation::truncate(); - (new ScoreSearch())->deleteAll(); + static::withDbAccess(function () { + Beatmap::truncate(); + Beatmapset::truncate(); + Country::truncate(); + Genre::truncate(); + Group::truncate(); + Language::truncate(); + Score::truncate(); + User::truncate(); + UserGroup::truncate(); + UserGroupEvent::truncate(); + UserRelation::truncate(); + (new ScoreSearch())->deleteAll(); + }); } /** diff --git a/tests/TestCase.php b/tests/TestCase.php index 727c6fa0a01..4d7bfd07d64 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -16,6 +16,7 @@ use Artisan; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use Firebase\JWT\JWT; +use Illuminate\Database\DatabaseManager; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; @@ -44,6 +45,25 @@ protected static function reindexScores() $search->indexWait(); } + protected static function resetAppDb(DatabaseManager $database): void + { + foreach (array_keys(config('database.connections')) as $name) { + $connection = $database->connection($name); + + $connection->rollBack(); + $connection->disconnect(); + } + } + + protected static function withDbAccess(callable $callback): void + { + $db = (new static())->createApplication()->make('db'); + + $callback(); + + static::resetAppDb($db); + } + protected $connectionsToTransact = [ 'mysql', 'mysql-chat', @@ -82,15 +102,8 @@ protected function setUp(): void // Force connections to reset even if transactional tests were not used. // Should fix tests going wonky when different queue drivers are used, or anything that // breaks assumptions of object destructor timing. - $database = $this->app->make('db'); - $this->beforeApplicationDestroyed(function () use ($database) { - foreach (array_keys(config('database.connections')) as $name) { - $connection = $database->connection($name); - - $connection->rollBack(); - $connection->disconnect(); - } - }); + $db = $this->app->make('db'); + $this->beforeApplicationDestroyed(fn () => static::resetAppDb($db)); app(BroadcastsPendingForTests::class)->reset(); }