1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-16 02:37:19 +08:00

Merge pull request #27239 from peppy/fix-cached-beatmap

Fix `WorkingBeatmapCache` caching beatmap in wrong state leading to crash
This commit is contained in:
Bartłomiej Dach 2024-02-19 12:06:45 +01:00 committed by GitHub
commit f5666185ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 73 additions and 3 deletions

View File

@ -4,6 +4,7 @@
#nullable disable #nullable disable
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -18,6 +19,7 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Collections; using osu.Game.Collections;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
@ -221,6 +223,67 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
} }
[Test]
public void TestAttemptPlayBeatmapWrongHashFails()
{
Screens.Select.SongSelect songSelect = null;
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely());
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
AddStep("change beatmap files", () =>
{
foreach (var file in Game.Beatmap.Value.BeatmapSetInfo.Files.Where(f => Path.GetExtension(f.Filename) == ".osu"))
{
using (var stream = Game.Storage.GetStream(Path.Combine("files", file.File.GetStoragePath()), FileAccess.ReadWrite))
stream.WriteByte(0);
}
});
AddStep("invalidate cache", () =>
{
((IWorkingBeatmapCache)Game.BeatmapManager).Invalidate(Game.Beatmap.Value.BeatmapSetInfo);
});
AddStep("select next difficulty", () => InputManager.Key(Key.Down));
AddStep("press enter", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for player loader", () => Game.ScreenStack.CurrentScreen is PlayerLoader);
AddUntilStep("wait for song select", () => songSelect.IsCurrentScreen());
}
[Test]
public void TestAttemptPlayBeatmapMissingFails()
{
Screens.Select.SongSelect songSelect = null;
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely());
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded);
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
AddStep("delete beatmap files", () =>
{
foreach (var file in Game.Beatmap.Value.BeatmapSetInfo.Files.Where(f => Path.GetExtension(f.Filename) == ".osu"))
Game.Storage.Delete(Path.Combine("files", file.File.GetStoragePath()));
});
AddStep("invalidate cache", () =>
{
((IWorkingBeatmapCache)Game.BeatmapManager).Invalidate(Game.Beatmap.Value.BeatmapSetInfo);
});
AddStep("select next difficulty", () => InputManager.Key(Key.Down));
AddStep("press enter", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for player loader", () => Game.ScreenStack.CurrentScreen is PlayerLoader);
AddUntilStep("wait for song select", () => songSelect.IsCurrentScreen());
}
[Test] [Test]
public void TestRetryCountIncrements() public void TestRetryCountIncrements()
{ {

View File

@ -9,6 +9,7 @@ using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Rendering.Dummy;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
@ -143,8 +144,6 @@ namespace osu.Game.Beatmaps
{ {
string fileStorePath = BeatmapSetInfo.GetPathForFile(BeatmapInfo.Path); string fileStorePath = BeatmapSetInfo.GetPathForFile(BeatmapInfo.Path);
// TODO: check validity of file
var stream = GetStream(fileStorePath); var stream = GetStream(fileStorePath);
if (stream == null) if (stream == null)
@ -153,6 +152,12 @@ namespace osu.Game.Beatmaps
return null; return null;
} }
if (stream.ComputeMD5Hash() != BeatmapInfo.MD5Hash)
{
Logger.Log($"Beatmap failed to load (file {BeatmapInfo.Path} does not have the expected hash).", level: LogLevel.Error);
return null;
}
using (var reader = new LineBufferedReader(stream)) using (var reader = new LineBufferedReader(stream))
return Decoder.GetDecoder<Beatmap>(reader).Decode(reader); return Decoder.GetDecoder<Beatmap>(reader).Decode(reader);
} }

View File

@ -153,6 +153,8 @@ namespace osu.Game.Tests.Visual
public new Bindable<IReadOnlyList<Mod>> SelectedMods => base.SelectedMods; public new Bindable<IReadOnlyList<Mod>> SelectedMods => base.SelectedMods;
public new Storage Storage => base.Storage;
public new SpectatorClient SpectatorClient => base.SpectatorClient; public new SpectatorClient SpectatorClient => base.SpectatorClient;
// if we don't apply these changes, when running under nUnit the version that gets populated is that of nUnit. // if we don't apply these changes, when running under nUnit the version that gets populated is that of nUnit.
@ -166,7 +168,7 @@ namespace osu.Game.Tests.Visual
public TestOsuGame(Storage storage, IAPIProvider api, string[] args = null) public TestOsuGame(Storage storage, IAPIProvider api, string[] args = null)
: base(args) : base(args)
{ {
Storage = storage; base.Storage = storage;
API = api; API = api;
} }