mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 09:59:48 -05:00
* Remove xunit dependency from testdriver * swap expected/actual as needed * Convert Test.Common to nunit * port hosting unit tests to nunit * port batchparser integration tests to nunit * port testdriver.tests to nunit * fix target to copy dependency * port servicelayer unittests to nunit * more unit test fixes * port integration tests to nunit * fix test method type * try using latest windows build for PRs * reduce test memory use
322 lines
12 KiB
C#
322 lines
12 KiB
C#
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
//
|
|
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.SqlTools.DataProtocol.Contracts;
|
|
using Microsoft.SqlTools.Hosting.Channels;
|
|
using Microsoft.SqlTools.Hosting.Contracts;
|
|
using Microsoft.SqlTools.Hosting.Contracts.Internal;
|
|
using Microsoft.SqlTools.Hosting.Protocol;
|
|
using Moq;
|
|
using Newtonsoft.Json.Linq;
|
|
using NUnit.Framework;
|
|
|
|
namespace Microsoft.SqlTools.Hosting.UnitTests.ServiceHostTests
|
|
{
|
|
[TestFixture]
|
|
public class ServiceHostTests
|
|
{
|
|
#region Construction Tests
|
|
|
|
[Test]
|
|
public void ServiceHostConstructDefaultServer()
|
|
{
|
|
// If: I construct a default server service host
|
|
var sh = ServiceHost.CreateDefaultServer();
|
|
|
|
var jh = sh.jsonRpcHost as JsonRpcHost;
|
|
Assert.NotNull(jh);
|
|
Assert.That(jh.protocolChannel, Is.InstanceOf<StdioServerChannel>(), "The underlying json rpc host should be using the stdio server channel");
|
|
Assert.False(jh.protocolChannel.IsConnected);
|
|
}
|
|
|
|
[Test]
|
|
public void ServiceHostNullParameter()
|
|
{
|
|
// If: I create a service host with missing parameters
|
|
// Then: I should get an exception
|
|
Assert.Throws<ArgumentNullException>(() => new ServiceHost(null));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IServiceHost Tests
|
|
|
|
[Test]
|
|
public void RegisterInitializeTask()
|
|
{
|
|
// Setup: Create mock initialize handler
|
|
var mockHandler = new Mock<Func<InitializeParameters, IEventSender, Task>>().Object;
|
|
|
|
// If: I register a couple initialize tasks with the service host
|
|
var sh = GetServiceHost();
|
|
sh.RegisterInitializeTask(mockHandler);
|
|
sh.RegisterInitializeTask(mockHandler);
|
|
|
|
// Then: There should be two initialize tasks registered
|
|
Assert.AreEqual(2, sh.initCallbacks.Count);
|
|
Assert.True(sh.initCallbacks.SequenceEqual(new[] {mockHandler, mockHandler}));
|
|
}
|
|
|
|
[Test]
|
|
public void RegisterInitializeTaskNullHandler()
|
|
{
|
|
// If: I register a null initialize task
|
|
// Then: I should get an exception
|
|
var sh = GetServiceHost();
|
|
Assert.Throws<ArgumentNullException>(() => sh.RegisterInitializeTask(null));
|
|
}
|
|
|
|
[Test]
|
|
public void RegisterShutdownTask()
|
|
{
|
|
// Setup: Create mock initialize handler
|
|
var mockHandler = new Mock<Func<object, IEventSender, Task>>().Object;
|
|
|
|
// If: I register a couple shutdown tasks with the service host
|
|
var sh = GetServiceHost();
|
|
sh.RegisterShutdownTask(mockHandler);
|
|
sh.RegisterShutdownTask(mockHandler);
|
|
|
|
// Then: There should be two initialize tasks registered
|
|
Assert.AreEqual(2, sh.shutdownCallbacks.Count);
|
|
Assert.True(sh.shutdownCallbacks.SequenceEqual(new[] {mockHandler, mockHandler}));
|
|
}
|
|
|
|
[Test]
|
|
public void RegisterShutdownTaskNullHandler()
|
|
{
|
|
// If: I register a null initialize task
|
|
// Then: I should get an exception
|
|
var sh = GetServiceHost();
|
|
Assert.Throws<ArgumentNullException>(() => sh.RegisterShutdownTask(null));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IJsonRpcHost Tests
|
|
|
|
[Test]
|
|
public void SendEvent()
|
|
{
|
|
// If: I send an event
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.SendEvent(CommonObjects.EventType, CommonObjects.TestMessageContents.DefaultInstance);
|
|
|
|
// Then: The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.SendEvent(CommonObjects.EventType, CommonObjects.TestMessageContents.DefaultInstance), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public async Task SendRequest()
|
|
{
|
|
// If: I send a request
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
await sh.SendRequest(CommonObjects.RequestType, CommonObjects.TestMessageContents.DefaultInstance);
|
|
|
|
// Then: The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.SendRequest(CommonObjects.RequestType, CommonObjects.TestMessageContents.DefaultInstance), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public void SetAsyncEventHandler()
|
|
{
|
|
// If: I set an event handler
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.SetAsyncEventHandler(CommonObjects.EventType, null, true);
|
|
|
|
// Then: The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.SetAsyncEventHandler(CommonObjects.EventType, null, true), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public void SetSyncEventHandler()
|
|
{
|
|
// If: I set an event handler
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.SetEventHandler(CommonObjects.EventType, null, true);
|
|
|
|
// Then: The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.SetEventHandler(CommonObjects.EventType, null, true), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public void SetAsyncRequestHandler()
|
|
{
|
|
// If: I set a request handler
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.SetAsyncRequestHandler(CommonObjects.RequestType, null, true);
|
|
|
|
// Then: The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.SetAsyncRequestHandler(CommonObjects.RequestType, null, true), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public void SetSyncRequestHandler()
|
|
{
|
|
// If: I set a request handler
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.SetRequestHandler(CommonObjects.RequestType, null, true);
|
|
|
|
// Then: The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.SetRequestHandler(CommonObjects.RequestType, null, true), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public void Start()
|
|
{
|
|
// If: I start a service host
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.Start();
|
|
|
|
// Then:
|
|
// ... The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.Start(), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public void Stop()
|
|
{
|
|
// If: I stop a service host
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.Stop();
|
|
|
|
// Then: The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.Stop(), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public void WaitForExit()
|
|
{
|
|
// If: I wait for service host to exit
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.WaitForExit();
|
|
|
|
// Then: The underlying json rpc host should have handled it
|
|
jh.Verify(o => o.WaitForExit());
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Request Handling Tests
|
|
|
|
[Test]
|
|
public void HandleExitNotification()
|
|
{
|
|
// If: I handle an exit notification
|
|
var jh = GetJsonRpcHostMock();
|
|
var sh = GetServiceHost(jh.Object);
|
|
sh.HandleExitNotification(null, null);
|
|
|
|
// Then: The json rpc host should have been stopped
|
|
jh.Verify(o => o.Stop(), Times.Once);
|
|
}
|
|
|
|
[Test]
|
|
public async Task HandleInitializeRequest()
|
|
{
|
|
// Setup:
|
|
// ... Create an initialize handler and register it in the service host
|
|
var mockHandler = new Mock<Func<InitializeParameters, IEventSender, Task>>();
|
|
mockHandler.Setup(f => f(It.IsAny<InitializeParameters>(), It.IsAny<IEventSender>()))
|
|
.Returns(Task.FromResult(true));
|
|
|
|
var sh = GetServiceHost();
|
|
sh.RegisterInitializeTask(mockHandler.Object);
|
|
sh.RegisterInitializeTask(mockHandler.Object);
|
|
|
|
// ... Set a dummy value to return as the initialize response
|
|
var ir = new InitializeResponse();
|
|
|
|
// ... Create a mock request that will handle sending a result
|
|
// TODO: Replace with event flow validation
|
|
var initParams = new InitializeParameters();
|
|
var bc = new BlockingCollection<Message>();
|
|
var mockContext = new RequestContext<InitializeResponse>(Message.CreateRequest(InitializeRequest.Type, CommonObjects.MessageId, initParams), bc);
|
|
|
|
// If: I handle an initialize request
|
|
await sh.HandleInitializeRequest(initParams, mockContext);
|
|
|
|
// Then:
|
|
// ... The mock handler should have been called twice
|
|
mockHandler.Verify(h => h(initParams, mockContext), Times.Exactly(2));
|
|
|
|
var outgoing = bc.ToArray();
|
|
Assert.That(outgoing.Select(m => m.Id), Is.EqualTo(new[] { CommonObjects.MessageId }), "There should have been a response sent");
|
|
Assert.AreEqual(JToken.FromObject(ir), JToken.FromObject(ir));
|
|
}
|
|
|
|
[Test]
|
|
public async Task HandleShutdownRequest()
|
|
{
|
|
// Setup:
|
|
// ... Create a shutdown handler and register it in the service host
|
|
var mockHandler = new Mock<Func<object, IEventSender, Task>>();
|
|
mockHandler.Setup(f => f(It.IsAny<object>(), It.IsAny<IEventSender>()))
|
|
.Returns(Task.FromResult(true));
|
|
|
|
var sh = GetServiceHost();
|
|
sh.RegisterShutdownTask(mockHandler.Object);
|
|
sh.RegisterShutdownTask(mockHandler.Object);
|
|
|
|
// ... Create a mock request that will handle sending a result
|
|
// TODO: Replace with the event flow validation
|
|
var shutdownParams = new object();
|
|
var bc = new BlockingCollection<Message>();
|
|
var mockContext = new RequestContext<object>(Message.CreateRequest(ShutdownRequest.Type, CommonObjects.MessageId, shutdownParams), bc);
|
|
|
|
// If: I handle a shutdown request
|
|
await sh.HandleShutdownRequest(shutdownParams, mockContext);
|
|
|
|
mockHandler.Verify(h => h(shutdownParams, mockContext), Times.Exactly(2), "The mock handler should have been called twice");
|
|
|
|
|
|
Assert.That(bc.Count, Is.EqualTo(1), "There should have been a response sent");
|
|
}
|
|
|
|
#endregion
|
|
|
|
private static ServiceHost GetServiceHost(IJsonRpcHost jsonRpcHost = null)
|
|
{
|
|
return new ServiceHost
|
|
{
|
|
jsonRpcHost = jsonRpcHost
|
|
};
|
|
}
|
|
|
|
private static Mock<IJsonRpcHost> GetJsonRpcHostMock()
|
|
{
|
|
var anyEventType = It.IsAny<EventType<object>>();
|
|
var anyRequestType = It.IsAny<RequestType<object, object>>();
|
|
var anyParams = It.IsAny<object>();
|
|
|
|
var mock = new Mock<IJsonRpcHost>();
|
|
mock.Setup(jh => jh.SendEvent(anyEventType, anyParams));
|
|
mock.Setup(jh => jh.SendRequest(anyRequestType, anyParams)).ReturnsAsync(null);
|
|
mock.Setup(jh => jh.SetAsyncEventHandler(anyEventType, It.IsAny<Func<object, EventContext, Task>>(), It.IsAny<bool>()));
|
|
mock.Setup(jh => jh.SetEventHandler(anyEventType, It.IsAny<Action<object, EventContext>>(), It.IsAny<bool>()));
|
|
mock.Setup(jh => jh.SetAsyncRequestHandler(anyRequestType, It.IsAny<Func<object, RequestContext<object>, Task>>(), It.IsAny<bool>()));
|
|
mock.Setup(jh => jh.SetRequestHandler(anyRequestType, It.IsAny<Action<object, RequestContext<object>>>(), It.IsAny<bool>()));
|
|
mock.Setup(jh => jh.Start());
|
|
mock.Setup(jh => jh.Stop());
|
|
mock.Setup(jh => jh.WaitForExit());
|
|
|
|
return mock;
|
|
}
|
|
}
|
|
}
|