mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-17 01:25:40 -05:00
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:
@@ -0,0 +1,310 @@
|
||||
//
|
||||
// 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.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
{
|
||||
public class BatchTests
|
||||
{
|
||||
[Fact]
|
||||
public void BatchCreationTest()
|
||||
{
|
||||
// If I create a new batch...
|
||||
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory(null));
|
||||
|
||||
// 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
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
|
||||
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
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
|
||||
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
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
|
||||
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
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
|
||||
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
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Batch batch = new Batch(Common.StandardQuery, Common.SubsectionDocument, Common.Ordinal, fileStreamFactory);
|
||||
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<InvalidOperationException>(() =>
|
||||
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<ArgumentException>(() => new Batch(query, Common.SubsectionDocument, Common.Ordinal, Common.GetFileStreamFactory(null)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BatchNoBufferFactory()
|
||||
{
|
||||
// If:
|
||||
// ... I create a batch that has no file stream factory
|
||||
// Then:
|
||||
// ... It should throw an exception
|
||||
Assert.Throws<ArgumentNullException>(() => 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<ArgumentOutOfRangeException>(() => new Batch("stuff", Common.SubsectionDocument, -1, Common.GetFileStreamFactory(null)));
|
||||
}
|
||||
|
||||
private static DbConnection GetConnection(ConnectionInfo info)
|
||||
{
|
||||
return info.Factory.CreateSqlConnection(ConnectionService.BuildConnectionString(info.ConnectionDetails));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
//
|
||||
// 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.Collections.Generic;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
{
|
||||
public class QueryTests
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public void QueryExecuteNoQueryText()
|
||||
{
|
||||
// If:
|
||||
// ... I create a query that has a null query text
|
||||
// Then:
|
||||
// ... It should throw an exception
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
new Query(null, Common.CreateTestConnectionInfo(null, false), new QueryExecutionSettings(), Common.GetFileStreamFactory(null)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueryExecuteNoConnectionInfo()
|
||||
{
|
||||
// If:
|
||||
// ... I create a query that has a null connection info
|
||||
// Then:
|
||||
// ... It should throw an exception
|
||||
Assert.Throws<ArgumentNullException>(() => new Query("Some Query", null, new QueryExecutionSettings(), Common.GetFileStreamFactory(null)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueryExecuteNoSettings()
|
||||
{
|
||||
// If:
|
||||
// ... I create a query that has a null settings
|
||||
// Then:
|
||||
// ... It should throw an exception
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
new Query("Some query", Common.CreateTestConnectionInfo(null, false), null, Common.GetFileStreamFactory(null)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueryExecuteNoBufferFactory()
|
||||
{
|
||||
// If:
|
||||
// ... I create a query that has a null file stream factory
|
||||
// Then:
|
||||
// ... It should throw an exception
|
||||
Assert.Throws<ArgumentNullException>(() =>
|
||||
new Query("Some query", Common.CreateTestConnectionInfo(null, false), new QueryExecutionSettings(), null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueryExecuteSingleBatch()
|
||||
{
|
||||
// If:
|
||||
// ... I create a query from a single batch (without separator)
|
||||
ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Query query = new Query(Common.StandardQuery, ci, new QueryExecutionSettings(), fileStreamFactory);
|
||||
|
||||
// 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<InvalidOperationException>(() => 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueryExecuteNoOpBatch()
|
||||
{
|
||||
// If:
|
||||
// ... I create a query from a single batch that does nothing
|
||||
ConnectionInfo ci = Common.CreateTestConnectionInfo(null, false);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Query query = new Query(Common.NoOpQuery, ci, new QueryExecutionSettings(), fileStreamFactory);
|
||||
|
||||
// Then:
|
||||
// ... I should get no batches back
|
||||
Assert.NotEmpty(query.QueryText);
|
||||
Assert.Empty(query.Batches);
|
||||
Assert.False(query.HasExecuted);
|
||||
Assert.Throws<InvalidOperationException>(() => 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()
|
||||
{
|
||||
// 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);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Query query = new Query(queryText, ci, new QueryExecutionSettings(), fileStreamFactory);
|
||||
|
||||
// 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<InvalidOperationException>(() => 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueryExecuteMultipleBatchesWithNoOp()
|
||||
{
|
||||
// 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);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Query query = new Query(queryText, ci, new QueryExecutionSettings(), fileStreamFactory);
|
||||
|
||||
// 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<InvalidOperationException>(() => 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void QueryExecuteInvalidBatch()
|
||||
{
|
||||
// If:
|
||||
// ... I create a query from an invalid batch
|
||||
ConnectionInfo ci = Common.CreateTestConnectionInfo(null, true);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
Query query = new Query(Common.InvalidQuery, ci, new QueryExecutionSettings(), fileStreamFactory);
|
||||
|
||||
// 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<InvalidOperationException>(() => 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// 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.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
{
|
||||
public class ResultSetTests
|
||||
{
|
||||
[Fact]
|
||||
public void ResultCreation()
|
||||
{
|
||||
// If:
|
||||
// ... I create a new result set with a valid db data reader
|
||||
|
||||
DbDataReader mockReader = GetReader(null, false, string.Empty);
|
||||
ResultSet resultSet = new ResultSet(mockReader, Common.GetFileStreamFactory(new Dictionary<string, byte[]>()));
|
||||
|
||||
// Then:
|
||||
// ... There should not be any data read yet
|
||||
Assert.Null(resultSet.Columns);
|
||||
Assert.Equal(0, resultSet.RowCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResultCreationInvalidReader()
|
||||
{
|
||||
// If:
|
||||
// ... I create a new result set without a reader
|
||||
// Then:
|
||||
// ... It should throw an exception
|
||||
Assert.Throws<ArgumentNullException>(() => new ResultSet(null, null));
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadToEndSuccess()
|
||||
{
|
||||
// If:
|
||||
// ... I create a new resultset with a valid db data reader that has data
|
||||
// ... and I read it to the end
|
||||
DbDataReader mockReader = GetReader(new [] {Common.StandardTestData}, false, Common.StandardQuery);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
ResultSet resultSet = new ResultSet(mockReader, fileStreamFactory);
|
||||
await resultSet.ReadResultToEnd(CancellationToken.None);
|
||||
|
||||
// Then:
|
||||
// ... The columns should be set
|
||||
// ... There should be rows to read back
|
||||
Assert.NotNull(resultSet.Columns);
|
||||
Assert.NotEmpty(resultSet.Columns);
|
||||
Assert.Equal(Common.StandardRows, resultSet.RowCount);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("JSON")]
|
||||
[InlineData("XML")]
|
||||
public async Task ReadToEndForXmlJson(string forType)
|
||||
{
|
||||
// Setup:
|
||||
// ... Build a FOR XML or FOR JSON data set
|
||||
string columnName = string.Format("{0}_F52E2B61-18A1-11d1-B105-00805F49916B", forType);
|
||||
List<Dictionary<string, string>> data = new List<Dictionary<string, string>>();
|
||||
for(int i = 0; i < Common.StandardRows; i++)
|
||||
{
|
||||
data.Add(new Dictionary<string, string> { { columnName, "test data"} });
|
||||
}
|
||||
Dictionary<string, string>[][] dataSets = {data.ToArray()};
|
||||
|
||||
// If:
|
||||
// ... I create a new resultset with a valid db data reader that is FOR XML/JSON
|
||||
// ... and I read it to the end
|
||||
DbDataReader mockReader = GetReader(dataSets, false, Common.StandardQuery);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
ResultSet resultSet = new ResultSet(mockReader, fileStreamFactory);
|
||||
await resultSet.ReadResultToEnd(CancellationToken.None);
|
||||
|
||||
// Then:
|
||||
// ... There should only be one column
|
||||
// ... There should only be one row
|
||||
// ... The result should be marked as complete
|
||||
Assert.Equal(1, resultSet.Columns.Length);
|
||||
Assert.Equal(1, resultSet.RowCount);
|
||||
|
||||
// If:
|
||||
// ... I attempt to read back the results
|
||||
// Then:
|
||||
// ... I should only get one row
|
||||
var subset = await resultSet.GetSubset(0, 10);
|
||||
Assert.Equal(1, subset.RowCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSubsetWithoutExecution()
|
||||
{
|
||||
// If:
|
||||
// ... I create a new result set with a valid db data reader without executing it
|
||||
DbDataReader mockReader = GetReader(null, false, string.Empty);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
ResultSet resultSet = new ResultSet(mockReader, fileStreamFactory);
|
||||
|
||||
// Then:
|
||||
// ... Attempting to read a subset should fail miserably
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => resultSet.GetSubset(0, 0));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-1, 0)] // Too small start row
|
||||
[InlineData(20, 0)] // Too large start row
|
||||
[InlineData(0, -1)] // Negative row count
|
||||
public async Task GetSubsetInvalidParameters(int startRow, int rowCount)
|
||||
{
|
||||
// If:
|
||||
// ... I create a new result set with a valid db data reader
|
||||
// ... And execute the result
|
||||
DbDataReader mockReader = GetReader(new[] {Common.StandardTestData}, false, Common.StandardQuery);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
ResultSet resultSet = new ResultSet(mockReader, fileStreamFactory);
|
||||
await resultSet.ReadResultToEnd(CancellationToken.None);
|
||||
|
||||
// ... And attempt to get a subset with invalid parameters
|
||||
// Then:
|
||||
// ... It should throw an exception for an invalid parameter
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => resultSet.GetSubset(startRow, rowCount));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 3)] // Standard scenario, 3 rows should come back
|
||||
[InlineData(0, 20)] // Asking for too many rows, 5 rows should come back
|
||||
[InlineData(1, 3)] // Standard scenario from non-zero start
|
||||
[InlineData(1, 20)] // Asking for too many rows at a non-zero start
|
||||
public async Task GetSubsetSuccess(int startRow, int rowCount)
|
||||
{
|
||||
// If:
|
||||
// ... I create a new result set with a valid db data reader
|
||||
// ... And execute the result set
|
||||
DbDataReader mockReader = GetReader(new[] { Common.StandardTestData }, false, Common.StandardQuery);
|
||||
var fileStreamFactory = Common.GetFileStreamFactory(new Dictionary<string, byte[]>());
|
||||
ResultSet resultSet = new ResultSet(mockReader, fileStreamFactory);
|
||||
await resultSet.ReadResultToEnd(CancellationToken.None);
|
||||
|
||||
// ... And attempt to get a subset with valid number of rows
|
||||
ResultSetSubset subset = await resultSet.GetSubset(startRow, rowCount);
|
||||
|
||||
// Then:
|
||||
// ... There should be rows in the subset, either the number of rows or the number of
|
||||
// rows requested or the number of rows in the result set, whichever is lower
|
||||
long availableRowsFromStart = resultSet.RowCount - startRow;
|
||||
Assert.Equal(Math.Min(availableRowsFromStart, rowCount), subset.RowCount);
|
||||
|
||||
// ... The rows should have the same number of columns as the resultset
|
||||
Assert.Equal(resultSet.Columns.Length, subset.Rows[0].Length);
|
||||
}
|
||||
|
||||
private static DbDataReader GetReader(Dictionary<string, string>[][] dataSet, bool throwOnRead, string query)
|
||||
{
|
||||
var info = Common.CreateTestConnectionInfo(dataSet, throwOnRead);
|
||||
var connection = info.Factory.CreateSqlConnection(ConnectionService.BuildConnectionString(info.ConnectionDetails));
|
||||
var command = connection.CreateCommand();
|
||||
command.CommandText = query;
|
||||
return command.ExecuteReader();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Workspace;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
{
|
||||
public class ServiceIntegrationTests
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public async void QueryExecuteValidNoResultsTest()
|
||||
{
|
||||
// Given:
|
||||
// ... Default settings are stored in the workspace service
|
||||
// ... A workspace with a standard query is configured
|
||||
WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings = new SqlToolsSettings();
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a valid query with no results
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { QuerySelection = Common.WholeDocument, OwnerUri = Common.OwnerUri };
|
||||
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams completeParams = null;
|
||||
QueryExecuteBatchCompleteParams batchCompleteParams = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, p) => completeParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchCompleteParams = p);
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a valid query with results
|
||||
var queryService = Common.GetPrimedExecutionService(new[] { Common.StandardTestData }, true, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
|
||||
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams completeParams = null;
|
||||
QueryExecuteBatchCompleteParams batchCompleteParams = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, p) => completeParams = p)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchCompleteParams = p);
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
|
||||
// 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()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a query using a file URI that isn't connected
|
||||
var queryService = Common.GetPrimedExecutionService(null, false, false, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = "notConnected", QuerySelection = Common.WholeDocument };
|
||||
|
||||
object error = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(null)
|
||||
.AddErrorHandling(e => error = e);
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
|
||||
// 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<string>(error);
|
||||
Assert.NotEmpty((string)error);
|
||||
Assert.Empty(queryService.ActiveQueries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void QueryExecuteInProgressTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a query
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
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<QueryExecuteResult>(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
|
||||
object error = null;
|
||||
var secondRequestContext = RequestContextMocks.Create<QueryExecuteResult>(null)
|
||||
.AddErrorHandling(e => error = e);
|
||||
await Common.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<string>(error);
|
||||
Assert.NotEmpty((string)error);
|
||||
Assert.Equal(1, queryService.ActiveQueries.Count);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async void QueryExecuteCompletedTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a query
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, false, workspaceService);
|
||||
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<QueryExecuteResult>(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<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, qecp) => complete = qecp)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchComplete = p);
|
||||
await Common.AwaitExecution(queryService, queryParams, secondRequestContext.Object);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
public async Task QueryExecuteMissingSelectionTest(SelectionData selection)
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(string.Empty);
|
||||
|
||||
// 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 };
|
||||
|
||||
object errorResult = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(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<string>(errorResult);
|
||||
Assert.DoesNotContain(Common.OwnerUri, queryService.ActiveQueries.Keys);
|
||||
|
||||
// ... There should not be an active query
|
||||
Assert.Empty(queryService.ActiveQueries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void QueryExecuteInvalidQueryTest()
|
||||
{
|
||||
// Given:
|
||||
// ... A workspace with a standard query is configured
|
||||
var workspaceService = Common.GetPrimedWorkspaceService(Common.StandardQuery);
|
||||
|
||||
// If:
|
||||
// ... I request to execute a query that is invalid
|
||||
var queryService = Common.GetPrimedExecutionService(null, true, true, workspaceService);
|
||||
var queryParams = new QueryExecuteParams { OwnerUri = Common.OwnerUri, QuerySelection = Common.WholeDocument };
|
||||
|
||||
QueryExecuteResult result = null;
|
||||
QueryExecuteCompleteParams complete = null;
|
||||
QueryExecuteBatchCompleteParams batchComplete = null;
|
||||
var requestContext = RequestContextMocks.Create<QueryExecuteResult>(qer => result = qer)
|
||||
.AddEventHandling(QueryExecuteCompleteEvent.Type, (et, qecp) => complete = qecp)
|
||||
.AddEventHandling(QueryExecuteBatchCompleteEvent.Type, (et, p) => batchComplete = p);
|
||||
await Common.AwaitExecution(queryService, queryParams, requestContext.Object);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
private static void VerifyQueryExecuteCallCount(Mock<RequestContext<QueryExecuteResult>> mock, Times sendResultCalls,
|
||||
Times sendCompletionEventCalls, Times sendBatchCompletionEvent, Times sendErrorCalls)
|
||||
{
|
||||
mock.Verify(rc => rc.SendResult(It.IsAny<QueryExecuteResult>()), sendResultCalls);
|
||||
mock.Verify(rc => rc.SendEvent(
|
||||
It.Is<EventType<QueryExecuteCompleteParams>>(m => m == QueryExecuteCompleteEvent.Type),
|
||||
It.IsAny<QueryExecuteCompleteParams>()), sendCompletionEventCalls);
|
||||
mock.Verify(rc => rc.SendEvent(
|
||||
It.Is<EventType<QueryExecuteBatchCompleteParams>>(m => m == QueryExecuteBatchCompleteEvent.Type),
|
||||
It.IsAny<QueryExecuteBatchCompleteParams>()), sendBatchCompletionEvent);
|
||||
mock.Verify(rc => rc.SendError(It.IsAny<object>()), sendErrorCalls);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user