// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.IO; using System.Threading.Tasks; using System.Runtime.InteropServices; using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.QueryExecution; using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; using Microsoft.SqlTools.ServiceLayer.Test.Utility; using Moq; using Xunit; namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution { /// /// Tests for saving a result set to a file /// public class SaveResultsTests { /// /// Test save results to a file as CSV with correct parameters /// [Fact] public async void SaveResultsAsCsvSuccessTest() { // Execute a query var workplaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(new [] {Common.StandardTestData}, true, false, workplaceService); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create(null); await Common.AwaitExecution(queryService, executeParams, executeRequest.Object); // Request to save the results as csv with correct parameters var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_1.csv", IncludeHeaders = true }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); // Call save results and wait on the save task await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; await selectedResultSet.GetSaveTask(saveParams.FilePath); // Expect to see a file successfully created in filepath and a success message VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); Assert.Null(result.Messages); Assert.True(File.Exists(saveParams.FilePath)); // Delete temp file after test if (File.Exists(saveParams.FilePath)) { File.Delete(saveParams.FilePath); } } /// /// Test save results to a file as CSV with a selection of cells and correct parameters /// [Fact] public async void SaveResultsAsCsvWithSelectionSuccessTest() { // Execute a query var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(new []{Common.StandardTestData}, true, false, workspaceService); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument , OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create(null); await Common.AwaitExecution(queryService, executeParams, executeRequest.Object); // Request to save the results as csv with correct parameters var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_2.csv", IncludeHeaders = true, RowStartIndex = 0, RowEndIndex = 0, ColumnStartIndex = 0, ColumnEndIndex = 0 }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); // Call save results and wait on the save task await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; Task saveTask = selectedResultSet.GetSaveTask(saveParams.FilePath); await saveTask; // Expect to see a file successfully created in filepath and a success message VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); Assert.Null(result.Messages); Assert.True(File.Exists(saveParams.FilePath)); // Delete temp file after test if (File.Exists(saveParams.FilePath)) { File.Delete(saveParams.FilePath); } } /// /// Test handling exception in saving results to CSV file /// [Fact] public async void SaveResultsAsCsvExceptionTest() { // Execute a query var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(new[] {Common.StandardTestData}, true, false, workspaceService); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create(null); await Common.AwaitExecution(queryService, executeParams, executeRequest.Object); // Request to save the results as csv with incorrect filepath var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "G:\\test.csv" : "/test.csv" }; SaveResultRequestError errMessage = null; var saveRequest = GetSaveResultsContextMock( null, err => errMessage = (SaveResultRequestError) err); // Call save results and wait on the save task await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; await selectedResultSet.GetSaveTask(saveParams.FilePath); // Expect to see error message VerifySaveResultsCallCount(saveRequest, Times.Never(), Times.Once()); Assert.NotNull(errMessage); Assert.False(File.Exists(saveParams.FilePath)); } /// /// Test saving results to CSV file when the requested result set is no longer active /// [Fact] public async Task SaveResultsAsCsvQueryNotFoundTest() { // Create a query execution service var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService); // Request to save the results as csv with query that is no longer active var saveParams = new SaveResultsAsCsvRequestParams { OwnerUri = "falseuri", ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_3.csv" }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); await queryService.HandleSaveResultsAsCsvRequest(saveParams, saveRequest.Object); // Expect message that save failed VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); Assert.NotNull(result.Messages); Assert.False(File.Exists(saveParams.FilePath)); } /// /// Test save results to a file as JSON with correct parameters /// [Fact] public async void SaveResultsAsJsonSuccessTest() { // Execute a query var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(new[] {Common.StandardTestData}, true, false, workspaceService); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create(null); await Common.AwaitExecution(queryService, executeParams, executeRequest.Object); // Request to save the results as json with correct parameters var saveParams = new SaveResultsAsJsonRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_4.json" }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); // Call save results and wait on the save task await queryService.HandleSaveResultsAsJsonRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; Task saveTask = selectedResultSet.GetSaveTask(saveParams.FilePath); await saveTask; // Expect to see a file successfully created in filepath and a success message Assert.Null(result.Messages); Assert.True(File.Exists(saveParams.FilePath)); VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); // Delete temp file after test if (File.Exists(saveParams.FilePath)) { File.Delete(saveParams.FilePath); } } /// /// Test save results to a file as JSON with a selection of cells and correct parameters /// [Fact] public async void SaveResultsAsJsonWithSelectionSuccessTest() { // Execute a query var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(new[] { Common.StandardTestData }, true, false, workspaceService); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument , OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create(null); await Common.AwaitExecution(queryService, executeParams, executeRequest.Object); // Request to save the results as json with correct parameters var saveParams = new SaveResultsAsJsonRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_5.json", RowStartIndex = 0, RowEndIndex = 1, ColumnStartIndex = 0, ColumnEndIndex = 1 }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); // Call save results and wait on the save task await queryService.HandleSaveResultsAsJsonRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; await selectedResultSet.GetSaveTask(saveParams.FilePath); // Expect to see a file successfully created in filepath and a success message VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); Assert.Null(result.Messages); Assert.True(File.Exists(saveParams.FilePath)); // Delete temp file after test if (File.Exists(saveParams.FilePath)) { File.Delete(saveParams.FilePath); } } /// /// Test handling exception in saving results to JSON file /// [Fact] public async void SaveResultsAsJsonExceptionTest() { // Execute a query var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(new [] {Common.StandardTestData}, true, false, workspaceService); var executeParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri }; var executeRequest = RequestContextMocks.Create(null); await Common.AwaitExecution(queryService, executeParams, executeRequest.Object); // Request to save the results as json with incorrect filepath var saveParams = new SaveResultsAsJsonRequestParams { OwnerUri = Common.OwnerUri, ResultSetIndex = 0, BatchIndex = 0, FilePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "G:\\test.json" : "/test.json" }; SaveResultRequestError errMessage = null; var saveRequest = GetSaveResultsContextMock( null, err => errMessage = (SaveResultRequestError) err); queryService.ActiveQueries[Common.OwnerUri].Batches[0] = Common.GetBasicExecutedBatch(); // Call save results and wait on the save task await queryService.HandleSaveResultsAsJsonRequest(saveParams, saveRequest.Object); ResultSet selectedResultSet = queryService.ActiveQueries[saveParams.OwnerUri].Batches[saveParams.BatchIndex].ResultSets[saveParams.ResultSetIndex]; await selectedResultSet.GetSaveTask(saveParams.FilePath); // Expect to see error message Assert.NotNull(errMessage); VerifySaveResultsCallCount(saveRequest, Times.Never(), Times.Once()); Assert.False(File.Exists(saveParams.FilePath)); } /// /// Test saving results to JSON file when the requested result set is no longer active /// [Fact] public async Task SaveResultsAsJsonQueryNotFoundTest() { // Create a query service var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery); var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService); // Request to save the results as json with query that is no longer active var saveParams = new SaveResultsAsJsonRequestParams { OwnerUri = "falseuri", ResultSetIndex = 0, BatchIndex = 0, FilePath = "testwrite_6.json" }; SaveResultRequestResult result = null; var saveRequest = GetSaveResultsContextMock(qcr => result = qcr, null); await queryService.HandleSaveResultsAsJsonRequest(saveParams, saveRequest.Object); // Expect message that save failed Assert.Equal("Failed to save results, ID not found.", result.Messages); Assert.False(File.Exists(saveParams.FilePath)); VerifySaveResultsCallCount(saveRequest, Times.Once(), Times.Never()); } #region Mocking /// /// Mock the requestContext for saving a result set /// /// /// /// private static Mock> GetSaveResultsContextMock( Action resultCallback, Action errorCallback) { var requestContext = RequestContextMocks.Create(resultCallback) .AddErrorHandling(errorCallback); return requestContext; } /// /// Verify the call count for sendResult and error /// /// /// /// private static void VerifySaveResultsCallCount(Mock> mock, Times sendResultCalls, Times sendErrorCalls) { mock.Verify(rc => rc.SendResult(It.IsAny()), sendResultCalls); mock.Verify(rc => rc.SendError(It.IsAny()), sendErrorCalls); } #endregion } }