diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs
index 51a35a7d..1bbce090 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs
@@ -31,7 +31,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
private bool disposed;
///
- /// Factory for creating readers/writrs for the output of the batch
+ /// Factory for creating readers/writers for the output of the batch
///
private readonly IFileStreamFactory outputFileFactory;
@@ -151,7 +151,8 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
}
// Make sure we aren't using a ReliableCommad since we do not want automatic retry
- Debug.Assert(!(command is ReliableSqlConnection.ReliableSqlCommand), "ReliableSqlCommand command should not be used to execute queries");
+ Debug.Assert(!(command is ReliableSqlConnection.ReliableSqlCommand),
+ "ReliableSqlCommand command should not be used to execute queries");
// Create a command that we'll use for executing the query
using (command)
@@ -170,18 +171,19 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
{
// Create a message with the number of affected rows -- IF the query affects rows
resultMessages.Add(new ResultMessage(reader.RecordsAffected >= 0
- ? SR.QueryServiceAffectedRows(reader.RecordsAffected)
- : SR.QueryServiceCompletedSuccessfully));
+ ? SR.QueryServiceAffectedRows(reader.RecordsAffected)
+ : SR.QueryServiceCompletedSuccessfully));
continue;
}
// This resultset has results (ie, SELECT/etc queries)
- // Read until we hit the end of the result set
ResultSet resultSet = new ResultSet(reader, outputFileFactory);
- await resultSet.ReadResultToEnd(cancellationToken);
-
+
// Add the result set to the results of the query
resultSets.Add(resultSet);
+
+ // Read until we hit the end of the result set
+ await resultSet.ReadResultToEnd(cancellationToken);
// Add a message for the number of rows the query returned
resultMessages.Add(new ResultMessage(SR.QueryServiceAffectedRows(resultSet.RowCount)));
@@ -194,9 +196,15 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
HasError = true;
UnwrapDbException(dbe);
}
- catch (Exception)
+ catch (TaskCanceledException)
+ {
+ resultMessages.Add(new ResultMessage(SR.QueryServiceQueryCancelled));
+ throw;
+ }
+ catch (Exception e)
{
HasError = true;
+ resultMessages.Add(new ResultMessage(SR.QueryServiceQueryFailed(e.Message)));
throw;
}
finally
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs
index cf2df73c..1c48d516 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs
@@ -96,6 +96,22 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
#region Properties
+ ///
+ /// Delegate type for callback when a query completes or fails
+ ///
+ /// The query that completed
+ public delegate Task QueryAsyncEventHandler(Query q);
+
+ ///
+ /// Callback for when the query has completed successfully
+ ///
+ public event QueryAsyncEventHandler QueryCompleted;
+
+ ///
+ /// Callback for when the query has failed
+ ///
+ public event QueryAsyncEventHandler QueryFailed;
+
///
/// The batches underneath this query
///
@@ -124,6 +140,8 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
}
}
+ internal Task ExecutionTask { get; private set; }
+
///
/// Whether or not the query has completed executed, regardless of success or failure
///
@@ -167,10 +185,44 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
cancellationSource.Cancel();
}
+ public void Execute()
+ {
+ ExecutionTask = Task.Run(ExecuteInternal);
+ }
+
+ ///
+ /// Retrieves a subset of the result sets
+ ///
+ /// The index for selecting the batch item
+ /// The index for selecting the result set
+ /// The starting row of the results
+ /// How many rows to retrieve
+ /// A subset of results
+ public Task GetSubset(int batchIndex, int resultSetIndex, int startRow, int rowCount)
+ {
+ // Sanity check that the results are available
+ if (!HasExecuted)
+ {
+ throw new InvalidOperationException(SR.QueryServiceSubsetNotCompleted);
+ }
+
+ // Sanity check to make sure that the batch is within bounds
+ if (batchIndex < 0 || batchIndex >= Batches.Length)
+ {
+ throw new ArgumentOutOfRangeException(nameof(batchIndex), SR.QueryServiceSubsetBatchOutOfRange);
+ }
+
+ return Batches[batchIndex].GetSubset(resultSetIndex, startRow, rowCount);
+ }
+
+ #endregion
+
+ #region Private Helpers
+
///
/// Executes this query asynchronously and collects all result sets
///
- public async Task Execute()
+ private async Task ExecuteInternal()
{
// Mark that we've internally executed
hasExecuteBeenCalled = true;
@@ -202,6 +254,20 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
{
await b.Execute(conn, cancellationSource.Token);
}
+
+ // Call the query execution callback
+ if (QueryCompleted != null)
+ {
+ await QueryCompleted(this);
+ }
+ }
+ catch (Exception)
+ {
+ // Call the query failure callback
+ if (QueryFailed != null)
+ {
+ await QueryFailed(this);
+ }
}
finally
{
@@ -227,7 +293,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
throw new InvalidOperationException(SR.QueryServiceMessageSenderNotSql);
}
- foreach(SqlError error in args.Errors)
+ foreach (SqlError error in args.Errors)
{
// Did the database context change (error code 5701)?
if (error.Number == DatabaseContextChangeErrorNumber)
@@ -237,31 +303,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
}
}
- ///
- /// Retrieves a subset of the result sets
- ///
- /// The index for selecting the batch item
- /// The index for selecting the result set
- /// The starting row of the results
- /// How many rows to retrieve
- /// A subset of results
- public Task GetSubset(int batchIndex, int resultSetIndex, int startRow, int rowCount)
- {
- // Sanity check that the results are available
- if (!HasExecuted)
- {
- throw new InvalidOperationException(SR.QueryServiceSubsetNotCompleted);
- }
-
- // Sanity check to make sure that the batch is within bounds
- if (batchIndex < 0 || batchIndex >= Batches.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(batchIndex), SR.QueryServiceSubsetBatchOutOfRange);
- }
-
- return Batches[batchIndex].GetSubset(resultSetIndex, startRow, rowCount);
- }
-
#endregion
#region IDisposable Implementation
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
index d0ff8d1a..e6abce65 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
@@ -129,19 +129,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
public async Task HandleExecuteRequest(QueryExecuteParams executeParams,
RequestContext requestContext)
{
- try
- {
- // Get a query new active query
- Query newQuery = await CreateAndActivateNewQuery(executeParams, requestContext);
+ // Get a query new active query
+ Query newQuery = await CreateAndActivateNewQuery(executeParams, requestContext);
- // Execute the query
- await ExecuteAndCompleteQuery(executeParams, requestContext, newQuery);
- }
- catch (Exception e)
- {
- // Dump any unexpected exceptions as errors
- await requestContext.SendError(e.Message);
- }
+ // Execute the query -- asynchronously
+ await ExecuteAndCompleteQuery(executeParams, requestContext, newQuery);
}
public async Task HandleResultSubsetRequest(QueryExecuteSubsetParams subsetParams,
@@ -399,7 +391,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
{
//get column name
DbColumnWrapper col = selectedResultSet.Columns[i];
- string val = row[i]?.ToString();
+ string val = row[i];
jsonWriter.WritePropertyName(col.ColumnName);
if (val == null)
{
@@ -440,10 +432,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
ConnectionInfo connectionInfo;
if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo))
{
- await requestContext.SendResult(new QueryExecuteResult
- {
- Messages = SR.QueryServiceQueryInvalidOwnerUri
- });
+ await requestContext.SendError(SR.QueryServiceQueryInvalidOwnerUri);
return null;
}
@@ -488,24 +477,22 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
Query newQuery = new Query(queryText, connectionInfo, settings, BufferFileFactory);
if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery))
{
- await requestContext.SendResult(new QueryExecuteResult
- {
- Messages = SR.QueryServiceQueryInProgress
- });
+ await requestContext.SendError(SR.QueryServiceQueryInProgress);
+ newQuery.Dispose();
return null;
}
return newQuery;
}
- catch (ArgumentException ane)
+ catch (Exception e)
{
- await requestContext.SendResult(new QueryExecuteResult { Messages = ane.Message });
+ await requestContext.SendError(e.Message);
return null;
}
// Any other exceptions will fall through here and be collected at the end
}
- private async Task ExecuteAndCompleteQuery(QueryExecuteParams executeParams, RequestContext requestContext, Query query)
+ private static async Task ExecuteAndCompleteQuery(QueryExecuteParams executeParams, RequestContext requestContext, Query query)
{
// Skip processing if the query is null
if (query == null)
@@ -513,21 +500,29 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
return;
}
- // Launch the query and respond with successfully launching it
- Task executeTask = query.Execute();
+ // Setup the query completion/failure callbacks
+ Query.QueryAsyncEventHandler callback = async q =>
+ {
+ // Send back the results
+ QueryExecuteCompleteParams eventParams = new QueryExecuteCompleteParams
+ {
+ OwnerUri = executeParams.OwnerUri,
+ BatchSummaries = q.BatchSummaries
+ };
+ await requestContext.SendEvent(QueryExecuteCompleteEvent.Type, eventParams);
+ };
+
+ query.QueryCompleted += callback;
+ query.QueryFailed += callback;
+
+ // Launch this as an asynchronous task
+ query.Execute();
+
+ // Send back a result showing we were successful
await requestContext.SendResult(new QueryExecuteResult
{
Messages = null
});
-
- // Wait for query execution and then send back the results
- await Task.WhenAll(executeTask);
- QueryExecuteCompleteParams eventParams = new QueryExecuteCompleteParams
- {
- OwnerUri = executeParams.OwnerUri,
- BatchSummaries = query.BatchSummaries
- };
- await requestContext.SendEvent(QueryExecuteCompleteEvent.Type, eventParams);
}
#endregion
diff --git a/src/Microsoft.SqlTools.ServiceLayer/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/sr.cs
index 811ab975..dbe3bac6 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/sr.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/sr.cs
@@ -165,6 +165,14 @@ namespace Microsoft.SqlTools.ServiceLayer
}
}
+ public static string QueryServiceQueryCancelled
+ {
+ get
+ {
+ return Keys.GetString(Keys.QueryServiceQueryCancelled);
+ }
+ }
+
public static string QueryServiceSubsetNotCompleted
{
get
@@ -363,6 +371,11 @@ namespace Microsoft.SqlTools.ServiceLayer
return Keys.GetString(Keys.QueryServiceErrorFormat, msg, lvl, state, line, newLine, message);
}
+ public static string QueryServiceQueryFailed(string message)
+ {
+ return Keys.GetString(Keys.QueryServiceQueryFailed, message);
+ }
+
public static string WorkspaceServicePositionColumnOutOfRange(int line)
{
return Keys.GetString(Keys.WorkspaceServicePositionColumnOutOfRange, line);
@@ -376,7 +389,7 @@ namespace Microsoft.SqlTools.ServiceLayer
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Keys
{
- static ResourceManager resourceManager = new ResourceManager(typeof(SR));
+ static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.SR", typeof(SR).GetTypeInfo().Assembly);
static CultureInfo _culture = null;
@@ -444,6 +457,9 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string QueryServiceCancelDisposeFailed = "QueryServiceCancelDisposeFailed";
+ public const string QueryServiceQueryCancelled = "QueryServiceQueryCancelled";
+
+
public const string QueryServiceSubsetNotCompleted = "QueryServiceSubsetNotCompleted";
@@ -480,6 +496,9 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string QueryServiceErrorFormat = "QueryServiceErrorFormat";
+ public const string QueryServiceQueryFailed = "QueryServiceQueryFailed";
+
+
public const string QueryServiceColumnNull = "QueryServiceColumnNull";
diff --git a/src/Microsoft.SqlTools.ServiceLayer/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/sr.resx
index 63d7e71b..ebcaa126 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/sr.resx
+++ b/src/Microsoft.SqlTools.ServiceLayer/sr.resx
@@ -205,6 +205,10 @@
Query successfully cancelled, failed to dispose query. Owner URI not found.
+
+ Query was canceled by user
+
+
The query has not completed, yet
@@ -254,6 +258,11 @@
Msg {0}, Level {1}, State {2}, Line {3}{4}{5}.
Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string)
+
+
+ Query failed: {0}
+ .
+ Parameters: 0 - message (string) (No column name)
diff --git a/src/Microsoft.SqlTools.ServiceLayer/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/sr.strings
index a74a54d9..35bca9c5 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/sr.strings
+++ b/src/Microsoft.SqlTools.ServiceLayer/sr.strings
@@ -79,6 +79,8 @@ QueryServiceCancelAlreadyCompleted = The query has already completed, it cannot
QueryServiceCancelDisposeFailed = Query successfully cancelled, failed to dispose query. Owner URI not found.
+QueryServiceQueryCancelled = Query was canceled by user
+
### Subset Request
QueryServiceSubsetNotCompleted = The query has not completed, yet
@@ -111,6 +113,8 @@ QueryServiceCompletedSuccessfully = Command(s) copleted successfully.
QueryServiceErrorFormat(int msg, int lvl, int state, int line, string newLine, string message) = Msg {0}, Level {1}, State {2}, Line {3}{4}{5}
+QueryServiceQueryFailed(string message) = Query failed: {0}
+
QueryServiceColumnNull = (No column name)
QueryServiceRequestsNoQuery = The requested query does not exist
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/CancelTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/CancelTests.cs
index d27fe156..2ff2045d 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/CancelTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/CancelTests.cs
@@ -24,7 +24,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
// Set up file for returning the query
var fileMock = new Mock();
fileMock.Setup(file => file.GetLinesInRange(It.IsAny()))
- .Returns(new string[] { Common.StandardQuery });
+ .Returns(new[] { Common.StandardQuery });
// Set up workspace mock
var workspaceService = new Mock>();
workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
@@ -36,7 +36,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var executeParams = new QueryExecuteParams { QuerySelection = Common.GetSubSectionDocument(), OwnerUri = Common.OwnerUri };
var executeRequest =
RequestContextMocks.SetupRequestContextMock(null, QueryExecuteCompleteEvent.Type, null, null);
- queryService.HandleExecuteRequest(executeParams, executeRequest.Object).Wait();
+ 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
@@ -71,13 +72,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var executeParams = new QueryExecuteParams {QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri};
var executeRequest =
RequestContextMocks.SetupRequestContextMock(null, QueryExecuteCompleteEvent.Type, null, null);
- queryService.HandleExecuteRequest(executeParams, executeRequest.Object).Wait();
+ 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);
- queryService.HandleCancelRequest(cancelParams, cancelRequest.Object).Wait();
+ await queryService.HandleCancelRequest(cancelParams, cancelRequest.Object);
// Then:
// ... I should have seen a result event with an error message
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
index c3f6df75..bd5abe81 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
@@ -14,9 +14,6 @@ using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
using Microsoft.SqlServer.Management.Common;
-using Microsoft.SqlServer.Management.SmoMetadataProvider;
-using Microsoft.SqlServer.Management.SqlParser.Binder;
-using Microsoft.SqlServer.Management.SqlParser.MetadataProvider;
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
@@ -95,7 +92,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
{
ConnectionInfo ci = CreateTestConnectionInfo(new[] {StandardTestData}, false);
Query query = new Query(StandardQuery, ci, new QueryExecutionSettings(), GetFileStreamFactory());
- query.Execute().Wait();
+ query.Execute();
+ query.ExecutionTask.Wait();
return query;
}
@@ -287,6 +285,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
return new QueryExecutionService(connectionService, workspaceService) {BufferFileStreamFactory = GetFileStreamFactory()};
}
+ public static WorkspaceService GetPrimedWorkspaceService()
+ {
+ // Set up file for returning the query
+ var fileMock = new Mock();
+ fileMock.SetupGet(file => file.Contents).Returns(StandardQuery);
+
+ // Set up workspace mock
+ var workspaceService = new Mock>();
+ workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
+ .Returns(fileMock.Object);
+
+ return workspaceService.Object;
+ }
+
#endregion
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DisposeTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DisposeTests.cs
index b3ff5efd..2f103ec0 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DisposeTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DisposeTests.cs
@@ -4,7 +4,6 @@
//
using System;
-using System.Data.Common;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
@@ -51,7 +50,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
var executeParams = new QueryExecuteParams {QuerySelection = null, OwnerUri = Common.OwnerUri};
var executeRequest = RequestContextMocks.SetupRequestContextMock(null, QueryExecuteCompleteEvent.Type, null, null);
- queryService.HandleExecuteRequest(executeParams, executeRequest.Object).Wait();
+ 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};
@@ -107,6 +107,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var queryParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri };
var requestContext = RequestContextMocks.Create(null);
await queryService.HandleExecuteRequest(queryParams, requestContext.Object);
+ await queryService.ActiveQueries[Common.OwnerUri].ExecutionTask;
// ... And it sticks around as an active query
Assert.Equal(1, queryService.ActiveQueries.Count);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/ExecuteTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/ExecuteTests.cs
index 2484e233..c5694fa1 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/ExecuteTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/ExecuteTests.cs
@@ -19,7 +19,6 @@ using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
using Microsoft.SqlTools.ServiceLayer.Workspace;
using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
-using Microsoft.SqlTools.Test.Utility;
using Moq;
using Xunit;
@@ -295,7 +294,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
// If:
// ... I then execute the query
- query.Execute().Wait();
+ query.Execute();
+ query.ExecutionTask.Wait();
// Then:
// ... The query should have completed successfully with one batch summary returned
@@ -321,7 +321,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
// If:
// ... I Then execute the query
- query.Execute().Wait();
+ query.Execute();
+ query.ExecutionTask.Wait();
// Then:
// ... The query should have completed successfully with no batch summaries returned
@@ -348,7 +349,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
// If:
// ... I then execute the query
- query.Execute().Wait();
+ query.Execute();
+ query.ExecutionTask.Wait();
// Then:
// ... The query should have completed successfully with two batch summaries returned
@@ -376,7 +378,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
// If:
// .. I then execute the query
- query.Execute().Wait();
+ query.Execute();
+ query.ExecutionTask.Wait();
// ... The query should have completed successfully with one batch summary returned
Assert.True(query.HasExecuted);
@@ -402,7 +405,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
// If:
// ... I then execute the query
- query.Execute().Wait();
+ query.Execute();
+ query.ExecutionTask.Wait();
// Then:
// ... There should be an error on the batch
@@ -444,7 +448,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
expectedEvent: QueryExecuteCompleteEvent.Type,
eventCallback: (et, cp) => completeParams = cp,
errorCallback: null);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
+ await AwaitExecution(queryService, queryParams, requestContext.Object);
// Then:
// ... No Errors should have been sent
@@ -485,7 +489,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
expectedEvent: QueryExecuteCompleteEvent.Type,
eventCallback: (et, cp) => completeParams = cp,
errorCallback: null);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
+ await AwaitExecution(queryService, queryParams, requestContext.Object);
// Then:
// ... No errors should have been sent
@@ -512,18 +516,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), false, workspaceService.Object);
var queryParams = new QueryExecuteParams { OwnerUri = "notConnected", QuerySelection = Common.WholeDocument };
- QueryExecuteResult result = null;
- var requestContext = RequestContextMocks.SetupRequestContextMock(qer => result = qer, QueryExecuteCompleteEvent.Type, null, null);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
+ object error = null;
+ var requestContext = RequestContextMocks.Create(null)
+ .AddErrorHandling(e => error = e);
+ await queryService.HandleExecuteRequest(queryParams, requestContext.Object);
// Then:
- // ... An error message should have been returned via the result
+ // ... An error should have been returned
+ // ... No result should have been returned
// ... No completion event should have been fired
- // ... No error event should have been fired
// ... There should be no active queries
- VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Never(), Times.Never());
- Assert.NotNull(result.Messages);
- Assert.NotEmpty(result.Messages);
+ VerifyQueryExecuteCallCount(requestContext, Times.Never(), Times.Never(), Times.Once());
+ Assert.IsType(error);
+ Assert.NotEmpty((string)error);
Assert.Empty(queryService.ActiveQueries);
}
@@ -545,24 +550,25 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
// Note, we don't care about the results of the first request
- var firstRequestContext = RequestContextMocks.SetupRequestContextMock(null, QueryExecuteCompleteEvent.Type, null, null);
- queryService.HandleExecuteRequest(queryParams, firstRequestContext.Object).Wait();
+ var firstRequestContext = RequestContextMocks.Create(null);
+ await AwaitExecution(queryService, queryParams, firstRequestContext.Object);
// ... And then I request another query without waiting for the first to complete
queryService.ActiveQueries[Common.OwnerUri].HasExecuted = false; // Simulate query hasn't finished
- QueryExecuteResult result = null;
- var secondRequestContext = RequestContextMocks.SetupRequestContextMock(qer => result = qer, QueryExecuteCompleteEvent.Type, null, null);
- queryService.HandleExecuteRequest(queryParams, secondRequestContext.Object).Wait();
+ object error = null;
+ var secondRequestContext = RequestContextMocks.Create(null)
+ .AddErrorHandling(e => error = e);
+ await AwaitExecution(queryService, queryParams, secondRequestContext.Object);
// Then:
- // ... No errors should have been sent
- // ... A result should have been sent with an error message
+ // ... An error should have been sent
+ // ... A result should have not have been sent
// ... No completion event should have been fired
- // ... There should only be one active query
- VerifyQueryExecuteCallCount(secondRequestContext, Times.Once(), Times.AtMostOnce(), Times.Never());
- Assert.NotNull(result.Messages);
- Assert.NotEmpty(result.Messages);
- Assert.Equal(1, queryService.ActiveQueries.Count);
+ // ... The original query should exist
+ VerifyQueryExecuteCallCount(secondRequestContext, Times.Never(), Times.Never(), Times.Once());
+ Assert.IsType(error);
+ Assert.NotEmpty((string)error);
+ Assert.Contains(Common.OwnerUri, queryService.ActiveQueries.Keys);
}
[Fact]
@@ -584,15 +590,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
// Note, we don't care about the results of the first request
var firstRequestContext = RequestContextMocks.SetupRequestContextMock(null, QueryExecuteCompleteEvent.Type, null, null);
-
- queryService.HandleExecuteRequest(queryParams, firstRequestContext.Object).Wait();
+ await AwaitExecution(queryService, queryParams, firstRequestContext.Object);
// ... And then I request another query after waiting for the first to complete
QueryExecuteResult result = null;
QueryExecuteCompleteParams complete = null;
var secondRequestContext =
RequestContextMocks.SetupRequestContextMock(qer => result = qer, QueryExecuteCompleteEvent.Type, (et, qecp) => complete = qecp, null);
- queryService.HandleExecuteRequest(queryParams, secondRequestContext.Object).Wait();
+ await AwaitExecution(queryService, queryParams, secondRequestContext.Object);
// Then:
// ... No errors should have been sent
@@ -606,7 +611,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
[Theory]
[InlineData(null)]
- public async void QueryExecuteMissingSelectionTest(SelectionData selection)
+ public async Task QueryExecuteMissingSelectionTest(SelectionData selection)
{
// Set up file for returning the query
@@ -621,18 +626,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = selection };
- QueryExecuteResult result = null;
- var requestContext =
- RequestContextMocks.SetupRequestContextMock(qer => result = qer, QueryExecuteCompleteEvent.Type, null, null);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
+ object errorResult = null;
+ var requestContext = RequestContextMocks.Create(null)
+ .AddErrorHandling(error => errorResult = error);
+ await queryService.HandleExecuteRequest(queryParams, requestContext.Object);
// Then:
- // ... No errors should have been sent
- // ... A result should have been sent with an error message
+ // ... Am error should have been sent
+ // ... No result should have been sent
// ... No completion event should have been fired
- VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Never(), Times.Never());
- Assert.NotNull(result.Messages);
- Assert.NotEmpty(result.Messages);
+ // ... An active query should not have been added
+ VerifyQueryExecuteCallCount(requestContext, Times.Never(), Times.Never(), Times.Once());
+ Assert.NotNull(errorResult);
+ Assert.IsType(errorResult);
+ Assert.DoesNotContain(Common.OwnerUri, queryService.ActiveQueries.Keys);
// ... There should not be an active query
Assert.Empty(queryService.ActiveQueries);
@@ -657,7 +664,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
QueryExecuteCompleteParams complete = null;
var requestContext =
RequestContextMocks.SetupRequestContextMock(qer => result = qer, QueryExecuteCompleteEvent.Type, (et, qecp) => complete = qecp, null);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
+ await AwaitExecution(queryService, queryParams, requestContext.Object);
// Then:
// ... No errors should have been sent
@@ -700,7 +707,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
#endregion
- private void VerifyQueryExecuteCallCount(Mock> mock, Times sendResultCalls, Times sendEventCalls, Times sendErrorCalls)
+ private static void VerifyQueryExecuteCallCount(Mock> mock, Times sendResultCalls, Times sendEventCalls, Times sendErrorCalls)
{
mock.Verify(rc => rc.SendResult(It.IsAny()), sendResultCalls);
mock.Verify(rc => rc.SendEvent(
@@ -709,9 +716,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
mock.Verify(rc => rc.SendError(It.IsAny