diff --git a/src/core/Akka.TestKit.Tests/Akka.TestKit.Tests.csproj b/src/core/Akka.TestKit.Tests/Akka.TestKit.Tests.csproj index 220b17aef65..670f9c73307 100644 --- a/src/core/Akka.TestKit.Tests/Akka.TestKit.Tests.csproj +++ b/src/core/Akka.TestKit.Tests/Akka.TestKit.Tests.csproj @@ -4,6 +4,7 @@ Akka.TestKit.Tests $(NetFrameworkTestVersion);$(NetTestVersion);$(NetCoreTestVersion) + 8.0 diff --git a/src/core/Akka.TestKit.Tests/TestKitBaseTests/ReceiveTests.cs b/src/core/Akka.TestKit.Tests/TestKitBaseTests/ReceiveTests.cs index 6963f5c7e90..208fad462f5 100644 --- a/src/core/Akka.TestKit.Tests/TestKitBaseTests/ReceiveTests.cs +++ b/src/core/Akka.TestKit.Tests/TestKitBaseTests/ReceiveTests.cs @@ -7,98 +7,95 @@ using System; using System.Collections; -using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Akka.Actor; -using Akka.TestKit; using FluentAssertions; using Xunit; using Xunit.Sdk; +using static FluentAssertions.FluentActions; -namespace Akka.Testkit.Tests.TestKitBaseTests +namespace Akka.TestKit.Tests.TestKitBaseTests { public class ReceiveTests : AkkaSpec { [Fact] - public void ReceiveN_should_receive_correct_number_of_messages() + public async Task ReceiveNAsync_should_receive_correct_number_of_messages() { TestActor.Tell("1"); TestActor.Tell("2"); TestActor.Tell("3"); TestActor.Tell("4"); - ReceiveN(3).ShouldOnlyContainInOrder("1", "2", "3"); - ReceiveN(1).ShouldOnlyContainInOrder("4"); + await ReceiveNAsync(3).ShouldOnlyContainInOrderAsync("1", "2", "3"); + await ReceiveNAsync(1).ShouldOnlyContainInOrderAsync("4"); } [Fact] - public void ReceiveN_should_timeout_if_no_messages() + public async Task ReceiveNAsync_should_timeout_if_no_messages() { - Intercept(() => ReceiveN(3, TimeSpan.FromMilliseconds(10))); + await Awaiting(async () => await ReceiveNAsync(3, TimeSpan.FromMilliseconds(10)).ToListAsync()) + .Should().ThrowAsync(); } [Fact] - public void ReceiveN_should_timeout_if_to_few_messages() + public async Task ReceiveNAsync_should_timeout_if_to_few_messages() { TestActor.Tell("1"); TestActor.Tell("2"); - Intercept(() => ReceiveN(3, TimeSpan.FromMilliseconds(100))); + await Awaiting(async () => await ReceiveNAsync(3, TimeSpan.FromMilliseconds(100)).ToListAsync()) + .Should().ThrowAsync(); } - [Fact] - public void FishForMessage_should_return_matched_message() + public async Task FishForMessageAsync_should_return_matched_message() { TestActor.Tell(1); TestActor.Tell(2); TestActor.Tell(10); TestActor.Tell(20); - FishForMessage(i => i >= 10).ShouldBe(10); + await FishForMessageAsync(i => i >= 10).ShouldBeAsync(10); } [Fact] - public void FishForMessage_should_timeout_if_no_messages() + public async Task FishForMessageAsync_should_timeout_if_no_messages() { - Intercept(() => FishForMessage(_ => false, TimeSpan.FromMilliseconds(10))); + await Awaiting(async () => await FishForMessageAsync(_ => false, TimeSpan.FromMilliseconds(10))) + .Should().ThrowAsync(); } [Fact] - public void FishForMessage_should_timeout_if_to_few_messages() + public async Task FishForMessageAsync_should_timeout_if_too_few_messages() { TestActor.Tell("1"); TestActor.Tell("2"); - Intercept(() => FishForMessage(_ => false, TimeSpan.FromMilliseconds(100))); + await Awaiting(async () => await FishForMessageAsync(_ => false, TimeSpan.FromMilliseconds(100))) + .Should().ThrowAsync(); } [Fact] - public async Task FishForMessage_should_fill_the_all_messages_param_if_not_null() + public async Task FishForMessageAsync_should_fill_the_all_messages_param_if_not_null() { - await Task.Run(delegate - { - var probe = base.CreateTestProbe("probe"); - probe.Tell("1"); - probe.Tell(2); - probe.Tell("3"); - probe.Tell(4); - var allMessages = new ArrayList(); - probe.FishForMessage(isMessage: s => s == "3", allMessages: allMessages); - allMessages.Should().BeEquivalentTo(new ArrayList { "1", 2 }); - }); + var probe = CreateTestProbe("probe"); + probe.Tell("1"); + probe.Tell(2); + probe.Tell("3"); + probe.Tell(4); + var allMessages = new ArrayList(); + await probe.FishForMessageAsync(isMessage: s => s == "3", allMessages: allMessages); + allMessages.Should().BeEquivalentTo(new ArrayList { "1", 2 }); } [Fact] - public async Task FishForMessage_should_clear_the_all_messages_param_if_not_null_before_filling_it() + public async Task FishForMessageAsync_should_clear_the_all_messages_param_if_not_null_before_filling_it() { - await Task.Run(delegate - { - var probe = base.CreateTestProbe("probe"); - probe.Tell("1"); - probe.Tell(2); - probe.Tell("3"); - probe.Tell(4); - var allMessages = new ArrayList() { "pre filled data" }; - probe.FishForMessage(isMessage: x => x == "3", allMessages: allMessages); - allMessages.Should().BeEquivalentTo(new ArrayList { "1", 2 }); - }); + var probe = CreateTestProbe("probe"); + probe.Tell("1"); + probe.Tell(2); + probe.Tell("3"); + probe.Tell(4); + var allMessages = new ArrayList { "pre filled data" }; + await probe.FishForMessageAsync(isMessage: x => x == "3", allMessages: allMessages); + allMessages.Should().BeEquivalentTo(new ArrayList { "1", 2 }); } [Fact] @@ -106,17 +103,17 @@ public async Task FishUntilMessageAsync_should_succeed_with_good_input() { var probe = CreateTestProbe("probe"); probe.Ref.Tell(1d, TestActor); - await probe.FishUntilMessageAsync(max: TimeSpan.FromMilliseconds(10)); + await Awaiting(() => probe.FishUntilMessageAsync(max: TimeSpan.FromMilliseconds(10))) + .Should().NotThrowAsync(); } - [Fact] public async Task FishUntilMessageAsync_should_fail_with_bad_input() { var probe = CreateTestProbe("probe"); probe.Ref.Tell(3, TestActor); - Func func = () => probe.FishUntilMessageAsync(max: TimeSpan.FromMilliseconds(10)); - await func.Should().ThrowAsync(); + await Awaiting(() => probe.FishUntilMessageAsync(max: TimeSpan.FromMilliseconds(10))) + .Should().ThrowAsync(); } [Fact] @@ -169,86 +166,82 @@ public async Task WaitForRadioSilenceAsync_should_fail_immediately_with_bad_inpu { var probe = CreateTestProbe("probe"); probe.Ref.Tell(3, TestActor); - try - { - await probe.WaitForRadioSilenceAsync(max: TimeSpan.FromMilliseconds(0), maxMessages: 0); - Assert.True(false, "we should never get here"); - } - catch (XunitException) { } + await Awaiting(() => probe.WaitForRadioSilenceAsync(max: TimeSpan.FromMilliseconds(0), maxMessages: 0)) + .Should().ThrowAsync().WithMessage("maxMessages violated*"); } [Fact] - public void ReceiveWhile_Filter_should_on_a_timeout_return_no_messages() + public async Task ReceiveWhileAsync_Filter_should_on_a_timeout_return_no_messages() { - ReceiveWhile(_ => _, TimeSpan.FromMilliseconds(10)).Count.ShouldBe(0); + await using var e = ReceiveWhileAsync(_ => _, TimeSpan.FromMilliseconds(10)).GetAsyncEnumerator(); + (await e.MoveNextAsync()).Should().BeFalse(); } [Fact] - public void ReceiveWhile_Filter_should_break_on_function_returning_null_and_return_correct_messages() + public async Task ReceiveWhileAsync_Filter_should_break_on_function_returning_null_and_return_correct_messages() { TestActor.Tell("1"); TestActor.Tell(2); TestActor.Tell("3"); TestActor.Tell(99999.0); TestActor.Tell(4); - ReceiveWhile(_ => _ is double ? null : _.ToString()).ShouldOnlyContainInOrder("1", "2", "3"); + await ReceiveWhileAsync(_ => _ is double ? null : _.ToString()).ShouldOnlyContainInOrderAsync("1", "2", "3"); } [Fact] - public void ReceiveWhile_Filter_should_not_consume_last_message_that_didnt_match() + public async Task ReceiveWhileAsync_Filter_should_not_consume_last_message_that_didnt_match() { TestActor.Tell("1"); TestActor.Tell("2"); TestActor.Tell(4711); - ReceiveWhile(_ => _ is string ? _ : null); - ExpectMsg(4711); + await ReceiveWhileAsync(_ => _ is string ? _ : null).ToListAsync(); + await ExpectMsgAsync(4711); } [Fact] - public void ReceiveWhile_Predicate_should_on_a_timeout_return_no_messages() + public async Task ReceiveWhileAsync_Predicate_should_on_a_timeout_return_no_messages() { - ReceiveWhile(_ => false, TimeSpan.FromMilliseconds(10)).Count.ShouldBe(0); + await using var e = ReceiveWhileAsync(_ => false, TimeSpan.FromMilliseconds(10)).GetAsyncEnumerator(); + (await e.MoveNextAsync()).Should().BeFalse(); } [Fact] - public void ReceiveWhile_Predicate_should_break_when_predicate_returns_false_and_return_correct_messages() + public async Task ReceiveWhileAsync_Predicate_should_break_when_predicate_returns_false_and_return_correct_messages() { TestActor.Tell("1"); TestActor.Tell("2"); TestActor.Tell("3"); TestActor.Tell("-----------"); TestActor.Tell("4"); - ReceiveWhile(s => s.Length == 1).ShouldOnlyContainInOrder("1", "2", "3"); + await ReceiveWhileAsync(s => s.Length == 1).ShouldOnlyContainInOrderAsync("1", "2", "3"); } [Fact] - public void - ReceiveWhile_Predicate_should_break_when_type_is_wrong_and_we_dont_ignore_those_and_return_correct_messages() + public async Task ReceiveWhileAsync_Predicate_should_break_when_type_is_wrong_and_we_dont_ignore_those_and_return_correct_messages() { TestActor.Tell("1"); TestActor.Tell("2"); TestActor.Tell("3"); TestActor.Tell(4); TestActor.Tell("5"); - ReceiveWhile(s => s.Length == 1, shouldIgnoreOtherMessageTypes: false) - .ShouldOnlyContainInOrder("1", "2", "3"); + await ReceiveWhileAsync(s => s.Length == 1, shouldIgnoreOtherMessageTypes: false) + .ShouldOnlyContainInOrderAsync("1", "2", "3"); } [Fact] - public void - ReceiveWhile_Predicate_should_continue_when_type_is_other_but_we_ignore_other_types_and_return_correct_messages() + public async Task ReceiveWhileAsync_Predicate_should_continue_when_type_is_other_but_we_ignore_other_types_and_return_correct_messages() { TestActor.Tell("1"); TestActor.Tell("2"); TestActor.Tell("3"); TestActor.Tell(4); TestActor.Tell("5"); - ReceiveWhile(s => s.Length == 1, shouldIgnoreOtherMessageTypes: true) - .ShouldOnlyContainInOrder("1", "2", "3", "5"); + await ReceiveWhileAsync(s => s.Length == 1, shouldIgnoreOtherMessageTypes: true) + .ShouldOnlyContainInOrderAsync("1", "2", "3", "5"); } [Fact] - public void ReceiveWhile_Predicate_should_not_consume_last_message_that_didnt_match() + public async Task ReceiveWhileAsync_Predicate_should_not_consume_last_message_that_didnt_match() { TestActor.Tell("1"); TestActor.Tell("2"); @@ -260,15 +253,10 @@ public void ReceiveWhile_Predicate_should_not_consume_last_message_that_didnt_ma TestActor.Tell("7"); TestActor.Tell("8"); - var received = ReceiveWhile(_ => _ is string); - received.ShouldOnlyContainInOrder("1", "2"); - - ExpectMsg(4711); - - received = ReceiveWhile(_ => _ is string); - received.ShouldOnlyContainInOrder("3", "4", "5"); - - ExpectMsg(6); + await ReceiveWhileAsync(_ => _ is string).ShouldOnlyContainInOrderAsync("1", "2"); + await ExpectMsgAsync(4711); + await ReceiveWhileAsync(_ => _ is string).ShouldOnlyContainInOrderAsync("3", "4", "5"); + await ExpectMsgAsync(6); } } } \ No newline at end of file diff --git a/src/core/Akka.TestKit/TestKitBase_Receive.cs b/src/core/Akka.TestKit/TestKitBase_Receive.cs index 922fc1925b8..eee1d2c6ecc 100644 --- a/src/core/Akka.TestKit/TestKitBase_Receive.cs +++ b/src/core/Akka.TestKit/TestKitBase_Receive.cs @@ -730,7 +730,7 @@ public IReadOnlyCollection ReceiveN( /// public async IAsyncEnumerable ReceiveNAsync( int numberOfMessages, - [EnumeratorCancellation] CancellationToken cancellationToken) + [EnumeratorCancellation] CancellationToken cancellationToken = default) { var enumerable = InternalReceiveNAsync(numberOfMessages, RemainingOrDefault, true, cancellationToken) .ConfigureAwait(false).WithCancellation(cancellationToken); diff --git a/src/core/Akka.Tests.Shared.Internals/Akka.Tests.Shared.Internals.csproj b/src/core/Akka.Tests.Shared.Internals/Akka.Tests.Shared.Internals.csproj index 759da88562b..6def2bfa86c 100644 --- a/src/core/Akka.Tests.Shared.Internals/Akka.Tests.Shared.Internals.csproj +++ b/src/core/Akka.Tests.Shared.Internals/Akka.Tests.Shared.Internals.csproj @@ -1,7 +1,8 @@  - $(NetStandardLibVersion) + $(NetStandardLibVersion) + 8.0 diff --git a/src/core/Akka.Tests.Shared.Internals/AkkaSpecExtensions.cs b/src/core/Akka.Tests.Shared.Internals/AkkaSpecExtensions.cs index 957540559b5..ba0d889b264 100644 --- a/src/core/Akka.Tests.Shared.Internals/AkkaSpecExtensions.cs +++ b/src/core/Akka.Tests.Shared.Internals/AkkaSpecExtensions.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Akka.Util.Internal; using Xunit; +using Xunit.Sdk; // ReSharper disable once CheckNamespace namespace Akka.TestKit @@ -51,10 +52,50 @@ public static void ShouldHaveCount(this IReadOnlyCollection self, int expe /// TBD public static void ShouldBe(this IEnumerable self, IEnumerable other) { - var expected = string.Join(",", other.Select(i => string.Format("'{0}'", i))); - var actual = string.Join(",", self.Select(i => string.Format("'{0}'", i))); + var otherList = other.ToList(); + var selfList = self.ToList(); + var expected = string.Join(",", otherList.Select(i => $"'{i}'")); + var actual = string.Join(",", selfList.Select(i => $"'{i}'")); - Assert.True(self.SequenceEqual(other), "Expected " + expected + " got " + actual); + Assert.True(selfList.SequenceEqual(otherList), "Expected " + expected + " got " + actual); + } + + public static async Task ShouldBeAsync(this IAsyncEnumerable self, IEnumerable other) + { + if (self is null) + throw new ArgumentNullException(nameof(self)); + if (other is null) + throw new ArgumentNullException(nameof(other)); + + var l1 = new List(); + var l2 = new List(); + var index = 0; + + await using var e1 = self.GetAsyncEnumerator(); + using var e2 = other.GetEnumerator(); + + var comparer = EqualityComparer.Default; + while (await e1.MoveNextAsync()) + { + l1.Add($"'{e1.Current}'"); + if (!e2.MoveNext()) + throw new AssertActualExpectedException( + l2, l1, $"Input has more elements than expected, differ at index {index}"); + + l2.Add($"'{e2.Current}'"); + if(!comparer.Equals(e1.Current, e2.Current)) + throw new AssertActualExpectedException( + l2, l1, $"Input is not equal to expected, differ at index {index}"); + + index++; + } + + if (e2.MoveNext()) + { + l2.Add($"'{e2.Current}'"); + throw new AssertActualExpectedException( + l2, l1, $"Input has less elements than expected, differ at index {index}"); + } } /// @@ -69,6 +110,18 @@ public static void ShouldBe(this T self, T expected, string message = null) Assert.Equal(expected, self); } + /// + /// TBD + /// + /// TBD + /// TBD + /// TBD + /// TBD + public static async Task ShouldBeAsync(this ValueTask self, T expected, string message = null) + { + Assert.Equal(expected, await self); + } + /// /// TBD /// @@ -199,6 +252,15 @@ public static void ShouldOnlyContainInOrder(this IEnumerable actual, param ShouldBe(actual, expected); } + /// + /// TBD + /// + /// TBD + /// TBD + /// TBD + public static async Task ShouldOnlyContainInOrderAsync(this IAsyncEnumerable actual, params T[] expected) + => await ShouldBeAsync(actual, expected).ConfigureAwait(false); + /// /// TBD ///