1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-17 10:32:54 +08:00
osu-lazer/osu.Game.Tests/Beatmaps/WorkingBeatmapTest.cs
Bartłomiej Dach 6100bf66a6
Clean up cancellation handling in WorkingBeatmap
After the recent changes introducing cancellation support to
`WorkingBeatmap`, it turned out that if the cancellation support was
used, `GetPlayableBeatmap()` would raise timeout exceptions rather than
the expected `OperationCanceledException`.

To that end, split off a separate overload for the typical usage, that
catches `OperationCanceledException` and converts them to beatmap load
timeout exceptions, and use normal `OperationCanceledException`s in the
overload that requires a cancellation token to work.
2021-11-20 17:23:55 +01:00

116 lines
3.7 KiB
C#

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Beatmaps;
namespace osu.Game.Tests.Beatmaps
{
[TestFixture]
public class WorkingBeatmapTest
{
[Test]
public void TestGetPlayableSuccess()
{
var working = new TestNeverLoadsWorkingBeatmap();
working.ResetEvent.Set();
Assert.NotNull(working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo));
}
[Test]
public void TestGetPlayableCancellationToken()
{
var working = new TestNeverLoadsWorkingBeatmap();
var cts = new CancellationTokenSource();
var loadStarted = new ManualResetEventSlim();
var loadCompleted = new ManualResetEventSlim();
Task.Factory.StartNew(() =>
{
loadStarted.Set();
Assert.Throws<OperationCanceledException>(() => working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo, Array.Empty<Mod>(), cts.Token));
loadCompleted.Set();
}, TaskCreationOptions.LongRunning);
Assert.IsTrue(loadStarted.Wait(10000));
cts.Cancel();
Assert.IsTrue(loadCompleted.Wait(10000));
working.ResetEvent.Set();
}
[Test]
public void TestGetPlayableDefaultTimeout()
{
var working = new TestNeverLoadsWorkingBeatmap();
Assert.Throws(Is.InstanceOf<TimeoutException>(), () => working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo));
working.ResetEvent.Set();
}
[Test]
public void TestGetPlayableRulesetLoadFailure()
{
var working = new TestWorkingBeatmap(new Beatmap());
// by default mocks return nulls if not set up, which is actually desired here to simulate a ruleset load failure scenario.
var ruleset = new Mock<IRulesetInfo>();
Assert.Throws<RulesetLoadException>(() => working.GetPlayableBeatmap(ruleset.Object));
}
public class TestNeverLoadsWorkingBeatmap : TestWorkingBeatmap
{
public ManualResetEventSlim ResetEvent = new ManualResetEventSlim();
public TestNeverLoadsWorkingBeatmap()
: base(new Beatmap())
{
}
protected override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => new TestConverter(beatmap, ResetEvent);
public class TestConverter : IBeatmapConverter
{
private readonly ManualResetEventSlim resetEvent;
public TestConverter(IBeatmap beatmap, ManualResetEventSlim resetEvent)
{
this.resetEvent = resetEvent;
Beatmap = beatmap;
}
public event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
protected virtual void OnObjectConverted(HitObject arg1, IEnumerable<HitObject> arg2) => ObjectConverted?.Invoke(arg1, arg2);
public IBeatmap Beatmap { get; }
public bool CanConvert() => true;
public IBeatmap Convert(CancellationToken cancellationToken = default)
{
resetEvent.Wait(cancellationToken);
return new OsuBeatmap();
}
}
}
}
}