diff --git a/samples/NScatterGather.Samples.CompetingTasks/Program.cs b/samples/NScatterGather.Samples.CompetingTasks/Program.cs index c7c1463..71a4064 100644 --- a/samples/NScatterGather.Samples.CompetingTasks/Program.cs +++ b/samples/NScatterGather.Samples.CompetingTasks/Program.cs @@ -71,7 +71,7 @@ static void PrettyPrint(IReadOnlyList evaluations) foreach (var invocation in resultsWithPrice.OrderBy(x => x.Duration)) { var productName = isFirstPrice ? evaluation.Product.Name : string.Empty; - var supplierName = invocation.RecipientName; + var supplierName = invocation.Recipient.Name; var supplierPrice = invocation.Result!.Value; var isBestPrice = supplierPrice == bestPrice; var resultColor = isBestPrice ? "green3_1" : "red"; diff --git a/samples/NScatterGather.Samples/Samples/4.HandleErrors.cs b/samples/NScatterGather.Samples/Samples/4.HandleErrors.cs index 8cfaa3f..9ded89b 100644 --- a/samples/NScatterGather.Samples/Samples/4.HandleErrors.cs +++ b/samples/NScatterGather.Samples/Samples/4.HandleErrors.cs @@ -22,7 +22,7 @@ public async Task Run() Console.WriteLine($"Completed {response.Completed.Count}"); Console.WriteLine( $"Faulted {response.Faulted.Count}: " + - $"{response.Faulted[0].RecipientType?.Name} => " + + $"{response.Faulted[0].Recipient.Type?.Name} => " + $"{response.Faulted[0].Exception?.Message}"); } @@ -34,7 +34,7 @@ public string Get(string s) => class Bar { - public string Todo(string s) => + public string Todo(string _) => throw new NotImplementedException("TODO"); } } diff --git a/samples/NScatterGather.Samples/Samples/5.Timeout.cs b/samples/NScatterGather.Samples/Samples/5.Timeout.cs index 89e8c43..45f6fb8 100644 --- a/samples/NScatterGather.Samples/Samples/5.Timeout.cs +++ b/samples/NScatterGather.Samples/Samples/5.Timeout.cs @@ -26,8 +26,8 @@ public async Task Run() Console.WriteLine($"Completed {response.Completed.Count}"); Console.WriteLine( $"Incomplete {response.Incomplete.Count}: " + - $"{response.Incomplete[0].RecipientType?.Name}, " + - $"{response.Incomplete[1].RecipientType?.Name}"); + $"{response.Incomplete[0].Recipient.Type?.Name}, " + + $"{response.Incomplete[1].Recipient.Type?.Name}"); } class Foo @@ -46,7 +46,7 @@ public async Task Long(int n) class Baz { - public Task Block(int n) + public Task Block(int _) { var tcs = new TaskCompletionSource(); return tcs.Task; // It will never complete. diff --git a/src/NScatterGather/Invocations/CompletedInvocation.cs b/src/NScatterGather/Invocations/CompletedInvocation.cs index 19f1dd7..5ef3bb9 100644 --- a/src/NScatterGather/Invocations/CompletedInvocation.cs +++ b/src/NScatterGather/Invocations/CompletedInvocation.cs @@ -3,37 +3,28 @@ namespace NScatterGather { - public class CompletedInvocation + public class CompletedInvocation : Invocation { - public string? RecipientName { get; } - - public Type? RecipientType { get; } - [AllowNull, MaybeNull] public TResponse Result { get; } public TimeSpan Duration { get; } internal CompletedInvocation( - string? recipientName, - Type? recipientType, + RecipientDescription recipient, [AllowNull] TResponse result, - TimeSpan duration) + TimeSpan duration) : base(recipient) { - RecipientName = recipientName; - RecipientType = recipientType; Result = result; Duration = duration; } public void Deconstruct( - out string? recipientName, - out Type? recipientType, + out RecipientDescription recipient, [MaybeNull] out TResponse result, out TimeSpan duration) { - recipientName = RecipientName; - recipientType = RecipientType; + recipient = Recipient; result = Result; duration = Duration; } diff --git a/src/NScatterGather/Invocations/FaultedInvocation.cs b/src/NScatterGather/Invocations/FaultedInvocation.cs index 7045ba3..3526c2d 100644 --- a/src/NScatterGather/Invocations/FaultedInvocation.cs +++ b/src/NScatterGather/Invocations/FaultedInvocation.cs @@ -2,36 +2,27 @@ namespace NScatterGather { - public class FaultedInvocation + public class FaultedInvocation : Invocation { - public string? RecipientName { get; } - - public Type? RecipientType { get; } - public Exception? Exception { get; } public TimeSpan Duration { get; } internal FaultedInvocation( - string? recipientName, - Type? recipientType, + RecipientDescription recipient, Exception? exception, - TimeSpan duration) + TimeSpan duration) : base(recipient) { - RecipientName = recipientName; - RecipientType = recipientType; Exception = exception; Duration = duration; } public void Deconstruct( - out string? recipientName, - out Type? recipientType, + out RecipientDescription recipient, out Exception? exception, out TimeSpan duration) { - recipientName = RecipientName; - recipientType = RecipientType; + recipient = Recipient; exception = Exception; duration = Duration; } diff --git a/src/NScatterGather/Invocations/IncompleteInvocation.cs b/src/NScatterGather/Invocations/IncompleteInvocation.cs index b86417b..2e28b99 100644 --- a/src/NScatterGather/Invocations/IncompleteInvocation.cs +++ b/src/NScatterGather/Invocations/IncompleteInvocation.cs @@ -1,27 +1,9 @@ -using System; - -namespace NScatterGather +namespace NScatterGather { - public class IncompleteInvocation + public class IncompleteInvocation : Invocation { - public string? RecipientName { get; } - - public Type? RecipientType { get; } - - internal IncompleteInvocation( - string? recipientName, - Type? recipientType) + internal IncompleteInvocation(RecipientDescription recipient) : base(recipient) { - RecipientName = recipientName; - RecipientType = recipientType; - } - - public void Deconstruct( - out string? recipientName, - out Type? recipientType) - { - recipientName = RecipientName; - recipientType = RecipientType; } } } diff --git a/src/NScatterGather/Invocations/Invocation.cs b/src/NScatterGather/Invocations/Invocation.cs new file mode 100644 index 0000000..c57621b --- /dev/null +++ b/src/NScatterGather/Invocations/Invocation.cs @@ -0,0 +1,12 @@ +namespace NScatterGather +{ + public abstract class Invocation + { + public RecipientDescription Recipient { get; } + + protected Invocation(RecipientDescription recipient) + { + Recipient = recipient; + } + } +} diff --git a/src/NScatterGather/Invocations/RecipientDescription.cs b/src/NScatterGather/Invocations/RecipientDescription.cs new file mode 100644 index 0000000..1029601 --- /dev/null +++ b/src/NScatterGather/Invocations/RecipientDescription.cs @@ -0,0 +1,45 @@ +using System; + +namespace NScatterGather +{ + public class RecipientDescription + { + public Guid Id { get; } + + public string? Name { get; } + + public Type? Type { get; } + + public Lifetime Lifetime { get; } + + public CollisionStrategy CollisionStrategy { get; } + + internal RecipientDescription( + Guid id, + string? name, + Type? type, + Lifetime lifetime, + CollisionStrategy collisionStrategy) + { + Id = id; + Name = name; + Type = type; + Lifetime = lifetime; + CollisionStrategy = collisionStrategy; + } + + public void Deconstruct( + out Guid id, + out string? name, + out Type? type, + out Lifetime lifetime, + out CollisionStrategy collisionStrategy) + { + id = Id; + name = Name; + type = Type; + lifetime = Lifetime; + collisionStrategy = CollisionStrategy; + } + } +} diff --git a/src/NScatterGather/Invocations/RecipientDescriptionFactory.cs b/src/NScatterGather/Invocations/RecipientDescriptionFactory.cs new file mode 100644 index 0000000..9823874 --- /dev/null +++ b/src/NScatterGather/Invocations/RecipientDescriptionFactory.cs @@ -0,0 +1,21 @@ +using NScatterGather.Recipients; + +namespace NScatterGather.Invocations +{ + internal class RecipientDescriptionFactory + { + public static RecipientDescription CreateFrom(Recipient recipient) + { + var recipientType = recipient is TypeRecipient ir ? ir.Type : null; + + var description = new RecipientDescription( + recipient.Id, + recipient.Name, + recipientType, + recipient.Lifetime, + recipient.CollisionStrategy); + + return description; + } + } +} diff --git a/src/NScatterGather/Recipients/Collection/RecipientsCollection.cs b/src/NScatterGather/Recipients/Collection/RecipientsCollection.cs index 1eabe86..ea875a6 100644 --- a/src/NScatterGather/Recipients/Collection/RecipientsCollection.cs +++ b/src/NScatterGather/Recipients/Collection/RecipientsCollection.cs @@ -24,36 +24,36 @@ public RecipientsCollection(CollisionStrategy defaultCollisionStrategy = IgnoreR _defaultCollisionStrategy = defaultCollisionStrategy; } - public void Add(string name) => - AddWithDefaultFactoryMethod(name: name); + public Guid Add(string name) => + AddTypeRecipientWithDefaultFactoryMethod(name: name); - public void Add(Lifetime lifetime) => - AddWithDefaultFactoryMethod(lifetime: lifetime); + public Guid Add(Lifetime lifetime) => + AddTypeRecipientWithDefaultFactoryMethod(lifetime: lifetime); - public void Add(Func factoryMethod) => - Internal_Add(factoryMethod: factoryMethod); + public Guid Add(Func factoryMethod) => + AddTypeRecipient(factoryMethod: factoryMethod); - public void Add(CollisionStrategy collisionStrategy) => - AddWithDefaultFactoryMethod(collisionStrategy: collisionStrategy); + public Guid Add(CollisionStrategy collisionStrategy) => + AddTypeRecipientWithDefaultFactoryMethod(collisionStrategy: collisionStrategy); - public void Add( + public Guid Add( string? name = null, Lifetime lifetime = Transient, CollisionStrategy? collisionStrategy = null) { - AddWithDefaultFactoryMethod(name, lifetime, collisionStrategy); + return AddTypeRecipientWithDefaultFactoryMethod(name, lifetime, collisionStrategy); } - public void Add( + public Guid Add( Func factoryMethod, string? name = null, Lifetime lifetime = Transient, CollisionStrategy? collisionStrategy = null) { - Internal_Add(factoryMethod, name, lifetime, collisionStrategy); + return AddTypeRecipient(factoryMethod, name, lifetime, collisionStrategy); } - internal void AddWithDefaultFactoryMethod( + internal Guid AddTypeRecipientWithDefaultFactoryMethod( string? name = null, Lifetime lifetime = Transient, CollisionStrategy? collisionStrategy = null) @@ -63,7 +63,7 @@ internal void AddWithDefaultFactoryMethod( static TRecipient factoryMethod() => ((TRecipient)Activator.CreateInstance(typeof(TRecipient)))!; - Internal_Add(factoryMethod, name, lifetime, collisionStrategy); + return AddTypeRecipient(factoryMethod, name, lifetime, collisionStrategy); // Local functions. @@ -74,7 +74,7 @@ static bool HasADefaultConstructor() } } - internal void Internal_Add( + internal Guid AddTypeRecipient( Func factoryMethod, string? name = null, Lifetime lifetime = Transient, @@ -86,10 +86,12 @@ internal void Internal_Add( var typeRecipient = TypeRecipient.Create( _registry, factoryMethod, name, lifetime, collisionStrategy ?? _defaultCollisionStrategy); - Add(typeRecipient); + _recipients.Add(typeRecipient); + + return typeRecipient.Id; } - public void Add( + public Guid Add( object instance, string? name = null, CollisionStrategy? collisionStrategy = null) @@ -100,10 +102,12 @@ public void Add( var instanceRecipient = InstanceRecipient.Create( _registry, instance, name, collisionStrategy ?? _defaultCollisionStrategy); - Add(instanceRecipient); + _recipients.Add(instanceRecipient); + + return instanceRecipient.Id; } - public void Add( + public Guid Add( Func @delegate, string? name = null) { @@ -112,12 +116,9 @@ public void Add( var delegateRecipient = DelegateRecipient.Create(@delegate, name); - Add(delegateRecipient); - } + _recipients.Add(delegateRecipient); - private void Add(Recipient recipient) - { - _recipients.Add(recipient); + return delegateRecipient.Id; } internal IRecipientsScope CreateScope() diff --git a/src/NScatterGather/Recipients/Recipient.cs b/src/NScatterGather/Recipients/Recipient.cs index 393f242..d9f9b2e 100644 --- a/src/NScatterGather/Recipients/Recipient.cs +++ b/src/NScatterGather/Recipients/Recipient.cs @@ -9,6 +9,8 @@ namespace NScatterGather.Recipients { internal abstract class Recipient { + public Guid Id { get; } = Guid.NewGuid(); + public string? Name { get; } public Lifetime Lifetime { get; } diff --git a/src/NScatterGather/Recipients/Run/RecipientRunner.cs b/src/NScatterGather/Recipients/Run/RecipientRunner.cs index 0c938a6..4d60e9e 100644 --- a/src/NScatterGather/Recipients/Run/RecipientRunner.cs +++ b/src/NScatterGather/Recipients/Run/RecipientRunner.cs @@ -84,8 +84,8 @@ private void InspectAndExtract(Task task) private Exception? ExtractException(Exception exception) { - if (exception is AggregateException aEx && aEx.InnerExceptions.Count == 1) - return aEx.InnerException is null ? aEx : ExtractException(aEx.InnerException); + if (exception is AggregateException aEx) + return aEx.InnerExceptions.Count == 1 ? ExtractException(aEx.InnerException!) : aEx; if (exception is TargetInvocationException tIEx) return tIEx.InnerException is null ? tIEx : ExtractException(tIEx.InnerException); diff --git a/src/NScatterGather/Responses/AggregatedResponseExtensions.cs b/src/NScatterGather/Responses/AggregatedResponseExtensions.cs index 38b5cff..1e59129 100644 --- a/src/NScatterGather/Responses/AggregatedResponseExtensions.cs +++ b/src/NScatterGather/Responses/AggregatedResponseExtensions.cs @@ -6,17 +6,14 @@ namespace NScatterGather { public static class AggregatedResponseExtensions { - public static IReadOnlyDictionary AsResultsDictionary( + public static IReadOnlyDictionary AsResultsDictionary( this AggregatedResponse aggregatedResponse) { if (aggregatedResponse is null) throw new ArgumentNullException(nameof(aggregatedResponse)); var dictionary = aggregatedResponse.Completed - .Where(x => x.RecipientType is not null) - .ToDictionary( - x => x.RecipientType!, - x => x.Result!); + .ToDictionary(keySelector: i => i.Recipient, elementSelector: i => i.Result!); return dictionary; } diff --git a/src/NScatterGather/Responses/AggregatedResponseFactory.cs b/src/NScatterGather/Responses/AggregatedResponseFactory.cs index 6a7a09a..14dd6a3 100644 --- a/src/NScatterGather/Responses/AggregatedResponseFactory.cs +++ b/src/NScatterGather/Responses/AggregatedResponseFactory.cs @@ -1,6 +1,5 @@ -using System; -using System.Collections.Generic; -using NScatterGather.Recipients; +using System.Collections.Generic; +using NScatterGather.Invocations; using NScatterGather.Recipients.Run; namespace NScatterGather.Responses @@ -16,13 +15,12 @@ public static AggregatedResponse CreateFrom( foreach (var invocation in invocations) { - var recipientType = invocation.Recipient is TypeRecipient ir ? ir.Type : null; + var recipientDescription = RecipientDescriptionFactory.CreateFrom(invocation.Recipient); if (invocation.CompletedSuccessfully) { var completedInvocation = new CompletedInvocation( - invocation.Recipient.Name, - recipientType, + recipientDescription, invocation.Result, invocation.Duration); @@ -31,15 +29,16 @@ public static AggregatedResponse CreateFrom( else if (invocation.Faulted) { var faultedInvocation = new FaultedInvocation( - invocation.Recipient.Name, - recipientType, + recipientDescription, invocation.Exception, invocation.Duration); faulted.Add(faultedInvocation); } else - incomplete.Add(new IncompleteInvocation(invocation.Recipient.Name, recipientType)); + { + incomplete.Add(new IncompleteInvocation(recipientDescription)); + } } return new AggregatedResponse(completed, faulted, incomplete); diff --git a/tests/NScatterGather.Tests/AggregatorTests.cs b/tests/NScatterGather.Tests/AggregatorTests.cs index efabb6f..56d3c10 100644 --- a/tests/NScatterGather.Tests/AggregatorTests.cs +++ b/tests/NScatterGather.Tests/AggregatorTests.cs @@ -29,15 +29,15 @@ public async Task Sends_request_and_aggregates_responses() Assert.NotNull(result); Assert.Equal(3, result.Completed.Count); - Assert.Contains(typeof(SomeType), result.Completed.Select(x => x.RecipientType)); - Assert.Contains(typeof(SomeAsyncType), result.Completed.Select(x => x.RecipientType)); - Assert.Contains(typeof(SomePossiblyAsyncType), result.Completed.Select(x => x.RecipientType)); + Assert.Contains(typeof(SomeType), result.Completed.Select(x => x.Recipient.Type)); + Assert.Contains(typeof(SomeAsyncType), result.Completed.Select(x => x.Recipient.Type)); + Assert.Contains(typeof(SomePossiblyAsyncType), result.Completed.Select(x => x.Recipient.Type)); Assert.Single(result.Faulted); - Assert.Contains(typeof(SomeFaultingType), result.Faulted.Select(x => x.RecipientType)); + Assert.Contains(typeof(SomeFaultingType), result.Faulted.Select(x => x.Recipient.Type)); Assert.Single(result.Incomplete); - Assert.Contains(typeof(SomeNeverEndingType), result.Incomplete.Select(x => x.RecipientType)); + Assert.Contains(typeof(SomeNeverEndingType), result.Incomplete.Select(x => x.Recipient.Type)); } [Fact(Timeout = 5_000)] @@ -47,15 +47,15 @@ public async Task Receives_expected_response_types() Assert.NotNull(result); Assert.Equal(3, result.Completed.Count); - Assert.Contains(typeof(SomeType), result.Completed.Select(x => x.RecipientType)); - Assert.Contains(typeof(SomeAsyncType), result.Completed.Select(x => x.RecipientType)); - Assert.Contains(typeof(SomePossiblyAsyncType), result.Completed.Select(x => x.RecipientType)); + Assert.Contains(typeof(SomeType), result.Completed.Select(x => x.Recipient.Type)); + Assert.Contains(typeof(SomeAsyncType), result.Completed.Select(x => x.Recipient.Type)); + Assert.Contains(typeof(SomePossiblyAsyncType), result.Completed.Select(x => x.Recipient.Type)); Assert.Single(result.Faulted); - Assert.Contains(typeof(SomeFaultingType), result.Faulted.Select(x => x.RecipientType)); + Assert.Contains(typeof(SomeFaultingType), result.Faulted.Select(x => x.Recipient.Type)); Assert.Single(result.Incomplete); - Assert.Contains(typeof(SomeNeverEndingType), result.Incomplete.Select(x => x.RecipientType)); + Assert.Contains(typeof(SomeNeverEndingType), result.Incomplete.Select(x => x.Recipient.Type)); } [Fact] @@ -72,16 +72,16 @@ public async Task Responses_expose_the_recipient_name_and_type() Assert.NotNull(result); Assert.Equal(1, result.Completed.Count); - Assert.Equal("Some delegate", result.Completed[0].RecipientName); - Assert.Null(result.Completed[0].RecipientType); + Assert.Equal("Some delegate", result.Completed[0].Recipient.Name); + Assert.Null(result.Completed[0].Recipient.Type); Assert.Equal(1, result.Faulted.Count); - Assert.Equal("Some faulting type", result.Faulted[0].RecipientName); - Assert.Equal(typeof(SomeFaultingType), result.Faulted[0].RecipientType); + Assert.Equal("Some faulting type", result.Faulted[0].Recipient.Name); + Assert.Equal(typeof(SomeFaultingType), result.Faulted[0].Recipient.Type); Assert.Equal(1, result.Incomplete.Count); - Assert.Equal("Some never ending type", result.Incomplete[0].RecipientName); - Assert.Equal(typeof(SomeNeverEndingType), result.Incomplete[0].RecipientType); + Assert.Equal("Some never ending type", result.Incomplete[0].Recipient.Name); + Assert.Equal(typeof(SomeNeverEndingType), result.Incomplete[0].Recipient.Type); } [Fact] @@ -141,7 +141,7 @@ public async Task Recipients_can_return_null() Assert.Empty(response.Faulted); var completed = response.Completed[0]; - Assert.Equal(typeof(SomeTypeReturningNull), completed.RecipientType); + Assert.Equal(typeof(SomeTypeReturningNull), completed.Recipient.Type); Assert.Null(completed.Result); } @@ -160,7 +160,7 @@ public async Task Recipients_can_return_nullable() Assert.Empty(response.Faulted); var completed = response.Completed[0]; - Assert.Equal(typeof(SomeTypeReturningNullable), completed.RecipientType); + Assert.Equal(typeof(SomeTypeReturningNullable), completed.Recipient.Type); Assert.Null(completed.Result); } diff --git a/tests/NScatterGather.Tests/Invocations/CompletedInvocationTests.cs b/tests/NScatterGather.Tests/Invocations/CompletedInvocationTests.cs index e7411de..a1d0cd9 100644 --- a/tests/NScatterGather.Tests/Invocations/CompletedInvocationTests.cs +++ b/tests/NScatterGather.Tests/Invocations/CompletedInvocationTests.cs @@ -8,18 +8,28 @@ public class CompletedInvocationTests [Fact] public void Can_be_deconstructed() { - var expectedName = "foo"; - var expectedType = typeof(int); + var expectedDescription = new RecipientDescription( + Guid.NewGuid(), + "My name is", + typeof(SomeType), + Lifetime.Singleton, + CollisionStrategy.UseAllMethodsMatching); + var expectedResult = 42; var expectedDuration = TimeSpan.FromSeconds(1); var invocation = new CompletedInvocation( - expectedName, expectedType, expectedResult, expectedDuration); + expectedDescription, + expectedResult, + expectedDuration); - var (name, type, result, duration) = invocation; + var ((id, name, type, lifetime, strategy), result, duration) = invocation; - Assert.Equal(expectedName, name); - Assert.Equal(expectedType, type); + Assert.Equal(expectedDescription.Id, id); + Assert.Equal(expectedDescription.Name, name); + Assert.Equal(expectedDescription.Type, type); + Assert.Equal(expectedDescription.Lifetime, lifetime); + Assert.Equal(expectedDescription.CollisionStrategy, strategy); Assert.Equal(expectedResult, result); Assert.Equal(expectedDuration, duration); } diff --git a/tests/NScatterGather.Tests/Invocations/FaultedInvocation.cs b/tests/NScatterGather.Tests/Invocations/FaultedInvocation.cs index 2cad899..ba94e09 100644 --- a/tests/NScatterGather.Tests/Invocations/FaultedInvocation.cs +++ b/tests/NScatterGather.Tests/Invocations/FaultedInvocation.cs @@ -8,18 +8,28 @@ public class FaultedInvocationTests [Fact] public void Can_be_deconstructed() { - var expectedName = "foo"; - var expectedType = typeof(int); + var expectedDescription = new RecipientDescription( + Guid.NewGuid(), + "My name is", + typeof(SomeType), + Lifetime.Singleton, + CollisionStrategy.UseAllMethodsMatching); + var expectedException = new Exception(); var expectedDuration = TimeSpan.FromSeconds(1); var invocation = new FaultedInvocation( - expectedName, expectedType, expectedException, expectedDuration); + expectedDescription, + expectedException, + expectedDuration); - var (name, type, exception, duration) = invocation; + var ((id, name, type, lifetime, strategy), exception, duration) = invocation; - Assert.Equal(expectedName, name); - Assert.Equal(expectedType, type); + Assert.Equal(expectedDescription.Id, id); + Assert.Equal(expectedDescription.Name, name); + Assert.Equal(expectedDescription.Type, type); + Assert.Equal(expectedDescription.Lifetime, lifetime); + Assert.Equal(expectedDescription.CollisionStrategy, strategy); Assert.Equal(expectedException, exception); Assert.Equal(expectedDuration, duration); } diff --git a/tests/NScatterGather.Tests/Invocations/IncompleteInvocationTests.cs b/tests/NScatterGather.Tests/Invocations/IncompleteInvocationTests.cs index 24d5181..f3c732c 100644 --- a/tests/NScatterGather.Tests/Invocations/IncompleteInvocationTests.cs +++ b/tests/NScatterGather.Tests/Invocations/IncompleteInvocationTests.cs @@ -1,4 +1,5 @@ -using Xunit; +using System; +using Xunit; namespace NScatterGather.Invocations { @@ -7,14 +8,21 @@ public class IncompleteInvocationTests [Fact] public void Can_be_deconstructed() { - var expectedName = "foo"; - var expectedType = typeof(int); + var expectedDescription = new RecipientDescription( + Guid.NewGuid(), + "My name is", + typeof(SomeType), + Lifetime.Singleton, + CollisionStrategy.UseAllMethodsMatching); - var invocation = new IncompleteInvocation(expectedName, expectedType); - var (name, type) = invocation; + var invocation = new IncompleteInvocation(expectedDescription); + var (id, name, type, lifetime, strategy) = invocation.Recipient; - Assert.Equal(expectedName, name); - Assert.Equal(expectedType, type); + Assert.Equal(expectedDescription.Id, id); + Assert.Equal(expectedDescription.Name, name); + Assert.Equal(expectedDescription.Type, type); + Assert.Equal(expectedDescription.Lifetime, lifetime); + Assert.Equal(expectedDescription.CollisionStrategy, strategy); } } } diff --git a/tests/NScatterGather.Tests/Recipients/Collection/RecipientsCollectionTests.cs b/tests/NScatterGather.Tests/Recipients/Collection/RecipientsCollectionTests.cs index ddaba0c..06279ea 100644 --- a/tests/NScatterGather.Tests/Recipients/Collection/RecipientsCollectionTests.cs +++ b/tests/NScatterGather.Tests/Recipients/Collection/RecipientsCollectionTests.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; using Xunit; namespace NScatterGather.Recipients.Collection @@ -16,33 +15,42 @@ public RecipientsCollectionTests() [Fact] public void Can_add_generic_type() { - _collection.Add(); + var id = _collection.Add(); + Assert.NotEqual(default, id); } [Fact] public void Can_add_generic_type_with_name() { - _collection.Add("My name is"); + var id = _collection.Add("My name is"); + Assert.NotEqual(default, id); } [Fact] public void Can_add_generic_type_with_lifetime() { - _collection.Add(Lifetime.Transient); - _collection.Add(Lifetime.Scoped); - _collection.Add(Lifetime.Singleton); + var id1 = _collection.Add(Lifetime.Transient); + Assert.NotEqual(default, id1); + + var id2 = _collection.Add(Lifetime.Scoped); + Assert.NotEqual(default, id2); + + var id3 = _collection.Add(Lifetime.Singleton); + Assert.NotEqual(default, id3); } [Fact] public void Can_add_generic_type_with_factory_method() { - _collection.Add(() => new SomeType()); + var id = _collection.Add(() => new SomeType()); + Assert.NotEqual(default, id); } [Fact] public void Can_add_generic_type_with_collision_strategy() { - _collection.Add(CollisionStrategy.UseAllMethodsMatching); + var id = _collection.Add(CollisionStrategy.UseAllMethodsMatching); + Assert.NotEqual(default, id); } [Fact] @@ -62,7 +70,8 @@ public void Error_if_lifetime_is_not_valid() [Fact] public void Can_add_instance() { - _collection.Add(new SomeType()); + var id = _collection.Add(new SomeType()); + Assert.NotEqual(default, id); } [Fact] @@ -100,7 +109,8 @@ public void Error_if_type_is_null() [Fact] public void Can_add_recipient_instance() { - _collection.Add(new SomeType()); + var id = _collection.Add(new SomeType()); + Assert.NotEqual(default, id); } [Fact] diff --git a/tests/NScatterGather.Tests/Recipients/Run/RecipientRunnerTests.cs b/tests/NScatterGather.Tests/Recipients/Run/RecipientRunnerTests.cs index 50afa01..5a0c0dc 100644 --- a/tests/NScatterGather.Tests/Recipients/Run/RecipientRunnerTests.cs +++ b/tests/NScatterGather.Tests/Recipients/Run/RecipientRunnerTests.cs @@ -1,7 +1,10 @@ using System; +using System.Reflection; using System.Threading.Tasks; using NScatterGather.Inspection; using NScatterGather.Recipients; +using NScatterGather.Recipients.Invokers; +using NScatterGather.Recipients.Run; using Xunit; using static NScatterGather.CollisionStrategy; @@ -155,5 +158,59 @@ public async Task Reflection_exception_are_decomposed() Assert.NotNull(runner.Exception); Assert.Equal("An invocation failure.", runner.Exception!.Message); } + + [Fact] + public async Task Aggregate_exception_without_inner_is_handled() + { + var aggEx = new AggregateException("Empty inner exceptions"); + var runner = new RecipientRunner(_recipient, new PreparedInvocation(() => throw aggEx)); + + await runner.Start(); + Assert.Same(aggEx, runner.Exception); + } + + [Fact] + public async Task Aggregate_exception_with_inner_is_handled() + { + var ex1 = new Exception(); + var ex2 = new Exception(); + var aggEx = new AggregateException(ex1, ex2); + var runner = new RecipientRunner(_recipient, new PreparedInvocation(() => throw aggEx)); + + await runner.Start(); + Assert.Same(aggEx, runner.Exception); + } + + [Fact] + public async Task Aggregate_exception_with_one_inner_is_handled() + { + var ex = new Exception(); + var aggEx = new AggregateException(ex); + var runner = new RecipientRunner(_recipient, new PreparedInvocation(() => throw aggEx)); + + await runner.Start(); + Assert.Same(ex, runner.Exception); + } + + [Fact] + public async Task Target_invocation_exception_without_inner_is_handled() + { + var tiEx = new TargetInvocationException("Empty inner exception", null); + var runner = new RecipientRunner(_recipient, new PreparedInvocation(() => throw tiEx)); + + await runner.Start(); + Assert.Same(tiEx, runner.Exception); + } + + [Fact] + public async Task Target_invocation_exception_with_inner_is_handled() + { + var ex = new Exception(); + var tiEx = new TargetInvocationException(ex); + var runner = new RecipientRunner(_recipient, new PreparedInvocation(() => throw tiEx)); + + await runner.Start(); + Assert.Same(ex, runner.Exception); + } } } diff --git a/tests/NScatterGather.Tests/Responses/AggregatedResponseExtensionsTests.cs b/tests/NScatterGather.Tests/Responses/AggregatedResponseExtensionsTests.cs index f90d872..31e9b99 100644 --- a/tests/NScatterGather.Tests/Responses/AggregatedResponseExtensionsTests.cs +++ b/tests/NScatterGather.Tests/Responses/AggregatedResponseExtensionsTests.cs @@ -51,7 +51,7 @@ public void Can_be_projected_onto_results_dictionary() var results = response.AsResultsDictionary(); Assert.NotNull(results); Assert.Single(results.Keys); - Assert.Equal(typeof(SomeType), results.Keys.First()); + Assert.Equal(typeof(SomeType), results.Keys.First().Type); Assert.Single(results.Values); Assert.Equal("42", results.Values.First()); } diff --git a/tests/NScatterGather.Tests/Responses/AggregatedResponseTests.cs b/tests/NScatterGather.Tests/Responses/AggregatedResponseTests.cs index 97ade03..5d5622c 100644 --- a/tests/NScatterGather.Tests/Responses/AggregatedResponseTests.cs +++ b/tests/NScatterGather.Tests/Responses/AggregatedResponseTests.cs @@ -47,13 +47,13 @@ public void Invocations_are_grouped_correctly() { var response = AggregatedResponseFactory.CreateFrom(_runners); - Assert.Equal(typeof(SomeType), response.Completed[0].RecipientType); + Assert.Equal(typeof(SomeType), response.Completed[0].Recipient.Type); Assert.Equal("42", response.Completed[0].Result); - Assert.Equal(typeof(SomeFaultingType), response.Faulted[0].RecipientType); + Assert.Equal(typeof(SomeFaultingType), response.Faulted[0].Recipient.Type); Assert.Equal("A failure.", response.Faulted[0].Exception?.Message); - Assert.Equal(typeof(SomeNeverEndingType), response.Incomplete[0].RecipientType); + Assert.Equal(typeof(SomeNeverEndingType), response.Incomplete[0].Recipient.Type); } [Fact]