mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-14 17:23:27 -05:00
* Fix to make sql exceptions surface properly to user (with important notes!) * Adding support for detecting column size issues when updating a cell * Adding unit tests for the exception on read scenario
420 lines
19 KiB
C#
420 lines
19 KiB
C#
//
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
//
|
|
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts.ExecuteRequests;
|
|
using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage;
|
|
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
|
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
|
using Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking;
|
|
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
|
|
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.SaveResults
|
|
{
|
|
public class ServiceIntegrationTests
|
|
{
|
|
#region CSV Tests
|
|
|
|
[Fact]
|
|
public async Task SaveResultsCsvNonExistentQuery()
|
|
{
|
|
// Given: A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(null);
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(null, false, false, false, ws);
|
|
|
|
// If: I attempt to save a result set from a query that doesn't exist
|
|
SaveResultsAsCsvRequestParams saveParams = new SaveResultsAsCsvRequestParams
|
|
{
|
|
OwnerUri = Constants.OwnerUri // Won't exist because nothing has executed
|
|
};
|
|
var evf = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardErrorValidation()
|
|
.Complete();
|
|
await qes.HandleSaveResultsAsCsvRequest(saveParams, evf.Object);
|
|
|
|
// Then:
|
|
// ... An error event should have been fired
|
|
// ... No success event should have been fired
|
|
evf.Validate();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveResultAsCsvFailure()
|
|
{
|
|
// Given:
|
|
// ... A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(Constants.StandardQuery);
|
|
ConcurrentDictionary<string, byte[]> storage;
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(Common.ExecutionPlanTestDataSet, true, false, false, ws, out storage);
|
|
|
|
// ... The query execution service has executed a query with results
|
|
var executeParams = new ExecuteDocumentSelectionParams { QuerySelection = null, OwnerUri = Constants.OwnerUri };
|
|
var executeRequest = RequestContextMocks.Create<ExecuteRequestResult>(null);
|
|
await qes.HandleExecuteRequest(executeParams, executeRequest.Object);
|
|
await qes.ActiveQueries[Constants.OwnerUri].ExecutionTask;
|
|
|
|
// If: I attempt to save a result set and get it to throw because of invalid column selection
|
|
SaveResultsAsCsvRequestParams saveParams = new SaveResultsAsCsvRequestParams
|
|
{
|
|
BatchIndex = 0,
|
|
FilePath = "qqq",
|
|
OwnerUri = Constants.OwnerUri,
|
|
ResultSetIndex = 0,
|
|
ColumnStartIndex = -1,
|
|
ColumnEndIndex = 100,
|
|
RowStartIndex = 0,
|
|
RowEndIndex = 5
|
|
};
|
|
qes.CsvFileFactory = GetCsvStreamFactory(storage, saveParams);
|
|
var efv = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardErrorValidation()
|
|
.Complete();
|
|
|
|
|
|
await qes.HandleSaveResultsAsCsvRequest(saveParams, efv.Object);
|
|
await qes.ActiveQueries[saveParams.OwnerUri]
|
|
.Batches[saveParams.BatchIndex]
|
|
.ResultSets[saveParams.ResultSetIndex]
|
|
.SaveTasks[saveParams.FilePath];
|
|
|
|
// Then:
|
|
// ... An error event should have been fired
|
|
// ... No success event should have been fired
|
|
efv.Validate();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveResultsAsCsvSuccess()
|
|
{
|
|
// Given:
|
|
// ... A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(Constants.StandardQuery);
|
|
ConcurrentDictionary<string, byte[]> storage;
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(Common.ExecutionPlanTestDataSet, true, false, false, ws, out storage);
|
|
|
|
// ... The query execution service has executed a query with results
|
|
var executeParams = new ExecuteDocumentSelectionParams {QuerySelection = null, OwnerUri = Constants.OwnerUri};
|
|
var executeRequest = RequestContextMocks.Create<ExecuteRequestResult>(null);
|
|
await qes.HandleExecuteRequest(executeParams, executeRequest.Object);
|
|
await qes.ActiveQueries[Constants.OwnerUri].ExecutionTask;
|
|
|
|
// If: I attempt to save a result set from a query
|
|
SaveResultsAsCsvRequestParams saveParams = new SaveResultsAsCsvRequestParams
|
|
{
|
|
OwnerUri = Constants.OwnerUri,
|
|
FilePath = "qqq",
|
|
BatchIndex = 0,
|
|
ResultSetIndex = 0
|
|
};
|
|
qes.CsvFileFactory = GetCsvStreamFactory(storage, saveParams);
|
|
var efv = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardResultValidator()
|
|
.Complete();
|
|
|
|
await qes.HandleSaveResultsAsCsvRequest(saveParams, efv.Object);
|
|
await qes.ActiveQueries[saveParams.OwnerUri]
|
|
.Batches[saveParams.BatchIndex]
|
|
.ResultSets[saveParams.ResultSetIndex]
|
|
.SaveTasks[saveParams.FilePath];
|
|
|
|
// Then:
|
|
// ... I should have a successful result
|
|
// ... There should not have been an error
|
|
efv.Validate();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region JSON tests
|
|
|
|
[Fact]
|
|
public async Task SaveResultsJsonNonExistentQuery()
|
|
{
|
|
// Given: A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(null);
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(null, false, false, false, ws);
|
|
|
|
// If: I attempt to save a result set from a query that doesn't exist
|
|
SaveResultsAsJsonRequestParams saveParams = new SaveResultsAsJsonRequestParams
|
|
{
|
|
OwnerUri = Constants.OwnerUri // Won't exist because nothing has executed
|
|
};
|
|
var efv = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardErrorValidation()
|
|
.Complete();
|
|
await qes.HandleSaveResultsAsJsonRequest(saveParams, efv.Object);
|
|
|
|
// Then:
|
|
// ... An error event should have been fired
|
|
// ... No success event should have been fired
|
|
efv.Validate();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveResultAsJsonFailure()
|
|
{
|
|
// Given:
|
|
// ... A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(Constants.StandardQuery);
|
|
ConcurrentDictionary<string, byte[]> storage;
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(Common.StandardTestDataSet, true, false, false, ws, out storage);
|
|
|
|
// ... The query execution service has executed a query with results
|
|
var executeParams = new ExecuteDocumentSelectionParams { QuerySelection = null, OwnerUri = Constants.OwnerUri };
|
|
var executeRequest = RequestContextMocks.Create<ExecuteRequestResult>(null);
|
|
await qes.HandleExecuteRequest(executeParams, executeRequest.Object);
|
|
await qes.ActiveQueries[Constants.OwnerUri].ExecutionTask;
|
|
|
|
// If: I attempt to save a result set and get it to throw because of invalid column selection
|
|
SaveResultsAsJsonRequestParams saveParams = new SaveResultsAsJsonRequestParams
|
|
{
|
|
BatchIndex = 0,
|
|
FilePath = "qqq",
|
|
OwnerUri = Constants.OwnerUri,
|
|
ResultSetIndex = 0,
|
|
ColumnStartIndex = -1,
|
|
ColumnEndIndex = 100,
|
|
RowStartIndex = 0,
|
|
RowEndIndex = 5
|
|
};
|
|
qes.JsonFileFactory = GetJsonStreamFactory(storage, saveParams);
|
|
var efv = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardErrorValidation()
|
|
.Complete();
|
|
await qes.HandleSaveResultsAsJsonRequest(saveParams, efv.Object);
|
|
await qes.ActiveQueries[saveParams.OwnerUri]
|
|
.Batches[saveParams.BatchIndex]
|
|
.ResultSets[saveParams.ResultSetIndex]
|
|
.SaveTasks[saveParams.FilePath];
|
|
|
|
// Then:
|
|
// ... An error event should have been fired
|
|
// ... No success event should have been fired
|
|
efv.Validate();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveResultsAsJsonSuccess()
|
|
{
|
|
// Given:
|
|
// ... A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(Constants.StandardQuery);
|
|
ConcurrentDictionary<string, byte[]> storage;
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(Common.StandardTestDataSet, true, false, false, ws, out storage);
|
|
|
|
// ... The query execution service has executed a query with results
|
|
var executeParams = new ExecuteDocumentSelectionParams { QuerySelection = null, OwnerUri = Constants.OwnerUri };
|
|
var executeRequest = RequestContextMocks.Create<ExecuteRequestResult>(null);
|
|
await qes.HandleExecuteRequest(executeParams, executeRequest.Object);
|
|
await qes.ActiveQueries[Constants.OwnerUri].ExecutionTask;
|
|
|
|
// If: I attempt to save a result set from a query
|
|
SaveResultsAsJsonRequestParams saveParams = new SaveResultsAsJsonRequestParams
|
|
{
|
|
OwnerUri = Constants.OwnerUri,
|
|
FilePath = "qqq",
|
|
BatchIndex = 0,
|
|
ResultSetIndex = 0
|
|
};
|
|
qes.JsonFileFactory = GetJsonStreamFactory(storage, saveParams);
|
|
var efv = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardResultValidator()
|
|
.Complete();
|
|
await qes.HandleSaveResultsAsJsonRequest(saveParams, efv.Object);
|
|
await qes.ActiveQueries[saveParams.OwnerUri]
|
|
.Batches[saveParams.BatchIndex]
|
|
.ResultSets[saveParams.ResultSetIndex]
|
|
.SaveTasks[saveParams.FilePath];
|
|
|
|
// Then:
|
|
// ... I should have a successful result
|
|
// ... There should not have been an error
|
|
efv.Validate();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Excel Tests
|
|
|
|
[Fact]
|
|
public async Task SaveResultsExcelNonExistentQuery()
|
|
{
|
|
// Given: A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(null);
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(null, false, false, false, ws);
|
|
|
|
// If: I attempt to save a result set from a query that doesn't exist
|
|
SaveResultsAsExcelRequestParams saveParams = new SaveResultsAsExcelRequestParams
|
|
{
|
|
OwnerUri = Constants.OwnerUri // Won't exist because nothing has executed
|
|
};
|
|
var efv = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardErrorValidation()
|
|
.Complete();
|
|
await qes.HandleSaveResultsAsExcelRequest(saveParams, efv.Object);
|
|
|
|
// Then:
|
|
// ... An error event should have been fired
|
|
// ... No success event should have been fired
|
|
efv.Validate();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveResultAsExcelFailure()
|
|
{
|
|
// Given:
|
|
// ... A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(Constants.StandardQuery);
|
|
ConcurrentDictionary<string, byte[]> storage;
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(Common.StandardTestDataSet, true, false, false, ws, out storage);
|
|
|
|
// ... The query execution service has executed a query with results
|
|
var executeParams = new ExecuteDocumentSelectionParams { QuerySelection = null, OwnerUri = Constants.OwnerUri };
|
|
var executeRequest = RequestContextMocks.Create<ExecuteRequestResult>(null);
|
|
await qes.HandleExecuteRequest(executeParams, executeRequest.Object);
|
|
await qes.ActiveQueries[Constants.OwnerUri].ExecutionTask;
|
|
|
|
// If: I attempt to save a result set and get it to throw because of invalid column selection
|
|
SaveResultsAsExcelRequestParams saveParams = new SaveResultsAsExcelRequestParams
|
|
{
|
|
BatchIndex = 0,
|
|
FilePath = "qqq",
|
|
OwnerUri = Constants.OwnerUri,
|
|
ResultSetIndex = 0,
|
|
ColumnStartIndex = -1,
|
|
ColumnEndIndex = 100,
|
|
RowStartIndex = 0,
|
|
RowEndIndex = 5
|
|
};
|
|
qes.JsonFileFactory = GetExcelStreamFactory(storage, saveParams);
|
|
var efv = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardErrorValidation()
|
|
.Complete();
|
|
await qes.HandleSaveResultsAsExcelRequest(saveParams, efv.Object);
|
|
await qes.ActiveQueries[saveParams.OwnerUri]
|
|
.Batches[saveParams.BatchIndex]
|
|
.ResultSets[saveParams.ResultSetIndex]
|
|
.SaveTasks[saveParams.FilePath];
|
|
|
|
// Then:
|
|
// ... An error event should have been fired
|
|
// ... No success event should have been fired
|
|
efv.Validate();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveResultsAsExcelSuccess()
|
|
{
|
|
// Given:
|
|
// ... A working query and workspace service
|
|
WorkspaceService<SqlToolsSettings> ws = Common.GetPrimedWorkspaceService(Constants.StandardQuery);
|
|
ConcurrentDictionary<string, byte[]> storage;
|
|
QueryExecutionService qes = Common.GetPrimedExecutionService(Common.StandardTestDataSet, true, false, false, ws, out storage);
|
|
|
|
// ... The query execution service has executed a query with results
|
|
var executeParams = new ExecuteDocumentSelectionParams { QuerySelection = null, OwnerUri = Constants.OwnerUri };
|
|
var executeRequest = RequestContextMocks.Create<ExecuteRequestResult>(null);
|
|
await qes.HandleExecuteRequest(executeParams, executeRequest.Object);
|
|
await qes.ActiveQueries[Constants.OwnerUri].ExecutionTask;
|
|
|
|
// If: I attempt to save a result set from a query
|
|
SaveResultsAsExcelRequestParams saveParams = new SaveResultsAsExcelRequestParams
|
|
{
|
|
OwnerUri = Constants.OwnerUri,
|
|
FilePath = "qqq",
|
|
BatchIndex = 0,
|
|
ResultSetIndex = 0
|
|
};
|
|
qes.ExcelFileFactory = GetExcelStreamFactory(storage, saveParams);
|
|
var efv = new EventFlowValidator<SaveResultRequestResult>()
|
|
.AddStandardResultValidator()
|
|
.Complete();
|
|
await qes.HandleSaveResultsAsExcelRequest(saveParams, efv.Object);
|
|
await qes.ActiveQueries[saveParams.OwnerUri]
|
|
.Batches[saveParams.BatchIndex]
|
|
.ResultSets[saveParams.ResultSetIndex]
|
|
.SaveTasks[saveParams.FilePath];
|
|
|
|
// Then:
|
|
// ... I should have a successful result
|
|
// ... There should not have been an error
|
|
efv.Validate();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private Helpers
|
|
|
|
private static IFileStreamFactory GetCsvStreamFactory(IDictionary<string, byte[]> storage, SaveResultsAsCsvRequestParams saveParams)
|
|
{
|
|
Mock<IFileStreamFactory> mock = new Mock<IFileStreamFactory>();
|
|
mock.Setup(fsf => fsf.GetReader(It.IsAny<string>()))
|
|
.Returns<string>(output => new ServiceBufferFileStreamReader(new MemoryStream(storage[output]), new QueryExecutionSettings()));
|
|
mock.Setup(fsf => fsf.GetWriter(It.IsAny<string>()))
|
|
.Returns<string>(output =>
|
|
{
|
|
storage.Add(output, new byte[8192]);
|
|
return new SaveAsCsvFileStreamWriter(new MemoryStream(storage[output]), saveParams);
|
|
});
|
|
|
|
return mock.Object;
|
|
}
|
|
|
|
private static IFileStreamFactory GetJsonStreamFactory(IDictionary<string, byte[]> storage, SaveResultsAsJsonRequestParams saveParams)
|
|
{
|
|
Mock<IFileStreamFactory> mock = new Mock<IFileStreamFactory>();
|
|
mock.Setup(fsf => fsf.GetReader(It.IsAny<string>()))
|
|
.Returns<string>(output => new ServiceBufferFileStreamReader(new MemoryStream(storage[output]), new QueryExecutionSettings()));
|
|
mock.Setup(fsf => fsf.GetWriter(It.IsAny<string>()))
|
|
.Returns<string>(output =>
|
|
{
|
|
storage.Add(output, new byte[8192]);
|
|
return new SaveAsJsonFileStreamWriter(new MemoryStream(storage[output]), saveParams);
|
|
});
|
|
|
|
return mock.Object;
|
|
}
|
|
|
|
private static IFileStreamFactory GetExcelStreamFactory(IDictionary<string, byte[]> storage,
|
|
SaveResultsAsExcelRequestParams saveParams)
|
|
{
|
|
Mock<IFileStreamFactory> mock = new Mock<IFileStreamFactory>();
|
|
mock.Setup(fsf => fsf.GetReader(It.IsAny<string>()))
|
|
.Returns<string>(output => new ServiceBufferFileStreamReader(new MemoryStream(storage[output]), new QueryExecutionSettings()));
|
|
mock.Setup(fsf => fsf.GetWriter(It.IsAny<string>()))
|
|
.Returns<string>(output =>
|
|
{
|
|
storage.Add(output, new byte[8192]);
|
|
return new SaveAsExcelFileStreamWriter(new MemoryStream(storage[output]), saveParams);
|
|
});
|
|
|
|
return mock.Object;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
public static class SaveResultEventFlowValidatorExtensions
|
|
{
|
|
public static EventFlowValidator<SaveResultRequestResult> AddStandardResultValidator(
|
|
this EventFlowValidator<SaveResultRequestResult> efv)
|
|
{
|
|
return efv.AddResultValidation(r =>
|
|
{
|
|
Assert.NotNull(r);
|
|
Assert.Null(r.Messages);
|
|
});
|
|
}
|
|
}
|
|
}
|