From 4169c12a1ff60adb7b4fe8c6c491055feaa718db Mon Sep 17 00:00:00 2001 From: Miheichev Aleksandr Sergeevich Date: Sun, 1 Nov 2026 12:35:38 +0000 Subject: [PATCH] test: strengthen ProfileExManager concurrency regression coverage (#10410) --- .../ProfileExManagerConcurrencyTests.cs | 53 ++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/v2rayN/ServiceLib.Tests/Manager/ProfileExManagerConcurrencyTests.cs b/v2rayN/ServiceLib.Tests/Manager/ProfileExManagerConcurrencyTests.cs index a5d97f09..845da5c3 100644 --- a/v2rayN/ServiceLib.Tests/Manager/ProfileExManagerConcurrencyTests.cs +++ b/v2rayN/ServiceLib.Tests/Manager/ProfileExManagerConcurrencyTests.cs @@ -58,18 +58,59 @@ public class ProfileExManagerConcurrencyTests { var manager = CreateManager(); - await Parallel.ForEachAsync(Enumerable.Range(0, 500), new ParallelOptions { MaxDegreeOfParallelism = 32 }, - async (i, ct) => - { - manager.SetTestDelay($"same{i % 10}", i); - await Task.CompletedTask; - }); + await RunConcurrentUpdates(8, 10, (_, index) => manager.SetTestDelay($"same{index}", index)); var items = await manager.GetProfileExs(); await items.Count.Should().BeEqualTo(10); await items.Select(t => t.IndexId).Distinct().Count().Should().BeEqualTo(10); } + [Test] + public async Task SetTestResults_ConcurrentUpdates_ShouldKeepAllValuesOnOneEntry() + { + var manager = CreateManager(); + Action[] updates = + [ + indexId => manager.SetTestDelay(indexId, 123), + indexId => manager.SetTestSpeed(indexId, 45.6m), + indexId => manager.SetTestMessage(indexId, "result"), + indexId => manager.SetTestIpInfo(indexId, "203.0.113.1"), + indexId => manager.SetSort(indexId, 7) + ]; + + await RunConcurrentUpdates(updates.Length, 100, (worker, index) => updates[worker]($"profile{index}")); + + var items = await manager.GetProfileExs(); + await items.Count.Should().BeEqualTo(100); + await items.Select(item => item.IndexId).Distinct().Count().Should().BeEqualTo(100); + foreach (var item in items) + { + await item.Delay.Should().BeEqualTo(123); + await item.Speed.Should().BeEqualTo(45.6m); + await item.Message.Should().BeEqualTo("result"); + await item.IpInfo.Should().BeEqualTo("203.0.113.1"); + await item.Sort.Should().BeEqualTo(7); + } + } + + private static async Task RunConcurrentUpdates(int workers, int indexes, Action update) + { + using var barrier = new Barrier(workers); + var tasks = Enumerable.Range(0, workers).Select(worker => Task.Factory.StartNew(() => + { + for (var index = 0; index < indexes; index++) + { + if (!barrier.SignalAndWait(TimeSpan.FromSeconds(10))) + { + throw new TimeoutException("Concurrent update workers did not synchronize."); + } + update(worker, index); + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)).ToArray(); + + await Task.WhenAll(tasks); + } + private static ProfileExManager CreateManager() { return (ProfileExManager)Activator.CreateInstance(typeof(ProfileExManager), nonPublic: true)!;