Unit Test Cleanup (#141)

This is a fairly large set of changes to the unit tests that help isolate the effectiveness of the unit tests.

* Unit tests for query execution have been split into separate files for different classes.
* Unit tests have been added for the ResultSet class which previously did not have tests
* The InMemoryStreamWrapper has been improved to share memory, creating a simulated filesystem
* Creating a mock ConnectionService to decrease noisy exceptions and prevent "row stealing". Unfortunately this lowers code coverage. However, since the tests that touched the connection service were not really testing it, this helps keep us honest. But it will require adding more unit tests for connection service.
* Standardizing the await mechanism for query execution
* Cleaning up the mechanism for getting WorkspaceService mocks and mock FileStreamFactories

* Refactor the query execution tests into their own files

* Removing tests from ExecuteTests.cs that were moved to separate files

* Adding tests for ResultSet class

* Adding test for the FOR XML/JSON component of the resultset class

* Setting up shared storage between file stream readers/writers

* Standardizing on Workspace mocking, awaiting execution completion

* Adding comment for ResultSet class
This commit is contained in:
Benjamin Russell
2016-11-10 11:42:31 -08:00
committed by GitHub
parent 9ff9a02932
commit ec94d986a8
16 changed files with 1171 additions and 1069 deletions

View File

@@ -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<string, byte[]>()));
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<string, byte[]>()));
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<QueryExecuteResult> 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<string, byte[]> storage)
{
Mock<IFileStreamFactory> mock = new Mock<IFileStreamFactory>();
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<string>()))
.Returns(new ServiceBufferFileStreamReader(new InMemoryWrapper(), It.IsAny<string>()));
.Returns<string>(output => new ServiceBufferFileStreamReader(new InMemoryWrapper(storage[output]), output));
mock.Setup(fsf => fsf.GetWriter(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(new ServiceBufferFileStreamWriter(new InMemoryWrapper(), It.IsAny<string>(), 1024,
1024));
.Returns<string, int, int>((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<string, string>[][] data, bool isConnected, bool throwOnRead, WorkspaceService<SqlToolsSettings> 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<string, byte[]> storage = new Dictionary<string, byte[]>();
// 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<ConnectionService>();
ConnectionInfo ci = new ConnectionInfo(factory, OwnerUri, StandardConnectionDetails);
ConnectionInfo outValMock;
connectionService
.Setup(service => service.TryFindConnection(It.IsAny<string>(), 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<QueryExecutionService> GetPrimedExecutionService(ISqlConnectionFactory factory, bool isConnected, WorkspaceService<SqlToolsSettings> 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<SqlToolsSettings> GetPrimedWorkspaceService()
public static WorkspaceService<SqlToolsSettings> GetPrimedWorkspaceService(string query)
{
// Set up file for returning the query
var fileMock = new Mock<ScriptFile>();
fileMock.SetupGet(file => file.Contents).Returns(StandardQuery);
fileMock.SetupGet(file => file.Contents).Returns(query);
// Set up workspace mock
var workspaceService = new Mock<WorkspaceService<SqlToolsSettings>>();