JD2022-TU1/main/tools/framework/Shuttle/TestsToMove/ManagersTests/AsyncProvider_Tests.cs

393 lines
No EOL
13 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Shuttle.Servers.Managers.AsyncProviders;
using Shuttle.Servers.Managers.AsyncProviders.Exceptions;
namespace Shuttle.TestsToMove.ManagersTests
{
[TestFixture]
public class AsyncProvider_Tests
{
private const int TestTimeout = 10_000; // max duration of a unit test
private const int Resource = 2;
private const string RequestHint = "test";
private const int WaitTimeout = 2_500; // max duration of Wait method
[Test]
public void CreateResourceRequest_ValidHint_ReturnsCorrectToken()
{
// Token can be splitted as date + hint + GUID
// Example of match: 2019-06-25T17:39:01-test-9da80e9f-c46e-433d-b02a-789c608c5422
Regex regex = new Regex(@"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}-" + RequestHint + @"-\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$");
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
Assert.IsNotNull(token);
Assert.IsTrue(regex.IsMatch(token), $"Token should be looking like <date>-<hint>-<GUID> (like this: 2019-06-25T17:39:01-test-9da80e9f-c46e-433d-b02a-789c608c5422), but was '{token}'.");
}
[Test]
public void CreateResourceRequest_Null_ThrowsException()
{
var asyncProvider = new AsyncProvider();
Assert.Throws<ArgumentNullException>(() => asyncProvider.CreateResourceRequest(null));
}
[Test]
[Description("Nobody should ever deposit a null resource. Use the Abort method instead to notify about a null resource.")]
public void DepositResource_NullResource_ThrowsException()
{
var asyncProvider = new AsyncProvider();
string token = asyncProvider.CreateResourceRequest(RequestHint);
Assert.Throws<NullResourceException>(() => asyncProvider.DepositResource(token, null));
}
[Test]
public void DepositResource_NullToken_ThrowsException()
{
var asyncProvider = new AsyncProvider();
Assert.Throws<ArgumentNullException>(() => asyncProvider.DepositResource(null, Resource));
}
[Test]
public void DepositResource_UnknownToken_ThrowsException()
{
var asyncProvider = new AsyncProvider();
Assert.Throws<RequestNotFoundException>(() => asyncProvider.DepositResource("beep boop!", Resource));
}
[Test]
[Description("One and only one resource should ever be deposited for a given request token.")]
public void DepositResource_ParallelDeposit_OnlyOneResourceDeposited()
{
var asyncProvider = new AsyncProvider();
string token = asyncProvider.CreateResourceRequest(RequestHint);
ConcurrentDictionary<int, bool> results = new ConcurrentDictionary<int, bool>();
Parallel.ForEach(Enumerable.Range(1, 1000), i =>
{
try
{
asyncProvider.DepositResource(token, Resource);
results.TryAdd(i, true);
}
catch (RequestNotFoundException)
{
results.TryAdd(i, false);
}
});
var succeded = results.Where(result => result.Value == true).ToList();
var discarded = results.Where(result => result.Value == false).ToList();
Assert.AreEqual(1, succeded.Count);
Assert.AreEqual(999, discarded.Count);
}
[Test]
public void GetResource_ResourceWasCorrectlyDeposited_ReturnsResource()
{
var asyncProvider = new AsyncProvider();
string token = asyncProvider.CreateResourceRequest(RequestHint);
asyncProvider.DepositResource(token, Resource);
int resource = asyncProvider.GetResource<int>(token);
Assert.AreEqual(Resource, resource);
}
[Test]
public void GetResource_ResourceWasNeverDeposited_ThrowsException()
{
var asyncProvider = new AsyncProvider();
string token = asyncProvider.CreateResourceRequest(RequestHint);
Assert.Throws<ResourceNotFoundException>(() => asyncProvider.GetResource<int>(token));
}
[Test]
public void GetResource_ResourceWasAlreadyClaimed_ThrowsException()
{
var asyncProvider = new AsyncProvider();
string token = asyncProvider.CreateResourceRequest(RequestHint);
asyncProvider.DepositResource(token, Resource);
asyncProvider.GetResource<int>(token);
Assert.Throws<ResourceNotFoundException>(() => asyncProvider.GetResource<int>(token));
}
[Test]
[Description("One and only one resource should ever be provided for a given request token.")]
public void GetResource_ParallelGet_OnlyOneResourceProvided()
{
var asyncProvider = new AsyncProvider();
string token = asyncProvider.CreateResourceRequest(RequestHint);
asyncProvider.DepositResource(token, Resource);
ConcurrentDictionary<int, bool> results = new ConcurrentDictionary<int, bool>();
Parallel.ForEach(Enumerable.Range(1, 1000), i =>
{
try
{
asyncProvider.GetResource<int>(token);
results.TryAdd(i, true);
}
catch (ResourceNotFoundException)
{
results.TryAdd(i, false);
}
});
var succeded = results.Where(result => result.Value == true).ToList();
var discarded = results.Where(result => result.Value == false).ToList();
Assert.AreEqual(1, succeded.Count);
Assert.AreEqual(999, discarded.Count);
}
[Test]
public void GetResource_WrongResourceType_ThrowsException()
{
var asyncProvider = new AsyncProvider();
string token = asyncProvider.CreateResourceRequest(RequestHint);
asyncProvider.DepositResource(token, Resource);
Assert.Throws<InvalidResourceTypeException>(() => asyncProvider.GetResource<Delegate>(token)); // Resource is an int, not a Delegate
}
[Test]
public void GetResource_NullToken_ThrowsException()
{
var asyncProvider = new AsyncProvider();
Assert.Throws<ArgumentNullException>(() => asyncProvider.GetResource<int>(null));
}
[Test]
[Timeout(TestTimeout)]
public void Wait_ResourceAlreadyDeposited_ReturnsTrue()
{
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
asyncProvider.DepositResource(token, Resource);
bool success = asyncProvider.Wait(token, WaitTimeout).Result;
Assert.IsTrue(success);
}
[Test]
[Timeout(TestTimeout)]
public void Wait_ResourceyDepositedLater_ReturnsTrue()
{
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
var steps = new Queue<int>();
steps.Enqueue(0);
var thread = new Thread(() => DepositLater(asyncProvider, token, steps));
thread.Start();
steps.Enqueue(1);
bool success = asyncProvider.Wait(token, WaitTimeout).Result;
steps.Enqueue(4);
Assert.IsTrue(success);
Assert.AreEqual(0, steps.Dequeue());
Assert.AreEqual(1, steps.Dequeue());
Assert.AreEqual(2, steps.Dequeue());
Assert.AreEqual(3, steps.Dequeue());
Assert.AreEqual(4, steps.Dequeue());
}
[Test]
[Timeout(TestTimeout)]
public void Wait_ResourceNeverDesposited_ReturnsFalse()
{
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
bool success = asyncProvider.Wait(token, WaitTimeout).Result;
Assert.IsFalse(success);
}
//[Test]
//[Timeout(TestTimeout)]
//public void Wait_CalledThroughTask_IDK()
//{
// var asyncProvider = new AsyncProvider();
// var token = asyncProvider.CreateResourceRequest(RequestHint);
// var steps = new Queue<int>();
// steps.Enqueue(0);
// var thread = new Thread(() => DepositLater(asyncProvider, token, steps));
// thread.Start();
// steps.Enqueue(1);
// var task = new Task<bool>(() =>
// {
// steps.Enqueue(2);
// var waitTask = asyncProvider.Wait(token, WaitTimeout);
// var res = waitTask.Result;
// steps.Enqueue(4);
// return res;
// });
// var success = task.Result;
// steps.Enqueue(4);
// Assert.IsTrue(success);
// Assert.AreEqual(0, steps.Dequeue());
// Assert.AreEqual(1, steps.Dequeue());
// Assert.AreEqual(2, steps.Dequeue());
// Assert.AreEqual(3, steps.Dequeue());
// Assert.AreEqual(4, steps.Dequeue());
//}
[Test]
[Timeout(TestTimeout)]
public void Wait_InvalidToken_ThrowsException()
{
var asyncProvider = new AsyncProvider();
try
{
bool success = asyncProvider.Wait("beep boop!", WaitTimeout).Result;
}
catch (AggregateException e)
{
var inner = e.InnerExceptions[0].GetType();
Assert.AreEqual(typeof(RequestNotFoundException), inner);
}
}
[Test]
[Timeout(TestTimeout)]
public void Wait_NullToken_ThrowsException()
{
var asyncProvider = new AsyncProvider();
try
{
bool success = asyncProvider.Wait(null, WaitTimeout).Result;
}
catch (AggregateException e)
{
var inner = e.InnerExceptions[0].GetType();
Assert.AreEqual(typeof(ArgumentNullException), inner);
}
}
[Test]
[Timeout(TestTimeout)]
public void Wait_NegativeTimeout_ThrowsException()
{
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
try
{
bool success = asyncProvider.Wait(token, -1).Result;
}
catch (AggregateException e)
{
var inner = e.InnerExceptions[0].GetType();
Assert.AreEqual(typeof(ArgumentException), inner);
}
}
[Test]
public void Abort_ValidRequest_RequestGetsDeleted()
{
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
asyncProvider.Abort(token);
Assert.Throws<RequestNotFoundException>(() => asyncProvider.DepositResource(token, Resource));
try
{
bool success = asyncProvider.Wait(token, WaitTimeout).Result;
}
catch (AggregateException e)
{
var inner = e.InnerExceptions[0].GetType();
Assert.AreEqual(typeof(RequestNotFoundException), inner);
}
}
[Test]
[Timeout(TestTimeout)]
public void WaitLongForResource_ValidRequest_ReturnsTrue()
{
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
asyncProvider.DepositResource(token, Resource);
bool success = asyncProvider.WaitLong(token).Result;
Assert.IsTrue(success);
}
[Test]
[Timeout(TestTimeout)]
public void WaitShortForResource_ValidRequest_ReturnsTrue()
{
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
asyncProvider.DepositResource(token, Resource);
bool success = asyncProvider.WaitShort(token).Result;
Assert.IsTrue(success);
}
[Test]
[Timeout(TestTimeout)]
public void WaitShortForResource_ResourceNeverDeposited_ReturnsFalse()
{
var asyncProvider = new AsyncProvider();
var token = asyncProvider.CreateResourceRequest(RequestHint);
bool success = asyncProvider.WaitShort(token).Result;
Assert.IsFalse(success);
}
private void DepositLater(AsyncProvider asyncProvider, string token, Queue<int> queue)
{
Thread.Sleep(1000);
queue.Enqueue(2);
asyncProvider.DepositResource(token, Resource);
queue.Enqueue(3);
}
}
}