diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
index 0d4ab4b0..16982606 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs
@@ -77,9 +77,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
///
- /// Default constructor is private since it's a singleton class
+ /// Default constructor should be private since it's a singleton class, but we need a constructor
+ /// for use in unit test mocking.
///
- private ConnectionService()
+ public ConnectionService()
{
}
@@ -129,7 +130,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection
}
// Attempts to link a URI to an actively used connection for this URI
- public bool TryFindConnection(string ownerUri, out ConnectionInfo connectionInfo)
+ public virtual bool TryFindConnection(string ownerUri, out ConnectionInfo connectionInfo)
{
return this.ownerToConnectionMap.TryGetValue(ownerUri, out connectionInfo);
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs
index a96de759..a74a38d1 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/ResultSet.cs
@@ -8,7 +8,6 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
@@ -17,6 +16,10 @@ using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
{
+ ///
+ /// Class that represents a resultset the was generated from a query. Contains logic for
+ /// storing and retrieving results. Is contained by a Batch class.
+ ///
public class ResultSet : IDisposable
{
#region Constants
@@ -35,11 +38,21 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
#region Member Variables
+ ///
+ /// The reader to use for this resultset
+ ///
+ private readonly StorageDataReader dataReader;
+
///
/// For IDisposable pattern, whether or not object has been disposed
///
private bool disposed;
+ ///
+ /// A list of offsets into the buffer file that correspond to where rows start
+ ///
+ private readonly LongList fileOffsets;
+
///
/// The factory to use to get reading/writing handlers
///
@@ -63,12 +76,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
///
/// Whether the resultSet is in the process of being disposed
///
- private bool isBeingDisposed;
-
- ///
- /// All save tasks currently saving this ResultSet
- ///
- private ConcurrentDictionary saveTasks;
+ private readonly ConcurrentDictionary saveTasks;
#endregion
@@ -82,11 +90,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
// Sanity check to make sure we got a reader
Validate.IsNotNull(nameof(reader), SR.QueryServiceResultSetReaderNull);
- DataReader = new StorageDataReader(reader);
+ dataReader = new StorageDataReader(reader);
// Initialize the storage
outputFileName = factory.CreateFile();
- FileOffsets = new LongList();
+ fileOffsets = new LongList();
// Store the factory
fileStreamFactory = factory;
@@ -100,29 +108,13 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
/// Whether the resultSet is in the process of being disposed
///
///
- internal bool IsBeingDisposed
- {
- get
- {
- return isBeingDisposed;
- }
- }
+ internal bool IsBeingDisposed { get; private set; }
///
/// The columns for this result set
///
public DbColumnWrapper[] Columns { get; private set; }
- ///
- /// The reader to use for this resultset
- ///
- private StorageDataReader DataReader { get; set; }
-
- ///
- /// A list of offsets into the buffer file that correspond to where rows start
- ///
- private LongList FileOffsets { get; set; }
-
///
/// Maximum number of characters to store for a field
///
@@ -178,14 +170,14 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
if (isSingleColumnXmlJsonResultSet)
{
// Iterate over all the rows and process them into a list of string builders
- IEnumerable rowValues = FileOffsets.Select(rowOffset => fileStreamReader.ReadRow(rowOffset, Columns)[0].DisplayValue);
+ IEnumerable rowValues = fileOffsets.Select(rowOffset => fileStreamReader.ReadRow(rowOffset, Columns)[0].DisplayValue);
rows = new[] { new[] { string.Join(string.Empty, rowValues) } };
}
else
{
// Figure out which rows we need to read back
- IEnumerable rowOffsets = FileOffsets.Skip(startRow).Take(rowCount);
+ IEnumerable rowOffsets = fileOffsets.Skip(startRow).Take(rowCount);
// Iterate over the rows we need and process them into output
rows = rowOffsets.Select(rowOffset =>
@@ -216,18 +208,22 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
using (IFileStreamWriter fileWriter = fileStreamFactory.GetWriter(outputFileName, MaxCharsToStore, MaxXmlCharsToStore))
{
// If we can initialize the columns using the column schema, use that
- if (!DataReader.DbDataReader.CanGetColumnSchema())
+ if (!dataReader.DbDataReader.CanGetColumnSchema())
{
throw new InvalidOperationException(SR.QueryServiceResultSetNoColumnSchema);
}
- Columns = DataReader.Columns;
- long currentFileOffset = 0;
+ Columns = dataReader.Columns;
- while (await DataReader.ReadAsync(cancellationToken))
+ long currentFileOffset = 0;
+ while (await dataReader.ReadAsync(cancellationToken))
{
+ // Store the beginning of the row
+ long rowStart = currentFileOffset;
+ currentFileOffset += fileWriter.WriteRow(dataReader);
+
+ // Add the row to the list of rows we have only if the row was successfully written
RowCount++;
- FileOffsets.Add(currentFileOffset);
- currentFileOffset += fileWriter.WriteRow(DataReader);
+ fileOffsets.Add(rowStart);
}
}
// Check if resultset is 'for xml/json'. If it is, set isJson/isXml value in column metadata
@@ -251,7 +247,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
return;
}
- isBeingDisposed = true;
+ IsBeingDisposed = true;
// Check if saveTasks are running for this ResultSet
if (!saveTasks.IsEmpty)
{
@@ -263,7 +259,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
fileStreamFactory.DisposeFile(outputFileName);
}
disposed = true;
- isBeingDisposed = false;
+ IsBeingDisposed = false;
});
}
else
@@ -274,7 +270,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
fileStreamFactory.DisposeFile(outputFileName);
}
disposed = true;
- isBeingDisposed = false;
+ IsBeingDisposed = false;
}
}
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/CancelTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/CancelTests.cs
index 29afec38..3be28f64 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/CancelTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/CancelTests.cs
@@ -32,7 +32,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
// If:
// ... I request a query (doesn't matter what kind) and execute it
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
+ var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService.Object);
var executeParams = new QueryExecuteParams { QuerySelection = Common.SubsectionDocument, OwnerUri = Common.OwnerUri };
var executeRequest =
RequestContextMocks.SetupRequestContextMock(null, QueryExecuteCompleteEvent.Type, null, null);
@@ -44,7 +44,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
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 successful event (no messages)
@@ -68,7 +68,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
.Returns(fileMock.Object);
// If:
// ... I request a query (doesn't matter what kind) and wait for execution
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
+ var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService.Object);
var executeParams = new QueryExecuteParams {QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri};
var executeRequest =
RequestContextMocks.SetupRequestContextMock(null, QueryExecuteCompleteEvent.Type, null, null);
@@ -97,11 +97,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var workspaceService = new Mock>();
// If:
// ... I request to cancel a query that doesn't exist
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), false, workspaceService.Object);
+ var queryService = Common.GetPrimedExecutionService(null, false, false, workspaceService.Object);
var cancelParams = new QueryCancelParams {OwnerUri = "Doesn't Exist"};
QueryCancelResult result = null;
var cancelRequest = GetQueryCancelResultContextMock(qcr => result = qcr, null);
- 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 0747792f..c8f8c15f 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/Common.cs
@@ -6,16 +6,12 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
-using System.Data.SqlClient;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
-using Microsoft.SqlServer.Management.Common;
-using Microsoft.SqlServer.Management.SmoMetadataProvider;
-using Microsoft.SqlServer.Management.SqlParser.Binder;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Connection.Contracts;
-using Microsoft.SqlTools.ServiceLayer.LanguageServices;
+using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
@@ -71,7 +67,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
public static Batch GetBasicExecutedBatch()
{
- Batch batch = new Batch(StandardQuery, SubsectionDocument, 1, GetFileStreamFactory());
+ Batch batch = new Batch(StandardQuery, SubsectionDocument, 1, GetFileStreamFactory(new Dictionary()));
batch.Execute(CreateTestConnection(new[] {StandardTestData}, false), CancellationToken.None).Wait();
return batch;
}
@@ -79,7 +75,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
public static Query GetBasicExecutedQuery()
{
ConnectionInfo ci = CreateTestConnectionInfo(new[] {StandardTestData}, false);
- Query query = new Query(StandardQuery, ci, new QueryExecutionSettings(), GetFileStreamFactory());
+ Query query = new Query(StandardQuery, ci, new QueryExecutionSettings(), GetFileStreamFactory(new Dictionary()));
query.Execute();
query.ExecutionTask.Wait();
return query;
@@ -101,18 +97,35 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
return output;
}
+ public static async Task AwaitExecution(QueryExecutionService service, QueryExecuteParams qeParams,
+ RequestContext requestContext)
+ {
+ await service.HandleExecuteRequest(qeParams, requestContext);
+ if (service.ActiveQueries.ContainsKey(qeParams.OwnerUri) && service.ActiveQueries[qeParams.OwnerUri].ExecutionTask != null)
+ {
+ await service.ActiveQueries[qeParams.OwnerUri].ExecutionTask;
+ }
+ }
+
#endregion
#region FileStreamWriteMocking
- public static IFileStreamFactory GetFileStreamFactory()
+ public static IFileStreamFactory GetFileStreamFactory(Dictionary storage)
{
Mock mock = new Mock();
+ mock.Setup(fsf => fsf.CreateFile())
+ .Returns(() =>
+ {
+ string fileName = Guid.NewGuid().ToString();
+ storage.Add(fileName, new byte[8192]);
+ return fileName;
+ });
mock.Setup(fsf => fsf.GetReader(It.IsAny()))
- .Returns(new ServiceBufferFileStreamReader(new InMemoryWrapper(), It.IsAny()));
+ .Returns(output => new ServiceBufferFileStreamReader(new InMemoryWrapper(storage[output]), output));
mock.Setup(fsf => fsf.GetWriter(It.IsAny(), It.IsAny(), It.IsAny()))
- .Returns(new ServiceBufferFileStreamWriter(new InMemoryWrapper(), It.IsAny(), 1024,
- 1024));
+ .Returns((output, chars, xml) => new ServiceBufferFileStreamWriter(
+ new InMemoryWrapper(storage[output]), output, chars, xml));
return mock.Object;
}
@@ -121,9 +134,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
{
private readonly MemoryStream memoryStream;
private bool readingOnly;
- private readonly byte[] storage = new byte[8192];
- public InMemoryWrapper()
+ public InMemoryWrapper(byte[] storage)
{
memoryStream = new MemoryStream(storage);
}
@@ -226,62 +238,31 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
#region Service Mocking
- public static void GetAutoCompleteTestObjects(
- out TextDocumentPosition textDocument,
- out ScriptFile scriptFile,
- out ConnectionInfo connInfo
- )
+ public static QueryExecutionService GetPrimedExecutionService(Dictionary[][] data, bool isConnected, bool throwOnRead, WorkspaceService workspaceService)
{
- textDocument = new TextDocumentPosition
- {
- TextDocument = new TextDocumentIdentifier {Uri = OwnerUri},
- Position = new Position
- {
- Line = 0,
- Character = 0
- }
- };
+ // Create a place for the temp "files" to be written
+ Dictionary storage = new Dictionary();
+ // Create the connection factory with the dataset
+ var factory = CreateTestConnectionInfo(data, throwOnRead).Factory;
- connInfo = CreateTestConnectionInfo(null, false);
-
- var srvConn = GetServerConnection(connInfo);
- var metadataProvider = SmoMetadataProvider.CreateConnectedProvider(srvConn);
- var binder = BinderProvider.CreateBinder(metadataProvider);
- connInfo = Common.CreateTestConnectionInfo(null, false);
-
- LanguageService.Instance.ScriptParseInfoMap.Add(textDocument.TextDocument.Uri, new ScriptParseInfo());
-
- scriptFile = new ScriptFile {ClientFilePath = textDocument.TextDocument.Uri};
+ // Mock the connection service
+ var connectionService = new Mock();
+ ConnectionInfo ci = new ConnectionInfo(factory, OwnerUri, StandardConnectionDetails);
+ ConnectionInfo outValMock;
+ connectionService
+ .Setup(service => service.TryFindConnection(It.IsAny(), out outValMock))
+ .OutCallback((string owner, out ConnectionInfo connInfo) => connInfo = isConnected ? ci : null)
+ .Returns(isConnected);
+ return new QueryExecutionService(connectionService.Object, workspaceService) {BufferFileStreamFactory = GetFileStreamFactory(storage)};
}
- public static ServerConnection GetServerConnection(ConnectionInfo connection)
- {
- string connectionString = ConnectionService.BuildConnectionString(connection.ConnectionDetails);
- var sqlConnection = new SqlConnection(connectionString);
- return new ServerConnection(sqlConnection);
- }
-
- public static async Task GetPrimedExecutionService(ISqlConnectionFactory factory, bool isConnected, WorkspaceService workspaceService)
- {
- var connectionService = new ConnectionService(factory);
- if (isConnected)
- {
- await connectionService.Connect(new ConnectParams
- {
- Connection = StandardConnectionDetails,
- OwnerUri = OwnerUri
- });
- }
- return new QueryExecutionService(connectionService, workspaceService) {BufferFileStreamFactory = GetFileStreamFactory()};
- }
-
- public static WorkspaceService GetPrimedWorkspaceService()
+ public static WorkspaceService GetPrimedWorkspaceService(string query)
{
// Set up file for returning the query
var fileMock = new Mock();
- fileMock.SetupGet(file => file.Contents).Returns(StandardQuery);
+ fileMock.SetupGet(file => file.Contents).Returns(query);
// Set up workspace mock
var workspaceService = new Mock>();
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs
index 87076204..80ca7fbc 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DataStorage/ServiceBufferFileStreamReaderWriterTests.cs
@@ -17,7 +17,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
private static void VerifyReadWrite(int valueLength, T value, Func writeFunc, Func readFunc)
{
// Setup: Create a mock file stream wrapper
- Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper();
+ Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
try
{
// If:
@@ -223,7 +223,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
public void StringNullTest()
{
// Setup: Create a mock file stream wrapper
- Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper();
+ Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
// If:
// ... I write null as a string to the writer
@@ -259,7 +259,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.DataStorage
public void BytesNullTest()
{
// Setup: Create a mock file stream wrapper
- Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper();
+ Common.InMemoryWrapper mockWrapper = new Common.InMemoryWrapper(new byte[8192]);
// If:
// ... I write null as a string to the writer
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DisposeTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DisposeTests.cs
index 2f103ec0..bc706bb3 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DisposeTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/DisposeTests.cs
@@ -47,7 +47,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
.Returns(fileMock.Object);
// If:
// ... I request a query (doesn't matter what kind)
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
+ var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService.Object);
var executeParams = new QueryExecuteParams {QuerySelection = null, OwnerUri = Common.OwnerUri};
var executeRequest = RequestContextMocks.SetupRequestContextMock(null, QueryExecuteCompleteEvent.Type, null, null);
await queryService.HandleExecuteRequest(executeParams, executeRequest.Object);
@@ -59,7 +59,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var disposeRequest = GetQueryDisposeResultContextMock(qdr => {
result = qdr;
}, null);
- queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object).Wait();
+ await queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object);
// Then:
// ... I should have seen a successful result
@@ -75,11 +75,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
var workspaceService = new Mock>();
// If:
// ... I attempt to dispose a query that doesn't exist
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), false, workspaceService.Object);
+ var queryService = Common.GetPrimedExecutionService(null, false, false, workspaceService.Object);
var disposeParams = new QueryDisposeParams {OwnerUri = Common.OwnerUri};
QueryDisposeResult result = null;
var disposeRequest = GetQueryDisposeResultContextMock(qdr => result = qdr, null);
- queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object).Wait();
+ await queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object);
// Then:
// ... I should have gotten an error result
@@ -99,8 +99,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
.Returns(fileMock.Object);
// ... We need a query service
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true,
- workspaceService.Object);
+ var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService.Object);
// If:
// ... I execute some bogus query
diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/ExecuteTests.cs b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/ExecuteTests.cs
index e76b4ecf..c61237fa 100644
--- a/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/ExecuteTests.cs
+++ b/test/Microsoft.SqlTools.ServiceLayer.Test/QueryExecution/ExecuteTests.cs
@@ -5,839 +5,17 @@
//#define USE_LIVE_CONNECTION
-using System;
using System.Data.Common;
-using System.Linq;
-using System.Threading;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
-using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
-using Microsoft.SqlTools.ServiceLayer.SqlContext;
-using Microsoft.SqlTools.ServiceLayer.Test.Utility;
-using Microsoft.SqlTools.ServiceLayer.Workspace;
-using Microsoft.SqlTools.ServiceLayer.Workspace.Contracts;
-using Moq;
-using Xunit;
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
{
public class ExecuteTests
{
- #region Batch Class Tests
-
- [Fact]
- public void BatchCreationTest()
- {
- // If I create a new batch...
- Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory());
-
- // Then:
- // ... The text of the batch should be stored
- Assert.NotEmpty(batch.BatchText);
-
- // ... 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);
-
- // ... It's ordinal ID should be what I set it to
- Assert.Equal(Common.Ordinal, batch.Id);
- }
-
- [Fact]
- public void BatchExecuteNoResultSets()
- {
- // Setup: Create a callback for batch completion
- BatchSummary batchSummaryFromCallback = null;
- bool completionCallbackFired = false;
- Batch.BatchAsyncEventHandler callback = b =>
- {
- completionCallbackFired = true;
- batchSummaryFromCallback = b.Summary;
- return Task.FromResult(0);
- };
-
- // If I execute a query that should get no result sets
- Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory());
- batch.BatchCompletion += callback;
- batch.Execute(GetConnection(Common.CreateTestConnectionInfo(null, false)), CancellationToken.None).Wait();
-
- // 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");
-
- // ... 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 completion should have been fired
- Assert.True(completionCallbackFired);
- Assert.NotNull(batchSummaryFromCallback);
- }
-
- [Fact]
- public void BatchExecuteOneResultSet()
- {
- const int resultSets = 1;
- ConnectionInfo ci = Common.CreateTestConnectionInfo(new[] { Common.StandardTestData }, false);
-
- // Setup: Create a callback for batch completion
- BatchSummary batchSummaryFromCallback = null;
- bool completionCallbackFired = false;
- Batch.BatchAsyncEventHandler callback = b =>
- {
- completionCallbackFired = true;
- batchSummaryFromCallback = b.Summary;
- return Task.FromResult(0);
- };
-
- // If I execute a query that should get one result set
- Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory());
- batch.BatchCompletion += callback;
- batch.Execute(GetConnection(ci), CancellationToken.None).Wait();
-
- // 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");
-
- // ... 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.True(completionCallbackFired);
- Assert.NotNull(batchSummaryFromCallback);
- }
-
- [Fact]
- public void BatchExecuteTwoResultSets()
- {
- var dataset = new[] { Common.StandardTestData, Common.StandardTestData };
- int resultSets = dataset.Length;
- ConnectionInfo ci = Common.CreateTestConnectionInfo(dataset, false);
-
- // Setup: Create a callback for batch completion
- BatchSummary batchSummaryFromCallback = null;
- bool completionCallbackFired = false;
- Batch.BatchAsyncEventHandler callback = b =>
- {
- completionCallbackFired = true;
- batchSummaryFromCallback = b.Summary;
- return Task.FromResult(0);
- };
-
- // If I execute a query that should get two result sets
- Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory());
- batch.BatchCompletion += callback;
- batch.Execute(GetConnection(ci), CancellationToken.None).Wait();
-
- // 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");
-
- // ... 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.True(completionCallbackFired);
- Assert.NotNull(batchSummaryFromCallback);
- }
-
- [Fact]
- public void BatchExecuteInvalidQuery()
- {
- // Setup: Create a callback for batch completion
- BatchSummary batchSummaryFromCallback = null;
- bool completionCallbackFired = false;
- Batch.BatchAsyncEventHandler callback = b =>
- {
- completionCallbackFired = true;
- batchSummaryFromCallback = b.Summary;
- return Task.FromResult(0);
- };
-
- ConnectionInfo ci = Common.CreateTestConnectionInfo(null, true);
-
- // If I execute a batch that is invalid
- Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory());
- batch.BatchCompletion += callback;
- batch.Execute(GetConnection(ci), CancellationToken.None).Wait();
-
- // Then:
- // ... It should have executed with error
- Assert.True(batch.HasExecuted);
- Assert.True(batch.HasError);
-
- // ... There should be no result sets
- Assert.Empty(batch.ResultSets);
- Assert.Empty(batch.ResultSummaries);
-
- // ... There should be plenty of messages for the error
- Assert.NotEmpty(batch.ResultMessages);
-
- // ... The callback for batch completion should have been fired
- Assert.True(completionCallbackFired);
- Assert.NotNull(batchSummaryFromCallback);
- }
-
- [Fact]
- public async Task BatchExecuteExecuted()
- {
- // Setup: Create a callback for batch completion
- BatchSummary batchSummaryFromCallback = null;
- bool completionCallbackFired = false;
- Batch.BatchAsyncEventHandler callback = b =>
- {
- completionCallbackFired = true;
- batchSummaryFromCallback = b.Summary;
- return Task.FromResult(0);
- };
-
- ConnectionInfo ci = Common.CreateTestConnectionInfo(new[] { Common.StandardTestData }, false);
-
- // If I execute a batch
- Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory());
- batch.BatchCompletion += callback;
- batch.Execute(GetConnection(ci), CancellationToken.None).Wait();
-
- // 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");
-
- // ... The callback for batch completion should have been fired
- Assert.True(completionCallbackFired);
- Assert.NotNull(batchSummaryFromCallback);
-
- // If I execute it again
- // Then:
- // ... It should throw an invalid operation exception
- 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);
- }
-
- [Theory]
- [InlineData("")]
- [InlineData(null)]
- public void BatchExecuteNoSql(string query)
- {
- // If:
- // ... I create a batch that has an empty query
- // Then:
- // ... It should throw an exception
- Assert.Throws(() => new Batch(query, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory()));
- }
-
- [Fact]
- public void BatchNoBufferFactory()
- {
- // If:
- // ... I create a batch that has no file stream factory
- // Then:
- // ... It should throw an exception
- Assert.Throws(() => new Batch("stuff", Common.SubsectionDocument, Common.Ordinal, null));
- }
-
- [Fact]
- public void BatchInvalidOrdinal()
- {
- // If:
- // ... I create a batch has has an ordinal less than 0
- // Then:
- // ... It should throw an exception
- Assert.Throws(() => new Batch("stuff", Common.SubsectionDocument, -1, Common.GetFileStreamFactory()));
- }
-
- #endregion
-
- #region Query Class Tests
-
- [Fact]
- public void QueryExecuteNoQueryText()
- {
- // If:
- // ... I create a query that has a null query text
- // Then:
- // ... It should throw an exception
- Assert.Throws(() =>
- new Query(null, Common.CreateTestConnectionInfo(null, false), new QueryExecutionSettings(), Common.GetFileStreamFactory()));
- }
-
- [Fact]
- public void QueryExecuteNoConnectionInfo()
- {
- // If:
- // ... I create a query that has a null connection info
- // Then:
- // ... It should throw an exception
- Assert.Throws(() => new Query("Some Query", null, new QueryExecutionSettings(), Common.GetFileStreamFactory()));
- }
-
- [Fact]
- public void QueryExecuteNoSettings()
- {
- // If:
- // ... I create a query that has a null settings
- // Then:
- // ... It should throw an exception
- Assert.Throws(() =>
- new Query("Some query", Common.CreateTestConnectionInfo(null, false), null, Common.GetFileStreamFactory()));
- }
-
- [Fact]
- public void QueryExecuteNoBufferFactory()
- {
- // If:
- // ... I create a query that has a null file stream factory
- // Then:
- // ... It should throw an exception
- Assert.Throws(() =>
- new Query("Some query", Common.CreateTestConnectionInfo(null, false), new QueryExecutionSettings(),null));
- }
-
- [Fact]
- public void QueryExecuteSingleBatch()
- {
- // Setup:
- // ... Create a callback for batch completion
- int batchCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchCallback = summary =>
- {
- batchCallbacksReceived++;
- return Task.CompletedTask;
- };
-
- // If:
- // ... I create a query from a single batch (without separator)
- ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
- Query query = new Query(Common.StandardQuery, ci, new QueryExecutionSettings(), Common.GetFileStreamFactory());
- query.BatchCompleted += batchCallback;
-
- // 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:
- // ... The query should have completed successfully with one batch summary returned
- Assert.True(query.HasExecuted);
- Assert.NotEmpty(query.BatchSummaries);
- Assert.Equal(1, query.BatchSummaries.Length);
-
- // ... The batch callback should have been called precisely 1 time
- Assert.Equal(1, batchCallbacksReceived);
- }
-
- [Fact]
- public void QueryExecuteNoOpBatch()
- {
- // Setup:
- // ... Create a callback for batch completion
- Batch.BatchAsyncEventHandler batchCallback = summary =>
- {
- throw new Exception("Batch completion callback was called");
- };
-
- // If:
- // ... I create a query from a single batch that does nothing
- ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
- Query query = new Query(Common.NoOpQuery, ci, new QueryExecutionSettings(), Common.GetFileStreamFactory());
- query.BatchCompleted += batchCallback;
-
- // Then:
- // ... I should get no batches back
- Assert.NotEmpty(query.QueryText);
- Assert.Empty(query.Batches);
- Assert.False(query.HasExecuted);
- Assert.Throws(() => query.BatchSummaries);
-
- // If:
- // ... I Then execute the query
- query.Execute();
- query.ExecutionTask.Wait();
-
- // Then:
- // ... The query should have completed successfully with no batch summaries returned
- Assert.True(query.HasExecuted);
- Assert.Empty(query.BatchSummaries);
- }
-
- [Fact]
- public void QueryExecuteMultipleBatches()
- {
- // Setup:
- // ... Create a callback for batch completion
- int batchCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchCallback = summary =>
- {
- batchCallbacksReceived++;
- return Task.CompletedTask;
- };
-
- // If:
- // ... I create a query from two batches (with separator)
- ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
- string queryText = string.Format("{0}\r\nGO\r\n{0}", Common.StandardQuery);
- Query query = new Query(queryText, ci, new QueryExecutionSettings(), Common.GetFileStreamFactory());
- query.BatchCompleted += batchCallback;
-
- // 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:
- // ... 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 callback should have been called precisely 2 times
- Assert.Equal(2, batchCallbacksReceived);
- }
-
- [Fact]
- public void QueryExecuteMultipleBatchesWithNoOp()
- {
- // Setup:
- // ... Create a callback for batch completion
- int batchCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchCallback = summary =>
- {
- batchCallbacksReceived++;
- return Task.CompletedTask;
- };
-
- // 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.StandardQuery, Common.NoOpQuery);
- Query query = new Query(queryText, ci, new QueryExecutionSettings(), Common.GetFileStreamFactory());
- query.BatchCompleted += batchCallback;
-
- // 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();
-
- // ... The query should have completed successfully with one batch summary returned
- Assert.True(query.HasExecuted);
- Assert.NotEmpty(query.BatchSummaries);
- Assert.Equal(1, query.BatchSummaries.Length);
-
- // ... The batch callback should have been called precisely 1 time
- Assert.Equal(1, batchCallbacksReceived);
- }
-
- [Fact]
- public void QueryExecuteInvalidBatch()
- {
- // Setup:
- // ... Create a callback for batch completion
- int batchCallbacksReceived = 0;
- Batch.BatchAsyncEventHandler batchCallback = summary =>
- {
- batchCallbacksReceived++;
- return Task.CompletedTask;
- };
-
- // If:
- // ... I create a query from an invalid batch
- ConnectionInfo ci = Common.CreateTestConnectionInfo(null, true);
- Query query = new Query(Common.InvalidQuery, ci, new QueryExecutionSettings(), Common.GetFileStreamFactory());
- query.BatchCompleted += batchCallback;
-
- // 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:
- // ... 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);
-
- // ... The batch callback should have been called once
- Assert.Equal(1, batchCallbacksReceived);
- }
-
- #endregion
-
- #region Service Tests
-
- [Fact]
- public async void QueryExecuteValidNoResultsTest()
- {
- // Given:
- // ... Default settings are stored in the workspace service
- WorkspaceService.Instance.CurrentSettings = new SqlToolsSettings();
-
- // Set up file for returning the query
- var fileMock = new Mock();
- fileMock.SetupGet(file => file.Contents).Returns(Common.StandardQuery);
- // Set up workspace mock
- var workspaceService = new Mock>();
- workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
- .Returns(fileMock.Object);
- // If:
- // ... I request to execute a valid query with no results
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
- var queryParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri };
-
- QueryExecuteResult result = null;
- QueryExecuteCompleteParams completeParams = null;
- QueryExecuteBatchCompleteParams batchCompleteParams = null;
- var requestContext = RequestContextMocks.Create(qer => result = qer)
- .AddEventHandling(QueryExecuteCompleteEvent.Type, (et, p) => completeParams = p)
- .AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchCompleteParams = p);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
-
- // Then:
- // ... No Errors should have been sent
- // ... A successful result should have been sent with messages on the first batch
- // ... A completion event should have been fired with empty results
- // ... A batch completion event should have been fired with empty results
- VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Once(), Times.Once(), Times.Never());
- Assert.Null(result.Messages);
-
- Assert.Equal(1, completeParams.BatchSummaries.Length);
- Assert.Empty(completeParams.BatchSummaries[0].ResultSetSummaries);
- Assert.NotEmpty(completeParams.BatchSummaries[0].Messages);
-
- Assert.NotNull(batchCompleteParams);
- Assert.Empty(batchCompleteParams.BatchSummary.ResultSetSummaries);
- Assert.NotEmpty(batchCompleteParams.BatchSummary.Messages);
- Assert.Equal(completeParams.OwnerUri, batchCompleteParams.OwnerUri);
-
- // ... There should be one active query
- Assert.Equal(1, queryService.ActiveQueries.Count);
- }
-
- [Fact]
- public async void QueryExecuteValidResultsTest()
- {
-
- // Set up file for returning the query
- var fileMock = new Mock();
- fileMock.SetupGet(file => file.Contents).Returns(Common.StandardQuery);
- // Set up workspace mock
- var workspaceService = new Mock>();
- workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
- .Returns(fileMock.Object);
- // If:
- // ... I request to execute a valid query with results
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(new[] { Common.StandardTestData }, false), true,
- workspaceService.Object);
- var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
-
- QueryExecuteResult result = null;
- QueryExecuteCompleteParams completeParams = null;
- QueryExecuteBatchCompleteParams batchCompleteParams = null;
- var requestContext = RequestContextMocks.Create(qer => result = qer)
- .AddEventHandling(QueryExecuteCompleteEvent.Type, (et, p) => completeParams = p)
- .AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchCompleteParams = p);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
-
- // Then:
- // ... No errors should have been sent
- // ... A successful result should have been sent with messages
- // ... A completion event should have been fired with one result
- VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Once(), Times.Once(), Times.Never());
- Assert.Null(result.Messages);
-
- Assert.Equal(1, completeParams.BatchSummaries.Length);
- Assert.NotEmpty(completeParams.BatchSummaries[0].ResultSetSummaries);
- Assert.NotEmpty(completeParams.BatchSummaries[0].Messages);
- Assert.False(completeParams.BatchSummaries[0].HasError);
-
- Assert.NotNull(batchCompleteParams);
- Assert.NotEmpty(batchCompleteParams.BatchSummary.ResultSetSummaries);
- Assert.NotEmpty(batchCompleteParams.BatchSummary.Messages);
- Assert.Equal(completeParams.OwnerUri, batchCompleteParams.OwnerUri);
-
- // ... There should be one active query
- Assert.Equal(1, queryService.ActiveQueries.Count);
- }
-
- [Fact]
- public async void QueryExecuteUnconnectedUriTest()
- {
-
- var workspaceService = new Mock>();
- // If:
- // ... I request to execute a query using a file URI that isn't connected
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), false, workspaceService.Object);
- var queryParams = new QueryExecuteParams { OwnerUri = "notConnected", QuerySelection = Common.WholeDocument };
-
- object error = null;
- var requestContext = RequestContextMocks.Create(null)
- .AddErrorHandling(e => error = e);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
-
- // Then:
- // ... An error should have been returned
- // ... No result should have been returned
- // ... No completion event should have been fired
- // ... There should be no active queries
- VerifyQueryExecuteCallCount(requestContext, Times.Never(), Times.Never(), Times.Never(), Times.Once());
- Assert.IsType(error);
- Assert.NotEmpty((string)error);
- Assert.Empty(queryService.ActiveQueries);
- }
-
- [Fact]
- public async void QueryExecuteInProgressTest()
- {
-
- // Set up file for returning the query
- var fileMock = new Mock();
- fileMock.SetupGet(file => file.Contents).Returns(Common.StandardQuery);
- // Set up workspace mock
- var workspaceService = new Mock>();
- workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
- .Returns(fileMock.Object);
-
- // If:
- // ... I request to execute a query
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
- 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 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
- object error = null;
- var secondRequestContext = RequestContextMocks.Create(null)
- .AddErrorHandling(e => error = e);
- await AwaitExecution(queryService, queryParams, secondRequestContext.Object);
-
- // Then:
- // ... 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.Never(), Times.AtMostOnce(), Times.AtMostOnce(), Times.Once());
- Assert.IsType(error);
- Assert.NotEmpty((string)error);
- Assert.Equal(1, queryService.ActiveQueries.Count);
- }
-
- [Fact]
- public async void QueryExecuteCompletedTest()
- {
-
- // Set up file for returning the query
- var fileMock = new Mock();
- fileMock.SetupGet(file => file.Contents).Returns(Common.StandardQuery);
- // Set up workspace mock
- var workspaceService = new Mock>();
- workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
- .Returns(fileMock.Object);
-
- // If:
- // ... I request to execute a query
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
- 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);
-
- queryService.HandleExecuteRequest(queryParams, firstRequestContext.Object).Wait();
-
- // ... And then I request another query after waiting for the first to complete
- QueryExecuteResult result = null;
- QueryExecuteCompleteParams complete = null;
- QueryExecuteBatchCompleteParams batchComplete = null;
- var secondRequestContext = RequestContextMocks.Create(qer => result = qer)
- .AddEventHandling(QueryExecuteCompleteEvent.Type, (et, qecp) => complete = qecp)
- .AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchComplete = p);
- queryService.HandleExecuteRequest(queryParams, secondRequestContext.Object).Wait();
-
- // Then:
- // ... No errors should have been sent
- // ... A result should have been sent with no errors
- // ... There should only be one active query
- VerifyQueryExecuteCallCount(secondRequestContext, Times.Once(), Times.Once(), Times.Once(), Times.Never());
- Assert.Null(result.Messages);
-
- Assert.False(complete.BatchSummaries.Any(b => b.HasError));
- Assert.Equal(1, queryService.ActiveQueries.Count);
-
- Assert.NotNull(batchComplete);
- Assert.False(batchComplete.BatchSummary.HasError);
- Assert.Equal(complete.OwnerUri, batchComplete.OwnerUri);
- }
-
- [Fact]
- public async Task QueryExecuteMissingSelectionTest()
- {
-
- // Set up file for returning the query
- var fileMock = new Mock();
- fileMock.SetupGet(file => file.Contents).Returns("");
- // Set up workspace mock
- var workspaceService = new Mock>();
- workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
- .Returns(fileMock.Object);
- // If:
- // ... I request to execute a query with a missing query string
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, false), true, workspaceService.Object);
- var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = null };
-
- object errorResult = null;
- var requestContext = RequestContextMocks.Create(null)
- .AddErrorHandling(error => errorResult = error);
- await queryService.HandleExecuteRequest(queryParams, requestContext.Object);
-
-
- // Then:
- // ... Am error should have been sent
- // ... No result should have been sent
- // ... No completion event should have been fired
- // ... An active query should not have been added
- VerifyQueryExecuteCallCount(requestContext, Times.Never(), 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);
- }
-
- [Fact]
- public async void QueryExecuteInvalidQueryTest()
- {
- // Set up file for returning the query
- var fileMock = new Mock();
- fileMock.SetupGet(file => file.Contents).Returns(Common.StandardQuery);
- // Set up workspace mock
- var workspaceService = new Mock>();
- workspaceService.Setup(service => service.Workspace.GetFile(It.IsAny()))
- .Returns(fileMock.Object);
- // If:
- // ... I request to execute a query that is invalid
- var queryService = await Common.GetPrimedExecutionService(Common.CreateMockFactory(null, true), true, workspaceService.Object);
- var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
-
- QueryExecuteResult result = null;
- QueryExecuteCompleteParams complete = null;
- QueryExecuteBatchCompleteParams batchComplete = null;
- var requestContext = RequestContextMocks.Create(qer => result = qer)
- .AddEventHandling(QueryExecuteCompleteEvent.Type, (et, qecp) => complete = qecp)
- .AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchComplete = p);
- queryService.HandleExecuteRequest(queryParams, requestContext.Object).Wait();
-
- // Then:
- // ... No errors should have been sent
- // ... A result should have been sent with success (we successfully started the query)
- // ... A completion event should have been sent with error
- VerifyQueryExecuteCallCount(requestContext, Times.Once(), Times.Once(), Times.Once(), Times.Never());
- Assert.Null(result.Messages);
-
- Assert.Equal(1, complete.BatchSummaries.Length);
- Assert.True(complete.BatchSummaries[0].HasError);
- Assert.NotEmpty(complete.BatchSummaries[0].Messages);
-
- Assert.NotNull(batchComplete);
- Assert.True(batchComplete.BatchSummary.HasError);
- Assert.NotEmpty(batchComplete.BatchSummary.Messages);
- Assert.Equal(complete.OwnerUri, batchComplete.OwnerUri);
- }
#if USE_LIVE_CONNECTION
[Fact]
@@ -866,32 +44,5 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
Assert.NotEmpty(query.BatchSummaries[0].Messages);
}
#endif
-
- #endregion
-
- private static void VerifyQueryExecuteCallCount(Mock> mock, Times sendResultCalls,
- Times sendCompletionEventCalls, Times sendBatchCompletionEvent, Times sendErrorCalls)
- {
- mock.Verify(rc => rc.SendResult(It.IsAny()), sendResultCalls);
- mock.Verify(rc => rc.SendEvent(
- It.Is>(m => m == QueryExecuteCompleteEvent.Type),
- It.IsAny()), sendCompletionEventCalls);
- mock.Verify(rc => rc.SendEvent(
- It.Is>(m => m == QueryExecuteBatchCompleteEvent.Type),
- It.IsAny()), sendBatchCompletionEvent);
- mock.Verify(rc => rc.SendError(It.IsAny