From 48dc2332fd5bc60d977897e3a4d6477dc8b0deec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Dec 2022 11:10:33 +0100 Subject: [PATCH] Refactor test to be easier to work with --- .../Online/TestSceneSoloStatisticsWatcher.cs | 241 +++++++++--------- .../Online/API/Requests/GetUsersRequest.cs | 6 +- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 2 +- 3 files changed, 130 insertions(+), 119 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs index 0797113ca1..008d54be63 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Testing; @@ -12,6 +13,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Solo; using osu.Game.Online.Spectator; +using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; using osu.Game.Users; @@ -33,9 +35,12 @@ namespace osu.Game.Tests.Visual.Online private Action? handleGetUsersRequest; private Action? handleGetUserRequest; + private readonly Dictionary<(int userId, string rulesetName), UserStatistics> serverSideStatistics = new Dictionary<(int userId, string rulesetName), UserStatistics>(); + [SetUpSteps] public void SetUpSteps() { + AddStep("clear server-side stats", () => serverSideStatistics.Clear()); AddStep("set up request handling", () => { handleGetUserRequest = null; @@ -46,11 +51,52 @@ namespace osu.Game.Tests.Visual.Online switch (request) { case GetUsersRequest getUsersRequest: - handleGetUsersRequest?.Invoke(getUsersRequest); + if (handleGetUsersRequest != null) + { + handleGetUsersRequest?.Invoke(getUsersRequest); + } + else + { + int userId = getUsersRequest.UserIds.Single(); + var response = new GetUsersResponse + { + Users = new List + { + new APIUser + { + Id = userId, + RulesetsStatistics = new Dictionary + { + ["osu"] = tryGetStatistics(userId, "osu"), + ["taiko"] = tryGetStatistics(userId, "taiko"), + ["fruits"] = tryGetStatistics(userId, "fruits"), + ["mania"] = tryGetStatistics(userId, "mania"), + } + } + } + }; + getUsersRequest.TriggerSuccess(response); + } + return true; case GetUserRequest getUserRequest: - handleGetUserRequest?.Invoke(getUserRequest); + if (handleGetUserRequest != null) + { + handleGetUserRequest.Invoke(getUserRequest); + } + else + { + int userId = int.Parse(getUserRequest.Lookup); + string rulesetName = getUserRequest.Ruleset.ShortName; + var response = new APIUser + { + Id = userId, + Statistics = tryGetStatistics(userId, rulesetName) + }; + getUserRequest.TriggerSuccess(response); + } + return true; default: @@ -65,120 +111,90 @@ namespace osu.Game.Tests.Visual.Online }); } + private UserStatistics tryGetStatistics(int userId, string rulesetName) + => serverSideStatistics.TryGetValue((userId, rulesetName), out var stats) ? stats : new UserStatistics(); + [Test] public void TestStatisticsUpdateFiredAfterRegistrationAddedAndScoreProcessed() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1234)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1234 }; - }); + int userId = getUserId(); + long scoreId = getScoreId(); + setUpUser(userId); + + var ruleset = new OsuRuleset().RulesetInfo; SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); + feignScoreProcessing(userId, ruleset, 5_000_000); - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1234, 5_000_000))); - - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1234, 5678)); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); AddUntilStep("update received", () => update != null); - AddAssert("values before are correct", () => update?.Before.TotalScore, () => Is.EqualTo(4_000_000)); - AddAssert("values after are correct", () => update?.After.TotalScore, () => Is.EqualTo(5_000_000)); + AddAssert("values before are correct", () => update!.Before.TotalScore, () => Is.EqualTo(4_000_000)); + AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(5_000_000)); } [Test] public void TestStatisticsUpdateFiredAfterScoreProcessedAndRegistrationAdded() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1235)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1235 }; - }); + int userId = getUserId(); + setUpUser(userId); - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1235, 5_000_000))); - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1235, 5678)); + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; + + // note ordering - in this test processing completes *before* the registration is added. + feignScoreProcessing(userId, ruleset, 5_000_000); SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - // note ordering - this test checks that even if the registration is late, it will receive data. - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); AddUntilStep("update received", () => update != null); - AddAssert("values before are correct", () => update?.Before.TotalScore, () => Is.EqualTo(4_000_000)); - AddAssert("values after are correct", () => update?.After.TotalScore, () => Is.EqualTo(5_000_000)); + AddAssert("values before are correct", () => update!.Before.TotalScore, () => Is.EqualTo(4_000_000)); + AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(5_000_000)); } [Test] public void TestStatisticsUpdateNotFiredIfUserLoggedOut() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1236)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1236 }; - }); + int userId = getUserId(); + setUpUser(userId); + + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); - - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1236, 5_000_000))); + feignScoreProcessing(userId, ruleset, 5_000_000); AddStep("log out user", () => dummyAPI.Logout()); - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1236, 5678)); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); AddWaitStep("wait a bit", 5); AddAssert("update not received", () => update == null); + + AddStep("log in user", () => dummyAPI.Login("user", "password")); } [Test] public void TestStatisticsUpdateNotFiredIfAnotherUserLoggedIn() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1237)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1237 }; - }); + int userId = getUserId(); + setUpUser(userId); + + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); + feignScoreProcessing(userId, ruleset, 5_000_000); - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1237, 5_000_000))); + AddStep("change user", () => dummyAPI.LocalUser.Value = new APIUser { Id = getUserId() }); - AddStep("log out user", () => dummyAPI.LocalUser.Value = new APIUser { Id = 5555 }); - - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1237, 5678)); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); AddWaitStep("wait a bit", 5); AddAssert("update not received", () => update == null); } @@ -186,56 +202,51 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestStatisticsUpdateNotFiredIfScoreIdDoesNotMatch() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1238)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1238 }; - }); + int userId = getUserId(); + setUpUser(userId); + + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); + feignScoreProcessing(userId, ruleset, 5_000_000); - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1238, 5_000_000))); - - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1238, 9012)); + AddStep("signal another score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, getScoreId())); AddWaitStep("wait a bit", 5); AddAssert("update not received", () => update == null); } - private GetUsersResponse createInitialUserResponse(int userId) => new GetUsersResponse - { - Users = new List - { - new APIUser - { - Id = userId, - RulesetsStatistics = new Dictionary - { - ["osu"] = new UserStatistics { TotalScore = 4_000_000 }, - ["taiko"] = new UserStatistics { TotalScore = 3_000_000 }, - ["fruits"] = new UserStatistics { TotalScore = 2_000_000 }, - ["mania"] = new UserStatistics { TotalScore = 1_000_000 } - } - } - } - }; + private int nextUserId = 2000; + private long nextScoreId = 50000; - private APIUser createIncrementalUserResponse(int userId, long totalScore) => new APIUser + private int getUserId() => ++nextUserId; + private long getScoreId() => ++nextScoreId; + + private void setUpUser(int userId) { - Id = userId, - Statistics = new UserStatistics + AddStep("fetch initial stats", () => { - TotalScore = totalScore - } - }; + serverSideStatistics[(userId, "osu")] = new UserStatistics { TotalScore = 4_000_000 }; + serverSideStatistics[(userId, "taiko")] = new UserStatistics { TotalScore = 3_000_000 }; + serverSideStatistics[(userId, "fruits")] = new UserStatistics { TotalScore = 2_000_000 }; + serverSideStatistics[(userId, "mania")] = new UserStatistics { TotalScore = 1_000_000 }; + + dummyAPI.LocalUser.Value = new APIUser { Id = userId }; + }); + } + + private void registerForUpdates(long scoreId, RulesetInfo rulesetInfo, Action onUpdateReady) => + AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( + new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + { + Ruleset = rulesetInfo, + OnlineID = scoreId + }, + onUpdateReady)); + + private void feignScoreProcessing(int userId, RulesetInfo rulesetInfo, long newTotalScore) + => AddStep("feign score processing", () => serverSideStatistics[(userId, rulesetInfo.ShortName)] = new UserStatistics { TotalScore = newTotalScore }); } } diff --git a/osu.Game/Online/API/Requests/GetUsersRequest.cs b/osu.Game/Online/API/Requests/GetUsersRequest.cs index bbaf241384..b57bb215aa 100644 --- a/osu.Game/Online/API/Requests/GetUsersRequest.cs +++ b/osu.Game/Online/API/Requests/GetUsersRequest.cs @@ -9,7 +9,7 @@ namespace osu.Game.Online.API.Requests { public class GetUsersRequest : APIRequest { - private readonly int[] userIds; + public readonly int[] UserIds; private const int max_ids_per_request = 50; @@ -18,9 +18,9 @@ namespace osu.Game.Online.API.Requests if (userIds.Length > max_ids_per_request) throw new ArgumentException($"{nameof(GetUsersRequest)} calls only support up to {max_ids_per_request} IDs at once"); - this.userIds = userIds; + UserIds = userIds; } - protected override string Target => "users/?ids[]=" + string.Join("&ids[]=", userIds); + protected override string Target => "users/?ids[]=" + string.Join("&ids[]=", UserIds); } } diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 197ad410a9..1befbe2af0 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -71,7 +71,7 @@ namespace osu.Game.Online.Solo if (!api.IsLoggedIn) return; - Debug.Assert(localUser != null && localUser.OnlineID > 1); + Debug.Assert(localUser != null); var userRequest = new GetUsersRequest(new[] { localUser.OnlineID }); userRequest.Success += response => Schedule(() =>