using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CommonUtilities.Schedulers;
[TestClass]
public sealed class TimeboundThrottlerTest
{
[TestMethod]
public void Test_TimeboundThrottler_ctor_Success()
{
TimeboundThrottler validThrottler = new TimeboundThrottler(10);
Assert.IsNotNull(validThrottler);
}
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Test_TimeboundThrottler_ctor_Failure()
{
TimeboundThrottler invalidThrottler = new TimeboundThrottler(0);
}
[TestMethod]
public void Test_TimeboundThrottler_Enqueue()
{
TimeboundThrottler throttler = new TimeboundThrottler(3);
int runningTasks = 0;
int completedTasks = 0;
List<Task> tasks = new List<Task>();
List<CancellationTokenSource> cancellationTokens = new List<CancellationTokenSource>();
for (int i = 0; i < 15; i++)
{
var cts = new CancellationTokenSource();
ChangeNotifier notifier = new ChangeNotifier();
notifier.StartStateChanged += (s, e) => { lock (this) { runningTasks++; } };
notifier.CompletedStateChanged += (s, e) => { lock (this) { completedTasks++; } };
cancellationTokens.Add(cts);
tasks.Add(throttler.Enqueue(() => TestFuncWithCancellationAsync(cts, notifier)));
}
// Initially verify that only 3 tasks are picked and rest of the tasks are waiting
Assert.AreEqual(3, runningTasks);
Assert.AreEqual(0, completedTasks);
Thread.Sleep(1100);
// Initially verify that 3 new tasks are picked and rest of the tasks are waiting
Assert.AreEqual(6, runningTasks);
Assert.AreEqual(0, completedTasks);
// Complete one task, still verify that only 3 tasks are picked in next 1sec
cancellationTokens[0].Cancel();
Thread.Sleep(1100);
Assert.AreEqual(9, runningTasks);
Assert.AreEqual(1, completedTasks);
}
[TestMethod]
public void Test_TimeboundThrottler_Enqueue_TaskwithResult()
{
TimeboundThrottler throttler = new TimeboundThrottler(3);
int runningTasks = 0;
int completedTasks = 0;
List<Task<CancellationToken>> tasks = new List<Task<CancellationToken>>();
List<CancellationTokenSource> cancellationTokens = new List<CancellationTokenSource>();
for (int i = 0; i < 15; i++)
{
var cts = new CancellationTokenSource();
ChangeNotifier notifier = new ChangeNotifier();
notifier.StartStateChanged += (s, e) => { lock (this) { runningTasks++; } };
notifier.CompletedStateChanged += (s, e) => { lock (this) { completedTasks++; } };
cancellationTokens.Add(cts);
tasks.Add(throttler.Enqueue(() => TestFuncWithCancellation2Async(cts, notifier)));
}
// Initially verify that only 3 tasks are picked and rest of the tasks are waiting
Assert.AreEqual(3, runningTasks);
Assert.AreEqual(0, completedTasks);
Thread.Sleep(1100);
// Initially verify that 3 new tasks are picked and rest of the tasks are waiting
Assert.AreEqual(6, runningTasks);
Assert.AreEqual(0, completedTasks);
// Complete one task, still verify that only 3 tasks are picked in next 1sec
cancellationTokens[0].Cancel();
Thread.Sleep(1100);
Assert.AreEqual(9, runningTasks);
Assert.AreEqual(1, completedTasks);
Assert.AreEqual(tasks[0].Result, cancellationTokens[0].Token);
}
private async Task TestFuncWithCancellationAsync(CancellationTokenSource cts, ChangeNotifier notifier)
{
notifier.IsStarted = true;
while (true)
{
if (cts.Token.IsCancellationRequested)
{
break;
}
await Task.Delay(1000);
}
notifier.IsCompleted = true;
}
private async Task<CancellationToken> TestFuncWithCancellation2Async(CancellationTokenSource cts, ChangeNotifier notifier)
{
notifier.IsStarted = true;
while (true)
{
if (cts.Token.IsCancellationRequested)
{
break;
}
await Task.Delay(1000);
}
notifier.IsCompleted = true;
return cts.Token;
}
public class ChangeNotifier
{
// Local data
private bool isStarted = false;
private bool isCompleted = false;
// Ctor to assign data
public ChangeNotifier() { this.isStarted = false; this.isCompleted = false; }
// The event that can be subscribed to
public event EventHandler StartStateChanged;
public event EventHandler CompletedStateChanged;
public bool IsStarted
{
get { return this.isStarted; }
set
{
// If the value has changed...
if (this.isStarted != value)
{
// Assign the new value to private storage
this.isStarted = value;
// And raise the event
if (this.StartStateChanged != null)
this.StartStateChanged(this, EventArgs.Empty);
}
}
}
public bool IsCompleted
{
get { return this.isCompleted; }
set
{
// If the value has changed...
if (this.isCompleted != value)
{
// Assign the new value to private storage
this.isCompleted = value;
// And raise the event
if (this.CompletedStateChanged != null)
this.CompletedStateChanged(this, EventArgs.Empty);
}
}
}
}
}
No comments:
Post a Comment