Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Async TestKit] Fix WithinAsync and Remaining logic #6010

Conversation

Arkatufus
Copy link
Contributor

@Arkatufus Arkatufus commented Jun 20, 2022

Changes

  • Make sure that Remaining always return a positive TimeSpan
  • Put a limit on how long WithinAsync will wait for the function block to complete. Prevents bad unit tests from deadlocking the entire unit test suite.
  • Make WithinAsync use the cancellationToken passed in the function parameter
  • Fix some assertion and error message errors
  • Warn user if unit test is waiting or peeking with infinite timeout
  • Guard against negative duration values in Dilated

@Arkatufus Arkatufus changed the title Fix WithinAsync and Remaining logic [Async TestKit] Fix WithinAsync and Remaining logic Jun 20, 2022
@Aaronontheweb
Copy link
Member

@Arkatufus looks like you have a DocFx build error here

@Arkatufus
Copy link
Contributor Author

Looks like it creeped past the last merge, it should be fixed in #6012

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - caught a lot of small errors in the testkit itself. Should help a lot with test hygiene going forward. Nice work @Arkatufus

@@ -150,7 +150,8 @@ protected async Task<TimeSpan> TimeUntilPassivate(IActorRef region, TestProbe pr
probe.ExpectMsg<Entity.GotIt>().Id.ShouldBe("2");

var timeSinceOneSawAMessage = DateTime.Now.Ticks - timeOneSawMessage;
return settings.PassivateIdleEntityAfter - TimeSpan.FromTicks(timeSinceOneSawAMessage) + smallTolerance;
var time = settings.PassivateIdleEntityAfter - TimeSpan.FromTicks(timeSinceOneSawAMessage) + smallTolerance;
return time < smallTolerance ? smallTolerance : time;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - prevents negative timespans from being returned. Nice catch.

@@ -94,7 +94,7 @@ await outputStream.WriteAsync(_bytesArray, 0, _bytesArray.Length)
var f = outputStream.FlushAsync();

await ExpectTimeout(f, Timeout);
await probe.ExpectNoMsgAsync(TimeSpan.MinValue);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this was definitely an error.

@@ -130,7 +130,7 @@ public static bool IsInfiniteTimeout(this TimeSpan? timeSpan)
public static void EnsureIsPositiveFinite(this TimeSpan timeSpan, string parameterName)
{
if(!IsPositiveFinite(timeSpan))
throw new ArgumentException($"The timespan must be greater than zero. Actual value: {timeSpan}", nameof(parameterName));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this was a bug. Nice catch.

throw new InvalidOperationException(@"Remaining may not be called outside of ""within""");

if (_testState.End < TimeSpan.Zero)
throw new InvalidOperationException($"End can not be negative, was: {_testState.End}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sanity check

@@ -448,7 +456,7 @@ protected TimeSpan RemainingOr(TimeSpan duration)
public TimeSpan RemainingOrDilated(TimeSpan? duration)
{
if(!duration.HasValue) return RemainingOrDefault;
if(duration.IsInfinite()) throw new ArgumentException("max duration cannot be infinite");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only considered -1, whereas now we check for all possible negative timespan values.

@@ -267,7 +267,7 @@ public async ValueTask<object> ReceiveOneAsync(TimeSpan? max = null, Cancellatio
}
else if (maxDuration == Timeout.InfiniteTimeSpan)
{
ConditionalLog(shouldLog, "Trying to receive message from TestActor queue. Will wait indefinitely.");
Log.Warning("Trying to receive message from TestActor queue with infinite timeout! Will wait indefinitely!");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to explicitly warn here.

var executionTask = function();
// Limit the execution time block to the maximum allowed execution time.
// 200 milliseconds is added because Task.Delay() timer is not precise and can return prematurely.
var resultTask = await Task.WhenAny(executionTask, Task.Delay(max + 200.Milliseconds(), cts.Token));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, so this ensures that even if the CTS isn't fired we can still cap the execution time for any spec to max + 200.milliseconds

@Aaronontheweb Aaronontheweb merged commit f3469d7 into akkadotnet:dev Jun 24, 2022
@Arkatufus Arkatufus deleted the async_testkit/Fix_WithinAsync_and_Remaining branch February 27, 2023 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants