mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-30 09:35:38 -05:00
Inter-Service API for executing queries (#223)
Adding new methods for executing queries from other services (such as the upcoming edit data service). The code is written to avoid duplicating logic by using lambdas to perform custom logic. Additionally, the service host protocol has been slightly modified to split the IMessageSender into IEventSender and IRequestSender. This allows us to use either a ServiceHost or any RequestContext<T> to send events. It becomes very convenient to use another service's request context to send the events for query execution. **Breaking Change**: This removes the messages property for query dispose results and instead elects to use error for any errors encountered during query disposal. A result is only used when something is successful. * Splitting IMessageSender into IEventSender and IRequestSender * Adding inter-service method for executing queries * Adding inter-service method for disposing of a query * Adding null checking for the success/error handlers
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
|
||||
{
|
||||
public interface IEventSender
|
||||
{
|
||||
Task SendEvent<TParams>(EventType<TParams> eventType, TParams eventParams);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
|
||||
/// respond to requests and events, send their own requests, and listen for notifications
|
||||
/// sent by the other side of the endpoint
|
||||
/// </summary>
|
||||
public interface IProtocolEndpoint : IMessageSender
|
||||
public interface IProtocolEndpoint : IEventSender, IRequestSender
|
||||
{
|
||||
void SetRequestHandler<TParams, TResult>(
|
||||
RequestType<TParams, TResult> requestType,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
@@ -8,16 +8,9 @@ using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
|
||||
{
|
||||
public interface IMessageSender
|
||||
public interface IRequestSender
|
||||
{
|
||||
Task SendEvent<TParams>(
|
||||
EventType<TParams> eventType,
|
||||
TParams eventParams);
|
||||
|
||||
Task<TResult> SendRequest<TParams, TResult>(
|
||||
RequestType<TParams, TResult> requestType,
|
||||
TParams requestParams,
|
||||
Task<TResult> SendRequest<TParams, TResult>(RequestType<TParams, TResult> requestType, TParams requestParams,
|
||||
bool waitForResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
|
||||
/// Provides behavior for a client or server endpoint that
|
||||
/// communicates using the specified protocol.
|
||||
/// </summary>
|
||||
public class ProtocolEndpoint : IMessageSender, IProtocolEndpoint
|
||||
public class ProtocolEndpoint : IProtocolEndpoint
|
||||
{
|
||||
private bool isStarted;
|
||||
private int currentMessageId;
|
||||
|
||||
@@ -9,10 +9,10 @@ using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
|
||||
{
|
||||
public class RequestContext<TResult>
|
||||
public class RequestContext<TResult> : IEventSender
|
||||
{
|
||||
private Message requestMessage;
|
||||
private MessageWriter messageWriter;
|
||||
private readonly Message requestMessage;
|
||||
private readonly MessageWriter messageWriter;
|
||||
|
||||
public RequestContext(Message requestMessage, MessageWriter messageWriter)
|
||||
{
|
||||
@@ -24,7 +24,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Hosting.Protocol
|
||||
|
||||
public virtual async Task SendResult(TResult resultDetails)
|
||||
{
|
||||
await this.messageWriter.WriteResponse<TResult>(
|
||||
await this.messageWriter.WriteResponse(
|
||||
resultDetails,
|
||||
requestMessage.Method,
|
||||
requestMessage.Id);
|
||||
|
||||
@@ -20,11 +20,6 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts
|
||||
/// </summary>
|
||||
public class QueryDisposeResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Any error messages that occurred during disposing the result set. Optional, can be set
|
||||
/// to null if there were no errors.
|
||||
/// </summary>
|
||||
public string Messages { get; set; }
|
||||
}
|
||||
|
||||
public class QueryDisposeRequest
|
||||
|
||||
@@ -87,17 +87,14 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// <summary>
|
||||
/// The collection of active queries
|
||||
/// </summary>
|
||||
internal ConcurrentDictionary<string, Query> ActiveQueries
|
||||
{
|
||||
get { return queries.Value; }
|
||||
}
|
||||
internal ConcurrentDictionary<string, Query> ActiveQueries => queries.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Instance of the connection service, used to get the connection info for a given owner URI
|
||||
/// </summary>
|
||||
private ConnectionService ConnectionService { get; set; }
|
||||
private ConnectionService ConnectionService { get; }
|
||||
|
||||
private WorkspaceService<SqlToolsSettings> WorkspaceService { get; set; }
|
||||
private WorkspaceService<SqlToolsSettings> WorkspaceService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Internal storage of active queries, lazily constructed as a threadsafe dictionary
|
||||
@@ -105,7 +102,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
private readonly Lazy<ConcurrentDictionary<string, Query>> queries =
|
||||
new Lazy<ConcurrentDictionary<string, Query>>(() => new ConcurrentDictionary<string, Query>());
|
||||
|
||||
private SqlToolsSettings Settings { get { return WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings; } }
|
||||
private SqlToolsSettings Settings => WorkspaceService<SqlToolsSettings>.Instance.CurrentSettings;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -146,20 +143,21 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// <summary>
|
||||
/// Handles request to execute a selection of a document in the workspace service
|
||||
/// </summary>
|
||||
public async Task HandleExecuteRequest(ExecuteRequestParamsBase executeDocumentSelectionParams,
|
||||
internal Task HandleExecuteRequest(ExecuteRequestParamsBase executeParams,
|
||||
RequestContext<ExecuteRequestResult> requestContext)
|
||||
{
|
||||
// Get a query new active query
|
||||
Query newQuery = await CreateAndActivateNewQuery(executeDocumentSelectionParams, requestContext);
|
||||
// Setup actions to perform upon successful start and on failure to start
|
||||
Func<Task> queryCreationAction = () => requestContext.SendResult(new ExecuteRequestResult());
|
||||
Func<string, Task> queryFailAction = requestContext.SendError;
|
||||
|
||||
// Execute the query -- asynchronously
|
||||
ExecuteAndCompleteQuery(executeDocumentSelectionParams, requestContext, newQuery);
|
||||
// Use the internal handler to launch the query
|
||||
return InterServiceExecuteQuery(executeParams, requestContext, queryCreationAction, queryFailAction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles a request to get a subset of the results of this query
|
||||
/// </summary>
|
||||
public async Task HandleResultSubsetRequest(SubsetParams subsetParams,
|
||||
internal async Task HandleResultSubsetRequest(SubsetParams subsetParams,
|
||||
RequestContext<SubsetResult> requestContext)
|
||||
{
|
||||
try
|
||||
@@ -210,7 +208,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// <summary>
|
||||
/// Handles a request to get an execution plan
|
||||
/// </summary>
|
||||
public async Task HandleExecutionPlanRequest(QueryExecutionPlanParams planParams,
|
||||
internal async Task HandleExecutionPlanRequest(QueryExecutionPlanParams planParams,
|
||||
RequestContext<QueryExecutionPlanResult> requestContext)
|
||||
{
|
||||
try
|
||||
@@ -240,41 +238,21 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
/// <summary>
|
||||
/// Handles a request to dispose of this query
|
||||
/// </summary>
|
||||
public async Task HandleDisposeRequest(QueryDisposeParams disposeParams,
|
||||
internal async Task HandleDisposeRequest(QueryDisposeParams disposeParams,
|
||||
RequestContext<QueryDisposeResult> requestContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Attempt to remove the query for the owner uri
|
||||
Query result;
|
||||
if (!ActiveQueries.TryRemove(disposeParams.OwnerUri, out result))
|
||||
{
|
||||
await requestContext.SendResult(new QueryDisposeResult
|
||||
{
|
||||
Messages = SR.QueryServiceRequestsNoQuery
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Setup action for success and failure
|
||||
Func<Task> successAction = () => requestContext.SendResult(new QueryDisposeResult());
|
||||
Func<string, Task> failureAction = requestContext.SendError;
|
||||
|
||||
// Cleanup the query
|
||||
result.Dispose();
|
||||
|
||||
// Success
|
||||
await requestContext.SendResult(new QueryDisposeResult
|
||||
{
|
||||
Messages = null
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e.Message);
|
||||
}
|
||||
// Use the inter-service dispose functionality
|
||||
await InterServiceDisposeQuery(disposeParams.OwnerUri, successAction, failureAction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles a request to cancel this query if it is in progress
|
||||
/// </summary>
|
||||
public async Task HandleCancelRequest(QueryCancelParams cancelParams,
|
||||
internal async Task HandleCancelRequest(QueryCancelParams cancelParams,
|
||||
RequestContext<QueryCancelResult> requestContext)
|
||||
{
|
||||
try
|
||||
@@ -338,9 +316,75 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inter-Service API Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Query execution meant to be called from another service. Utilizes callbacks to allow
|
||||
/// custom actions to be taken upon creation of query and failure to create query.
|
||||
/// </summary>
|
||||
/// <param name="executeParams">Params for creating the new query</param>
|
||||
/// <param name="eventSender">Object that can send events for query execution progress</param>
|
||||
/// <param name="queryCreatedAction">
|
||||
/// Action to perform when query has been successfully created, right before execution of
|
||||
/// the query
|
||||
/// </param>
|
||||
/// <param name="failureAction">Action to perform if query was not successfully created</param>
|
||||
public async Task InterServiceExecuteQuery(ExecuteRequestParamsBase executeParams, IEventSender eventSender,
|
||||
Func<Task> queryCreatedAction, Func<string, Task> failureAction)
|
||||
{
|
||||
Validate.IsNotNull(nameof(executeParams), executeParams);
|
||||
Validate.IsNotNull(nameof(eventSender), eventSender);
|
||||
Validate.IsNotNull(nameof(queryCreatedAction), queryCreatedAction);
|
||||
Validate.IsNotNull(nameof(failureAction), failureAction);
|
||||
|
||||
// Get a new active query
|
||||
Query newQuery = await CreateAndActivateNewQuery(executeParams, queryCreatedAction, failureAction);
|
||||
|
||||
// Execute the query asynchronously
|
||||
ExecuteAndCompleteQuery(executeParams.OwnerUri, eventSender, newQuery);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query disposal meant to be called from another service. Utilizes callbacks to allow
|
||||
/// custom actions to be performed on success or failure.
|
||||
/// </summary>
|
||||
/// <param name="ownerUri">The identifier of the query to be disposed</param>
|
||||
/// <param name="successAction">Action to perform on success</param>
|
||||
/// <param name="failureAction">Action to perform on failure</param>
|
||||
/// <returns></returns>
|
||||
public async Task InterServiceDisposeQuery(string ownerUri, Func<Task> successAction,
|
||||
Func<string, Task> failureAction)
|
||||
{
|
||||
Validate.IsNotNull(nameof(successAction), successAction);
|
||||
Validate.IsNotNull(nameof(failureAction), failureAction);
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to remove the query for the owner uri
|
||||
Query result;
|
||||
if (!ActiveQueries.TryRemove(ownerUri, out result))
|
||||
{
|
||||
await failureAction(SR.QueryServiceRequestsNoQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cleanup the query
|
||||
result.Dispose();
|
||||
|
||||
// Success
|
||||
await successAction();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await failureAction(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helpers
|
||||
|
||||
private async Task<Query> CreateAndActivateNewQuery(ExecuteRequestParamsBase executeParams, RequestContext<ExecuteRequestResult> requestContext)
|
||||
private async Task<Query> CreateAndActivateNewQuery(ExecuteRequestParamsBase executeParams, Func<Task> successAction, Func<string, Task> failureAction)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -348,7 +392,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
ConnectionInfo connectionInfo;
|
||||
if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo))
|
||||
{
|
||||
await requestContext.SendError(SR.QueryServiceQueryInvalidOwnerUri);
|
||||
await failureAction(SR.QueryServiceQueryInvalidOwnerUri);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -370,24 +414,24 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
Query newQuery = new Query(GetSqlText(executeParams), connectionInfo, settings, BufferFileFactory);
|
||||
if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery))
|
||||
{
|
||||
await requestContext.SendError(SR.QueryServiceQueryInProgress);
|
||||
await failureAction(SR.QueryServiceQueryInProgress);
|
||||
newQuery.Dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
// Send the result stating that the query was successfully started
|
||||
await requestContext.SendResult(new ExecuteRequestResult());
|
||||
// Successfully created query
|
||||
await successAction();
|
||||
|
||||
return newQuery;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await requestContext.SendError(e.Message);
|
||||
await failureAction(e.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExecuteAndCompleteQuery(ExecuteRequestParamsBase executeDocumentSelectionParams, RequestContext<ExecuteRequestResult> requestContext, Query query)
|
||||
private static void ExecuteAndCompleteQuery(string ownerUri, IEventSender eventSender, Query query)
|
||||
{
|
||||
// Skip processing if the query is null
|
||||
if (query == null)
|
||||
@@ -401,11 +445,11 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
// Send back the results
|
||||
QueryCompleteParams eventParams = new QueryCompleteParams
|
||||
{
|
||||
OwnerUri = executeDocumentSelectionParams.OwnerUri,
|
||||
OwnerUri = ownerUri,
|
||||
BatchSummaries = q.BatchSummaries
|
||||
};
|
||||
|
||||
await requestContext.SendEvent(QueryCompleteEvent.Type, eventParams);
|
||||
await eventSender.SendEvent(QueryCompleteEvent.Type, eventParams);
|
||||
};
|
||||
|
||||
Query.QueryAsyncErrorEventHandler errorCallback = async errorMessage =>
|
||||
@@ -413,10 +457,10 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
// Send back the error message
|
||||
QueryCompleteParams eventParams = new QueryCompleteParams
|
||||
{
|
||||
OwnerUri = executeDocumentSelectionParams.OwnerUri,
|
||||
OwnerUri = ownerUri,
|
||||
//Message = errorMessage
|
||||
};
|
||||
await requestContext.SendEvent(QueryCompleteEvent.Type, eventParams);
|
||||
await eventSender.SendEvent(QueryCompleteEvent.Type, eventParams);
|
||||
};
|
||||
|
||||
query.QueryCompleted += callback;
|
||||
@@ -429,10 +473,10 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
BatchEventParams eventParams = new BatchEventParams
|
||||
{
|
||||
BatchSummary = b.Summary,
|
||||
OwnerUri = executeDocumentSelectionParams.OwnerUri
|
||||
OwnerUri = ownerUri
|
||||
};
|
||||
|
||||
await requestContext.SendEvent(BatchStartEvent.Type, eventParams);
|
||||
await eventSender.SendEvent(BatchStartEvent.Type, eventParams);
|
||||
};
|
||||
query.BatchStarted += batchStartCallback;
|
||||
|
||||
@@ -441,10 +485,10 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
BatchEventParams eventParams = new BatchEventParams
|
||||
{
|
||||
BatchSummary = b.Summary,
|
||||
OwnerUri = executeDocumentSelectionParams.OwnerUri
|
||||
OwnerUri = ownerUri
|
||||
};
|
||||
|
||||
await requestContext.SendEvent(BatchCompleteEvent.Type, eventParams);
|
||||
await eventSender.SendEvent(BatchCompleteEvent.Type, eventParams);
|
||||
};
|
||||
query.BatchCompleted += batchCompleteCallback;
|
||||
|
||||
@@ -453,9 +497,9 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
MessageParams eventParams = new MessageParams
|
||||
{
|
||||
Message = m,
|
||||
OwnerUri = executeDocumentSelectionParams.OwnerUri
|
||||
OwnerUri = ownerUri
|
||||
};
|
||||
await requestContext.SendEvent(MessageEvent.Type, eventParams);
|
||||
await eventSender.SendEvent(MessageEvent.Type, eventParams);
|
||||
};
|
||||
query.BatchMessageSent += batchMessageCallback;
|
||||
|
||||
@@ -465,9 +509,9 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution
|
||||
ResultSetEventParams eventParams = new ResultSetEventParams
|
||||
{
|
||||
ResultSetSummary = r.Summary,
|
||||
OwnerUri = executeDocumentSelectionParams.OwnerUri
|
||||
OwnerUri = ownerUri
|
||||
};
|
||||
await requestContext.SendEvent(ResultSetCompleteEvent.Type, eventParams);
|
||||
await eventSender.SendEvent(ResultSetCompleteEvent.Type, eventParams);
|
||||
};
|
||||
query.ResultSetCompleted += resultCallback;
|
||||
|
||||
|
||||
@@ -48,11 +48,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
// ... And then I dispose of the query
|
||||
var disposeParams = new QueryDisposeParams {OwnerUri = Common.OwnerUri};
|
||||
var disposeRequest = new EventFlowValidator<QueryDisposeResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
// Then: Messages should be null
|
||||
Assert.Null(r.Messages);
|
||||
}).Complete();
|
||||
.AddStandardQueryDisposeValidator()
|
||||
.Complete();
|
||||
await queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object);
|
||||
|
||||
// Then:
|
||||
@@ -71,13 +68,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
var disposeParams = new QueryDisposeParams {OwnerUri = Common.OwnerUri};
|
||||
|
||||
var disposeRequest = new EventFlowValidator<QueryDisposeResult>()
|
||||
.AddResultValidation(r =>
|
||||
{
|
||||
// Then: Messages should not be null
|
||||
Assert.NotNull(r.Messages);
|
||||
Assert.NotEmpty(r.Messages);
|
||||
}).Complete();
|
||||
.AddErrorValidation<string>(Assert.NotEmpty)
|
||||
.Complete();
|
||||
await queryService.HandleDisposeRequest(disposeParams, disposeRequest.Object);
|
||||
|
||||
// Then: I should have received an error
|
||||
disposeRequest.Validate();
|
||||
}
|
||||
|
||||
@@ -107,4 +102,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution
|
||||
Assert.Empty(queryService.ActiveQueries);
|
||||
}
|
||||
}
|
||||
|
||||
public static class QueryDisposeEventFlowValidatorExtensions
|
||||
{
|
||||
public static EventFlowValidator<QueryDisposeResult> AddStandardQueryDisposeValidator(
|
||||
this EventFlowValidator<QueryDisposeResult> evf)
|
||||
{
|
||||
// We just need to make sure that the result is not null
|
||||
evf.AddResultValidation(Assert.NotNull);
|
||||
|
||||
return evf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,97 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inter-Service API Tests
|
||||
|
||||
[Fact]
|
||||
public async Task InterServiceExecuteNullExecuteParams()
|
||||
{
|
||||
// Setup: Create a query service
|
||||
var qes = new QueryExecutionService(null, null);
|
||||
var eventSender = new EventFlowValidator<ExecuteRequestResult>().Complete().Object;
|
||||
Func<Task> successFunc = () => Task.FromResult(0);
|
||||
Func<string, Task> errorFunc = Task.FromResult;
|
||||
|
||||
|
||||
// If: I call the inter-service API to execute with a null execute params
|
||||
// Then: It should throw
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(
|
||||
() => qes.InterServiceExecuteQuery(null, eventSender, successFunc, errorFunc));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InterServiceExecuteNullEventSender()
|
||||
{
|
||||
// Setup: Create a query service, and execute params
|
||||
var qes = new QueryExecutionService(null, null);
|
||||
var executeParams = new ExecuteStringParams();
|
||||
Func<Task> successFunc = () => Task.FromResult(0);
|
||||
Func<string, Task> errorFunc = Task.FromResult;
|
||||
|
||||
// If: I call the inter-service API to execute a query with a a null event sender
|
||||
// Then: It should throw
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(
|
||||
() => qes.InterServiceExecuteQuery(executeParams, null, successFunc, errorFunc));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InterServiceExecuteNullSuccessFunc()
|
||||
{
|
||||
// Setup: Create a query service, and execute params
|
||||
var qes = new QueryExecutionService(null, null);
|
||||
var executeParams = new ExecuteStringParams();
|
||||
var eventSender = new EventFlowValidator<ExecuteRequestResult>().Complete().Object;
|
||||
Func<string, Task> errorFunc = Task.FromResult;
|
||||
|
||||
// If: I call the inter-service API to execute a query with a a null success function
|
||||
// Then: It should throw
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(
|
||||
() => qes.InterServiceExecuteQuery(executeParams, eventSender, null, errorFunc));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InterServiceExecuteNullFailureFunc()
|
||||
{
|
||||
// Setup: Create a query service, and execute params
|
||||
var qes = new QueryExecutionService(null, null);
|
||||
var executeParams = new ExecuteStringParams();
|
||||
var eventSender = new EventFlowValidator<ExecuteRequestResult>().Complete().Object;
|
||||
Func<Task> successFunc = () => Task.FromResult(0);
|
||||
|
||||
// If: I call the inter-service API to execute a query with a a null failure function
|
||||
// Then: It should throw
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(
|
||||
() => qes.InterServiceExecuteQuery(executeParams, eventSender, successFunc, null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InterServiceDisposeNullSuccessFunc()
|
||||
{
|
||||
// Setup: Create a query service and dispose params
|
||||
var qes = new QueryExecutionService(null, null);
|
||||
Func<string, Task> failureFunc = Task.FromResult;
|
||||
|
||||
// If: I call the inter-service API to dispose a query with a null success function
|
||||
// Then: It should throw
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(
|
||||
() => qes.InterServiceDisposeQuery(Common.OwnerUri, null, failureFunc));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InterServiceDisposeNullFailureFunc()
|
||||
{
|
||||
// Setup: Create a query service and dispose params
|
||||
var qes = new QueryExecutionService(null, null);
|
||||
Func<Task> successFunc = () => Task.FromResult(0);
|
||||
|
||||
// If: I call the inter-service API to dispose a query with a null success function
|
||||
// Then: It should throw
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(
|
||||
() => qes.InterServiceDisposeQuery(Common.OwnerUri, successFunc, null));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Execution Tests
|
||||
// NOTE: In order to limit test duplication, we're running the ExecuteDocumentSelection
|
||||
// version of execute query. The code paths are almost identical.
|
||||
@@ -378,7 +469,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Test.QueryExecution.Execution
|
||||
}
|
||||
}
|
||||
|
||||
public static class EventFlowValidatorExtensions
|
||||
public static class QueryExecutionEventFlowValidatorExtensions
|
||||
{
|
||||
public static EventFlowValidator<ExecuteRequestResult> AddStandardQueryResultValidator(
|
||||
this EventFlowValidator<ExecuteRequestResult> efv)
|
||||
|
||||
Reference in New Issue
Block a user