mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-13 17:23:02 -05:00
Event Flow Validator (#199)
This is a reworking of the unit tests to permit us to better test events from the service host. This new Event Flow Validator class allows creating a chain of events that can then be validated after execution of the request. Each event can have its own custom validation logic for verifying that the object sent via the service host is correct. It also allows us to validate that the order of events are correct. The big drawback is that (at this time) the validator cannot support asynchronous events or non-determinant ordering of events. We don't need this for the query execution functionality despite messages being sent asynchronously because async messages aren't sent during unit tests (due to the db message event only being present on SqlDbConnection classes). If the need arises to do async or out of order event validation, then I have some ideas for how we can do that. * Applying the event flow validator to the query execution service integration tests * Undoing changes to events that were included in cherry-picked commit * Cleaning up event flow validation to query execution * Add efv to cancel tests * Adding efv to dispose tests * Adding efv to subset tests * Adding efv to SaveResults tests * Copyright
This commit is contained in:
@@ -3,14 +3,11 @@
|
||||
// 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.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
@@ -21,131 +18,77 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
[Fact]
|
||||
public async void CancelInProgressQueryTest()
|
||||
{
|
||||
// Set up file for returning the query
|
||||
var fileMock = new Mock<ScriptFile>();
|
||||
fileMock.Setup(file => file.GetLinesInRange(It.IsAny<BufferRange>()))
|
||||
.Returns(new[] { Common.StandardQuery });
|
||||
// Set up workspace mock
|
||||
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny<string>()))
|
||||
.Returns(fileMock.Object);
|
||||
|
||||
// If:
|
||||
// ... I request a query (doesn't matter what kind) and execute it
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService.Object);
|
||||
var executeParams = new QueryExecuteParams { QuerySelection = Common.SubsectionDocument, OwnerUri = Common.OwnerUri };
|
||||
var executeRequest =
|
||||
RequestContextMocks.SetupRequestContextMock<QueryExecuteResult, QueryExecuteCompleteParams>(null, QueryExecuteCompleteEvent.Type, null, null);
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri };
|
||||
var executeRequest = RequestContextMocks.Create<QueryExecuteResult>(null);
|
||||
|
||||
await queryService.HandleExecuteRequest(executeParams, executeRequest.Object);
|
||||
await queryService.ActiveQueries[Common.OwnerUri].ExecutionTask;
|
||||
queryService.ActiveQueries[Common.OwnerUri].HasExecuted = false; // Fake that it hasn't completed execution
|
||||
|
||||
// ... And then I request to cancel the query
|
||||
var cancelParams = new QueryCancelParams {OwnerUri = Common.OwnerUri};
|
||||
QueryCancelResult result = null;
|
||||
var cancelRequest = GetQueryCancelResultContextMock(qcr => result = qcr, null);
|
||||
var cancelRequest = new EventFlowValidator<QueryCancelResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.Null(r.Messages);
|
||||
}).Complete();
|
||||
await queryService.HandleCancelRequest(cancelParams, cancelRequest.Object);
|
||||
|
||||
// Then:
|
||||
// ... I should have seen a successful event (no messages)
|
||||
VerifyQueryCancelCallCount(cancelRequest, Times.Once(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
|
||||
// ... The query should not have been disposed
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
cancelRequest.Validate();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void CancelExecutedQueryTest()
|
||||
{
|
||||
|
||||
// Set up file for returning the query
|
||||
var fileMock = new Mock<ScriptFile>();
|
||||
fileMock.SetupGet(file => file.Contents).Returns(Common.StandardQuery);
|
||||
// Set up workspace mock
|
||||
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny<string>()))
|
||||
.Returns(fileMock.Object);
|
||||
// If:
|
||||
// ... I request a query (doesn't matter what kind) and wait for execution
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService.Object);
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var executeParams = new QueryExecuteParams {QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri};
|
||||
var executeRequest =
|
||||
RequestContextMocks.SetupRequestContextMock<QueryExecuteResult, QueryExecuteCompleteParams>(null, QueryExecuteCompleteEvent.Type, null, null);
|
||||
var executeRequest = RequestContextMocks.Create<QueryExecuteResult>(null);
|
||||
|
||||
await queryService.HandleExecuteRequest(executeParams, executeRequest.Object);
|
||||
await queryService.ActiveQueries[Common.OwnerUri].ExecutionTask;
|
||||
|
||||
// ... And then I request to cancel the query
|
||||
var cancelParams = new QueryCancelParams {OwnerUri = Common.OwnerUri};
|
||||
QueryCancelResult result = null;
|
||||
var cancelRequest = GetQueryCancelResultContextMock(qcr => result = qcr, null);
|
||||
var cancelRequest = new EventFlowValidator<QueryCancelResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.False(string.IsNullOrWhiteSpace(r.Messages));
|
||||
}).Complete();
|
||||
|
||||
await queryService.HandleCancelRequest(cancelParams, cancelRequest.Object);
|
||||
|
||||
// Then:
|
||||
// ... I should have seen a result event with an error message
|
||||
VerifyQueryCancelCallCount(cancelRequest, Times.Once(), Times.Never());
|
||||
Assert.NotNull(result.Messages);
|
||||
|
||||
// ... The query should not have been disposed
|
||||
Assert.NotEmpty(queryService.ActiveQueries);
|
||||
cancelRequest.Validate();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CancelNonExistantTest()
|
||||
{
|
||||
|
||||
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
// If:
|
||||
// ... I request to cancel a query that doesn't exist
|
||||
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
var queryService = Common.GetPrimedExecutionService(null, false, false, workspaceService.Object);
|
||||
var cancelParams = new QueryCancelParams {OwnerUri = "Doesn't Exist"};
|
||||
QueryCancelResult result = null;
|
||||
var cancelRequest = GetQueryCancelResultContextMock(qcr => result = qcr, null);
|
||||
|
||||
var cancelParams = new QueryCancelParams { OwnerUri = "Doesn't Exist" };
|
||||
var cancelRequest = new EventFlowValidator<QueryCancelResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.False(string.IsNullOrWhiteSpace(r.Messages));
|
||||
}).Complete();
|
||||
await queryService.HandleCancelRequest(cancelParams, cancelRequest.Object);
|
||||
|
||||
// Then:
|
||||
// ... I should have seen a result event with an error message
|
||||
VerifyQueryCancelCallCount(cancelRequest, Times.Once(), Times.Never());
|
||||
Assert.NotNull(result.Messages);
|
||||
cancelRequest.Validate();
|
||||
}
|
||||
|
||||
#region Mocking
|
||||
|
||||
private static Mock<RequestContext<QueryCancelResult>> GetQueryCancelResultContextMock(
|
||||
Action<QueryCancelResult> resultCallback,
|
||||
Action<object> errorCallback)
|
||||
{
|
||||
var requestContext = new Mock<RequestContext<QueryCancelResult>>();
|
||||
|
||||
// Setup the mock for SendResult
|
||||
var sendResultFlow = requestContext
|
||||
.Setup(rc => rc.SendResult(It.IsAny<QueryCancelResult>()))
|
||||
.Returns(Task.FromResult(0));
|
||||
if (resultCallback != null)
|
||||
{
|
||||
sendResultFlow.Callback(resultCallback);
|
||||
}
|
||||
|
||||
// Setup the mock for SendError
|
||||
var sendErrorFlow = requestContext
|
||||
.Setup(rc => rc.SendError(It.IsAny<object>()))
|
||||
.Returns(Task.FromResult(0));
|
||||
if (errorCallback != null)
|
||||
{
|
||||
sendErrorFlow.Callback(errorCallback);
|
||||
}
|
||||
|
||||
return requestContext;
|
||||
}
|
||||
|
||||
private static void VerifyQueryCancelCallCount(Mock<RequestContext<QueryCancelResult>> mock,
|
||||
Times sendResultCalls, Times sendErrorCalls)
|
||||
{
|
||||
mock.Verify(rc => rc.SendResult(It.IsAny<QueryCancelResult>()), sendResultCalls);
|
||||
mock.Verify(rc => rc.SendError(It.IsAny<object>()), sendErrorCalls);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,13 @@
|
||||
// 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.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
@@ -38,69 +35,58 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
[Fact]
|
||||
public async void DisposeExecutedQuery()
|
||||
{
|
||||
// Set up file for returning the query
|
||||
var fileMock = new Mock<ScriptFile>();
|
||||
fileMock.SetupGet(file => file.Contents).Returns("doesn't matter");
|
||||
// Set up workspace mock
|
||||
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny<string>()))
|
||||
.Returns(fileMock.Object);
|
||||
// If:
|
||||
// ... I request a query (doesn't matter what kind)
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService.Object);
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var executeParams = new QueryExecuteParams {QuerySelection = null, OwnerUri = Common.OwnerUri};
|
||||
var executeRequest = RequestContextMocks.SetupRequestContextMock<QueryExecuteResult, QueryExecuteCompleteParams>(null, QueryExecuteCompleteEvent.Type, null, null);
|
||||
var executeRequest = RequestContextMocks.Create<QueryExecuteResult>(null);
|
||||
await queryService.HandleExecuteRequest(executeParams, executeRequest.Object);
|
||||
await queryService.ActiveQueries[Common.OwnerUri].ExecutionTask;
|
||||
|
||||
// ... And then I dispose of the query
|
||||
var disposeParams = new QueryDisposeParams {OwnerUri = Common.OwnerUri};
|
||||
QueryDisposeResult result = null;
|
||||
var disposeRequest = GetQueryDisposeResultContextMock(qdr => {
|
||||
result = qdr;
|
||||
}, null);
|
||||
var disposeRequest = new EventFlowValidator<QueryDisposeResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
// Then: Messages should be null
|
||||
Assert.Null(r.Messages);
|
||||
}).Complete();
|
||||
await queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object);
|
||||
|
||||
// Then:
|
||||
// ... I should have seen a successful result
|
||||
// ... And the active queries should be empty
|
||||
VerifyQueryDisposeCallCount(disposeRequest, Times.Once(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
disposeRequest.Validate();
|
||||
Assert.Empty(queryService.ActiveQueries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void QueryDisposeMissingQuery()
|
||||
{
|
||||
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
// If:
|
||||
// ... I attempt to dispose a query that doesn't exist
|
||||
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
var queryService = Common.GetPrimedExecutionService(null, false, false, workspaceService.Object);
|
||||
var disposeParams = new QueryDisposeParams {OwnerUri = Common.OwnerUri};
|
||||
QueryDisposeResult result = null;
|
||||
var disposeRequest = GetQueryDisposeResultContextMock(qdr => result = qdr, null);
|
||||
await queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object);
|
||||
|
||||
// Then:
|
||||
// ... I should have gotten an error result
|
||||
VerifyQueryDisposeCallCount(disposeRequest, Times.Once(), Times.Never());
|
||||
Assert.NotNull(result.Messages);
|
||||
Assert.NotEmpty(result.Messages);
|
||||
var disposeRequest = new EventFlowValidator<QueryDisposeResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
// Then: Messages should not be null
|
||||
Assert.NotNull(r.Messages);
|
||||
Assert.NotEmpty(r.Messages);
|
||||
}).Complete();
|
||||
await queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object);
|
||||
disposeRequest.Validate();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ServiceDispose()
|
||||
{
|
||||
// Setup:
|
||||
// ... We need a workspace service that returns a file
|
||||
var fileMock = new Mock<ScriptFile>();
|
||||
fileMock.SetupGet(file => file.Contents).Returns(Common.StandardQuery);
|
||||
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();
|
||||
workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny<string>()))
|
||||
.Returns(fileMock.Object);
|
||||
// ... We need a query service
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService.Object);
|
||||
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
|
||||
// If:
|
||||
// ... I execute some bogus query
|
||||
@@ -119,44 +105,5 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
// ... There should no longer be an active query
|
||||
Assert.Empty(queryService.ActiveQueries);
|
||||
}
|
||||
|
||||
#region Mocking
|
||||
|
||||
private Mock<RequestContext<QueryDisposeResult>> GetQueryDisposeResultContextMock(
|
||||
Action<QueryDisposeResult> resultCallback,
|
||||
Action<object> errorCallback)
|
||||
{
|
||||
var requestContext = new Mock<RequestContext<QueryDisposeResult>>();
|
||||
|
||||
// Setup the mock for SendResult
|
||||
var sendResultFlow = requestContext
|
||||
.Setup(rc => rc.SendResult(It.IsAny<QueryDisposeResult>()))
|
||||
.Returns(Task.FromResult(0));
|
||||
if (resultCallback != null)
|
||||
{
|
||||
sendResultFlow.Callback(resultCallback);
|
||||
}
|
||||
|
||||
// Setup the mock for SendError
|
||||
var sendErrorFlow = requestContext
|
||||
.Setup(rc => rc.SendError(It.IsAny<object>()))
|
||||
.Returns(Task.FromResult(0));
|
||||
if (errorCallback != null)
|
||||
{
|
||||
sendErrorFlow.Callback(errorCallback);
|
||||
}
|
||||
|
||||
return requestContext;
|
||||
}
|
||||
|
||||
private void VerifyQueryDisposeCallCount(Mock<RequestContext<QueryDisposeResult>> mock, Times sendResultCalls,
|
||||
Times sendErrorCalls)
|
||||
{
|
||||
mock.Verify(rc => rc.SendResult(It.IsAny<QueryDisposeResult>()), sendResultCalls);
|
||||
mock.Verify(rc => rc.SendError(It.IsAny<object>()), sendErrorCalls);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,134 +3,89 @@
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
{
|
||||
public class ServiceIntegrationTests
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public async void QueryExecuteSingleBatchNoResultsTest()
|
||||
public async Task QueryExecuteAllBatchesNoOp()
|
||||
{
|
||||
// Given:
|
||||
// ... Default settings are stored in the workspace service
|
||||
// ... A workspace with a standard query is configured
|
||||
WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings = new SqlToolsSettings();
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a valid query with no results
|
||||
// ... I request to execute a valid query with all batches as no op
|
||||
var workspaceService = GetDefaultWorkspaceService(string.Format("{0}\r\nGO\r\n{0}", Common.NoOpQuery));
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri };
|
||||
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams completeParams = null;
|
||||
QueryExecuteBatchNotificationParams batchStartParams = null;
|
||||
QueryExecuteBatchNotificationParams batchCompleteParams = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, p) => completeParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchStartEvent.Type, (et, p) => batchStartParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchCompleteParams = p)
|
||||
.AddEventHandling(QueryExecuteResultSetCompleteEvent.Type, null);
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddResultValidation(p =>
|
||||
{
|
||||
Assert.False(string.IsNullOrWhiteSpace(p.Messages));
|
||||
})
|
||||
.Complete();
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... No Errors should have been sent
|
||||
// ... A successful result should have been sent with messages on the first batch
|
||||
// ... A completion event should have been fired with empty results
|
||||
// ... A batch completion event should have been fired with empty results
|
||||
// ... A result set completion event should not have been fired
|
||||
VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Once(), Times.Once(), Times.Once(), Times.Never(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
// ... All events should have been called as per their flow validator
|
||||
efv.Validate();
|
||||
|
||||
Assert.Equal(1, completeParams.BatchSummaries.Length);
|
||||
Assert.Empty(completeParams.BatchSummaries[0].ResultSetSummaries);
|
||||
Assert.NotEmpty(completeParams.BatchSummaries[0].Messages);
|
||||
// ... There should be one active query
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QueryExecuteSingleBatchNoResultsTest()
|
||||
{
|
||||
// If:
|
||||
// ... I request to execute a valid query with no results
|
||||
var workspaceService = GetDefaultWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri };
|
||||
|
||||
// ... Batch start summary should not contain result sets, messages, but should contain owner URI
|
||||
Assert.NotNull(batchStartParams);
|
||||
Assert.NotNull(batchStartParams.BatchSummary);
|
||||
Assert.Null(batchStartParams.BatchSummary.Messages);
|
||||
Assert.Null(batchStartParams.BatchSummary.ResultSetSummaries);
|
||||
Assert.Equal(Common.OwnerUri, batchStartParams.OwnerUri);
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddStandardQueryResultValidator()
|
||||
.AddStandardBatchStartValidator()
|
||||
.AddStandardBatchCompleteValidator()
|
||||
.AddStandardQueryCompleteValidator(1)
|
||||
.Complete();
|
||||
|
||||
// ... Batch completion summary should contain result sets, messages, and the owner URI
|
||||
Assert.NotNull(batchCompleteParams);
|
||||
Assert.NotNull(batchCompleteParams.BatchSummary);
|
||||
Assert.Empty(batchCompleteParams.BatchSummary.ResultSetSummaries);
|
||||
Assert.NotEmpty(batchCompleteParams.BatchSummary.Messages);
|
||||
Assert.Equal(Common.OwnerUri, batchCompleteParams.OwnerUri);
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... All events should have been called as per their flow validator
|
||||
efv.Validate();
|
||||
|
||||
// ... There should be one active query
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async void QueryExecuteSingleBatchSingleResultTest()
|
||||
public async Task QueryExecuteSingleBatchSingleResultTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a valid query with results
|
||||
var workspaceService = GetDefaultWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(new[] { Common.StandardTestData }, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
|
||||
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams completeParams = null;
|
||||
QueryExecuteBatchNotificationParams batchStartParams = null;
|
||||
QueryExecuteBatchNotificationParams batchCompleteParams = null;
|
||||
QueryExecuteResultSetCompleteParams resultCompleteParams = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, p) => completeParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchStartEvent.Type, (et, p) => batchStartParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchCompleteParams = p)
|
||||
.AddEventHandling(QueryExecuteResultSetCompleteEvent.Type, (et, p) => resultCompleteParams = p);
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddStandardQueryResultValidator()
|
||||
.AddStandardBatchStartValidator()
|
||||
.AddStandardResultSetValidator()
|
||||
.AddStandardBatchCompleteValidator()
|
||||
.AddStandardQueryCompleteValidator(1)
|
||||
.Complete();
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... No errors should have been sent
|
||||
// ... A successful result should have been sent without messages
|
||||
// ... A completion event should have been fired with one result
|
||||
// ... A batch completion event should have been fired
|
||||
// ... A resultset completion event should have been fired
|
||||
VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Once(), Times.Once(), Times.Once(), Times.Once(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
|
||||
Assert.Equal(1, completeParams.BatchSummaries.Length);
|
||||
Assert.NotEmpty(completeParams.BatchSummaries[0].ResultSetSummaries);
|
||||
Assert.NotEmpty(completeParams.BatchSummaries[0].Messages);
|
||||
Assert.False(completeParams.BatchSummaries[0].HasError);
|
||||
|
||||
// ... Batch start summary should not contain result sets, messages, but should contain owner URI
|
||||
Assert.NotNull(batchStartParams);
|
||||
Assert.NotNull(batchStartParams.BatchSummary);
|
||||
Assert.Null(batchStartParams.BatchSummary.Messages);
|
||||
Assert.Null(batchStartParams.BatchSummary.ResultSetSummaries);
|
||||
Assert.Equal(Common.OwnerUri, batchStartParams.OwnerUri);
|
||||
|
||||
Assert.NotNull(batchCompleteParams);
|
||||
Assert.NotEmpty(batchCompleteParams.BatchSummary.ResultSetSummaries);
|
||||
Assert.NotEmpty(batchCompleteParams.BatchSummary.Messages);
|
||||
Assert.Equal(Common.OwnerUri, batchCompleteParams.OwnerUri);
|
||||
|
||||
Assert.NotNull(resultCompleteParams);
|
||||
Assert.Equal(Common.StandardColumns, resultCompleteParams.ResultSetSummary.ColumnInfo.Length);
|
||||
Assert.Equal(Common.StandardRows, resultCompleteParams.ResultSetSummary.RowCount);
|
||||
Assert.Equal(Common.OwnerUri, resultCompleteParams.OwnerUri);
|
||||
// ... All events should have been called as per their flow validator
|
||||
efv.Validate();
|
||||
|
||||
// ... There should be one active query
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
@@ -139,130 +94,55 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
[Fact]
|
||||
public async Task QueryExecuteSingleBatchMultipleResultTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a valid query with one batch and multiple result sets
|
||||
var workspaceService = GetDefaultWorkspaceService(Common.StandardQuery);
|
||||
var dataset = new[] { Common.StandardTestData, Common.StandardTestData };
|
||||
var queryService = Common.GetPrimedExecutionService(dataset, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
|
||||
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams completeParams = null;
|
||||
QueryExecuteBatchNotificationParams batchStartParams = null;
|
||||
QueryExecuteBatchNotificationParams batchCompleteParams = null;
|
||||
List<QueryExecuteResultSetCompleteParams> resultCompleteParams = new List<QueryExecuteResultSetCompleteParams>();
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, p) => completeParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchStartEvent.Type, (et, p) => batchStartParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchCompleteParams = p)
|
||||
.AddEventHandling(QueryExecuteResultSetCompleteEvent.Type, (et, p) => resultCompleteParams.Add(p));
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddStandardQueryResultValidator()
|
||||
.AddStandardBatchStartValidator()
|
||||
.AddStandardResultSetValidator()
|
||||
.AddStandardResultSetValidator()
|
||||
.AddStandardQueryCompleteValidator(1)
|
||||
.Complete();
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... No errors should have been sent
|
||||
// ... A successful result should have been sent without messages
|
||||
// ... A completion event should have been fired with one result
|
||||
// ... A batch completion event should have been fired
|
||||
// ... Two resultset completion events should have been fired
|
||||
VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Once(), Times.Once(), Times.Once(), Times.Exactly(2), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
// ... All events should have been called as per their flow validator
|
||||
efv.Validate();
|
||||
|
||||
Assert.Equal(1, completeParams.BatchSummaries.Length);
|
||||
Assert.NotEmpty(completeParams.BatchSummaries[0].ResultSetSummaries);
|
||||
Assert.NotEmpty(completeParams.BatchSummaries[0].Messages);
|
||||
Assert.False(completeParams.BatchSummaries[0].HasError);
|
||||
|
||||
// ... Batch start summary should not contain result sets, messages, but should contain owner URI
|
||||
Assert.NotNull(batchStartParams);
|
||||
Assert.NotNull(batchStartParams.BatchSummary);
|
||||
Assert.Null(batchStartParams.BatchSummary.Messages);
|
||||
Assert.Null(batchStartParams.BatchSummary.ResultSetSummaries);
|
||||
Assert.Equal(Common.OwnerUri, batchStartParams.OwnerUri);
|
||||
|
||||
Assert.NotNull(batchCompleteParams);
|
||||
Assert.NotEmpty(batchCompleteParams.BatchSummary.ResultSetSummaries);
|
||||
Assert.NotEmpty(batchCompleteParams.BatchSummary.Messages);
|
||||
Assert.Equal(Common.OwnerUri, batchCompleteParams.OwnerUri);
|
||||
|
||||
Assert.Equal(2, resultCompleteParams.Count);
|
||||
foreach (var resultParam in resultCompleteParams)
|
||||
{
|
||||
Assert.NotNull(resultCompleteParams);
|
||||
Assert.Equal(Common.StandardColumns, resultParam.ResultSetSummary.ColumnInfo.Length);
|
||||
Assert.Equal(Common.StandardRows, resultParam.ResultSetSummary.RowCount);
|
||||
Assert.Equal(Common.OwnerUri, resultParam.OwnerUri);
|
||||
}
|
||||
// ... There should be one active query
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QueryExecuteMultipleBatchSingleResultTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(string.Format("{0}\r\nGO\r\n{0}", Common.StandardQuery));
|
||||
|
||||
// If:
|
||||
// ... I request a to execute a valid query with multiple batches
|
||||
var workspaceService = GetDefaultWorkspaceService(string.Format("{0}\r\nGO\r\n{0}", Common.StandardQuery));
|
||||
var dataSet = new[] { Common.StandardTestData };
|
||||
var queryService = Common.GetPrimedExecutionService(dataSet, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
|
||||
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams completeParams = null;
|
||||
List<QueryExecuteBatchNotificationParams> batchStartParams = new List<QueryExecuteBatchNotificationParams>();
|
||||
List<QueryExecuteBatchNotificationParams> batchCompleteParams = new List<QueryExecuteBatchNotificationParams>();
|
||||
List<QueryExecuteResultSetCompleteParams> resultCompleteParams = new List<QueryExecuteResultSetCompleteParams>();
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, p) => completeParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchStartEvent.Type, (et, p) => batchStartParams.Add(p))
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchCompleteParams.Add(p))
|
||||
.AddEventHandling(QueryExecuteResultSetCompleteEvent.Type, (et, p) => resultCompleteParams.Add(p));
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddStandardQueryResultValidator()
|
||||
.AddStandardBatchStartValidator()
|
||||
.AddStandardResultSetValidator()
|
||||
.AddStandardBatchCompleteValidator()
|
||||
.AddStandardBatchCompleteValidator()
|
||||
.AddStandardResultSetValidator()
|
||||
.AddStandardBatchCompleteValidator()
|
||||
.AddStandardQueryCompleteValidator(2)
|
||||
.Complete();
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... No errors should have been sent
|
||||
// ... A successful result should have been sent without messages
|
||||
|
||||
VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Once(), Times.Exactly(2), Times.Exactly(2), Times.Exactly(2), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
|
||||
// ... A completion event should have been fired with one two batch summaries, one result each
|
||||
Assert.Equal(2, completeParams.BatchSummaries.Length);
|
||||
Assert.Equal(1, completeParams.BatchSummaries[0].ResultSetSummaries.Length);
|
||||
Assert.Equal(1, completeParams.BatchSummaries[1].ResultSetSummaries.Length);
|
||||
Assert.NotEmpty(completeParams.BatchSummaries[0].Messages);
|
||||
Assert.NotEmpty(completeParams.BatchSummaries[1].Messages);
|
||||
|
||||
// ... Two batch start events should have been fired
|
||||
Assert.Equal(2, batchStartParams.Count);
|
||||
foreach (var batch in batchStartParams)
|
||||
{
|
||||
Assert.Null(batch.BatchSummary.Messages);
|
||||
Assert.Null(batch.BatchSummary.ResultSetSummaries);
|
||||
Assert.Equal(Common.OwnerUri, batch.OwnerUri);
|
||||
}
|
||||
|
||||
// ... Two batch completion events should have been fired
|
||||
Assert.Equal(2, batchCompleteParams.Count);
|
||||
foreach (var batch in batchCompleteParams)
|
||||
{
|
||||
Assert.NotEmpty(batch.BatchSummary.ResultSetSummaries);
|
||||
Assert.NotEmpty(batch.BatchSummary.Messages);
|
||||
Assert.Equal(Common.OwnerUri, batch.OwnerUri);
|
||||
}
|
||||
|
||||
// ... Two resultset completion events should have been fired
|
||||
Assert.Equal(2, resultCompleteParams.Count);
|
||||
foreach (var resultParam in resultCompleteParams)
|
||||
{
|
||||
Assert.NotNull(resultParam.ResultSetSummary);
|
||||
Assert.Equal(Common.StandardColumns, resultParam.ResultSetSummary.ColumnInfo.Length);
|
||||
Assert.Equal(Common.StandardRows, resultParam.ResultSetSummary.RowCount);
|
||||
Assert.Equal(Common.OwnerUri, resultParam.OwnerUri);
|
||||
}
|
||||
// ... All events should have been called as per their flow validator
|
||||
efv.Validate();
|
||||
|
||||
// ... There should be one active query
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
@@ -272,39 +152,31 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
public async void QueryExecuteUnconnectedUriTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a query using a file URI that isn't connected
|
||||
var workspaceService = GetDefaultWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, false, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = "notConnected", QuerySelection = Common.WholeDocument };
|
||||
|
||||
object error = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(null)
|
||||
.AddErrorHandling(e => error = e);
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddErrorValidation<string>(Assert.NotEmpty)
|
||||
.Complete();
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... An error should have been returned
|
||||
// ... No result should have been returned
|
||||
// ... No completion event should have been fired
|
||||
// ... All events should have been called as per their flow validator
|
||||
efv.Validate();
|
||||
|
||||
// ... There should be no active queries
|
||||
VerifyQueryExecuteCallCount(requestContext, Times.Never(), Times.Never(), Times.Never(), Times.Never(), Times.Never(), Times.Once());
|
||||
Assert.IsType<string>(error);
|
||||
Assert.NotEmpty((string)error);
|
||||
Assert.Empty(queryService.ActiveQueries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void QueryExecuteInProgressTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a query
|
||||
var workspaceService = GetDefaultWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
|
||||
|
||||
@@ -314,33 +186,25 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
|
||||
// ... And then I request another query without waiting for the first to complete
|
||||
queryService.ActiveQueries[Common.OwnerUri].HasExecuted = false; // Simulate query hasn't finished
|
||||
object error = null;
|
||||
var secondRequestContext = RequestContextMocks.Create<QueryExecuteResult>(null)
|
||||
.AddErrorHandling(e => error = e);
|
||||
await Common.AwaitExecution(queryService, queryParams, secondRequestContext.Object);
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddErrorValidation<string>(Assert.NotEmpty)
|
||||
.Complete();
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... An error should have been sent
|
||||
// ... A result should have not have been sent
|
||||
// ... No completion event should have been fired
|
||||
// ... A batch completion event should have fired, but not a resultset event
|
||||
// ... All events should have been called as per their flow validator
|
||||
efv.Validate();
|
||||
|
||||
// ... There should only be one active query
|
||||
VerifyQueryExecuteCallCount(secondRequestContext, Times.Never(), Times.AtMostOnce(), Times.AtMostOnce(), Times.AtMostOnce(), Times.Never(), Times.Once());
|
||||
Assert.IsType<string>(error);
|
||||
Assert.NotEmpty((string)error);
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async void QueryExecuteCompletedTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a query
|
||||
var workspaceService = GetDefaultWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
|
||||
|
||||
@@ -349,31 +213,21 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
await Common.AwaitExecution(queryService, queryParams, firstRequestContext.Object);
|
||||
|
||||
// ... And then I request another query after waiting for the first to complete
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams complete = null;
|
||||
QueryExecuteBatchNotificationParams batchStart = null;
|
||||
QueryExecuteBatchNotificationParams batchComplete = null;
|
||||
var secondRequestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, qecp) => complete = qecp)
|
||||
.AddEventHandling(QueryExecuteBatchStartEvent.Type, (et, p) => batchStart = p)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchComplete = p);
|
||||
await Common.AwaitExecution(queryService, queryParams, secondRequestContext.Object);
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddStandardQueryResultValidator()
|
||||
.AddStandardBatchStartValidator()
|
||||
.AddStandardBatchCompleteValidator()
|
||||
.AddStandardQueryCompleteValidator(1)
|
||||
.Complete();
|
||||
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... No errors should have been sent
|
||||
// ... A result should have been sent with no errors
|
||||
// ... All events should have been called as per their flow validator
|
||||
efv.Validate();
|
||||
|
||||
// ... There should only be one active query
|
||||
// ... A batch completion event should have fired, but not a result set completion event
|
||||
VerifyQueryExecuteCallCount(secondRequestContext, Times.Once(), Times.Once(), Times.Once(), Times.Once(), Times.Never(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
|
||||
Assert.False(complete.BatchSummaries.Any(b => b.HasError));
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
|
||||
Assert.NotNull(batchStart);
|
||||
Assert.NotNull(batchComplete);
|
||||
Assert.False(batchComplete.BatchSummary.HasError);
|
||||
Assert.Equal(complete.OwnerUri, batchComplete.OwnerUri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -388,21 +242,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = null };
|
||||
|
||||
object errorResult = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(null)
|
||||
.AddErrorHandling(error => errorResult = error);
|
||||
await queryService.HandleExecuteRequest(queryParams, requestContext.Object);
|
||||
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddErrorValidation<string>(Assert.NotEmpty)
|
||||
.Complete();
|
||||
await queryService.HandleExecuteRequest(queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... Am error should have been sent
|
||||
// ... No result should have been sent
|
||||
// ... No completion events should have been fired
|
||||
// ... An active query should not have been added
|
||||
VerifyQueryExecuteCallCount(requestContext, Times.Never(), Times.Never(), Times.Never(), Times.Never(), Times.Never(), Times.Once());
|
||||
Assert.NotNull(errorResult);
|
||||
Assert.IsType<string>(errorResult);
|
||||
Assert.DoesNotContain(Common.OwnerUri, queryService.ActiveQueries.Keys);
|
||||
efv.Validate();
|
||||
|
||||
// ... There should not be an active query
|
||||
Assert.Empty(queryService.ActiveQueries);
|
||||
@@ -411,71 +258,92 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
[Fact]
|
||||
public async void QueryExecuteInvalidQueryTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a query that is invalid
|
||||
var workspaceService = GetDefaultWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, true, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
|
||||
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams complete = null;
|
||||
QueryExecuteBatchNotificationParams batchStart = null;
|
||||
QueryExecuteBatchNotificationParams batchComplete = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, qecp) => complete = qecp)
|
||||
.AddEventHandling(QueryExecuteBatchStartEvent.Type, (et, p) => batchStart = p)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchComplete = p);
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
var efv = new EventFlowValidator<QueryExecuteResult>()
|
||||
.AddStandardQueryResultValidator()
|
||||
.AddStandardBatchStartValidator()
|
||||
.AddStandardBatchCompleteValidator()
|
||||
.AddStandardQueryCompleteValidator(1)
|
||||
.Complete();
|
||||
|
||||
await Common.AwaitExecution(queryService, queryParams, efv.Object);
|
||||
|
||||
// Then:
|
||||
// ... No errors should have been sent
|
||||
// ... A result should have been sent with success (we successfully started the query)
|
||||
// ... A completion event (query, batch, not resultset) should have been sent with error
|
||||
VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Once(), Times.Once(), Times.Once(), Times.Never(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
// ... Am error should have been sent
|
||||
efv.Validate();
|
||||
|
||||
Assert.Equal(1, complete.BatchSummaries.Length);
|
||||
Assert.True(complete.BatchSummaries[0].HasError);
|
||||
Assert.NotEmpty(complete.BatchSummaries[0].Messages);
|
||||
|
||||
Assert.NotNull(batchStart);
|
||||
Assert.False(batchStart.BatchSummary.HasError);
|
||||
Assert.Null(batchStart.BatchSummary.Messages);
|
||||
Assert.Null(batchStart.BatchSummary.ResultSetSummaries);
|
||||
Assert.Equal(Common.OwnerUri, batchStart.OwnerUri);
|
||||
|
||||
Assert.NotNull(batchComplete);
|
||||
Assert.True(batchComplete.BatchSummary.HasError);
|
||||
Assert.NotEmpty(batchComplete.BatchSummary.Messages);
|
||||
Assert.Equal(Common.OwnerUri, batchComplete.OwnerUri);
|
||||
// ... There should not be an active query
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
}
|
||||
|
||||
private static void VerifyQueryExecuteCallCount(Mock<RequestContext<QueryExecuteResult>> mock,
|
||||
Times sendResultCalls,
|
||||
Times sendCompletionEventCalls,
|
||||
Times sendBatchStartEvent,
|
||||
Times sendBatchCompletionEvent,
|
||||
Times sendResultCompleteEvent,
|
||||
Times sendErrorCalls)
|
||||
private static WorkspaceService<SqlToolsSettings> GetDefaultWorkspaceService(string query)
|
||||
{
|
||||
mock.Verify(rc => rc.SendResult(It.IsAny<QueryExecuteResult>()), sendResultCalls);
|
||||
mock.Verify(rc => rc.SendEvent(
|
||||
It.Is<EventType<QueryExecuteCompleteParams>>(m => m == QueryExecuteCompleteEvent.Type),
|
||||
It.IsAny<QueryExecuteCompleteParams>()), sendCompletionEventCalls);
|
||||
mock.Verify(rc => rc.SendEvent(
|
||||
It.Is<EventType<QueryExecuteBatchNotificationParams>>(m => m == QueryExecuteBatchCompleteEvent.Type),
|
||||
It.IsAny<QueryExecuteBatchNotificationParams>()), sendBatchCompletionEvent);
|
||||
mock.Verify(rc => rc.SendEvent(
|
||||
It.Is<EventType<QueryExecuteBatchNotificationParams>>(m => m== QueryExecuteBatchStartEvent.Type),
|
||||
It.IsAny<QueryExecuteBatchNotificationParams>()), sendBatchStartEvent);
|
||||
mock.Verify(rc => rc.SendEvent(
|
||||
It.Is<EventType<QueryExecuteResultSetCompleteParams>>(m => m == QueryExecuteResultSetCompleteEvent.Type),
|
||||
It.IsAny<QueryExecuteResultSetCompleteParams>()), sendResultCompleteEvent);
|
||||
WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings = new SqlToolsSettings();
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(query);
|
||||
return workspaceService;
|
||||
}
|
||||
}
|
||||
|
||||
mock.Verify(rc => rc.SendError(It.IsAny<object>()), sendErrorCalls);
|
||||
public static class EventFlowValidatorExtensions
|
||||
{
|
||||
public static EventFlowValidator<QueryExecuteResult> AddStandardQueryResultValidator(
|
||||
this EventFlowValidator<QueryExecuteResult> efv)
|
||||
{
|
||||
// We just need to makes sure we get a result back, there's no params to validate
|
||||
return efv.AddResultValidation(r =>
|
||||
{
|
||||
Assert.Null(r.Messages);
|
||||
});
|
||||
}
|
||||
|
||||
public static EventFlowValidator<TRequestContext> AddStandardBatchStartValidator<TRequestContext>(
|
||||
this EventFlowValidator<TRequestContext> efv)
|
||||
{
|
||||
return efv.AddEventValidation(QueryExecuteBatchStartEvent.Type, p =>
|
||||
{
|
||||
// Validate OwnerURI and batch summary is returned
|
||||
Assert.Equal(Common.OwnerUri, p.OwnerUri);
|
||||
Assert.NotNull(p.BatchSummary);
|
||||
});
|
||||
}
|
||||
|
||||
public static EventFlowValidator<TRequestContext> AddStandardBatchCompleteValidator<TRequestContext>(
|
||||
this EventFlowValidator<TRequestContext> efv)
|
||||
{
|
||||
return efv.AddEventValidation(QueryExecuteBatchCompleteEvent.Type, p =>
|
||||
{
|
||||
// Validate OwnerURI and batch summary are returned
|
||||
Assert.Equal(Common.OwnerUri, p.OwnerUri);
|
||||
Assert.NotNull(p.BatchSummary);
|
||||
});
|
||||
}
|
||||
|
||||
public static EventFlowValidator<TRequestContext> AddStandardResultSetValidator<TRequestContext>(
|
||||
this EventFlowValidator<TRequestContext> efv)
|
||||
{
|
||||
return efv.AddEventValidation(QueryExecuteResultSetCompleteEvent.Type, p =>
|
||||
{
|
||||
// Validate OwnerURI and result summary are returned
|
||||
Assert.Equal(Common.OwnerUri, p.OwnerUri);
|
||||
Assert.NotNull(p.ResultSetSummary);
|
||||
});
|
||||
}
|
||||
|
||||
public static EventFlowValidator<TRequestContext> AddStandardQueryCompleteValidator<TRequestContext>(
|
||||
this EventFlowValidator<TRequestContext> efv, int expectedBatches)
|
||||
{
|
||||
return efv.AddEventValidation(QueryExecuteCompleteEvent.Type, p =>
|
||||
{
|
||||
Assert.True(string.IsNullOrWhiteSpace(p.Message));
|
||||
Assert.Equal(Common.OwnerUri, p.OwnerUri);
|
||||
Assert.NotNull(p.BatchSummaries);
|
||||
Assert.Equal(expectedBatches, p.BatchSummaries.Length);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,12 @@
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
@@ -42,8 +39,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
FilePath = "testwrite_1.csv",
|
||||
IncludeHeaders = true
|
||||
};
|
||||
SaveResultRequestResult result = null;
|
||||
var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null);
|
||||
var saveRequest = new EventFlowValidator<SaveResultRequestResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.Null(r.Messages);
|
||||
}).Complete();
|
||||
|
||||
// Call save results and wait on the save task
|
||||
await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object);
|
||||
@@ -51,8 +51,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
await selectedResultSet.GetSaveTask(saveParams.FilePath);
|
||||
|
||||
// Expect to see a file successfully created in filepath and a success message
|
||||
VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
saveRequest.Validate();
|
||||
Assert.True(File.Exists(saveParams.FilePath));
|
||||
|
||||
// Delete temp file after test
|
||||
@@ -88,8 +87,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
ColumnStartIndex = 0,
|
||||
ColumnEndIndex = 0
|
||||
};
|
||||
SaveResultRequestResult result = null;
|
||||
var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null);
|
||||
var saveRequest = new EventFlowValidator<SaveResultRequestResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.Null(r.Messages);
|
||||
}).Complete();
|
||||
|
||||
// Call save results and wait on the save task
|
||||
await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object);
|
||||
@@ -98,8 +100,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
await saveTask;
|
||||
|
||||
// Expect to see a file successfully created in filepath and a success message
|
||||
VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
saveRequest.Validate();
|
||||
Assert.True(File.Exists(saveParams.FilePath));
|
||||
|
||||
// Delete temp file after test
|
||||
@@ -130,9 +131,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
BatchIndex = 0,
|
||||
FilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "G:\\test.csv" : "/test.csv"
|
||||
};
|
||||
|
||||
SaveResultRequestError errMessage = null;
|
||||
var saveRequest = GetSaveResultsContextMock( null, err => errMessage = (SaveResultRequestError) err);
|
||||
var saveRequest = new EventFlowValidator<SaveResultRequestResult>()
|
||||
.AddErrorValidation<SaveResultRequestError>(e =>
|
||||
{
|
||||
Assert.False(string.IsNullOrWhiteSpace(e.message));
|
||||
}).Complete();
|
||||
|
||||
// Call save results and wait on the save task
|
||||
await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object);
|
||||
@@ -140,8 +143,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
await selectedResultSet.GetSaveTask(saveParams.FilePath);
|
||||
|
||||
// Expect to see error message
|
||||
VerifySaveResultsCallCount(saveRequest, Times.Never(), Times.Once());
|
||||
Assert.NotNull(errMessage);
|
||||
saveRequest.Validate();
|
||||
Assert.False(File.Exists(saveParams.FilePath));
|
||||
}
|
||||
|
||||
@@ -163,13 +165,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
BatchIndex = 0,
|
||||
FilePath = "testwrite_3.csv"
|
||||
};
|
||||
SaveResultRequestResult result = null;
|
||||
var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null);
|
||||
var saveRequest = new EventFlowValidator<SaveResultRequestResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.NotNull(r.Messages);
|
||||
}).Complete();
|
||||
await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object);
|
||||
|
||||
// Expect message that save failed
|
||||
VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never());
|
||||
Assert.NotNull(result.Messages);
|
||||
saveRequest.Validate();
|
||||
Assert.False(File.Exists(saveParams.FilePath));
|
||||
}
|
||||
|
||||
@@ -194,19 +198,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
BatchIndex = 0,
|
||||
FilePath = "testwrite_4.json"
|
||||
};
|
||||
SaveResultRequestResult result = null;
|
||||
var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null);
|
||||
var saveRequest = new EventFlowValidator<SaveResultRequestResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.Null(r.Messages);
|
||||
}).Complete();
|
||||
|
||||
// Call save results and wait on the save task
|
||||
await queryService.HandleSaveResultsAsJsonRequest(saveParams, saveRequest.Object);
|
||||
ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex];
|
||||
Task saveTask = selectedResultSet.GetSaveTask(saveParams.FilePath);
|
||||
await saveTask;
|
||||
await selectedResultSet.GetSaveTask(saveParams.FilePath);
|
||||
|
||||
// Expect to see a file successfully created in filepath and a success message
|
||||
Assert.Null(result.Messages);
|
||||
saveRequest.Validate();
|
||||
Assert.True(File.Exists(saveParams.FilePath));
|
||||
VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never());
|
||||
|
||||
// Delete temp file after test
|
||||
if (File.Exists(saveParams.FilePath))
|
||||
@@ -240,8 +245,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
ColumnStartIndex = 0,
|
||||
ColumnEndIndex = 1
|
||||
};
|
||||
SaveResultRequestResult result = null;
|
||||
var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null);
|
||||
var saveRequest = new EventFlowValidator<SaveResultRequestResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.Null(r.Messages);
|
||||
}).Complete();
|
||||
|
||||
// Call save results and wait on the save task
|
||||
await queryService.HandleSaveResultsAsJsonRequest(saveParams, saveRequest.Object);
|
||||
@@ -249,8 +257,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
await selectedResultSet.GetSaveTask(saveParams.FilePath);
|
||||
|
||||
// Expect to see a file successfully created in filepath and a success message
|
||||
VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never());
|
||||
Assert.Null(result.Messages);
|
||||
saveRequest.Validate();
|
||||
Assert.True(File.Exists(saveParams.FilePath));
|
||||
|
||||
// Delete temp file after test
|
||||
@@ -281,10 +288,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
BatchIndex = 0,
|
||||
FilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "G:\\test.json" : "/test.json"
|
||||
};
|
||||
|
||||
|
||||
SaveResultRequestError errMessage = null;
|
||||
var saveRequest = GetSaveResultsContextMock( null, err => errMessage = (SaveResultRequestError) err);
|
||||
var saveRequest = new EventFlowValidator<SaveResultRequestResult>()
|
||||
.AddErrorValidation<SaveResultRequestError>(e =>
|
||||
{
|
||||
Assert.False(string.IsNullOrWhiteSpace(e.message));
|
||||
}).Complete();
|
||||
queryService.ActiveQueries[Common.OwnerUri].Batches[0] = Common.GetBasicExecutedBatch();
|
||||
|
||||
// Call save results and wait on the save task
|
||||
@@ -293,8 +301,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
await selectedResultSet.GetSaveTask(saveParams.FilePath);
|
||||
|
||||
// Expect to see error message
|
||||
Assert.NotNull(errMessage);
|
||||
VerifySaveResultsCallCount(saveRequest, Times.Never(), Times.Once());
|
||||
saveRequest.Validate();
|
||||
Assert.False(File.Exists(saveParams.FilePath));
|
||||
}
|
||||
|
||||
@@ -316,48 +323,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
BatchIndex = 0,
|
||||
FilePath = "testwrite_6.json"
|
||||
};
|
||||
SaveResultRequestResult result = null;
|
||||
var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null);
|
||||
var saveRequest = new EventFlowValidator<SaveResultRequestResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
Assert.Equal("Failed to save results, ID not found.", r.Messages);
|
||||
}).Complete();
|
||||
await queryService.HandleSaveResultsAsJsonRequest(saveParams, saveRequest.Object);
|
||||
|
||||
// Expect message that save failed
|
||||
Assert.Equal("Failed to save results, ID not found.", result.Messages);
|
||||
saveRequest.Validate();
|
||||
Assert.False(File.Exists(saveParams.FilePath));
|
||||
VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never());
|
||||
}
|
||||
|
||||
#region Mocking
|
||||
|
||||
/// <summary>
|
||||
/// Mock the requestContext for saving a result set
|
||||
/// </summary>
|
||||
/// <param name="resultCallback"></param>
|
||||
/// <param name="errorCallback"></param>
|
||||
/// <returns></returns>
|
||||
private static Mock<RequestContext<SaveResultRequestResult>> GetSaveResultsContextMock(
|
||||
Action<SaveResultRequestResult> resultCallback,
|
||||
Action<object> errorCallback)
|
||||
{
|
||||
var requestContext = RequestContextMocks.Create(resultCallback)
|
||||
.AddErrorHandling(errorCallback);
|
||||
|
||||
return requestContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify the call count for sendResult and error
|
||||
/// </summary>
|
||||
/// <param name="mock"></param>
|
||||
/// <param name="sendResultCalls"></param>
|
||||
/// <param name="sendErrorCalls"></param>
|
||||
private static void VerifySaveResultsCallCount(Mock<RequestContext<SaveResultRequestResult>> mock,
|
||||
Times sendResultCalls, Times sendErrorCalls)
|
||||
{
|
||||
mock.Verify(rc => rc.SendResult(It.IsAny<SaveResultRequestResult>()), sendResultCalls);
|
||||
mock.Verify(rc => rc.SendError(It.IsAny<object>()), sendErrorCalls);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
@@ -140,17 +138,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
|
||||
// ... And I then ask for a valid set of results from it
|
||||
var subsetParams = new QueryExecuteSubsetParams { OwnerUri = Common.OwnerUri, RowsCount = 1, ResultSetIndex = 0, RowsStartIndex = 0 };
|
||||
QueryExecuteSubsetResult result = null;
|
||||
var subsetRequest = GetQuerySubsetResultContextMock(qesr => result = qesr, null);
|
||||
var subsetRequest = new EventFlowValidator<QueryExecuteSubsetResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
// Then: Messages should be null and subset should not be null
|
||||
Assert.Null(r.Message);
|
||||
Assert.NotNull(r.ResultSubset);
|
||||
}).Complete();
|
||||
await queryService.HandleResultSubsetRequest(subsetParams, subsetRequest.Object);
|
||||
|
||||
// Then:
|
||||
// ... I should have a successful result
|
||||
// ... There should be rows there (other test validate that the rows are correct)
|
||||
// ... There should not be any error calls
|
||||
VerifyQuerySubsetCallCount(subsetRequest, Times.Once(), Times.Never());
|
||||
Assert.Null(result.Message);
|
||||
Assert.NotNull(result.ResultSubset);
|
||||
subsetRequest.Validate();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -161,17 +157,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var subsetParams = new QueryExecuteSubsetParams { OwnerUri = Common.OwnerUri, RowsCount = 1, ResultSetIndex = 0, RowsStartIndex = 0 };
|
||||
QueryExecuteSubsetResult result = null;
|
||||
var subsetRequest = GetQuerySubsetResultContextMock(qesr => result = qesr, null);
|
||||
var subsetRequest = new EventFlowValidator<QueryExecuteSubsetResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
// Then: Messages should not be null and the subset should be null
|
||||
Assert.NotNull(r.Message);
|
||||
Assert.Null(r.ResultSubset);
|
||||
}).Complete();
|
||||
await queryService.HandleResultSubsetRequest(subsetParams, subsetRequest.Object);
|
||||
|
||||
// Then:
|
||||
// ... I should have an error result
|
||||
// ... There should be no rows in the result set
|
||||
// ... There should not be any error calls
|
||||
VerifyQuerySubsetCallCount(subsetRequest, Times.Once(), Times.Never());
|
||||
Assert.NotNull(result.Message);
|
||||
Assert.Null(result.ResultSubset);
|
||||
subsetRequest.Validate();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -189,21 +183,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
|
||||
// ... And I then ask for a valid set of results from it
|
||||
var subsetParams = new QueryExecuteSubsetParams { OwnerUri = Common.OwnerUri, RowsCount = 1, ResultSetIndex = 0, RowsStartIndex = 0 };
|
||||
QueryExecuteSubsetResult result = null;
|
||||
var subsetRequest = GetQuerySubsetResultContextMock(qesr => result = qesr, null);
|
||||
var subsetRequest = new EventFlowValidator<QueryExecuteSubsetResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
// Then: There should not be a subset and message should not be null
|
||||
Assert.NotNull(r.Message);
|
||||
Assert.Null(r.ResultSubset);
|
||||
}).Complete();
|
||||
await queryService.HandleResultSubsetRequest(subsetParams, subsetRequest.Object);
|
||||
|
||||
// Then:
|
||||
// ... I should get an error result
|
||||
// ... There should not be rows
|
||||
// ... There should not be any error calls
|
||||
VerifyQuerySubsetCallCount(subsetRequest, Times.Once(), Times.Never());
|
||||
Assert.NotNull(result.Message);
|
||||
Assert.Null(result.ResultSubset);
|
||||
subsetRequest.Validate();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void SubsetServiceOutOfRangeSubsetTest()
|
||||
public async Task SubsetServiceOutOfRangeSubsetTest()
|
||||
{
|
||||
// If:
|
||||
// ... I have a query that doesn't have any result sets
|
||||
@@ -216,39 +208,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
|
||||
// ... And I then ask for a set of results from it
|
||||
var subsetParams = new QueryExecuteSubsetParams { OwnerUri = Common.OwnerUri, RowsCount = 1, ResultSetIndex = 0, RowsStartIndex = 0 };
|
||||
QueryExecuteSubsetResult result = null;
|
||||
var subsetRequest = GetQuerySubsetResultContextMock(qesr => result = qesr, null);
|
||||
queryService.HandleResultSubsetRequest(subsetParams, subsetRequest.Object).Wait();
|
||||
|
||||
// Then:
|
||||
// ... I should get an error result
|
||||
// ... There should not be rows
|
||||
// ... There should not be any error calls
|
||||
VerifyQuerySubsetCallCount(subsetRequest, Times.Once(), Times.Never());
|
||||
Assert.NotNull(result.Message);
|
||||
Assert.Null(result.ResultSubset);
|
||||
var subsetRequest = new EventFlowValidator<QueryExecuteSubsetResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
// Then: There should be an error message and no subset
|
||||
Assert.NotNull(r.Message);
|
||||
Assert.Null(r.ResultSubset);
|
||||
}).Complete();
|
||||
await queryService.HandleResultSubsetRequest(subsetParams, subsetRequest.Object);
|
||||
subsetRequest.Validate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mocking
|
||||
|
||||
private static Mock<RequestContext<QueryExecuteSubsetResult>> GetQuerySubsetResultContextMock(
|
||||
Action<QueryExecuteSubsetResult> resultCallback,
|
||||
Action<object> errorCallback)
|
||||
{
|
||||
return RequestContextMocks.Create(resultCallback)
|
||||
.AddErrorHandling(errorCallback);
|
||||
}
|
||||
|
||||
private static void VerifyQuerySubsetCallCount(Mock<RequestContext<QueryExecuteSubsetResult>> mock, Times sendResultCalls,
|
||||
Times sendErrorCalls)
|
||||
{
|
||||
mock.Verify(rc => rc.SendResult(It.IsAny<QueryExecuteSubsetResult>()), sendResultCalls);
|
||||
mock.Verify(rc => rc.SendError(It.IsAny<object>()), sendErrorCalls);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// 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.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Test.Utility
|
||||
{
|
||||
public class EventFlowValidator<TRequestContext>
|
||||
{
|
||||
private readonly List<ExpectedEvent> expectedEvents = new List<ExpectedEvent>();
|
||||
private readonly List<ReceivedEvent> receivedEvents = new List<ReceivedEvent>();
|
||||
private readonly Mock<RequestContext<TRequestContext>> requestContext;
|
||||
private bool completed;
|
||||
|
||||
public EventFlowValidator()
|
||||
{
|
||||
requestContext = new Mock<RequestContext<TRequestContext>>(MockBehavior.Strict);
|
||||
}
|
||||
|
||||
public RequestContext<TRequestContext> Object
|
||||
{
|
||||
get { return requestContext.Object; }
|
||||
}
|
||||
|
||||
public EventFlowValidator<TRequestContext> AddEventValidation<TParams>(EventType<TParams> expectedEvent, Action<TParams> paramValidation)
|
||||
{
|
||||
expectedEvents.Add(new ExpectedEvent
|
||||
{
|
||||
EventType = EventTypes.Event,
|
||||
ParamType = typeof(TParams),
|
||||
Validator = paramValidation
|
||||
});
|
||||
|
||||
requestContext.Setup(rc => rc.SendEvent(expectedEvent, It.IsAny<TParams>()))
|
||||
.Callback<EventType<TParams>, TParams>((et, p) =>
|
||||
{
|
||||
receivedEvents.Add(new ReceivedEvent
|
||||
{
|
||||
EventObject = p,
|
||||
EventType = EventTypes.Event
|
||||
});
|
||||
})
|
||||
.Returns(Task.FromResult(0));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public EventFlowValidator<TRequestContext> AddResultValidation(Action<TRequestContext> paramValidation)
|
||||
{
|
||||
// Add the expected event
|
||||
expectedEvents.Add(new ExpectedEvent
|
||||
{
|
||||
EventType = EventTypes.Result,
|
||||
ParamType = typeof(TRequestContext),
|
||||
Validator = paramValidation
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public EventFlowValidator<TRequestContext> AddErrorValidation<TParams>(Action<TParams> paramValidation)
|
||||
{
|
||||
// Add the expected result
|
||||
expectedEvents.Add(new ExpectedEvent
|
||||
{
|
||||
EventType = EventTypes.Error,
|
||||
ParamType = typeof(TParams),
|
||||
Validator = paramValidation
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public EventFlowValidator<TRequestContext> Complete()
|
||||
{
|
||||
// Add general handler for result handling
|
||||
requestContext.Setup(rc => rc.SendResult(It.IsAny<TRequestContext>()))
|
||||
.Callback<TRequestContext>(r => receivedEvents.Add(new ReceivedEvent
|
||||
{
|
||||
EventObject = r,
|
||||
EventType = EventTypes.Result
|
||||
}))
|
||||
.Returns(Task.FromResult(0));
|
||||
|
||||
// Add general handler for error event
|
||||
requestContext.AddErrorHandling(o =>
|
||||
{
|
||||
receivedEvents.Add(new ReceivedEvent
|
||||
{
|
||||
EventObject = o,
|
||||
EventType = EventTypes.Error
|
||||
});
|
||||
});
|
||||
|
||||
completed = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
// Make sure the handlers have been added
|
||||
if (!completed)
|
||||
{
|
||||
throw new Exception("EventFlowValidator must be completed before it can be validated.");
|
||||
}
|
||||
|
||||
// Iterate over the two lists in sync to see if they are the same
|
||||
for (int i = 0; i < Math.Max(expectedEvents.Count, receivedEvents.Count); i++)
|
||||
{
|
||||
// Step 0) Make sure both events exist
|
||||
if (i >= expectedEvents.Count)
|
||||
{
|
||||
throw new Exception($"Unexpected event received: [{receivedEvents[i].EventType}] {receivedEvents[i].EventObject}");
|
||||
}
|
||||
ExpectedEvent expected = expectedEvents[i];
|
||||
|
||||
if (i >= receivedEvents.Count)
|
||||
{
|
||||
throw new Exception($"Expected additional events: [{expectedEvents[i].EventType}] {expectedEvents[i].ParamType}");
|
||||
}
|
||||
ReceivedEvent received = receivedEvents[i];
|
||||
|
||||
// Step 1) Make sure the event type matches
|
||||
Assert.Equal(expected.EventType, received.EventType);
|
||||
|
||||
// Step 2) Make sure the param type matches
|
||||
Assert.Equal(expected.ParamType, received.EventObject.GetType());
|
||||
|
||||
// Step 3) Run the validator on the param object
|
||||
Assert.NotNull(received.EventObject);
|
||||
expected.Validator?.DynamicInvoke(received.EventObject);
|
||||
}
|
||||
}
|
||||
|
||||
private enum EventTypes
|
||||
{
|
||||
Result,
|
||||
Error,
|
||||
Event
|
||||
}
|
||||
|
||||
private class ExpectedEvent
|
||||
{
|
||||
public EventTypes EventType { get; set; }
|
||||
public Type ParamType { get; set; }
|
||||
public Delegate Validator { get; set; }
|
||||
}
|
||||
|
||||
private class ReceivedEvent
|
||||
{
|
||||
public object EventObject { get; set; }
|
||||
public EventTypes EventType { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user