Files
Karl Burtram f288bee294 Make nullable warnings a per file opt-in (#1842)
* Make nullable warnings a per file opt-in

* Remove unneeded compiler directives

* Remove compiler directive for User Data
2023-02-03 18:10:07 -08:00

157 lines
6.0 KiB
C#

//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
#nullable disable
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.Hosting.Protocol.Channel;
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Moq;
using NUnit.Framework;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Messaging
{
public class MessageDispatcherTests
{
[Test]
public void SetRequestHandlerWithOverrideTest()
{
RequestType<int, int> requestType = RequestType<int, int>.Create("test/requestType");
var dispatcher = new MessageDispatcher(new Mock<ChannelBase>().Object);
dispatcher.SetRequestHandler<int, int>(
requestType,
(i, j) =>
{
return Task.FromResult(0);
},
true);
Assert.True(dispatcher.requestHandlers.Count > 0);
}
[Test]
public void SetEventHandlerTest()
{
EventType<int> eventType = EventType<int>.Create("test/eventType");
var dispatcher = new MessageDispatcher(new Mock<ChannelBase>().Object);
dispatcher.SetEventHandler<int>(
eventType,
(i, j) =>
{
return Task.FromResult(0);
});
Assert.True(dispatcher.eventHandlers.Count > 0);
}
[Test]
public void SetEventHandlerWithOverrideTest()
{
EventType<int> eventType = EventType<int>.Create("test/eventType");
var dispatcher = new MessageDispatcher(new Mock<ChannelBase>().Object);
dispatcher.SetEventHandler<int>(
eventType,
(i, j) =>
{
return Task.FromResult(0);
},
true);
Assert.True(dispatcher.eventHandlers.Count > 0);
}
[Test]
public void OnListenTaskCompletedFaultedTaskTest()
{
Task t = null;
try
{
t = Task.Run(() =>
{
throw new Exception();
});
t.Wait();
}
catch
{
}
finally
{
bool handlerCalled = false;
var dispatcher = new MessageDispatcher(new Mock<ChannelBase>().Object);
dispatcher.UnhandledException += (s, e) => handlerCalled = true;
dispatcher.OnListenTaskCompleted(t);
Assert.True(handlerCalled);
}
}
[Test]
public void ParallelMessageProcessingTest()
{
int numOfRequests = 10;
int msForEachRequest = 1000;
// Without parallel processing, this should take around numOfRequests * msForEachRequest ms to finish.
// With parallel process, this should take around 1 * msForEachRequest ms to finish in theory (with perfect parallelism).
// The diff should in theory be around (numOfRequests - 1) * msForEachRequest ms.
// In order to make this test stable on machines with poor hardware / few logical cores,
// we loose the assertion by only checking parallel process being faster than sequential processing.
Assert.IsTrue(GetTimeToHandleRequests(false, numOfRequests, msForEachRequest) > GetTimeToHandleRequests(true, numOfRequests, msForEachRequest));
}
/// <summary>
/// Gets the time to handle certain amount of requests in ms
/// </summary>
/// <param name="parallelMessageProcessing">Wheater to enable parallel processing</param>
/// <param name="numOfRequests">num of requests to handle</param>
/// <param name="msForEachRequest">rough time taken to finish each reqeust in ms</param>
/// <returns></returns>
private long GetTimeToHandleRequests(bool parallelMessageProcessing, int numOfRequests, int msForEachRequest)
{
RequestType<int, int> requestType = RequestType<int, int>.Create("test/requestType");
var mockChannel = new Mock<ChannelBase>();
SemaphoreSlim unfinishedRequestCount = new SemaphoreSlim(numOfRequests);
bool okayToEnd = false;
mockChannel.Setup(c => c.MessageReader.ReadMessage())
.Returns(Task.FromResult(Message.Request("1", "test/requestType", null)));
var dispatcher = new MessageDispatcher(mockChannel.Object);
dispatcher.ParallelMessageProcessing = parallelMessageProcessing;
Stopwatch stopwatch = Stopwatch.StartNew();
var handler = async (int _, RequestContext<int> _) =>
{
// simulate a slow sync call
Thread.Sleep(msForEachRequest / 2);
// simulate a delay async call
await Task.Delay(msForEachRequest / 2);
await unfinishedRequestCount.WaitAsync();
if (unfinishedRequestCount.CurrentCount == 0)
{
// cut off when we reach numOfRequests
stopwatch.Stop();
okayToEnd = true;
}
await Task.CompletedTask;
};
dispatcher.SetRequestHandler(requestType, handler, false, true);
dispatcher.Start();
while (true)
{
if (okayToEnd)
{
// wait until we finish handling the required amount of requests
break;
}
Thread.Sleep(1000);
}
dispatcher.Stop();
return stopwatch.ElapsedMilliseconds;
}
}
}