diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs
index 0ee7d550..718eea7b 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Batch.cs
@@ -40,16 +40,16 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
///
private DateTime executionStartTime;
+ ///
+ /// Whether or not any messages have been sent
+ ///
+ private bool messagesSent;
+
///
/// Factory for creating readers/writers for the output of the batch
///
private readonly IFileStreamFactory outputFileFactory;
- ///
- /// Internal representation of the messages so we can modify internally
- ///
- internal readonly List resultMessages;
-
///
/// Internal representation of the result sets so we can modify internally
///
@@ -71,7 +71,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
HasExecuted = false;
Id = ordinalId;
resultSets = new List();
- resultMessages = new List();
this.outputFileFactory = outputFileFactory;
}
@@ -83,11 +82,22 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
/// The batch that completed
public delegate Task BatchAsyncEventHandler(Batch batch);
+ ///
+ /// Asynchronous handler for when a message is emitted by the sql connection
+ ///
+ /// The message that was emitted
+ public delegate Task BatchAsyncMessageHandler(ResultMessage message);
+
///
/// Event that will be called when the batch has completed execution
///
public event BatchAsyncEventHandler BatchCompletion;
+ ///
+ /// Event that will be called when a message has been emitted
+ ///
+ public event BatchAsyncMessageHandler BatchMessageSent;
+
///
/// Event to call when the batch has started execution
///
@@ -132,11 +142,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
///
public string ExecutionStartTimeStamp { get { return executionStartTime.ToString("o"); } }
- ///
- /// Whether or not this batch has an error
- ///
- public bool HasError { get; set; }
-
///
/// Whether or not this batch has been executed, regardless of success or failure
///
@@ -147,14 +152,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
///
public int Id { get; private set; }
- ///
- /// Messages that have come back from the server
- ///
- public IEnumerable ResultMessages
- {
- get { return resultMessages; }
- }
-
///
/// The result sets of the batch execution
///
@@ -187,7 +184,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
// Batch summary with information available at start
BatchSummary summary = new BatchSummary
{
- HasError = HasError,
Id = Id,
Selection = Selection,
ExecutionStart = ExecutionStartTimeStamp
@@ -197,7 +193,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
if (HasExecuted)
{
summary.ResultSetSummaries = ResultSummaries;
- summary.Messages = ResultMessages.ToArray();
summary.ExecutionEnd = ExecutionEndTimeStamp;
summary.ExecutionElapsed = ExecutionElapsedTime;
}
@@ -244,7 +239,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
{
// Register the message listener to *this instance* of the batch
// Note: This is being done to associate messages with batches
- sqlConn.GetUnderlyingConnection().InfoMessage += StoreDbMessage;
+ sqlConn.GetUnderlyingConnection().InfoMessage += ServerMessageHandler;
command = sqlConn.GetUnderlyingConnection().CreateCommand();
// Add a handler for when the command completes
@@ -298,27 +293,25 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
// If there were no messages, for whatever reason (NO COUNT set, messages
// were emitted, records returned), output a "successful" message
- if (resultMessages.Count == 0)
+ if (!messagesSent)
{
- resultMessages.Add(new ResultMessage(SR.QueryServiceCompletedSuccessfully));
+ await SendMessage(SR.QueryServiceCompletedSuccessfully, false);
}
}
}
}
catch (DbException dbe)
{
- HasError = true;
- UnwrapDbException(dbe);
+ await UnwrapDbException(dbe);
}
catch (TaskCanceledException)
{
- resultMessages.Add(new ResultMessage(SR.QueryServiceQueryCancelled));
+ await SendMessage(SR.QueryServiceQueryCancelled, false);
throw;
}
catch (Exception e)
{
- HasError = true;
- resultMessages.Add(new ResultMessage(SR.QueryServiceQueryFailed(e.Message)));
+ await SendMessage(SR.QueryServiceQueryFailed(e.Message), true);
throw;
}
finally
@@ -327,7 +320,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
ReliableSqlConnection sqlConn = conn as ReliableSqlConnection;
if (sqlConn != null)
{
- sqlConn.GetUnderlyingConnection().InfoMessage -= StoreDbMessage;
+ sqlConn.GetUnderlyingConnection().InfoMessage -= ServerMessageHandler;
}
// Mark that we have executed
@@ -400,6 +393,19 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
#region Private Helpers
+ private async Task SendMessage(string message, bool isError)
+ {
+ // If the message event is null, this is a no-op
+ if (BatchMessageSent == null)
+ {
+ return;
+ }
+
+ // State that we've sent any message, and send it
+ messagesSent = true;
+ await BatchMessageSent(new ResultMessage(message, isError, Id));
+ }
+
///
/// Handler for when the StatementCompleted event is fired for this batch's command. This
/// will be executed ONLY when there is a rowcount to report. If this event is not fired
@@ -410,17 +416,10 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
internal void StatementCompletedHandler(object sender, StatementCompletedEventArgs args)
{
// Add a message for the number of rows the query returned
- string message;
- if (args.RecordCount == 1)
- {
- message = SR.QueryServiceAffectedOneRow;
- }
- else
- {
- message = SR.QueryServiceAffectedRows(args.RecordCount);
- }
-
- resultMessages.Add(new ResultMessage(message));
+ string message = args.RecordCount == 1
+ ? SR.QueryServiceAffectedOneRow
+ : SR.QueryServiceAffectedRows(args.RecordCount);
+ SendMessage(message, false).Wait();
}
///
@@ -430,30 +429,30 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
///
/// Object that fired the event
/// Arguments from the event
- private void StoreDbMessage(object sender, SqlInfoMessageEventArgs args)
+ private void ServerMessageHandler(object sender, SqlInfoMessageEventArgs args)
{
- resultMessages.Add(new ResultMessage(args.Message));
+ SendMessage(args.Message, false).Wait();
}
///
- /// Attempts to convert a to a that
+ /// Attempts to convert an to a that
/// contains much more info about Sql Server errors. The exception is then unwrapped and
- /// messages are formatted and stored in . If the exception
- /// cannot be converted to SqlException, the message is written to the messages list.
+ /// messages are formatted and sent to the extension. If the exception cannot be
+ /// converted to SqlException, the message is written to the messages list.
///
/// The exception to unwrap
- internal void UnwrapDbException(DbException dbe)
+ private async Task UnwrapDbException(Exception dbe)
{
SqlException se = dbe as SqlException;
if (se != null)
{
var errors = se.Errors.Cast().ToList();
+
// Detect user cancellation errors
if (errors.Any(error => error.Class == 11 && error.Number == 0))
{
// User cancellation error, add the single message
- HasError = false;
- resultMessages.Add(new ResultMessage(SR.QueryServiceQueryCancelled));
+ await SendMessage(SR.QueryServiceQueryCancelled, false);
}
else
{
@@ -464,13 +463,13 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
string message = string.Format("Msg {0}, Level {1}, State {2}, Line {3}{4}{5}",
error.Number, error.Class, error.State, lineNumber,
Environment.NewLine, error.Message);
- resultMessages.Add(new ResultMessage(message));
+ await SendMessage(message, true);
}
}
}
else
{
- resultMessages.Add(new ResultMessage(dbe.Message));
+ await SendMessage(dbe.Message, true);
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/BatchSummary.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/BatchSummary.cs
index 884d76f6..f9404039 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/BatchSummary.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/BatchSummary.cs
@@ -25,11 +25,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
///
public string ExecutionStart { get; set; }
- ///
- /// Whether or not the batch was successful. True indicates errors, false indicates success
- ///
- public bool HasError { get; set; }
-
///
/// The ID of the result set within the query results
///
@@ -40,11 +35,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
///
public SelectionData Selection { get; set; }
- ///
- /// Any messages that came back from the server during execution of the batch
- ///
- public ResultMessage[] Messages { get; set; }
-
///
/// The summaries of the result sets inside the batch
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteCompleteNotification.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteCompleteNotification.cs
index 8375235a..90c8c7b3 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteCompleteNotification.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteCompleteNotification.cs
@@ -21,11 +21,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
/// Summaries of the result sets that were returned with the query
///
public BatchSummary[] BatchSummaries { get; set; }
-
- ///
- /// Error message, if any
- ///
- public string Message { get; set; }
}
public class QueryExecuteCompleteEvent
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteMessageNotification.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteMessageNotification.cs
new file mode 100644
index 00000000..e65f90d0
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteMessageNotification.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
+
+namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
+{
+ ///
+ /// Parameters to be sent back with a message notification
+ ///
+ public class QueryExecuteMessageParams
+ {
+ ///
+ /// URI for the editor that owns the query
+ ///
+ public string OwnerUri { get; set; }
+
+ ///
+ /// The message that is being returned
+ ///
+ public ResultMessage Message { get; set; }
+ }
+
+ public class QueryExecuteMessageEvent
+ {
+ public static readonly
+ EventType Type =
+ EventType.Create("query/message");
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteRequest.cs
index 7630b712..b5671fd9 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteRequest.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/QueryExecuteRequest.cs
@@ -28,10 +28,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
///
public class QueryExecuteResult
{
- ///
- /// Informational messages from the query runner. Optional, can be set to null.
- ///
- public string Messages { get; set; }
}
public class QueryExecuteRequest
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultMessage.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultMessage.cs
index 90f66015..cc7ffc10 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultMessage.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ResultMessage.cs
@@ -12,6 +12,17 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
///
public class ResultMessage
{
+ ///
+ /// ID of the batch that generated this message. If null, this message
+ /// was not generated as part of a batch
+ ///
+ public int? BatchId { get; set; }
+
+ ///
+ /// Whether or not this message is an error
+ ///
+ public bool IsError { get; set; }
+
///
/// Timestamp of the message
/// Stored in UTC ISO 8601 format; should be localized before displaying to any user
@@ -23,20 +34,13 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
///
public string Message { get; set; }
- ///
- /// Full constructor
- ///
- public ResultMessage(string timeStamp, string message)
- {
- Time = timeStamp;
- Message = message;
- }
-
///
/// Constructor with default "Now" time
///
- public ResultMessage(string message)
+ public ResultMessage(string message, bool isError, int? batchId)
{
+ BatchId = batchId;
+ IsError = isError;
Time = DateTime.Now.ToString("o");
Message = message;
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs
index d5948a8a..1f23bc0b 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs
@@ -99,6 +99,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
///
public event Batch.BatchAsyncEventHandler BatchCompleted;
+ ///
+ /// Event that will be called when a message has been emitted
+ ///
+ public event Batch.BatchAsyncMessageHandler BatchMessageSent;
+
///
/// Event to be called when a batch starts execution.
///
@@ -272,6 +277,14 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
// Don't actually execute if there aren't any batches to execute
if (Batches.Length == 0)
{
+ if (BatchMessageSent != null)
+ {
+ await BatchMessageSent(new ResultMessage(SR.QueryServiceCompletedSuccessfully, false, null));
+ }
+ if (QueryCompleted != null)
+ {
+ await QueryCompleted(this);
+ }
return;
}
@@ -308,6 +321,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
{
b.BatchStart += BatchStarted;
b.BatchCompletion += BatchCompleted;
+ b.BatchMessageSent += BatchMessageSent;
b.ResultSetCompletion += ResultSetCompleted;
await b.Execute(conn, cancellationSource.Token);
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
index 7f307fee..b23e07eb 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs
@@ -370,10 +370,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
}
// Send the result stating that the query was successfully started
- await requestContext.SendResult(new QueryExecuteResult
- {
- Messages = newQuery.Batches.Length == 0 ? SR.QueryServiceCompletedSuccessfully : null
- });
+ await requestContext.SendResult(new QueryExecuteResult());
return newQuery;
}
@@ -411,7 +408,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
QueryExecuteCompleteParams eventParams = new QueryExecuteCompleteParams
{
OwnerUri = executeParams.OwnerUri,
- Message = errorMessage
+ //Message = errorMessage
};
await requestContext.SendEvent(QueryExecuteCompleteEvent.Type, eventParams);
};
@@ -443,6 +440,17 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
};
query.BatchCompleted += batchCompleteCallback;
+ Batch.BatchAsyncMessageHandler batchMessageCallback = async m =>
+ {
+ QueryExecuteMessageParams eventParams = new QueryExecuteMessageParams
+ {
+ Message = m,
+ OwnerUri = executeParams.OwnerUri
+ };
+ await requestContext.SendEvent(QueryExecuteMessageEvent.Type, eventParams);
+ };
+ query.BatchMessageSent += batchMessageCallback;
+
// Setup the ResultSet completion callback
ResultSet.ResultSetAsyncEventHandler resultCallback = async r =>
{
diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs
index 4a1f7f3c..49ac3e47 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Connection/ReliableConnectionTests.cs
@@ -777,9 +777,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Connection
var detectionStrategy2 = new TestSqlAzureTemporaryAndIgnorableErrorDetectionStrategy();
Assert.NotNull(detectionStrategy2.InvokeCanRetrySqlException(sqlException));
Assert.NotNull(detectionStrategy2.InvokeShouldIgnoreSqlException(sqlException));
-
- Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory(null));
- batch.UnwrapDbException(sqlException);
}
var unknownCodeReason = RetryPolicy.ThrottlingReason.FromReasonCode(-1);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/QueryExecutionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/QueryExecutionTests.cs
index 8d41cd1e..e5758458 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/QueryExecutionTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.PerfTests/Tests/QueryExecutionTests.cs
@@ -79,7 +79,7 @@ namespace Microsoft.SqlTools.ServiceLayer.PerfTests
};
var result = await testHelper.Driver.SendRequest(QueryExecuteRequest.Type, queryParams);
- if (result != null && string.IsNullOrEmpty(result.Messages))
+ if (result != null)
{
TestTimer timer = new TestTimer() { PrintResult = true };
await Common.ExecuteWithTimeout(timer, 100000, async () =>
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
index 4a5ead4b..f70c529c 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
@@ -97,6 +97,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
return output;
}
+ public static Dictionary[][] GetTestDataSet(int dataSets)
+ {
+ List[]> output = new List[]>();
+ for(int dataSet = 0; dataSet < dataSets; dataSet++)
+ {
+ output.Add(StandardTestData);
+ }
+ return output.ToArray();
+ }
+
public static async Task AwaitExecution(QueryExecutionService service, QueryExecuteParams qeParams,
RequestContext requestContext)
{
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/BatchTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/BatchTests.cs
index 9ac1f6c2..64133fa0 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/BatchTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/BatchTests.cs
@@ -7,8 +7,7 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
-using System.Data.SqlClient;
-using System.Linq;
+using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
@@ -32,12 +31,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... It should not have executed and no error
Assert.False(batch.HasExecuted, "The query should not have executed.");
- Assert.False(batch.HasError, "The batch should not have an error");
// ... The results should be empty
Assert.Empty(batch.ResultSets);
Assert.Empty(batch.ResultSummaries);
- Assert.Empty(batch.ResultMessages);
// ... The start line of the batch should be 0
Assert.Equal(0, batch.Selection.StartLine);
@@ -46,318 +43,186 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
Assert.Equal(Common.Ordinal, batch.Id);
// ... The summary should have the same info
- Assert.False(batch.Summary.HasError);
Assert.Equal(Common.Ordinal, batch.Summary.Id);
Assert.Null(batch.Summary.ResultSetSummaries);
- Assert.Null(batch.Summary.Messages);
Assert.Equal(0, batch.Summary.Selection.StartLine);
Assert.NotEqual(default(DateTime).ToString("o"), batch.Summary.ExecutionStart); // Should have been set at construction
Assert.Null(batch.Summary.ExecutionEnd);
Assert.Null(batch.Summary.ExecutionElapsed);
}
- ///
- /// Note: This test also tests the start notification feature
- ///
[Fact]
- public void BatchExecuteNoResultSets()
+ public async Task BatchExecuteNoResultSets()
{
// Setup:
- // ... Create a callback for batch start
- BatchSummary batchSummaryFromStart = null;
- Batch.BatchAsyncEventHandler batchStartCallback = b =>
- {
- batchSummaryFromStart = b.Summary;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for batch completion
- BatchSummary batchSummaryFromCompletion = null;
- Batch.BatchAsyncEventHandler batchCompleteCallback = b =>
- {
- batchSummaryFromCompletion = b.Summary;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for result completion
- bool resultCallbackFired = false;
- ResultSet.ResultSetAsyncEventHandler resultSetCallback = r =>
- {
- resultCallbackFired = true;
- return Task.FromResult(0);
- };
+ // ... Keep track of callbacks being called
+ int batchStartCalls = 0;
+ int batchEndCalls = 0;
+ int resultSetCalls = 0;
+ List messages = new List();
// If I execute a query that should get no result sets
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
- batch.BatchStart += batchStartCallback;
- batch.BatchCompletion += batchCompleteCallback;
- batch.ResultSetCompletion += resultSetCallback;
- batch.Execute(GetConnection(Common.CreateTestConnectionInfo(null, false)), CancellationToken.None).Wait();
+ BatchCallbackHelper(batch,
+ b => batchStartCalls++,
+ b => batchEndCalls++,
+ m => messages.Add(m),
+ r => resultSetCalls++);
+ await batch.Execute(GetConnection(Common.CreateTestConnectionInfo(null, false)), CancellationToken.None);
// Then:
- // ... It should have executed without error
- Assert.True(batch.HasExecuted, "The query should have been marked executed.");
- Assert.False(batch.HasError, "The batch should not have an error");
+ // ... Callbacks should have been called the appropriate number of times
+ Assert.Equal(1, batchStartCalls);
+ Assert.Equal(1, batchEndCalls);
+ Assert.Equal(0, resultSetCalls);
- // ... The results should be empty
- Assert.Empty(batch.ResultSets);
- Assert.Empty(batch.ResultSummaries);
-
- // ... The results should not be null
- Assert.NotNull(batch.ResultSets);
- Assert.NotNull(batch.ResultSummaries);
-
- // ... There should be a message for how many rows were affected
- Assert.Equal(1, batch.ResultMessages.Count());
-
- // ... The callback for batch start should have been called
- // ... The info from it should have been basic
- Assert.NotNull(batchSummaryFromStart);
- Assert.False(batchSummaryFromStart.HasError);
- Assert.Equal(Common.Ordinal, batchSummaryFromStart.Id);
- Assert.Equal(Common.SubsectionDocument, batchSummaryFromStart.Selection);
- Assert.True(DateTime.Parse(batchSummaryFromStart.ExecutionStart) > default(DateTime));
- Assert.Null(batchSummaryFromStart.ResultSetSummaries);
- Assert.Null(batchSummaryFromStart.Messages);
- Assert.Null(batchSummaryFromStart.ExecutionElapsed);
- Assert.Null(batchSummaryFromStart.ExecutionEnd);
-
- // ... The callback for batch completion should have been fired
- // ... The summary should match the expected info
- Assert.NotNull(batchSummaryFromCompletion);
- Assert.False(batchSummaryFromCompletion.HasError);
- Assert.Equal(Common.Ordinal, batchSummaryFromCompletion.Id);
- Assert.Equal(0, batchSummaryFromCompletion.ResultSetSummaries.Length);
- Assert.Equal(1, batchSummaryFromCompletion.Messages.Length);
- Assert.Equal(Common.SubsectionDocument, batchSummaryFromCompletion.Selection);
- Assert.True(DateTime.Parse(batchSummaryFromCompletion.ExecutionStart) > default(DateTime));
- Assert.True(DateTime.Parse(batchSummaryFromCompletion.ExecutionEnd) > default(DateTime));
- Assert.NotNull(batchSummaryFromCompletion.ExecutionElapsed);
-
- // ... The callback for the result set should NOT have been fired
- Assert.False(resultCallbackFired);
+ // ... The batch and the summary should be correctly assigned
+ ValidateBatch(batch, 0);
+ ValidateBatchSummary(batch);
+ ValidateMessages(batch, 1, messages);
}
[Fact]
- public void BatchExecuteOneResultSet()
+ public async Task BatchExecuteOneResultSet()
{
+ // Setup:
+ // ... Keep track of callbacks being called
+ int batchStartCalls = 0;
+ int batchEndCalls = 0;
+ int resultSetCalls = 0;
+ List messages = new List();
+
+ // ... Build a data set to return
const int resultSets = 1;
- ConnectionInfo ci = Common.CreateTestConnectionInfo(new[] { Common.StandardTestData }, false);
-
- // Setup: Create a callback for batch completion
- BatchSummary batchSummaryFromCallback = null;
- Batch.BatchAsyncEventHandler batchCallback = b =>
- {
- batchSummaryFromCallback = b.Summary;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for result set completion
- bool resultCallbackFired = false;
- ResultSet.ResultSetAsyncEventHandler resultSetCallback = r =>
- {
- resultCallbackFired = true;
- return Task.FromResult(0);
- };
+ ConnectionInfo ci = Common.CreateTestConnectionInfo(Common.GetTestDataSet(resultSets), false);
// If I execute a query that should get one result set
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
- batch.BatchCompletion += batchCallback;
- batch.ResultSetCompletion += resultSetCallback;
- batch.Execute(GetConnection(ci), CancellationToken.None).Wait();
+ BatchCallbackHelper(batch,
+ b => batchStartCalls++,
+ b => batchEndCalls++,
+ m => messages.Add(m),
+ r => resultSetCalls++);
+ await batch.Execute(GetConnection(ci), CancellationToken.None);
// Then:
- // ... It should have executed without error
- Assert.True(batch.HasExecuted, "The batch should have been marked executed.");
- Assert.False(batch.HasError, "The batch should not have an error");
+ // ... Callbacks should have been called the appropriate number of times
+ Assert.Equal(1, batchStartCalls);
+ Assert.Equal(1, batchEndCalls);
+ Assert.Equal(1, resultSetCalls);
// ... There should be exactly one result set
- Assert.Equal(resultSets, batch.ResultSets.Count);
- Assert.Equal(resultSets, batch.ResultSummaries.Length);
-
- // ... Inside the result set should be with 5 rows
- Assert.Equal(Common.StandardRows, batch.ResultSets.First().RowCount);
- Assert.Equal(Common.StandardRows, batch.ResultSummaries[0].RowCount);
-
- // ... Inside the result set should have 5 columns
- Assert.Equal(Common.StandardColumns, batch.ResultSets.First().Columns.Length);
- Assert.Equal(Common.StandardColumns, batch.ResultSummaries[0].ColumnInfo.Length);
-
- // ... There should be a message for how many rows were affected
- Assert.Equal(resultSets, batch.ResultMessages.Count());
-
- // ... The callback for batch completion should have been fired
- Assert.NotNull(batchSummaryFromCallback);
-
- // ... The callback for resultset completion should have been fired
- Assert.True(resultCallbackFired); // We only want to validate that it happened, validation of the
- // summary is done in result set tests
+ ValidateBatch(batch, resultSets);
+ ValidateBatchSummary(batch);
+ ValidateMessages(batch, 1, messages);
}
[Fact]
- public void BatchExecuteTwoResultSets()
+ public async Task BatchExecuteTwoResultSets()
{
- var dataset = new[] { Common.StandardTestData, Common.StandardTestData };
- int resultSets = dataset.Length;
- ConnectionInfo ci = Common.CreateTestConnectionInfo(dataset, false);
+ // Setup:
+ // ... Keep track of callbacks being called
+ int batchStartCalls = 0;
+ int batchEndCalls = 0;
+ int resultSetCalls = 0;
+ List messages = new List();
- // Setup: Create a callback for batch completion
- BatchSummary batchSummaryFromCallback = null;
- Batch.BatchAsyncEventHandler batchCallback = b =>
- {
- batchSummaryFromCallback = b.Summary;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for resultset completion
- int resultSummaryCount = 0;
- ResultSet.ResultSetAsyncEventHandler resultSetCallback = r =>
- {
- resultSummaryCount++;
- return Task.FromResult(0);
- };
+ // ... Build a data set to return
+ const int resultSets = 2;
+ ConnectionInfo ci = Common.CreateTestConnectionInfo(Common.GetTestDataSet(resultSets), false);
// If I execute a query that should get two result sets
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
- batch.BatchCompletion += batchCallback;
- batch.ResultSetCompletion += resultSetCallback;
- batch.Execute(GetConnection(ci), CancellationToken.None).Wait();
+ BatchCallbackHelper(batch,
+ b => batchStartCalls++,
+ b => batchEndCalls++,
+ m => messages.Add(m),
+ r => resultSetCalls++);
+ await batch.Execute(GetConnection(ci), CancellationToken.None);
// Then:
+ // ... Callbacks should have been called the appropriate number of times
+ Assert.Equal(1, batchStartCalls);
+ Assert.Equal(1, batchEndCalls);
+ Assert.Equal(2, resultSetCalls);
+
// ... It should have executed without error
- Assert.True(batch.HasExecuted, "The batch should have been marked executed.");
- Assert.False(batch.HasError, "The batch should not have an error");
-
- // ... There should be exactly two result sets
- Assert.Equal(resultSets, batch.ResultSets.Count());
-
- foreach (ResultSet rs in batch.ResultSets)
- {
- // ... Each result set should have 5 rows
- Assert.Equal(Common.StandardRows, rs.RowCount);
-
- // ... Inside each result set should be 5 columns
- Assert.Equal(Common.StandardColumns, rs.Columns.Length);
- }
-
- // ... There should be exactly two result set summaries
- Assert.Equal(resultSets, batch.ResultSummaries.Length);
-
- foreach (ResultSetSummary rs in batch.ResultSummaries)
- {
- // ... Inside each result summary, there should be 5 rows
- Assert.Equal(Common.StandardRows, rs.RowCount);
-
- // ... Inside each result summary, there should be 5 column definitions
- Assert.Equal(Common.StandardColumns, rs.ColumnInfo.Length);
- }
-
- // ... The callback for batch completion should have been fired
- Assert.NotNull(batchSummaryFromCallback);
-
- // ... The callback for result set completion should have been fired
- Assert.Equal(2, resultSummaryCount);
+ ValidateBatch(batch, resultSets);
+ ValidateBatchSummary(batch);
+ ValidateMessages(batch, 1, messages);
}
[Fact]
- public void BatchExecuteInvalidQuery()
+ public async Task BatchExecuteInvalidQuery()
{
- // Setup:
- // ... Create a callback for batch start
- bool batchStartCalled = false;
- Batch.BatchAsyncEventHandler batchStartCallback = b =>
- {
- batchStartCalled = true;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for batch completion
- BatchSummary batchSummaryFromCallback = null;
- Batch.BatchAsyncEventHandler batchCompleteCallback = b =>
- {
- batchSummaryFromCallback = b.Summary;
- return Task.FromResult(0);
- };
-
- // ... Create a callback that will fail the test if it's called
- ResultSet.ResultSetAsyncEventHandler resultSetCallback = r =>
- {
- throw new Exception("ResultSet callback was called when it should not have been.");
- };
-
- ConnectionInfo ci = Common.CreateTestConnectionInfo(null, true);
+ // Setup:
+ // ... Keep track of callbacks being called
+ int batchStartCalls = 0;
+ int batchEndCalls = 0;
+ List messages = new List();
// If I execute a batch that is invalid
+ var ci = Common.CreateTestConnectionInfo(null, true);
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
- batch.BatchStart += batchStartCallback;
- batch.BatchCompletion += batchCompleteCallback;
- batch.ResultSetCompletion += resultSetCallback;
- batch.Execute(GetConnection(ci), CancellationToken.None).Wait();
+ BatchCallbackHelper(batch,
+ b => batchStartCalls++,
+ b => batchEndCalls++,
+ m => messages.Add(m),
+ r => { throw new Exception("ResultSet callback was called when it should not have been."); });
+ await batch.Execute(GetConnection(ci), CancellationToken.None);
// Then:
- // ... It should have executed with error
- Assert.True(batch.HasExecuted);
- Assert.True(batch.HasError);
+ // ... Callbacks should have been called the appropriate number of times
+ Assert.Equal(1, batchStartCalls);
+ Assert.Equal(1, batchEndCalls);
- // ... There should be no result sets
- Assert.Empty(batch.ResultSets);
- Assert.Empty(batch.ResultSummaries);
+ // ... It should have executed without error
+ ValidateBatch(batch, 0);
+ ValidateBatchSummary(batch);
- // ... There should be plenty of messages for the error
- Assert.NotEmpty(batch.ResultMessages);
-
- // ... The callback for batch completion should have been fired
- Assert.NotNull(batchSummaryFromCallback);
-
- // ... The callback for batch start should have been fired
- Assert.True(batchStartCalled);
+ // ... There should be one error message returned
+ Assert.Equal(1, messages.Count);
+ Assert.All(messages, m =>
+ {
+ Assert.True(m.IsError);
+ Assert.Equal(batch.Id, m.BatchId);
+ });
}
[Fact]
public async Task BatchExecuteExecuted()
{
- ConnectionInfo ci = Common.CreateTestConnectionInfo(new[] { Common.StandardTestData }, false);
+ // Setup: Build a data set to return
+ const int resultSets = 1;
+ ConnectionInfo ci = Common.CreateTestConnectionInfo(Common.GetTestDataSet(resultSets), false);
// If I execute a batch
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
- batch.Execute(GetConnection(ci), CancellationToken.None).Wait();
+ await batch.Execute(GetConnection(ci), CancellationToken.None);
// Then:
// ... It should have executed without error
Assert.True(batch.HasExecuted, "The batch should have been marked executed.");
- Assert.False(batch.HasError, "The batch should not have an error");
-
- // Setup for part 2:
- // ... Create a callback for batch completion
- Batch.BatchAsyncEventHandler completeCallback = b =>
- {
- throw new Exception("Batch completion callback should not have been called");
- };
-
- // ... Create a callback for batch start
- Batch.BatchAsyncEventHandler startCallback = b =>
- {
- throw new Exception("Batch start callback should not have been called");
- };
// If I execute it again
// Then:
// ... It should throw an invalid operation exception
- batch.BatchStart += startCallback;
- batch.BatchCompletion += completeCallback;
- await Assert.ThrowsAsync(() =>
- batch.Execute(GetConnection(ci), CancellationToken.None));
+ BatchCallbackHelper(batch,
+ b => { throw new Exception("Batch start callback should not have been called"); },
+ b => { throw new Exception("Batch completion callback should not have been called"); },
+ m => { throw new Exception("Message callback should not have been called"); },
+ null);
+ await Assert.ThrowsAsync(
+ () => batch.Execute(GetConnection(ci), CancellationToken.None));
// ... The data should still be available without error
- Assert.False(batch.HasError, "The batch should not be in an error condition");
- Assert.True(batch.HasExecuted, "The batch should still be marked executed.");
- Assert.NotEmpty(batch.ResultSets);
- Assert.NotEmpty(batch.ResultSummaries);
+ ValidateBatch(batch, resultSets);
+ ValidateBatchSummary(batch);
}
[Theory]
@@ -397,13 +262,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
{
// If:
// ... I call the StatementCompletedHandler
+ Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory(null));
+ int messageCalls = 0;
+ batch.BatchMessageSent += args =>
+ {
+ messageCalls++;
+ return Task.FromResult(0);
+ };
+
// Then:
- // ... a ResultMaessage should be logged in the resultsMessages collection
- Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory(null));
- batch.StatementCompletedHandler(null, new StatementCompletedEventArgs(1));
- Assert.True(batch.ResultMessages.Count() == 1);
- batch.StatementCompletedHandler(null, new StatementCompletedEventArgs(2));
- Assert.True(batch.ResultMessages.Count() == 2);
+ // ... The message handler for the batch should havve been called twice
+ batch.StatementCompletedHandler(null, new StatementCompletedEventArgs(1));
+ Assert.True(messageCalls == 1);
+ batch.StatementCompletedHandler(null, new StatementCompletedEventArgs(2));
+ Assert.True(messageCalls == 2);
}
private static DbConnection GetConnection(ConnectionInfo info)
@@ -411,5 +283,81 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
return info.Factory.CreateSqlConnection(ConnectionService.BuildConnectionString(info.ConnectionDetails));
}
+ [SuppressMessage("ReSharper", "UnusedParameter.Local")]
+ private static void ValidateBatch(Batch batch, int expectedResultSets)
+ {
+ // The batch should be executed
+ Assert.True(batch.HasExecuted, "The query should have been marked executed.");
+
+ // Result set list should never be null
+ Assert.NotNull(batch.ResultSets);
+ Assert.NotNull(batch.ResultSummaries);
+
+ // Make sure the number of result sets matches
+ Assert.Equal(expectedResultSets, batch.ResultSets.Count);
+ Assert.Equal(expectedResultSets, batch.ResultSummaries.Length);
+ }
+
+ private static void ValidateBatchSummary(Batch batch)
+ {
+ BatchSummary batchSummary = batch.Summary;
+
+ Assert.NotNull(batchSummary);
+ Assert.Equal(batch.Id, batchSummary.Id);
+ Assert.Equal(batch.ResultSets.Count, batchSummary.ResultSetSummaries.Length);
+ Assert.Equal(batch.Selection, batchSummary.Selection);
+
+ // Something other than default date is provided for start and end times
+ Assert.True(DateTime.Parse(batchSummary.ExecutionStart) > default(DateTime));
+ Assert.True(DateTime.Parse(batchSummary.ExecutionEnd) > default(DateTime));
+ Assert.NotNull(batchSummary.ExecutionElapsed);
+ }
+
+ [SuppressMessage("ReSharper", "UnusedParameter.Local")]
+ private static void ValidateMessages(Batch batch, int expectedMessages, IList messages)
+ {
+ // There should be equal number of messages to result sets
+ Assert.Equal(expectedMessages, messages.Count);
+
+ // No messages should be errors
+ // All messages must have the batch ID
+ Assert.All(messages, m =>
+ {
+ Assert.False(m.IsError);
+ Assert.Equal(batch.Id, m.BatchId);
+ });
+ }
+
+ private static void BatchCallbackHelper(Batch batch, Action startCallback, Action endCallback,
+ Action messageCallback, Action resultCallback)
+ {
+ // Setup the callback for batch start
+ batch.BatchStart += b =>
+ {
+ startCallback?.Invoke(b);
+ return Task.FromResult(0);
+ };
+
+ // Setup the callback for batch completion
+ batch.BatchCompletion += b =>
+ {
+ endCallback?.Invoke(b);
+ return Task.FromResult(0);
+ };
+
+ // Setup the callback for batch messages
+ batch.BatchMessageSent += (m) =>
+ {
+ messageCallback?.Invoke(m);
+ return Task.FromResult(0);
+ };
+
+ // Setup the result set completion callback
+ batch.ResultSetCompletion += r =>
+ {
+ resultCallback?.Invoke(r);
+ return Task.FromResult(0);
+ };
+ }
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/QueryTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/QueryTests.cs
index 3df09e13..d2a67ede 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/QueryTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/QueryTests.cs
@@ -5,9 +5,12 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
+using Castle.Components.DictionaryAdapter;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
+using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Xunit;
@@ -16,6 +19,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
public class QueryTests
{
+ [Fact]
+ public void QueryCreationCorrect()
+ {
+ // If:
+ // ... I create a query
+ ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
+ var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
+ Query query = new Query(Common.StandardQuery, ci, new QueryExecutionSettings(), fileStreamFactory);
+
+ // Then:
+ // ... I should get back two batches to execute that haven't been executed
+ Assert.NotEmpty(query.QueryText);
+ Assert.False(query.HasExecuted);
+ Assert.Throws(() => query.BatchSummaries);
+ }
+
[Fact]
public void QueryExecuteNoQueryText()
{
@@ -63,44 +82,30 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
public void QueryExecuteSingleBatch()
{
// Setup:
- // ... Create a callback for atch start
+ // ... Keep track of how many times the callbacks were called
int batchStartCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchStartCallback = b =>
- {
- batchStartCallbacksReceived++;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for batch completion
int batchCompleteCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchCompleteCallback = summary =>
- {
- batchCompleteCallbacksReceived++;
- return Task.CompletedTask;
- };
+ int batchMessageCallbacksReceived = 0;
// If:
// ... I create a query from a single batch (without separator)
ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Query query = new Query(Common.StandardQuery, ci, new QueryExecutionSettings(), fileStreamFactory);
- query.BatchStarted += batchStartCallback;
- query.BatchCompleted += batchCompleteCallback;
+ BatchCallbackHelper(query,
+ b => batchStartCallbacksReceived++,
+ b => batchCompleteCallbacksReceived++,
+ m => batchMessageCallbacksReceived++);
- // Then:
- // ... I should get a single batch to execute that hasn't been executed
- Assert.NotEmpty(query.QueryText);
- Assert.NotEmpty(query.Batches);
- Assert.Equal(1, query.Batches.Length);
- Assert.False(query.HasExecuted);
- Assert.Throws(() => query.BatchSummaries);
-
- // If:
// ... I then execute the query
query.Execute();
query.ExecutionTask.Wait();
// Then:
+ // ... There should be exactly 1 batch
+ Assert.NotEmpty(query.Batches);
+ Assert.Equal(1, query.Batches.Length);
+
// ... The query should have completed successfully with one batch summary returned
Assert.True(query.HasExecuted);
Assert.NotEmpty(query.BatchSummaries);
@@ -109,38 +114,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... The batch callbacks should have been called precisely 1 time
Assert.Equal(1, batchStartCallbacksReceived);
Assert.Equal(1, batchCompleteCallbacksReceived);
+ Assert.Equal(1, batchMessageCallbacksReceived);
}
[Fact]
- public void QueryExecuteNoOpBatch()
+ public void QueryExecuteSingleNoOpBatch()
{
- // Setup:
- // ... Create a callback for batch startup
- Batch.BatchAsyncEventHandler batchStartCallback = b =>
- {
- throw new Exception("Batch startup callback should not have been called.");
- };
-
- // ... Create a callback for batch completion
- Batch.BatchAsyncEventHandler batchCompletionCallback = summary =>
- {
- throw new Exception("Batch completion callback was called");
- };
+ // Setup: Keep track of all the messages received
+ List messages = new List();
// If:
// ... I create a query from a single batch that does nothing
ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Query query = new Query(Common.NoOpQuery, ci, new QueryExecutionSettings(), fileStreamFactory);
- query.BatchStarted += batchStartCallback;
- query.BatchCompleted += batchCompletionCallback;
-
- // Then:
- // ... I should get no batches back
- Assert.NotEmpty(query.QueryText);
- Assert.Empty(query.Batches);
- Assert.False(query.HasExecuted);
- Assert.Throws(() => query.BatchSummaries);
+ BatchCallbackHelper(query,
+ b => { throw new Exception("Batch startup callback should not have been called."); },
+ b => { throw new Exception("Batch completion callback was called"); },
+ m => messages.Add(m));
// If:
// ... I Then execute the query
@@ -148,30 +139,27 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
query.ExecutionTask.Wait();
// Then:
+ // ... There should be no batches
+ Assert.Empty(query.Batches);
+
// ... The query should have completed successfully with no batch summaries returned
Assert.True(query.HasExecuted);
Assert.Empty(query.BatchSummaries);
+
+ // ... The message callback should have been called exactly once
+ // ... The message must not have a batch associated with it
+ Assert.Equal(1, messages.Count);
+ Assert.Null(messages[0].BatchId);
}
[Fact]
- public void QueryExecuteMultipleBatches()
+ public void QueryExecuteMultipleResultBatches()
{
// Setup:
- // ... Create a callback for batch start
+ // ... Keep track of how many callbacks are received
int batchStartCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchStartCallback = b =>
- {
- batchStartCallbacksReceived++;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for batch completion
int batchCompletedCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchCompletedCallback = summary =>
- {
- batchCompletedCallbacksReceived++;
- return Task.FromResult(0);
- };
+ int batchMessageCallbacksReceived = 0;
// If:
// ... I create a query from two batches (with separator)
@@ -179,52 +167,39 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
string queryText = string.Format("{0}\r\nGO\r\n{0}", Common.StandardQuery);
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Query query = new Query(queryText, ci, new QueryExecutionSettings(), fileStreamFactory);
- query.BatchStarted += batchStartCallback;
- query.BatchCompleted += batchCompletedCallback;
+ BatchCallbackHelper(query,
+ b => batchStartCallbacksReceived++,
+ b => batchCompletedCallbacksReceived++,
+ m => batchMessageCallbacksReceived++);
- // Then:
- // ... I should get back two batches to execute that haven't been executed
- Assert.NotEmpty(query.QueryText);
- Assert.NotEmpty(query.Batches);
- Assert.Equal(2, query.Batches.Length);
- Assert.False(query.HasExecuted);
- Assert.Throws(() => query.BatchSummaries);
-
- // If:
// ... I then execute the query
query.Execute();
query.ExecutionTask.Wait();
// Then:
+ // ... I should get back a query with one batch (no op batch is not included)
+ Assert.NotEmpty(query.Batches);
+ Assert.Equal(2, query.Batches.Length);
+
// ... The query should have completed successfully with two batch summaries returned
Assert.True(query.HasExecuted);
Assert.NotEmpty(query.BatchSummaries);
Assert.Equal(2, query.BatchSummaries.Length);
- // ... The batch start and completion callbacks should have been called precisely 2 times
+ // ... The batch start, complete, and message callbacks should have been called precisely 2 times
Assert.Equal(2, batchStartCallbacksReceived);
Assert.Equal(2, batchCompletedCallbacksReceived);
+ Assert.Equal(2, batchMessageCallbacksReceived);
}
[Fact]
public void QueryExecuteMultipleBatchesWithNoOp()
{
// Setup:
- // ... Create a callback for batch start
+ // ... Keep track of how many times callbacks are called
int batchStartCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchStartCallback = b =>
- {
- batchStartCallbacksReceived++;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for batch completion
int batchCompletionCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchCompletionCallback = summary =>
- {
- batchCompletionCallbacksReceived++;
- return Task.CompletedTask;
- };
+ int batchMessageCallbacksReceived = 0;
// If:
// ... I create a query from a two batches (with separator)
@@ -232,22 +207,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
string queryText = string.Format("{0}\r\nGO\r\n{1}", Common.StandardQuery, Common.NoOpQuery);
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Query query = new Query(queryText, ci, new QueryExecutionSettings(), fileStreamFactory);
- query.BatchStarted += batchStartCallback;
- query.BatchCompleted += batchCompletionCallback;
+ BatchCallbackHelper(query,
+ b => batchStartCallbacksReceived++,
+ b => batchCompletionCallbacksReceived++,
+ m => batchMessageCallbacksReceived++);
- // Then:
- // ... I should get back one batch to execute that hasn't been executed
- Assert.NotEmpty(query.QueryText);
- Assert.NotEmpty(query.Batches);
- Assert.Equal(1, query.Batches.Length);
- Assert.False(query.HasExecuted);
- Assert.Throws(() => query.BatchSummaries);
-
- // If:
// .. I then execute the query
query.Execute();
query.ExecutionTask.Wait();
+ // Then:
+ // ... I should get back a query with one batch (no op batch is not included)
+ Assert.NotEmpty(query.Batches);
+ Assert.Equal(1, query.Batches.Length);
+
// ... The query should have completed successfully with one batch summary returned
Assert.True(query.HasExecuted);
Assert.NotEmpty(query.BatchSummaries);
@@ -256,61 +229,107 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... The batch callbacks should have been called precisely 1 time
Assert.Equal(1, batchStartCallbacksReceived);
Assert.Equal(1, batchCompletionCallbacksReceived);
+ Assert.Equal(1, batchMessageCallbacksReceived);
+ }
+
+ [Fact]
+ public async Task QueryExecuteMultipleNoOpBatches()
+ {
+ // Setup:
+ // ... Keep track of how many messages were sent
+ List messages = new List();
+
+ // If:
+ // ... I create a query from a two batches (with separator)
+ ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
+ string queryText = string.Format("{0}\r\nGO\r\n{1}", Common.NoOpQuery, Common.NoOpQuery);
+ var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
+ Query query = new Query(queryText, ci, new QueryExecutionSettings(), fileStreamFactory);
+ BatchCallbackHelper(query,
+ b => { throw new Exception("Batch start handler was called"); },
+ b => { throw new Exception("Batch completed handler was called"); },
+ m => messages.Add(m));
+
+ // .. I then execute the query
+ query.Execute();
+ await query.ExecutionTask;
+
+ // Then:
+ // ... I should get back a query with no batches
+ Assert.Empty(query.Batches);
+
+ // ... The query should have completed successfully with one zero batch summaries returned
+ Assert.True(query.HasExecuted);
+ Assert.Empty(query.BatchSummaries);
+
+ // ... The message callback should have been called exactly once
+ // ... The message must not have a batch associated with it
+ Assert.Equal(1, messages.Count);
+ Assert.Null(messages[0].BatchId);
}
[Fact]
public void QueryExecuteInvalidBatch()
{
// Setup:
- // ... Create a callback for batch start
+ // ... Keep track of how many times a method is called
int batchStartCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchStartCallback = b =>
- {
- batchStartCallbacksReceived++;
- return Task.FromResult(0);
- };
-
- // ... Create a callback for batch completion
int batchCompletionCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchCompltionCallback = summary =>
- {
- batchCompletionCallbacksReceived++;
- return Task.CompletedTask;
- };
+ List messages = new List();
// If:
// ... I create a query from an invalid batch
ConnectionInfo ci = Common.CreateTestConnectionInfo(null, true);
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary());
Query query = new Query(Common.InvalidQuery, ci, new QueryExecutionSettings(), fileStreamFactory);
- query.BatchStarted += batchStartCallback;
- query.BatchCompleted += batchCompltionCallback;
+ BatchCallbackHelper(query,
+ b => batchStartCallbacksReceived++,
+ b => batchCompletionCallbacksReceived++,
+ m => messages.Add(m));
- // Then:
- // ... I should get back a query with one batch not executed
- Assert.NotEmpty(query.QueryText);
- Assert.NotEmpty(query.Batches);
- Assert.Equal(1, query.Batches.Length);
- Assert.False(query.HasExecuted);
- Assert.Throws(() => query.BatchSummaries);
-
- // If:
// ... I then execute the query
query.Execute();
query.ExecutionTask.Wait();
// Then:
+ // ... I should get back a query with one batch
+ Assert.NotEmpty(query.Batches);
+ Assert.Equal(1, query.Batches.Length);
+
// ... There should be an error on the batch
Assert.True(query.HasExecuted);
Assert.NotEmpty(query.BatchSummaries);
Assert.Equal(1, query.BatchSummaries.Length);
- Assert.True(query.BatchSummaries[0].HasError);
- Assert.NotEmpty(query.BatchSummaries[0].Messages);
+ Assert.True(messages.Any(m => m.IsError));
// ... The batch callbacks should have been called once
Assert.Equal(1, batchStartCallbacksReceived);
Assert.Equal(1, batchCompletionCallbacksReceived);
}
+ private static void BatchCallbackHelper(Query q, Action startCallback, Action endCallback,
+ Action messageCallback)
+ {
+ // Setup the callback for batch start
+ q.BatchStarted += b =>
+ {
+ startCallback?.Invoke(b);
+ return Task.FromResult(0);
+ };
+
+ // Setup the callback for batch completion
+ q.BatchCompleted += b =>
+ {
+ endCallback?.Invoke(b);
+ return Task.FromResult(0);
+ };
+
+ // Setup the callback for batch messages
+ q.BatchMessageSent += (m) =>
+ {
+ messageCallback?.Invoke(m);
+ return Task.FromResult(0);
+ };
+ }
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/ServiceIntegrationTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/ServiceIntegrationTests.cs
index ecea14ab..975f16a0 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/ServiceIntegrationTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Execution/ServiceIntegrationTests.cs
@@ -21,14 +21,18 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... 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 };
+ var queryParams = new QueryExecuteParams {QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri};
var efv = new EventFlowValidator()
- .AddResultValidation(p =>
+ .AddStandardQueryResultValidator()
+ .AddStandardMessageValidator()
+ .AddEventValidation(QueryExecuteCompleteEvent.Type, p =>
{
- Assert.False(string.IsNullOrWhiteSpace(p.Messages));
- })
- .Complete();
+ // Validate OwnerURI matches
+ Assert.Equal(Common.OwnerUri, p.OwnerUri);
+ Assert.NotNull(p.BatchSummaries);
+ Assert.Equal(0, p.BatchSummaries.Length);
+ }).Complete();
await Common.AwaitExecution(queryService, queryParams, efv.Object);
// Then:
@@ -38,7 +42,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... There should be one active query
Assert.Equal(1, queryService.ActiveQueries.Count);
}
-
+
[Fact]
public async Task QueryExecuteSingleBatchNoResultsTest()
{
@@ -46,11 +50,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... 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 };
+ var queryParams = new QueryExecuteParams {QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri};
var efv = new EventFlowValidator()
.AddStandardQueryResultValidator()
.AddStandardBatchStartValidator()
+ .AddStandardMessageValidator()
.AddStandardBatchCompleteValidator()
.AddStandardQueryCompleteValidator(1)
.Complete();
@@ -71,18 +76,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// 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 };
+ var queryService = Common.GetPrimedExecutionService(new[] {Common.StandardTestData}, true, false,
+ workspaceService);
+ var queryParams = new QueryExecuteParams {OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument};
var efv = new EventFlowValidator()
.AddStandardQueryResultValidator()
.AddStandardBatchStartValidator()
.AddStandardResultSetValidator()
+ .AddStandardMessageValidator()
.AddStandardBatchCompleteValidator()
.AddStandardQueryCompleteValidator(1)
.Complete();
await Common.AwaitExecution(queryService, queryParams, efv.Object);
-
+
// Then:
// ... All events should have been called as per their flow validator
efv.Validate();
@@ -97,15 +104,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// 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 dataset = new[] {Common.StandardTestData, Common.StandardTestData};
var queryService = Common.GetPrimedExecutionService(dataset, true, false, workspaceService);
- var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
+ var queryParams = new QueryExecuteParams {OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument};
var efv = new EventFlowValidator()
.AddStandardQueryResultValidator()
.AddStandardBatchStartValidator()
.AddStandardResultSetValidator()
.AddStandardResultSetValidator()
+ .AddStandardMessageValidator()
.AddStandardQueryCompleteValidator(1)
.Complete();
await Common.AwaitExecution(queryService, queryParams, efv.Object);
@@ -124,17 +132,19 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// 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 dataSet = new[] {Common.StandardTestData};
var queryService = Common.GetPrimedExecutionService(dataSet, true, false, workspaceService);
- var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
+ var queryParams = new QueryExecuteParams {OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument};
var efv = new EventFlowValidator()
.AddStandardQueryResultValidator()
.AddStandardBatchStartValidator()
.AddStandardResultSetValidator()
+ .AddStandardMessageValidator()
.AddStandardBatchCompleteValidator()
.AddStandardBatchCompleteValidator()
.AddStandardResultSetValidator()
+ .AddStandardMessageValidator()
.AddStandardBatchCompleteValidator()
.AddStandardQueryCompleteValidator(2)
.Complete();
@@ -156,7 +166,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... 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 };
+ var queryParams = new QueryExecuteParams {OwnerUri = "notConnected", QuerySelection = Common.WholeDocument};
var efv = new EventFlowValidator()
.AddErrorValidation(Assert.NotEmpty)
@@ -178,14 +188,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... 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 };
+ 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.Create(null);
await Common.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
+ queryService.ActiveQueries[Common.OwnerUri].HasExecuted = false; // Simulate query hasn't finished
var efv = new EventFlowValidator()
.AddErrorValidation(Assert.NotEmpty)
.Complete();
@@ -206,7 +216,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... 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 };
+ 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.Create(null);
@@ -240,7 +250,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// If:
// ... I request to execute a query with a missing query string
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
- var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = null };
+ var queryParams = new QueryExecuteParams {OwnerUri = Common.OwnerUri, QuerySelection = null};
var efv = new EventFlowValidator()
.AddErrorValidation(Assert.NotEmpty)
@@ -262,7 +272,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
// ... 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 };
+ var queryParams = new QueryExecuteParams {OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument};
var efv = new EventFlowValidator()
.AddStandardQueryResultValidator()
@@ -270,7 +280,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
.AddStandardBatchCompleteValidator()
.AddStandardQueryCompleteValidator(1)
.Complete();
-
await Common.AwaitExecution(queryService, queryParams, efv.Object);
// Then:
@@ -295,10 +304,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
this EventFlowValidator 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);
- });
+ return efv.AddResultValidation(Assert.NotNull);
}
public static EventFlowValidator AddStandardBatchStartValidator(
@@ -317,18 +323,29 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
{
return efv.AddEventValidation(QueryExecuteBatchCompleteEvent.Type, p =>
{
- // Validate OwnerURI and batch summary are returned
+ // Validate OwnerURI and result summary are returned
Assert.Equal(Common.OwnerUri, p.OwnerUri);
Assert.NotNull(p.BatchSummary);
});
}
+ public static EventFlowValidator AddStandardMessageValidator(
+ this EventFlowValidator efv)
+ {
+ return efv.AddEventValidation(QueryExecuteMessageEvent.Type, p =>
+ {
+ // Validate OwnerURI and message are returned
+ Assert.Equal(Common.OwnerUri, p.OwnerUri);
+ Assert.NotNull(p.Message);
+ });
+ }
+
public static EventFlowValidator AddStandardResultSetValidator(
this EventFlowValidator efv)
{
return efv.AddEventValidation(QueryExecuteResultSetCompleteEvent.Type, p =>
{
- // Validate OwnerURI and result summary are returned
+ // Validate OwnerURI and summary are returned
Assert.Equal(Common.OwnerUri, p.OwnerUri);
Assert.NotNull(p.ResultSetSummary);
});
@@ -339,7 +356,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
{
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);
diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/QueryExecutionTests.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/QueryExecutionTests.cs
index 75df010c..a9eb9ae7 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/QueryExecutionTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/QueryExecutionTests.cs
@@ -327,34 +327,33 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
}
*/
- [Fact]
- public async Task NoOpQueryReturnsMessage()
+ [Theory]
+ [InlineData("-- no-op")]
+ [InlineData("GO")]
+ [InlineData("GO -- no-op")]
+ public async Task NoOpQueryReturnsMessage(string query)
{
- // Given queries that do nothing (no-ops)...
- var queries = new string[]
- {
- "-- no-op",
- "GO",
- "GO -- no-op"
- };
-
using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile())
using (TestHelper testHelper = new TestHelper())
{
- foreach (var query in queries)
- {
- Assert.True(await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection));
+ Assert.True(await testHelper.Connect(queryTempFile.FilePath, ConnectionTestUtils.LocalhostConnection));
- // If the queries are executed...
- var queryResult = await testHelper.RunQueryAsync(queryTempFile.FilePath, query);
+ // If: the query is executed...
+ var queryResult = await testHelper.RunQueryAsync(queryTempFile.FilePath, query);
+ var message = await testHelper.WaitForMessage();
- // Then I expect messages that the commands were completed successfully to be in the result
- Assert.NotNull(queryResult);
- Assert.NotNull(queryResult.Messages);
- Assert.Equal("Commands completed successfully.", queryResult.Messages);
+ // Then:
+ // ... I expect a query result to indicate successfully started query
+ Assert.NotNull(queryResult);
- await testHelper.Disconnect(queryTempFile.FilePath);
- }
+ // ... I expect a non-error message to be returned without a batch associated with it
+ Assert.NotNull(message);
+ Assert.NotNull(message.Message);
+ Assert.NotNull(message.Message.Message);
+ Assert.False(message.Message.IsError);
+ Assert.Null(message.Message.BatchId);
+
+ await testHelper.Disconnect(queryTempFile.FilePath);
}
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestHelper.cs b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestHelper.cs
index d248ffff..255f54a6 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestHelper.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.TestDriver/Tests/TestHelper.cs
@@ -295,7 +295,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
};
var result = await Driver.SendRequest(QueryExecuteRequest.Type, queryParams);
- if (result != null && string.IsNullOrEmpty(result.Messages))
+ if (result != null)
{
var eventResult = await Driver.WaitForEvent(QueryExecuteCompleteEvent.Type, timeoutMilliseconds);
return eventResult;
@@ -384,6 +384,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TestDriver.Tests
return result;
}
+ ///
+ /// Waits for a message to be returned by the service
+ ///
+ /// A message from the service layer
+ public async Task WaitForMessage()
+ {
+ return await Driver.WaitForEvent(QueryExecuteMessageEvent.Type);
+ }
+
public void WriteToFile(string ownerUri, string query)
{
lock (fileLock)