From 8c96327f6b86ae088da18788ede6230667875e82 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Wed, 12 Feb 2025 17:46:21 +0000 Subject: [PATCH] ParallelGroup Order Property (#1825) * ParallelGroup Order Property * Equality members --- .../Attributes/ParallelGroupAttribute.cs | 6 +++-- TUnit.Core/ParallelGroupConstraint.cs | 22 ++++++++++++++++++- .../Extensions/TestContextExtensions.cs | 5 +++-- TUnit.Engine/Models/GroupedTests.cs | 5 +++-- TUnit.Engine/Services/TestGrouper.cs | 4 ++-- TUnit.Engine/Services/TestsExecutor.cs | 7 +++--- 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/TUnit.Core/Attributes/ParallelGroupAttribute.cs b/TUnit.Core/Attributes/ParallelGroupAttribute.cs index f617da7803..0a5f328c9e 100644 --- a/TUnit.Core/Attributes/ParallelGroupAttribute.cs +++ b/TUnit.Core/Attributes/ParallelGroupAttribute.cs @@ -4,12 +4,14 @@ namespace TUnit.Core; public class ParallelGroupAttribute(string group) : TUnitAttribute, ITestDiscoveryEventReceiver { - public int Order => 0; + int IEventReceiver.Order => 0; + + public int Order { get; set; } public string Group { get; } = group; public void OnTestDiscovery(DiscoveredTestContext discoveredTestContext) { - discoveredTestContext.SetParallelConstraint(new ParallelGroupConstraint(Group)); + discoveredTestContext.SetParallelConstraint(new ParallelGroupConstraint(Group, Order)); } } \ No newline at end of file diff --git a/TUnit.Core/ParallelGroupConstraint.cs b/TUnit.Core/ParallelGroupConstraint.cs index 4edc3a0212..bfaeaee45a 100644 --- a/TUnit.Core/ParallelGroupConstraint.cs +++ b/TUnit.Core/ParallelGroupConstraint.cs @@ -2,10 +2,30 @@ namespace TUnit.Core; -public record ParallelGroupConstraint(string Group) : IParallelConstraint, +public record ParallelGroupConstraint(string Group, int Order) : IParallelConstraint, IComparable, IComparable { + public virtual bool Equals(ParallelGroupConstraint? other) + { + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return Group == other.Group; + } + + public override int GetHashCode() + { + return Group.GetHashCode(); + } + public int CompareTo(ParallelGroupConstraint? other) { return string.Compare(Group, other?.Group, StringComparison.Ordinal); diff --git a/TUnit.Engine/Extensions/TestContextExtensions.cs b/TUnit.Engine/Extensions/TestContextExtensions.cs index 28b6017084..94fa30b2cd 100644 --- a/TUnit.Engine/Extensions/TestContextExtensions.cs +++ b/TUnit.Engine/Extensions/TestContextExtensions.cs @@ -1,4 +1,5 @@ -using System.Diagnostics.CodeAnalysis; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.ExceptionServices; using Microsoft.Testing.Platform.Extensions.TestFramework; @@ -64,7 +65,7 @@ await testContext.GetService().RegisterInstance(newTest, Parallel = [newTest], NotInParallel = new PriorityQueue(), KeyedNotInParallel = new Dictionary>(), - ParallelGroups = new Dictionary>() + ParallelGroups = new ConcurrentDictionary>() }, null, testContext.GetService()); } diff --git a/TUnit.Engine/Models/GroupedTests.cs b/TUnit.Engine/Models/GroupedTests.cs index 53f4f09962..332a3cb2fc 100644 --- a/TUnit.Engine/Models/GroupedTests.cs +++ b/TUnit.Engine/Models/GroupedTests.cs @@ -1,4 +1,5 @@ -using TUnit.Core; +using System.Collections.Concurrent; +using TUnit.Core; namespace TUnit.Engine.Models; @@ -8,5 +9,5 @@ internal record GroupedTests public required PriorityQueue NotInParallel { get; init; } public required IDictionary> KeyedNotInParallel { get; init; } public required IList Parallel { get; init; } - public required IDictionary> ParallelGroups { get; set; } + public required ConcurrentDictionary> ParallelGroups { get; set; } } \ No newline at end of file diff --git a/TUnit.Engine/Services/TestGrouper.cs b/TUnit.Engine/Services/TestGrouper.cs index 8d6ee78c4f..4d683209b5 100644 --- a/TUnit.Engine/Services/TestGrouper.cs +++ b/TUnit.Engine/Services/TestGrouper.cs @@ -11,7 +11,7 @@ public GroupedTests OrganiseTests(IReadOnlyCollection testCases) var notInParallel = new PriorityQueue(); var keyedNotInParallel = new ConcurrentDictionary>(); var parallel = new List(); - var parallelGroups = new ConcurrentDictionary>(); + var parallelGroups = new ConcurrentDictionary>(); foreach (var discoveredTest in testCases) { @@ -35,7 +35,7 @@ public GroupedTests OrganiseTests(IReadOnlyCollection testCases) } else if (discoveredTest.TestDetails.ParallelConstraint is ParallelGroupConstraint parallelGroupConstraint) { - parallelGroups.GetOrAdd(parallelGroupConstraint.Group, _ => []).Add(discoveredTest); + parallelGroups.GetOrAdd(parallelGroupConstraint, _ => []).Add(discoveredTest); } else { diff --git a/TUnit.Engine/Services/TestsExecutor.cs b/TUnit.Engine/Services/TestsExecutor.cs index 4e2aad7ec7..6c367a0593 100644 --- a/TUnit.Engine/Services/TestsExecutor.cs +++ b/TUnit.Engine/Services/TestsExecutor.cs @@ -1,4 +1,5 @@ -using EnumerableAsyncProcessor.Extensions; +using System.Collections.Concurrent; +using EnumerableAsyncProcessor.Extensions; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Extensions.TestFramework; using Microsoft.Testing.Platform.Requests; @@ -83,10 +84,10 @@ await testsToProcess.Values .ProcessInParallel(_maximumParallelTests); } - private async Task ProcessParallelGroups(IDictionary> groups, + private async Task ProcessParallelGroups(ConcurrentDictionary> groups, ITestExecutionFilter? filter, ExecuteRequestContext context) { - foreach (var (_, value) in groups) + foreach (var (_, value) in groups.OrderBy(x => x.Key.Order)) { await ProcessParallelTests(value, filter, context); }