Added task service (#374)

* Added task service
This commit is contained in:
Leila Lali
2017-06-12 11:02:57 -07:00
committed by GitHub
parent 04ed01c88d
commit b0263f8867
22 changed files with 1501 additions and 83 deletions

View File

@@ -396,30 +396,5 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
ServerInfo = TestObjects.GetTestServerInfo()
};
}
private async Task RunAndVerify<T, TResult>(Func<RequestContext<T>, Task<TResult>> test, Action<TResult> verify)
{
T result = default(T);
var contextMock = RequestContextMocks.Create<T>(r => result = r).AddErrorHandling(null);
TResult actualResult = await test(contextMock.Object);
if (actualResult == null && typeof(TResult) == typeof(T))
{
actualResult = (TResult)Convert.ChangeType(result, typeof(TResult));
}
VerifyResult(contextMock, verify, actualResult);
}
private void VerifyResult<T, TResult>(Mock<RequestContext<T>> contextMock, Action<TResult> verify, TResult actual)
{
contextMock.Verify(c => c.SendResult(It.IsAny<T>()), Times.Once);
contextMock.Verify(c => c.SendError(It.IsAny<string>(), It.IsAny<int>()), Times.Never);
verify(actual);
}
private void VerifyErrorSent<T>(Mock<RequestContext<T>> contextMock)
{
contextMock.Verify(c => c.SendResult(It.IsAny<T>()), Times.Never);
contextMock.Verify(c => c.SendError(It.IsAny<string>(), It.IsAny<int>()), Times.Once);
}
}
}

View File

@@ -12,27 +12,16 @@ using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer
{
// Base class providing common test functionality for OE tests
public abstract class ObjectExplorerTestBase
public abstract class ObjectExplorerTestBase : ServiceTestBase
{
protected RegisteredServiceProvider ServiceProvider
{
get;
set;
}
protected RegisteredServiceProvider CreateServiceProviderWithMinServices()
protected override RegisteredServiceProvider CreateServiceProviderWithMinServices()
{
return CreateProvider()
.RegisterSingleService(new ConnectionService())
.RegisterSingleService(new ObjectExplorerService());
}
protected RegisteredServiceProvider CreateProvider()
{
ServiceProvider = new RegisteredServiceProvider();
return ServiceProvider;
}
protected ObjectExplorerService CreateOEService(ConnectionService connService)
{
CreateProvider()

View File

@@ -0,0 +1,71 @@
//
// 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.Threading.Tasks;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
using Moq;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests
{
public abstract class ServiceTestBase
{
protected RegisteredServiceProvider ServiceProvider
{
get;
set;
}
protected RegisteredServiceProvider CreateProvider()
{
ServiceProvider = new RegisteredServiceProvider();
return ServiceProvider;
}
protected abstract RegisteredServiceProvider CreateServiceProviderWithMinServices();
protected async Task RunAndVerify<T, TResult>(Func<RequestContext<T>, Task<TResult>> test, Action<TResult> verify)
{
T result = default(T);
var contextMock = RequestContextMocks.Create<T>(r => result = r).AddErrorHandling(null);
TResult actualResult = await test(contextMock.Object);
if (actualResult == null && typeof(TResult) == typeof(T))
{
actualResult = (TResult)Convert.ChangeType(result, typeof(TResult));
}
VerifyResult<T, TResult>(contextMock, verify, actualResult);
}
protected async Task RunAndVerify<T>(Func<RequestContext<T>, Task> test, Action<T> verify)
{
T result = default(T);
var contextMock = RequestContextMocks.Create<T>(r => result = r).AddErrorHandling(null);
await test(contextMock.Object);
VerifyResult<T>(contextMock, verify, result);
}
protected void VerifyResult<T, TResult>(Mock<RequestContext<T>> contextMock, Action<TResult> verify, TResult actual)
{
contextMock.Verify(c => c.SendResult(It.IsAny<T>()), Times.Once);
contextMock.Verify(c => c.SendError(It.IsAny<string>(), It.IsAny<int>()), Times.Never);
verify(actual);
}
protected void VerifyResult<T>(Mock<RequestContext<T>> contextMock, Action<T> verify, T actual)
{
contextMock.Verify(c => c.SendResult(It.IsAny<T>()), Times.Once);
contextMock.Verify(c => c.SendError(It.IsAny<string>(), It.IsAny<int>()), Times.Never);
verify(actual);
}
protected void VerifyErrorSent<T>(Mock<RequestContext<T>> contextMock)
{
contextMock.Verify(c => c.SendResult(It.IsAny<T>()), Times.Never);
contextMock.Verify(c => c.SendError(It.IsAny<string>(), It.IsAny<int>()), Times.Once);
}
}
}

View File

@@ -0,0 +1,61 @@
//
// 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.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.TaskServices
{
public class DatabaseOperationStub
{
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
public void Stop()
{
IsStopped = true;
}
public void FailTheOperation()
{
Failed = true;
}
public TaskResult TaskResult { get; set; }
public bool IsStopped { get; set; }
public bool Failed { get; set; }
public async Task<TaskResult> FunctionToRun(SqlTask sqlTask)
{
sqlTask.TaskCanceled += OnTaskCanceled;
return await Task.Factory.StartNew(() =>
{
while (!IsStopped)
{
//Just keep running
if (cancellationTokenSource.Token.IsCancellationRequested)
{
throw new OperationCanceledException();
}
if (Failed)
{
throw new InvalidOperationException();
}
sqlTask.AddMessage("still running", SqlTaskStatus.InProgress, true);
}
sqlTask.AddMessage("done!", SqlTaskStatus.Succeeded);
return TaskResult;
});
}
private void OnTaskCanceled(object sender, TaskEventArgs<SqlTaskStatus> e)
{
cancellationTokenSource.Cancel();
}
}
}

View File

@@ -0,0 +1,139 @@
//
// 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 Microsoft.SqlTools.ServiceLayer.TaskServices;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.TaskServices
{
public class SqlTaskTests
{
[Fact]
public void CreateSqlTaskGivenInvalidArgumentShouldThrowException()
{
Assert.Throws<ArgumentNullException>(() => new SqlTask(null, new DatabaseOperationStub().FunctionToRun));
Assert.Throws<ArgumentNullException>(() => new SqlTask(new TaskMetadata(), null));
}
[Fact]
public void CreateSqlTaskShouldGenerateANewId()
{
SqlTask sqlTask = new SqlTask(new TaskMetadata(), new DatabaseOperationStub().FunctionToRun);
Assert.NotNull(sqlTask.TaskId);
Assert.True(sqlTask.TaskId != Guid.Empty);
SqlTask sqlTask2 = new SqlTask(new TaskMetadata(), new DatabaseOperationStub().FunctionToRun);
Assert.False(sqlTask.TaskId.CompareTo(sqlTask2.TaskId) == 0);
}
[Fact]
public void RunShouldRunTheFunctionAndGetTheResult()
{
SqlTaskStatus expectedStatus = SqlTaskStatus.Succeeded;
DatabaseOperationStub operation = new DatabaseOperationStub();
operation.TaskResult = new TaskResult
{
TaskStatus = expectedStatus
};
SqlTask sqlTask = new SqlTask(new TaskMetadata(), operation.FunctionToRun);
Assert.Equal(sqlTask.TaskStatus, SqlTaskStatus.NotStarted);
sqlTask.Run().ContinueWith(task => {
Assert.Equal(sqlTask.TaskStatus, expectedStatus);
Assert.Equal(sqlTask.IsCompleted, true);
Assert.True(sqlTask.Duration > 0);
});
Assert.Equal(sqlTask.TaskStatus, SqlTaskStatus.InProgress);
operation.Stop();
}
[Fact]
public void ToTaskInfoShouldReturnTaskInfo()
{
SqlTaskStatus expectedStatus = SqlTaskStatus.Succeeded;
DatabaseOperationStub operation = new DatabaseOperationStub();
operation.TaskResult = new TaskResult
{
TaskStatus = expectedStatus
};
SqlTask sqlTask = new SqlTask(new TaskMetadata
{
ServerName = "server name",
DatabaseName = "database name"
}, operation.FunctionToRun);
sqlTask.Run().ContinueWith(task =>
{
var taskInfo = sqlTask.ToTaskInfo();
Assert.Equal(taskInfo.TaskId, sqlTask.TaskId.ToString());
Assert.Equal(taskInfo.ServerName, "server name");
Assert.Equal(taskInfo.DatabaseName, "database name");
});
operation.Stop();
}
[Fact]
public void FailedOperationShouldReturnTheFailedResult()
{
SqlTaskStatus expectedStatus = SqlTaskStatus.Failed;
DatabaseOperationStub operation = new DatabaseOperationStub();
operation.TaskResult = new TaskResult
{
TaskStatus = expectedStatus
};
SqlTask sqlTask = new SqlTask(new TaskMetadata(), operation.FunctionToRun);
Assert.Equal(sqlTask.TaskStatus, SqlTaskStatus.NotStarted);
sqlTask.Run().ContinueWith(task => {
Assert.Equal(sqlTask.TaskStatus, expectedStatus);
Assert.Equal(sqlTask.IsCompleted, true);
Assert.True(sqlTask.Duration > 0);
});
Assert.Equal(sqlTask.TaskStatus, SqlTaskStatus.InProgress);
operation.Stop();
}
[Fact]
public void CancelingTheTaskShouldCancelTheOperation()
{
SqlTaskStatus expectedStatus = SqlTaskStatus.Canceled;
DatabaseOperationStub operation = new DatabaseOperationStub();
operation.TaskResult = new TaskResult
{
};
SqlTask sqlTask = new SqlTask(new TaskMetadata(), operation.FunctionToRun);
Assert.Equal(sqlTask.TaskStatus, SqlTaskStatus.NotStarted);
sqlTask.Run().ContinueWith(task => {
Assert.Equal(sqlTask.TaskStatus, expectedStatus);
Assert.Equal(sqlTask.IsCanceled, true);
Assert.True(sqlTask.Duration > 0);
});
Assert.Equal(sqlTask.TaskStatus, SqlTaskStatus.InProgress);
sqlTask.Cancel();
}
[Fact]
public void FailedOperationShouldFailTheTask()
{
SqlTaskStatus expectedStatus = SqlTaskStatus.Failed;
DatabaseOperationStub operation = new DatabaseOperationStub();
operation.TaskResult = new TaskResult
{
};
SqlTask sqlTask = new SqlTask(new TaskMetadata(), operation.FunctionToRun);
Assert.Equal(sqlTask.TaskStatus, SqlTaskStatus.NotStarted);
sqlTask.Run().ContinueWith(task => {
Assert.Equal(sqlTask.TaskStatus, expectedStatus);
Assert.Equal(sqlTask.IsCanceled, true);
Assert.True(sqlTask.Duration > 0);
});
Assert.Equal(sqlTask.TaskStatus, SqlTaskStatus.InProgress);
operation.FailTheOperation();
}
}
}

View File

@@ -0,0 +1,86 @@
//
// 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 Microsoft.SqlTools.ServiceLayer.TaskServices;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.TaskServices
{
public class TaskManagerTests
{
private TaskMetadata taskMetaData = new TaskMetadata
{
ServerName = "server name",
DatabaseName = "database name"
};
[Fact]
public void ManagerInstanceWithNoTaskShouldNotBreakOnCancelTask()
{
SqlTaskManager manager = new SqlTaskManager();
Assert.True(manager.Tasks.Count == 0);
manager.CancelTask(Guid.NewGuid());
}
[Fact]
public void VerifyCreateAndRunningTask()
{
using (SqlTaskManager manager = new SqlTaskManager())
{
bool taskAddedEventRaised = false;
manager.TaskAdded += (object sender, TaskEventArgs<SqlTask> e) =>
{
taskAddedEventRaised = true;
};
DatabaseOperationStub operation = new DatabaseOperationStub();
operation.TaskResult = new TaskResult
{
};
SqlTask sqlTask = manager.CreateTask(taskMetaData, operation.FunctionToRun);
Assert.NotNull(sqlTask);
Assert.True(taskAddedEventRaised);
Assert.False(manager.HasCompletedTasks());
sqlTask.Run().ContinueWith(task =>
{
Assert.True(manager.HasCompletedTasks());
manager.RemoveCompletedTask(sqlTask);
});
operation.Stop();
}
}
[Fact]
public void CancelTaskShouldCancelTheOperation()
{
using (SqlTaskManager manager = new SqlTaskManager())
{
SqlTaskStatus expectedStatus = SqlTaskStatus.Canceled;
DatabaseOperationStub operation = new DatabaseOperationStub();
operation.TaskResult = new TaskResult
{
};
SqlTask sqlTask = manager.CreateTask(taskMetaData, operation.FunctionToRun);
Assert.NotNull(sqlTask);
sqlTask.Run().ContinueWith(task =>
{
Assert.Equal(sqlTask.TaskStatus, expectedStatus);
Assert.Equal(sqlTask.IsCanceled, true);
manager.Reset();
});
manager.CancelTask(sqlTask.TaskId);
}
}
}
}

View File

@@ -0,0 +1,131 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.Extensibility;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
using Microsoft.SqlTools.ServiceLayer.TaskServices.Contracts;
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
using Moq;
using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.TaskServices
{
public class TaskServiceTests : ServiceTestBase
{
private TaskService service;
private Mock<IProtocolEndpoint> serviceHostMock;
private TaskMetadata taskMetaData = new TaskMetadata
{
ServerName = "server name",
DatabaseName = "database name"
};
public TaskServiceTests()
{
serviceHostMock = new Mock<IProtocolEndpoint>();
service = CreateService();
service.InitializeService(serviceHostMock.Object);
}
[Fact]
public async Task TaskListRequestErrorsIfParameterIsNull()
{
object errorResponse = null;
var contextMock = RequestContextMocks.Create<ListTasksResponse>(null)
.AddErrorHandling((errorMessage, errorCode) => errorResponse = errorMessage);
await service.HandleListTasksRequest(null, contextMock.Object);
VerifyErrorSent(contextMock);
Assert.True(((string)errorResponse).Contains("ArgumentNullException"));
}
[Fact]
public void NewTaskShouldSendNotification()
{
serviceHostMock.AddEventHandling(TaskCreatedNotification.Type, null);
serviceHostMock.AddEventHandling(TaskStatusChangedNotification.Type, null);
DatabaseOperationStub operation = new DatabaseOperationStub();
SqlTask sqlTask = service.TaskManager.CreateTask(taskMetaData, operation.FunctionToRun);
sqlTask.Run().ContinueWith(task =>
{
});
serviceHostMock.Verify(x => x.SendEvent(TaskCreatedNotification.Type,
It.Is<TaskInfo>(t => t.TaskId == sqlTask.TaskId.ToString())), Times.Once());
operation.Stop();
serviceHostMock.Verify(x => x.SendEvent(TaskStatusChangedNotification.Type,
It.Is<TaskProgressInfo>(t => t.TaskId == sqlTask.TaskId.ToString())), Times.AtLeastOnce());
}
[Fact]
public async Task CancelTaskShouldCancelTheOperationAndSendNotification()
{
serviceHostMock.AddEventHandling(TaskCreatedNotification.Type, null);
serviceHostMock.AddEventHandling(TaskStatusChangedNotification.Type, null);
DatabaseOperationStub operation = new DatabaseOperationStub();
SqlTask sqlTask = service.TaskManager.CreateTask(taskMetaData, operation.FunctionToRun);
sqlTask.Run().ContinueWith(task =>
{
serviceHostMock.Verify(x => x.SendEvent(TaskStatusChangedNotification.Type,
It.Is<TaskProgressInfo>(t => t.Status == SqlTaskStatus.Canceled)), Times.Once());
});
CancelTaskParams cancelParams = new CancelTaskParams
{
TaskId = sqlTask.TaskId.ToString()
};
await RunAndVerify<bool>(
test: (requestContext) => service.HandleCancelTaskRequest(cancelParams, requestContext),
verify: ((result) =>
{
}));
serviceHostMock.Verify(x => x.SendEvent(TaskCreatedNotification.Type,
It.Is<TaskInfo>(t => t.TaskId == sqlTask.TaskId.ToString())), Times.Once());
}
[Fact]
public async Task TaskListTaskShouldReturnAllTasks()
{
serviceHostMock.AddEventHandling(TaskCreatedNotification.Type, null);
serviceHostMock.AddEventHandling(TaskStatusChangedNotification.Type, null);
DatabaseOperationStub operation = new DatabaseOperationStub();
SqlTask sqlTask = service.TaskManager.CreateTask(taskMetaData, operation.FunctionToRun);
sqlTask.Run();
ListTasksParams listParams = new ListTasksParams
{
};
await RunAndVerify<ListTasksResponse>(
test: (requestContext) => service.HandleListTasksRequest(listParams, requestContext),
verify: ((result) =>
{
Assert.True(result.Tasks.Any(x => x.TaskId == sqlTask.TaskId.ToString()));
}));
operation.Stop();
}
protected TaskService CreateService()
{
CreateServiceProviderWithMinServices();
// Create the service using the service provider, which will initialize dependencies
return ServiceProvider.GetService<TaskService>();
}
protected override RegisteredServiceProvider CreateServiceProviderWithMinServices()
{
return CreateProvider()
.RegisterSingleService(new TaskService());
}
}
}