// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; using osu.Game.Screens.Play; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Visual; namespace osu.Game.Tests.Database { [HeadlessTest] public partial class BackgroundDataStoreProcessorTests : OsuTestScene, ILocalUserPlayInfo { public IBindable PlayingState => isPlaying; private readonly Bindable isPlaying = new Bindable(); private BeatmapSetInfo importedSet = null!; [BackgroundDependencyLoader] private void load(OsuGameBase osu) { importedSet = BeatmapImportHelper.LoadQuickOszIntoOsu(osu).GetResultSafely(); } [SetUpSteps] public void SetUpSteps() { AddStep("Set not playing", () => isPlaying.Value = LocalUserPlayingState.NotPlaying); } [Test] public void TestDifficultyProcessing() { AddAssert("Difficulty is initially set", () => { return Realm.Run(r => { var beatmapSetInfo = r.Find(importedSet.ID)!; return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0); }); }); AddStep("Reset difficulty", () => { Realm.Write(r => { var beatmapSetInfo = r.Find(importedSet.ID)!; foreach (var b in beatmapSetInfo.Beatmaps) b.StarRating = -1; }); }); AddStep("Run background processor", () => { Add(new TestBackgroundDataStoreProcessor()); }); AddUntilStep("wait for difficulties repopulated", () => { return Realm.Run(r => { var beatmapSetInfo = r.Find(importedSet.ID)!; return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0); }); }); } [Test] public void TestDifficultyProcessingWhilePlaying() { AddAssert("Difficulty is initially set", () => { return Realm.Run(r => { var beatmapSetInfo = r.Find(importedSet.ID)!; return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0); }); }); AddStep("Set playing", () => isPlaying.Value = LocalUserPlayingState.Playing); AddStep("Reset difficulty", () => { Realm.Write(r => { var beatmapSetInfo = r.Find(importedSet.ID)!; foreach (var b in beatmapSetInfo.Beatmaps) b.StarRating = -1; }); }); AddStep("Run background processor", () => { Add(new TestBackgroundDataStoreProcessor()); }); AddWaitStep("wait some", 500); AddAssert("Difficulty still not populated", () => { return Realm.Run(r => { var beatmapSetInfo = r.Find(importedSet.ID)!; return beatmapSetInfo.Beatmaps.All(b => b.StarRating == -1); }); }); AddStep("Set not playing", () => isPlaying.Value = LocalUserPlayingState.NotPlaying); AddUntilStep("wait for difficulties repopulated", () => { return Realm.Run(r => { var beatmapSetInfo = r.Find(importedSet.ID)!; return beatmapSetInfo.Beatmaps.All(b => b.StarRating > 0); }); }); } [TestCase(30000001)] [TestCase(30000002)] [TestCase(30000003)] [TestCase(30000004)] [TestCase(30000005)] public void TestScoreUpgradeSuccess(int scoreVersion) { ScoreInfo scoreInfo = null!; AddStep("Add score which requires upgrade (and has beatmap)", () => { Realm.Write(r => { r.Add(scoreInfo = new ScoreInfo(ruleset: r.All().First(), beatmap: r.All().First()) { TotalScoreVersion = scoreVersion, LegacyTotalScore = 123456, IsLegacyScore = true, }); }); }); AddStep("Run background processor", () => Add(new TestBackgroundDataStoreProcessor())); AddUntilStep("Score version upgraded", () => Realm.Run(r => r.Find(scoreInfo.ID)!.TotalScoreVersion), () => Is.EqualTo(LegacyScoreEncoder.LATEST_VERSION)); AddAssert("Score not marked as failed", () => Realm.Run(r => r.Find(scoreInfo.ID)!.BackgroundReprocessingFailed), () => Is.False); } [TestCase(30000002)] [TestCase(30000013)] public void TestScoreUpgradeFailed(int scoreVersion) { ScoreInfo scoreInfo = null!; AddStep("Add score which requires upgrade (but has no beatmap)", () => { Realm.Write(r => { r.Add(scoreInfo = new ScoreInfo(ruleset: r.All().First(), beatmap: new BeatmapInfo { BeatmapSet = new BeatmapSetInfo(), Ruleset = r.All().First(), }) { TotalScoreVersion = scoreVersion, IsLegacyScore = true, }); }); }); TestBackgroundDataStoreProcessor processor = null!; AddStep("Run background processor", () => Add(processor = new TestBackgroundDataStoreProcessor())); AddUntilStep("Wait for completion", () => processor.Completed); AddUntilStep("Score marked as failed", () => Realm.Run(r => r.Find(scoreInfo.ID)!.BackgroundReprocessingFailed), () => Is.True); AddAssert("Score version not upgraded", () => Realm.Run(r => r.Find(scoreInfo.ID)!.TotalScoreVersion), () => Is.EqualTo(scoreVersion)); } [Test] public void TestCustomRulesetScoreNotSubjectToUpgrades([Values] bool available) { RulesetInfo rulesetInfo = null!; ScoreInfo scoreInfo = null!; TestBackgroundDataStoreProcessor processor = null!; AddStep("Add unavailable ruleset", () => Realm.Write(r => r.Add(rulesetInfo = new RulesetInfo { ShortName = Guid.NewGuid().ToString(), Available = available }))); AddStep("Add score for unavailable ruleset", () => Realm.Write(r => r.Add(scoreInfo = new ScoreInfo( ruleset: rulesetInfo, beatmap: r.All().First()) { TotalScoreVersion = 30000001 }))); AddStep("Run background processor", () => Add(processor = new TestBackgroundDataStoreProcessor())); AddUntilStep("Wait for completion", () => processor.Completed); AddAssert("Score not marked as failed", () => Realm.Run(r => r.Find(scoreInfo.ID)!.BackgroundReprocessingFailed), () => Is.False); AddAssert("Score version not upgraded", () => Realm.Run(r => r.Find(scoreInfo.ID)!.TotalScoreVersion), () => Is.EqualTo(30000001)); } public partial class TestBackgroundDataStoreProcessor : BackgroundDataStoreProcessor { protected override int TimeToSleepDuringGameplay => 10; public bool Completed => ProcessingTask.IsCompleted; } } }