/// <summary> /// Writes the list of action execution timestamps to the output log. /// </summary> private void VerifyExecutionCount(CallbackActionService service, int expectedCount) { _outputHelper.WriteLine("Action execution times:"); foreach (DateTime timestamp in service.ExecutionTimestamps) { _outputHelper.WriteLine("- {0}", timestamp.TimeOfDay); } Assert.Equal(expectedCount, service.ExecutionTimestamps.Count); }
/// <summary> /// Manually trigger for a number of iterations (<paramref name="iterationCount"/>) and test /// that the actions are invoked for the number of expected iterations (<paramref name="expectedCount"/>) and /// are throttled for the remaining number of iterations. /// </summary> private async Task ManualTriggerAsync( ManualTriggerService triggerService, CallbackActionService callbackService, PipelineCallbacks callbacks, int iterationCount, int expectedCount, MockSystemClock clock, TimeSpan clockIncrementDuration, bool completesOnLastExpectedIteration, CancellationToken token) { if (iterationCount < expectedCount) { throw new InvalidOperationException("Number of iterations must be greater than or equal to number of expected iterations."); } int iteration = 0; Task actionStartedTask; Task actionsThrottledTask = callbacks.StartWaitForActionsThrottled(); // Test that the actions are run for each iteration where the actions are expected to run. while (iteration < expectedCount) { iteration++; TaskCompletionSource <object> startedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); EventHandler startedHandler = (s, e) => startedSource.TrySetResult(null); using var _ = token.Register(() => startedSource.TrySetCanceled(token)); actionStartedTask = await callbackService.StartWaitForCallbackAsync(token); triggerService.NotifyStarted += startedHandler; // Manually invoke the trigger. triggerService.NotifyTriggerSubscribers(); // Wait until action has started. await actionStartedTask.WithCancellation(token); // If the pipeline completes on the last expected iteration, the trigger will not be started again. // Skip this check for the last expected iteration if the pipeline is expected to complete. if (!completesOnLastExpectedIteration || iteration != expectedCount) { await startedSource.WithCancellation(token); } triggerService.NotifyStarted -= startedHandler; // Advance the clock source. clock.Increment(clockIncrementDuration); } // Check that actions were not throttled. Assert.False(actionsThrottledTask.IsCompleted); actionStartedTask = await callbackService.StartWaitForCallbackAsync(token); // Test that actions are throttled for remaining iterations. while (iteration < iterationCount) { iteration++; TaskCompletionSource <object> startedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); EventHandler startedHandler = (s, e) => startedSource.TrySetResult(null); using var _ = token.Register(() => startedSource.TrySetCanceled(token)); actionsThrottledTask = callbacks.StartWaitForActionsThrottled(); triggerService.NotifyStarted += startedHandler; // Manually invoke the trigger. triggerService.NotifyTriggerSubscribers(); // Check throttling has occurred. await actionsThrottledTask.WithCancellation(token); await startedSource.WithCancellation(token); triggerService.NotifyStarted -= startedHandler; // Advance the clock source. clock.Increment(clockIncrementDuration); } // Check that no actions have been executed. Assert.False(actionStartedTask.IsCompleted); }