From 926790b07155d735912ff4ad4fdc4afac442f807 Mon Sep 17 00:00:00 2001 From: Lukas <103962359+L4XB@users.noreply.github.com> Date: Sun, 1 Nov 2026 13:53:45 +0100 Subject: [PATCH] fix(speedtest): clear the last speed when a speed test starts (#10449) A speed test only stored a speed above zero, so a node that was skipped because its delay test failed, or whose download failed, kept the speed of the previous run. The list showed the skip or error text until it was sorted or refreshed; then the old speed came back and the node sorted as if it had been measured. Clear the stored speed when a speed or mixed test starts. --- .../Services/SpeedtestServiceResultTests.cs | 26 +++++++++++++++++++ .../ServiceLib/Services/SpeedtestService.cs | 3 +++ 2 files changed, 29 insertions(+) create mode 100644 v2rayN/ServiceLib.Tests/Services/SpeedtestServiceResultTests.cs diff --git a/v2rayN/ServiceLib.Tests/Services/SpeedtestServiceResultTests.cs b/v2rayN/ServiceLib.Tests/Services/SpeedtestServiceResultTests.cs new file mode 100644 index 00000000..491203a6 --- /dev/null +++ b/v2rayN/ServiceLib.Tests/Services/SpeedtestServiceResultTests.cs @@ -0,0 +1,26 @@ +namespace ServiceLib.Tests.Services; + +public class SpeedtestServiceResultTests +{ + [Test] + [Arguments(ESpeedActionType.Speedtest, 0)] + [Arguments(ESpeedActionType.Mixedtest, 0)] + [Arguments(ESpeedActionType.Realping, 12.5)] + public async Task StartingATest_ShouldClearTheLastSpeedOfSpeedTests(ESpeedActionType actionType, double expected) + { + var indexId = Guid.NewGuid().ToString(); + ProfileExManager.Instance.SetTestSpeed(indexId, 12.5m); + + await SetTestResult([new() { IndexId = indexId }], actionType, ResUI.Speedtesting); + + var profileEx = (await ProfileExManager.Instance.GetProfileExs()).First(t => t.IndexId == indexId); + await profileEx.Speed.Should().BeEqualTo((decimal)expected); + } + + private static Task SetTestResult(List items, ESpeedActionType actionType, string message) + { + var service = new SpeedtestService(new Config { SpeedTestItem = new() }, _ => Task.CompletedTask); + var method = typeof(SpeedtestService).GetMethod("SetTestResultAsync", BindingFlags.Instance | BindingFlags.NonPublic)!; + return (Task)method.Invoke(service, [items, actionType, message])!; + } +} diff --git a/v2rayN/ServiceLib/Services/SpeedtestService.cs b/v2rayN/ServiceLib/Services/SpeedtestService.cs index a5155589..ef5c4582 100644 --- a/v2rayN/ServiceLib/Services/SpeedtestService.cs +++ b/v2rayN/ServiceLib/Services/SpeedtestService.cs @@ -188,10 +188,13 @@ public class SpeedtestService(Config config, Func updateF break; case ESpeedActionType.Speedtest: + // A skipped or failed test must not leave the last speed behind for sorting. + ProfileExManager.Instance.SetTestSpeed(it.IndexId, 0); await UpdateFunc(it.IndexId, "", message); break; case ESpeedActionType.Mixedtest: + ProfileExManager.Instance.SetTestSpeed(it.IndexId, 0); await UpdateFunc(it.IndexId, message, message); break; }