1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-17 03:52:35 +08:00
Files
osu-lazer/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
T
Bartłomiej Dach 090fe44f86 Assorted test deflaking (#37191)
A few quick ones from https://github.com/ppy/osu/issues/37190.

## [Rewrite `TestSceneDeleteLocalScore` to have less context menu
containers (and hopefully no longer
flake)](https://github.com/ppy/osu/commit/ea0bc5b72374056d1749f8058f4874b7ef66a241)

As seen in
https://github.com/ppy/osu/actions/runs/23890777748#user-content-r3s3.

This is a speculative fix but I'm feeling somewhat confident about this
one.

`BeatmapLeaderboardWedge` has TWO separate `ContextMenuContainer`s
itself, and the test mentioned here was bringing a third. I have a
feeling that the test flaking may have something to do with the fact
that the test logic would attempt to click a menu item on specifically
ONE of the three context menus. My bet is that when it fails, it's
because it's trying the wrong one, but I don't have reproduction.

## [Wait for text to appear in flaking
`TestSceneDrawableRoomPlaylist.TestSelectableMouseHandling`
test](https://github.com/ppy/osu/commit/9d62eea8b56a0eb013e8116db0d38424b500876f)

As seen in
https://github.com/ppy/osu/actions/runs/23888446400#user-content-r1s1.

Speculative. Banking on the fact that it takes time to load the sprite
texts.

## [Remove all tests from `TestSceneWikiMarkdownContainer` dependent on
existence of wiki on
dev](https://github.com/ppy/osu/commit/8f319f91c98510b84e915bb61ec147618a584ce1)

Deletes a flaky as seen in
https://github.com/ppy/osu/actions/runs/23878899702#user-content-r2s2.

The year is 2026 and LLM scrapers hammer [the
entire](https://sourcehut.org/blog/2025-04-15-you-cannot-have-our-users-data/)
[internet](https://blog.metabrainz.org/2025/12/11/we-cant-have-nice-things-because-of-ai-scrapers/)
all over to scrape whatever ounce of Human Content there is left to feed
the Moloch so that it can regurgitate it back in the form of The Most
Average Speech You've Ever Read. We are not immune to this, and as such
the LLM homunculi have hit the dev.ppy.sh wiki instance enough times for
it to just completely [be banished to the
blagole](https://www.youtube.com/watch?v=AfA_2Ku1aJY).

Which means I get to freely delete flaky tests that should never have
been running as part of CI because they're completely useless now and
it's not like we're ever turning them back on again.

## [Use equality check in
`TestSceneBeatmapCarouselScrolling.TestScrollPositionMaintainedOnRemove_SecondSelected`
that's less sensitive to floating
point](https://github.com/ppy/osu/commit/6f2a1de58f7e816830c430e89117ee4c594f529d)

As seen in
https://github.com/ppy/osu/actions/runs/23826420794#user-content-r0s1.
2026-04-04 00:17:31 +09:00

193 lines
7.3 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.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics.UserInterface;
using osu.Game.Models;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Screens.Select;
using osu.Game.Tests.Resources;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.UserInterface
{
public partial class TestSceneDeleteLocalScore : OsuManualInputManagerTestScene
{
private readonly BeatmapLeaderboardWedge leaderboard;
private RulesetStore rulesets = null!;
private BeatmapManager beatmapManager = null!;
private ScoreManager scoreManager = null!;
private readonly List<ScoreInfo> importedScores = new List<ScoreInfo>();
private BeatmapInfo beatmapInfo = null!;
private LeaderboardManager leaderboardManager { get; set; } = null!;
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
[Cached(typeof(IDialogOverlay))]
private readonly DialogOverlay dialogOverlay;
private IEnumerable<ScoreInfo> scores => leaderboardManager.Scores.Value?.AllScores ?? Enumerable.Empty<ScoreInfo>();
public TestSceneDeleteLocalScore()
{
Children = new Drawable[]
{
leaderboard = new BeatmapLeaderboardWedge
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(0.6f),
},
dialogOverlay = new DialogOverlay()
};
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get<RulesetStore>(), () => beatmapManager, LocalStorage, Realm, API));
dependencies.Cache(leaderboardManager = new LeaderboardManager());
Dependencies.Cache(Realm);
Add(leaderboardManager);
return dependencies;
}
[BackgroundDependencyLoader]
private void load() => Schedule(() =>
{
var imported = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely();
imported?.PerformRead(s =>
{
beatmapInfo = s.Beatmaps[0];
for (int i = 0; i < 50; i++)
{
var score = new ScoreInfo
{
OnlineID = i,
BeatmapInfo = beatmapInfo,
BeatmapHash = beatmapInfo.Hash,
Accuracy = RNG.NextDouble(),
TotalScore = RNG.Next(1, 1000000),
MaxCombo = RNG.Next(1, 1000),
Rank = ScoreRank.XH,
User = new APIUser { Username = "TestUser" },
Ruleset = new OsuRuleset().RulesetInfo,
Files = { new RealmNamedFileUsage(new RealmFile { Hash = $"{i}" }, string.Empty) }
};
importedScores.Add(scoreManager.Import(score)!.Value);
}
});
});
[SetUpSteps]
public void SetupSteps()
{
AddUntilStep("ensure scores imported", () => importedScores.Count == 50);
AddStep("undelete scores", () =>
{
Realm.Run(r =>
{
// Due to soft deletions, we can re-use deleted scores between test runs
scoreManager.Undelete(r.All<ScoreInfo>().Where(s => s.DeletePending).ToList());
});
});
AddStep("set up leaderboard", () =>
{
Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo);
leaderboard.Show();
});
// Ensure the leaderboard items have finished showing up
AddStep("finish transforms", () => leaderboard.FinishTransforms(true));
AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType<BeatmapLeaderboardScore>().Any());
}
[Test]
public void TestDeleteViaRightClick()
{
ScoreInfo scoreBeingDeleted = null!;
AddStep("open menu for top score", () =>
{
var leaderboardScore = leaderboard.ChildrenOfType<BeatmapLeaderboardScore>().First();
scoreBeingDeleted = leaderboardScore.Score;
InputManager.MoveMouseTo(leaderboardScore);
InputManager.Click(MouseButton.Right);
});
// Ensure the context menu has finished showing
AddStep("finish transforms", () => leaderboard.FinishTransforms(true));
AddStep("click delete option", () =>
{
InputManager.MoveMouseTo(leaderboard.ChildrenOfType<DrawableOsuMenuItem>()
.First(i => string.Equals(i.Item.Text.Value.ToString(), "delete", System.StringComparison.OrdinalIgnoreCase)));
InputManager.Click(MouseButton.Left);
});
// Ensure the dialog has finished showing
AddStep("finish transforms", () => dialogOverlay.FinishTransforms(true));
AddStep("click delete button", () =>
{
InputManager.MoveMouseTo(dialogOverlay.ChildrenOfType<DialogButton>().First());
InputManager.PressButton(MouseButton.Left);
});
AddUntilStep("wait for fetch", () => scores.Any());
AddUntilStep("score removed from leaderboard", () => scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID));
// "Clean up"
AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
}
[Test]
public void TestDeleteViaDatabase()
{
AddStep("delete top score", () => scoreManager.Delete(importedScores[0]));
AddUntilStep("wait for fetch", () => scores.Any());
AddUntilStep("score removed from leaderboard", () => scores.All(s => s.OnlineID != importedScores[0].OnlineID));
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (rulesets.IsNotNull())
rulesets.Dispose();
}
}
}