From 8ab3a87b13b7a7d0efce52d8db67b2e8af9f6a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 1 May 2023 17:13:09 +0200 Subject: [PATCH] Add failing test case covering online ID reset on save This test scene passes at e58e1151f3c610d8019e1f1e408a1cb55d204c24 and fails at current master, due to an inadvertent regression caused by e72f103c1759e61c3afa7080f962c639265996c3. As it turns out, the online lookup flow that was causing UI thread freezes when saving beatmaps in the editor, was also responsible for resetting the online ID of locally-modified beatmaps if online lookup failed. --- ...TestSceneLocallyModifyingOnlineBeatmaps.cs | 56 +++++++++++++++++++ .../Tests/Visual/EditorSavingTestScene.cs | 27 ++++++++- 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs b/osu.Game.Tests/Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs new file mode 100644 index 0000000000..be9bbcfdd8 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneLocallyModifyingOnlineBeatmaps.cs @@ -0,0 +1,56 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using System.Net; +using NUnit.Framework; +using osu.Framework.Extensions; +using osu.Game.Database; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Tests.Resources; + +namespace osu.Game.Tests.Visual.Editing +{ + public partial class TestSceneLocallyModifyingOnlineBeatmaps : EditorSavingTestScene + { + private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + + public override void SetUpSteps() + { + CreateInitialBeatmap = () => + { + var importedSet = Game.BeatmapManager.Import(new ImportTask(TestResources.GetTestBeatmapForImport())).GetResultSafely(); + return Game.BeatmapManager.GetWorkingBeatmap(importedSet!.Value.Beatmaps.First()); + }; + + base.SetUpSteps(); + } + + [Test] + public void TestLocallyModifyingOnlineBeatmap() + { + AddAssert("editor beatmap has online ID", () => EditorBeatmap.BeatmapInfo.OnlineID, () => Is.GreaterThan(0)); + + AddStep("delete first hitobject", () => EditorBeatmap.RemoveAt(0)); + + AddStep("mock online lookup failure", () => + { + dummyAPI.HandleRequest = req => + { + if (req is GetBeatmapRequest) + { + req.TriggerFailure(new APIException("Beatmap not found", new WebException("NotFound"))); + return true; + } + + return false; + }; + }); + SaveEditor(); + + ReloadEditorToSameBeatmap(); + AddAssert("editor beatmap online ID reset", () => EditorBeatmap.BeatmapInfo.OnlineID, () => Is.EqualTo(-1)); + } + } +} diff --git a/osu.Game/Tests/Visual/EditorSavingTestScene.cs b/osu.Game/Tests/Visual/EditorSavingTestScene.cs index cd9e9e1d52..78188d7cf7 100644 --- a/osu.Game/Tests/Visual/EditorSavingTestScene.cs +++ b/osu.Game/Tests/Visual/EditorSavingTestScene.cs @@ -3,9 +3,12 @@ #nullable disable +using System; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Input; using osu.Framework.Testing; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Setup; @@ -24,18 +27,27 @@ namespace osu.Game.Tests.Visual protected EditorBeatmap EditorBeatmap => (EditorBeatmap)Editor.Dependencies.Get(typeof(EditorBeatmap)); + [CanBeNull] + protected Func CreateInitialBeatmap { get; set; } + [SetUpSteps] public override void SetUpSteps() { base.SetUpSteps(); - AddStep("set default beatmap", () => Game.Beatmap.SetDefault()); + if (CreateInitialBeatmap == null) + AddStep("set default beatmap", () => Game.Beatmap.SetDefault()); + else + { + AddStep("set test beatmap", () => Game.Beatmap.Value = CreateInitialBeatmap?.Invoke()); + } PushAndConfirm(() => new EditorLoader()); AddUntilStep("wait for editor load", () => Editor?.IsLoaded == true); - AddUntilStep("wait for metadata screen load", () => Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + if (CreateInitialBeatmap == null) + AddUntilStep("wait for metadata screen load", () => Editor.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); // We intentionally switch away from the metadata screen, else there is a feedback loop with the textbox handling which causes metadata changes below to get overwritten. @@ -50,6 +62,14 @@ namespace osu.Game.Tests.Visual protected void ReloadEditorToSameBeatmap() { + Guid beatmapSetGuid = Guid.Empty; + Guid beatmapGuid = Guid.Empty; + + AddStep("Store beatmap GUIDs", () => + { + beatmapSetGuid = EditorBeatmap.BeatmapInfo.BeatmapSet!.ID; + beatmapGuid = EditorBeatmap.BeatmapInfo.ID; + }); AddStep("Exit", () => InputManager.Key(Key.Escape)); AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu); @@ -59,7 +79,8 @@ namespace osu.Game.Tests.Visual PushAndConfirm(() => songSelect = new PlaySongSelect()); AddUntilStep("wait for carousel load", () => songSelect.BeatmapSetsLoaded); - AddUntilStep("Wait for beatmap selected", () => !Game.Beatmap.IsDefault); + AddStep("Present same beatmap", () => Game.PresentBeatmap(Game.BeatmapManager.QueryBeatmapSet(set => set.ID == beatmapSetGuid)!.Value, beatmap => beatmap.ID == beatmapGuid)); + AddUntilStep("Wait for beatmap selected", () => Game.Beatmap.Value.BeatmapInfo.ID == beatmapGuid); AddStep("Open options", () => InputManager.Key(Key.F3)); AddStep("Enter editor", () => InputManager.Key(Key.Number5));