From 0421d3ae7ced1209d031a17b30c750ec542c56b8 Mon Sep 17 00:00:00 2001 From: Justin M <63619224+JustinMDotNet@users.noreply.github.com> Date: Wed, 25 Aug 2021 11:38:35 -0700 Subject: [PATCH 1/3] Added check if metadata is empty to throw error exception. (#1236) * Added check if metadata is empty to throw error exception. * Changed error message. * Changed error message to be displayed when invalid Workspace ID is provided for AzureMonitorLogs. --- .../DataSource/Monitor/MonitorClient.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Monitor/MonitorClient.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Monitor/MonitorClient.cs index 54814cbb..300f095b 100644 --- a/src/Microsoft.Kusto.ServiceLayer/DataSource/Monitor/MonitorClient.cs +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Monitor/MonitorClient.cs @@ -1,6 +1,7 @@ using System; using System.Net.Http; using System.Net.Http.Headers; +using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -52,6 +53,17 @@ namespace Microsoft.Kusto.ServiceLayer.DataSource.Monitor }; _metadata = JsonSerializer.Deserialize(results, options); + + if (_metadata?.Tables is null && _metadata?.Workspaces is null && _metadata?.TableGroups is null) + { + var errorMessage = JsonSerializer.Deserialize(results, options); + var builder = new StringBuilder(); + builder.AppendLine( + "The Log Analytics Workspace can not be reached. Please validate the Workspace ID, the correct tenant is selected, and that you have access to the workspace. "); + builder.AppendLine($"Error Message: {errorMessage?.Error?.Message}"); + throw new Exception(builder.ToString()); + } + return _metadata; } From 5d5debbad6d88cc1820fcab976c80b1edb429e24 Mon Sep 17 00:00:00 2001 From: Karl Burtram Date: Thu, 26 Aug 2021 13:06:15 -0700 Subject: [PATCH 2/3] Enable scripting for subobjects such as triggers (#1237) * WIP 1 * Cleanups * Change how schema is appended in to urn * Add comment and fix incorrect condition * Add parent type name to support Views, etc. --- .../Metadata/Contracts/ObjectMetadata.cs | 4 ++ .../ObjectExplorer/SmoModel/SmoTreeNode.cs | 22 ++++++++--- .../Scripting/Contracts/ScriptingObject.cs | 31 +++++++++++++--- .../Scripting/ScriptingExtensionMethods.cs | 37 +++++++++++++++---- 4 files changed, 75 insertions(+), 19 deletions(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs b/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs index f5d9e55f..8d837b3b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs @@ -30,6 +30,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata.Contracts public string Schema { get; set; } public string Name { get; set; } + + public string ParentName { get; set; } + + public string ParentTypeName { get; set; } public string Urn { get; set; } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs index 9f71e840..7c2e076c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs @@ -4,6 +4,7 @@ // using System.Globalization; +using Microsoft.SqlServer.Management.Sdk.Sfc; using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlTools.ServiceLayer.ObjectExplorer.Nodes; @@ -56,13 +57,13 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel { SmoObject = smoObject; NodeValue = smoObject.Name; - ScriptSchemaObjectBase schemaBasecObject = smoObject as ScriptSchemaObjectBase; + ScriptSchemaObjectBase schemaBaseObject = smoObject as ScriptSchemaObjectBase; ObjectMetadata = new Metadata.Contracts.ObjectMetadata(); ObjectMetadata.Name = smoObject.Name; try { - if(smoObject.Urn != null) + if (smoObject.Urn != null) { ObjectMetadata.MetadataTypeName = smoObject.Urn.Type; } @@ -72,16 +73,27 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel //Ignore the exception, sometimes the urn returns exception and I' not sure why } - if (schemaBasecObject != null) + if (schemaBaseObject != null) { - ObjectMetadata.Schema = schemaBasecObject.Schema; + ObjectMetadata.Schema = schemaBaseObject.Schema; if (!string.IsNullOrEmpty(ObjectMetadata.Schema)) { NodeValue = $"{ObjectMetadata.Schema}.{smoObject.Name}"; } } + else + { + // Try to read the schema from the parent object + var parent = smoObject?.ParentCollection?.ParentInstance as ScriptSchemaObjectBase; + if (parent != null) + { + ObjectMetadata.Schema = parent.Schema; + ObjectMetadata.ParentName = parent.Name; + ObjectMetadata.ParentTypeName = parent.Urn.Type; + } + } } - + public virtual NamedSmoObject GetParentSmoObject() { if (SmoObject != null) diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingObject.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingObject.cs index 6ecea44c..49dad72c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingObject.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/Contracts/ScriptingObject.cs @@ -4,7 +4,6 @@ // using System; -using System.Collections.Generic; namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts { @@ -52,13 +51,28 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts /// public string Name { get; set; } + /// + /// Gets or sets the parent object name + /// + public string ParentName { get; set; } + + /// + /// Gets or sets the parent object type name, such as Table, View, etc. + /// + public string ParentTypeName { get; set; } + public override string ToString() { - string objectName = string.IsNullOrEmpty(this.Schema) - ? this.Name - : this.Schema + "." + this.Name; - - return objectName; + string objectName = string.Empty; + if (!string.IsNullOrEmpty(this.Schema)) + { + objectName += this.Schema + "."; + } + if (!string.IsNullOrEmpty(this.ParentName)) + { + objectName += this.ParentName + "."; + } + return objectName + this.Name; } public override int GetHashCode() @@ -66,6 +80,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts return StringComparer.OrdinalIgnoreCase.GetHashCode(this.Type ?? string.Empty) ^ StringComparer.OrdinalIgnoreCase.GetHashCode(this.Schema ?? string.Empty) ^ + StringComparer.OrdinalIgnoreCase.GetHashCode(this.ParentName ?? string.Empty) ^ + StringComparer.OrdinalIgnoreCase.GetHashCode(this.ParentTypeName ?? string.Empty) ^ StringComparer.OrdinalIgnoreCase.GetHashCode(this.Name ?? string.Empty); } @@ -87,6 +103,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting.Contracts return string.Equals(this.Type, other.Type, StringComparison.OrdinalIgnoreCase) && string.Equals(this.Schema, other.Schema, StringComparison.OrdinalIgnoreCase) && + string.Equals(this.ParentName, other.ParentName, StringComparison.OrdinalIgnoreCase) && + string.Equals(this.ParentTypeName, other.ParentTypeName, StringComparison.OrdinalIgnoreCase) && + string.Equals(this.ParentTypeName, other.ParentTypeName, StringComparison.OrdinalIgnoreCase) && string.Equals(this.Name, other.Name, StringComparison.OrdinalIgnoreCase); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs index df13e3e1..7e4f6197 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Scripting/ScriptingExtensionMethods.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text; using System.Threading.Tasks; using Microsoft.SqlServer.Management.Sdk.Sfc; using Microsoft.SqlServer.Management.SqlScriptPublish; @@ -100,15 +101,35 @@ namespace Microsoft.SqlTools.ServiceLayer.Scripting Validate.IsNotNullOrWhitespaceString("scriptingObject.Type", scriptingObject.Type); // Leaving the server name blank will automatically match whatever the server SMO is running against. - string urn = string.Format( - "Server[@Name='{0}']/Database[@Name='{1}']/{2}[@Name='{3}' {4}]", - server.ToUpper(), - Urn.EscapeString(database), - scriptingObject.Type, - Urn.EscapeString(scriptingObject.Name), - scriptingObject.Schema != null ? string.Format("and @Schema = '{0}'", Urn.EscapeString(scriptingObject.Schema)) : string.Empty); + StringBuilder urnBuilder = new StringBuilder(); + urnBuilder.AppendFormat("Server[@Name='{0}']/", server.ToUpper()); + urnBuilder.AppendFormat("Database[@Name='{0}']/", Urn.EscapeString(database)); - return new Urn(urn); + bool hasParentObject = !string.IsNullOrWhiteSpace(scriptingObject.ParentName) + && !string.IsNullOrWhiteSpace(scriptingObject.ParentTypeName); + if (hasParentObject) + { + urnBuilder.AppendFormat("{0}[@Name='{1}'", scriptingObject.ParentTypeName, Urn.EscapeString(scriptingObject.ParentName)); + if (!string.IsNullOrWhiteSpace(scriptingObject.Schema)) + { + urnBuilder.AppendFormat(" and @Schema = '{0}'", Urn.EscapeString(scriptingObject.Schema)); + } + urnBuilder.Append("]/"); + } + + urnBuilder.AppendFormat("{0}[@Name='{1}'", scriptingObject.Type, Urn.EscapeString(scriptingObject.Name)); + + // add schema to object only if there is no parent object specified + // the parent object field is only set for objects that don't have schema themselves + // so if parent is not null then the schema filter will already be set that part of the urn above + if (!string.IsNullOrWhiteSpace(scriptingObject.Schema) && !hasParentObject) + { + urnBuilder.AppendFormat(" and @Schema = '{0}'", Urn.EscapeString(scriptingObject.Schema)); + } + + urnBuilder.Append("]"); + + return new Urn(urnBuilder.ToString()); } /// From 431e4cfbf1f9ef3ce5a3dc42a6230ab9f05c2dec Mon Sep 17 00:00:00 2001 From: Alex Ma Date: Mon, 30 Aug 2021 11:06:07 -0700 Subject: [PATCH 3/3] Add changeConnectionUri action for query (#1227) * added wip rename query * added first rename test * added missing query handling and two new tests * removed ServiceDispose * added change to owneruri. * made fields private, used accessor methods * added readonly flag back * added didSave to sqltools.servicelayer * fix for docsavecallbacks * removed tryremove * test disconnect in queryExecutionService * removed debug message working query. * added comment to handlerenamerequest * added uri replacement function * removed duplicate removemap function * added minor fixes * changed connectionOwnerUri to getter setter * removed handledidsave and added setters * removed additional save parts * fixed space issues * more fixes for spaces * restored spaces * fixed workspaceservice * Update TextDocument.cs * changed renameRequest into notification WIP * restored textdocument * restored textdocument.cs * added rightwards arrow * renamed rename to ChangeConnectionUri * added more renames * rename changeconnectionuri to changeuri * renamed file names * Revert "renamed file names" This reverts commit 55228e65025b5179b15ae9a0adc095d95538723d. * Revert "rename changeconnectionuri to changeuri" This reverts commit 23f3813f609e3947f103e057f7c0919184075bdc. * removed logging message and other small changes * renamed class and method --- docs/guide/jsonrpc_protocol.md | 13 ++++ .../Connection/ConnectionInfo.cs | 2 +- .../Connection/ConnectionService.cs | 16 ++++ .../ConnectionUriChangedNotification.cs | 24 ++++++ .../QueryExecution/Query.cs | 14 ++++ .../QueryExecution/QueryExecutionService.cs | 28 +++++++ .../ChangeConnectionUriTests.cs | 73 +++++++++++++++++++ 7 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ConnectionUriChangedNotification.cs create mode 100644 test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/ChangeConnectionUriTests.cs diff --git a/docs/guide/jsonrpc_protocol.md b/docs/guide/jsonrpc_protocol.md index 423f8c0a..9820cb51 100644 --- a/docs/guide/jsonrpc_protocol.md +++ b/docs/guide/jsonrpc_protocol.md @@ -50,6 +50,7 @@ This document provides the protocol specification for all the service's JSON-RPC * :leftwards_arrow_with_hook: [query/subset](#query_subset) * :leftwards_arrow_with_hook: [query/dispose](#query_dispose) * :leftwards_arrow_with_hook: [query/cancel](#query_cancel) +* :arrow_right: [query/connectionUriChanged](#query_connectionUriChanged) * :leftwards_arrow_with_hook: [query/saveCsv](#query_saveCsv) * :leftwards_arrow_with_hook: [query/saveExcel](#query_saveExcel) * :leftwards_arrow_with_hook: [query/saveJson](#query_saveJson) @@ -889,6 +890,18 @@ Cancel the query in progress for the owner uri. public string Messages { get; set; } } ``` +### `query/connectionUriChanged` + +Change the uri associated with a query. + +#### Notification +```csharp + public class ConnectionUriChangedParams + { + public string NewOwnerUri { get; set; } + public string OriginalOwnerUri { get; set; + } +``` ### `query/saveCsv` diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionInfo.cs index 59445a12..9e8334dc 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionInfo.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionInfo.cs @@ -38,7 +38,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection /// /// URI identifying the owner/user of the connection. Could be a file, service, resource, etc. /// - public string OwnerUri { get; private set; } + public string OwnerUri { get; set; } /// /// Factory used for creating the SQL connection associated with the connection info. diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs index 3b13c2bc..23284e29 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs @@ -766,6 +766,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection return false; } + /// + /// Reassign the uri associated with a connection info with a new uri. + /// + public bool ReplaceUri(string originalOwnerUri, string newOwnerUri) + { + // Lookup the ConnectionInfo owned by the URI + ConnectionInfo info; + if (!OwnerToConnectionMap.TryGetValue(originalOwnerUri, out info)) + { + return false; + } + OwnerToConnectionMap.Remove(originalOwnerUri); + OwnerToConnectionMap.Add(newOwnerUri, info); + return true; + } + /// /// Close a connection with the specified connection details. /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ConnectionUriChangedNotification.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ConnectionUriChangedNotification.cs new file mode 100644 index 00000000..a1e8a28b --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Contracts/ConnectionUriChangedNotification.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Parameters for the connection uri changed notification. + /// + public class ConnectionUriChangedParams + { + public string NewOwnerUri { get; set; } + public string OriginalOwnerUri { get; set; } + } + public class ConnectionUriChangedNotification + { + public static readonly + EventType Type = + EventType.Create("query/connectionUriChanged"); + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs index 05ff9f3d..b803e941 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/Query.cs @@ -385,6 +385,20 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution Batches[saveParams.BatchIndex].SaveAs(saveParams, fileFactory, successHandler, failureHandler); } + /// + /// Changes the OwnerURI for the editor connection. + /// + public String ConnectionOwnerURI { + get + { + return this.editorConnection.OwnerUri; + } + set + { + this.editorConnection.OwnerUri = value; + } + } + #endregion #region Private Helpers diff --git a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs index 6a411987..1a4eed92 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/QueryExecution/QueryExecutionService.cs @@ -170,6 +170,7 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution serviceHost.SetRequestHandler(SubsetRequest.Type, HandleResultSubsetRequest); serviceHost.SetRequestHandler(QueryDisposeRequest.Type, HandleDisposeRequest); serviceHost.SetRequestHandler(QueryCancelRequest.Type, HandleCancelRequest); + serviceHost.SetEventHandler(ConnectionUriChangedNotification.Type, HandleConnectionUriChangedNotification); serviceHost.SetRequestHandler(SaveResultsAsCsvRequest.Type, HandleSaveResultsAsCsvRequest); serviceHost.SetRequestHandler(SaveResultsAsExcelRequest.Type, HandleSaveResultsAsExcelRequest); serviceHost.SetRequestHandler(SaveResultsAsJsonRequest.Type, HandleSaveResultsAsJsonRequest); @@ -351,6 +352,33 @@ namespace Microsoft.SqlTools.ServiceLayer.QueryExecution } } + + /// + /// Handles a request to change the uri associated with an active query and connection info. + /// + internal Task HandleConnectionUriChangedNotification(ConnectionUriChangedParams changeUriParams, + EventContext eventContext) + { + try { + string OriginalOwnerUri = changeUriParams.OriginalOwnerUri; + string NewOwnerUri = changeUriParams.NewOwnerUri; + // Attempt to load the query + Query query; + if(!ActiveQueries.TryRemove(OriginalOwnerUri, out query)){ + throw new Exception("Uri: " + OriginalOwnerUri + " is not associated with an active query."); + } + ConnectionService.ReplaceUri(OriginalOwnerUri, NewOwnerUri); + query.ConnectionOwnerURI = NewOwnerUri; + ActiveQueries.TryAdd(NewOwnerUri, query); + return Task.FromResult(true); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Error encountered " + ex.ToString()); + return Task.FromException(ex); + } + } + /// /// Handles a request to get a subset of the results of this query /// diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/ChangeConnectionUriTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/ChangeConnectionUriTests.cs new file mode 100644 index 00000000..1a02b843 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/QueryExecution/ChangeConnectionUriTests.cs @@ -0,0 +1,73 @@ +// +// 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.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.QueryExecution; +using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; +using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts.ExecuteRequests; +using Microsoft.SqlTools.ServiceLayer.SqlContext; +using Microsoft.SqlTools.ServiceLayer.Test.Common; +using Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking; +using Microsoft.SqlTools.ServiceLayer.Workspace; +using Moq; +using NUnit.Framework; + +namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution +{ + public class ConnectionUriChangedTests + { + [Test] + public async Task ChangeUriForExecutedQuery() + { + // If: + // ... I request a query (doesn't matter what kind) + var workspaceService = Common.GetPrimedWorkspaceService(Constants.StandardQuery); + var queryService = Common.GetPrimedExecutionService(null, true, false, false, workspaceService); + var executeParams = new ExecuteDocumentSelectionParams {QuerySelection = null, OwnerUri = Constants.OwnerUri}; + var executeRequest = RequestContextMocks.Create(null); + await queryService.HandleExecuteRequest(executeParams, executeRequest.Object); + await queryService.WorkTask; + await queryService.ActiveQueries[Constants.OwnerUri].ExecutionTask; + + const string newOwnerUri = "newTestFile"; + Query query; + queryService.ActiveQueries.TryGetValue(Constants.OwnerUri, out query); + + // ... And then I change the uri for the query + var changeUriParams = new ConnectionUriChangedParams { + OriginalOwnerUri = Constants.OwnerUri, + NewOwnerUri = newOwnerUri + }; + + + await queryService.HandleConnectionUriChangedNotification(changeUriParams, new TestEventContext()); + + // Then: + // ... And the active queries should have the new query. + Assert.That(queryService.ActiveQueries.TryGetValue(newOwnerUri, out query), "Query with newOwnerUri not found."); + Assert.That(Equals(query.ConnectionOwnerURI, newOwnerUri), "OwnerUri was not changed!"); + } + + [Test] + public void ChangeUriForMissingQuery() + { + // If: + // ... I attempt to change the uri a query that doesn't exist + var workspaceService = new Mock>(); + var queryService = Common.GetPrimedExecutionService(null, false, false, false, workspaceService.Object); + const string newOwnerUri = "newTestFile"; + var changeUriParams = new ConnectionUriChangedParams { + OriginalOwnerUri = Constants.OwnerUri, + NewOwnerUri = newOwnerUri + }; + + Assert.ThrowsAsync(async () => await queryService.HandleConnectionUriChangedNotification(changeUriParams, new TestEventContext())); + + Query query; + Assert.False(queryService.ActiveQueries.TryGetValue(Constants.OwnerUri, out query), "Query was removed from Active Queries"); + } + } +}