Added test driver program for service host (#113)

* Added test driver program for service host

* Fix typo
This commit is contained in:
Mitchell Sternke
2016-10-21 17:49:37 -07:00
committed by GitHub
parent 5a7b412c38
commit b389d275a2
5 changed files with 345 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
//
// The following is based upon code from PowerShell Editor Services
// License: https://github.com/PowerShell/PowerShellEditorServices/blob/develop/LICENSE
//
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Channel;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
{
/// <summary>
/// Test driver for the service host
/// </summary>
public class ServiceTestDriver : TestDriverBase
{
public ServiceTestDriver(string serviceHostExecutable)
{
var clientChannel = new StdioClientChannel(serviceHostExecutable);
this.protocolClient = new ProtocolEndpoint(clientChannel, MessageProtocolType.LanguageServer);
}
public async Task Start()
{
await this.protocolClient.Start();
await Task.Delay(1000); // Wait for the service host to start
}
public async Task Stop()
{
await this.protocolClient.Stop();
}
}
}

View File

@@ -0,0 +1,173 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
//
// The following is based upon code from PowerShell Editor Services
// License: https://github.com/PowerShell/PowerShellEditorServices/blob/develop/LICENSE
//
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Driver
{
/// <summary>
/// Wraps the ProtocolEndpoint class with queues to handle events/requests
/// </summary>
public class TestDriverBase
{
protected ProtocolEndpoint protocolClient;
private ConcurrentDictionary<string, AsyncQueue<object>> eventQueuePerType =
new ConcurrentDictionary<string, AsyncQueue<object>>();
private ConcurrentDictionary<string, AsyncQueue<object>> requestQueuePerType =
new ConcurrentDictionary<string, AsyncQueue<object>>();
public Task<TResult> SendRequest<TParams, TResult>(
RequestType<TParams, TResult> requestType,
TParams requestParams)
{
return
this.protocolClient.SendRequest(
requestType,
requestParams);
}
public Task SendEvent<TParams>(EventType<TParams> eventType, TParams eventParams)
{
return
this.protocolClient.SendEvent(
eventType,
eventParams);
}
public void QueueEventsForType<TParams>(EventType<TParams> eventType)
{
var eventQueue =
this.eventQueuePerType.AddOrUpdate(
eventType.MethodName,
new AsyncQueue<object>(),
(key, queue) => queue);
this.protocolClient.SetEventHandler(
eventType,
(p, ctx) =>
{
return eventQueue.EnqueueAsync(p);
});
}
public async Task<TParams> WaitForEvent<TParams>(
EventType<TParams> eventType,
int timeoutMilliseconds = 5000)
{
Task<TParams> eventTask = null;
// Use the event queue if one has been registered
AsyncQueue<object> eventQueue = null;
if (this.eventQueuePerType.TryGetValue(eventType.MethodName, out eventQueue))
{
eventTask =
eventQueue
.DequeueAsync()
.ContinueWith<TParams>(
task => (TParams)task.Result);
}
else
{
TaskCompletionSource<TParams> eventTaskSource = new TaskCompletionSource<TParams>();
this.protocolClient.SetEventHandler(
eventType,
(p, ctx) =>
{
if (!eventTaskSource.Task.IsCompleted)
{
eventTaskSource.SetResult(p);
}
return Task.FromResult(true);
},
true); // Override any existing handler
eventTask = eventTaskSource.Task;
}
await
Task.WhenAny(
eventTask,
Task.Delay(timeoutMilliseconds));
if (!eventTask.IsCompleted)
{
throw new TimeoutException(
string.Format(
"Timed out waiting for '{0}' event!",
eventType.MethodName));
}
return await eventTask;
}
public async Task<Tuple<TParams, RequestContext<TResponse>>> WaitForRequest<TParams, TResponse>(
RequestType<TParams, TResponse> requestType,
int timeoutMilliseconds = 5000)
{
Task<Tuple<TParams, RequestContext<TResponse>>> requestTask = null;
// Use the request queue if one has been registered
AsyncQueue<object> requestQueue = null;
if (this.requestQueuePerType.TryGetValue(requestType.MethodName, out requestQueue))
{
requestTask =
requestQueue
.DequeueAsync()
.ContinueWith(
task => (Tuple<TParams, RequestContext<TResponse>>)task.Result);
}
else
{
var requestTaskSource =
new TaskCompletionSource<Tuple<TParams, RequestContext<TResponse>>>();
this.protocolClient.SetRequestHandler(
requestType,
(p, ctx) =>
{
if (!requestTaskSource.Task.IsCompleted)
{
requestTaskSource.SetResult(
new Tuple<TParams, RequestContext<TResponse>>(p, ctx));
}
return Task.FromResult(true);
});
requestTask = requestTaskSource.Task;
}
await
Task.WhenAny(
requestTask,
Task.Delay(timeoutMilliseconds));
if (!requestTask.IsCompleted)
{
throw new TimeoutException(
string.Format(
"Timed out waiting for '{0}' request!",
requestType.MethodName));
}
return await requestTask;
}
}
}

View File

@@ -0,0 +1,66 @@
//
// 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.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.TestDriver.Driver;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver
{
internal class Program
{
internal static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine( "Microsoft.SqlTools.ServiceLayer.TestDriver.exe <service host executable> [tests]" + Environment.NewLine +
" <service host executable> is the path to the Microsoft.SqlTools.ServiceLayer.exe executable" + Environment.NewLine +
" [tests] is a space-separated list of tests to run." + Environment.NewLine +
" They are qualified within the Microsoft.SqlTools.ServiceLayer.TestDriver.Tests namespace");
Environment.Exit(0);
}
Task.Run(async () =>
{
var serviceHostExecutable = args[0];
var tests = args.Skip(1);
foreach (var test in tests)
{
ServiceTestDriver driver = null;
try
{
driver = new ServiceTestDriver(serviceHostExecutable);
var className = test.Substring(0, test.LastIndexOf('.'));
var methodName = test.Substring(test.LastIndexOf('.') + 1);
var type = Type.GetType("Microsoft.SqlTools.ServiceLayer.TestDriver.Tests." + className);
var typeInstance = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod(methodName);
await driver.Start();
Console.WriteLine("Running test " + test);
await (Task)methodInfo.Invoke(typeInstance, new object[] {driver});
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
if (driver != null)
{
await driver.Stop();
}
}
}
}).Wait();
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlTools.ServiceLayer.TestDriver.Driver;
namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
{
public class ExampleTests
{
/// <summary>
/// Example test that performs a connect, then disconnect.
/// All tests must have the same signature of returning an async Task
/// and taking in a ServiceTestDriver as a parameter.
/// </summary>
public async Task ConnectDisconnectTest(ServiceTestDriver driver)
{
var connectParams = new ConnectParams();
connectParams.OwnerUri = "file";
connectParams.Connection = new ConnectionDetails();
connectParams.Connection.ServerName = "localhost";
connectParams.Connection.AuthenticationType = "Integrated";
var result = await driver.SendRequest(ConnectionRequest.Type, connectParams);
if (result)
{
await driver.WaitForEvent(ConnectionCompleteNotification.Type);
var disconnectParams = new DisconnectParams();
disconnectParams.OwnerUri = "file";
var result2 = await driver.SendRequest(DisconnectRequest.Type, disconnectParams);
if (result2)
{
Console.WriteLine("success");
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
{
"name": "Microsoft.SqlTools.ServiceLayer.TestDriver",
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.SqlTools.ServiceLayer": {
"target": "project"
}
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0"
}
},
"imports": [
"dotnet5.4",
"portable-net451+win8"
],
}
},
"runtimes": {
"win7-x64": {}
}
}