From 35b19320d4b7de6ba44f791ec5ec48b539748b7e Mon Sep 17 00:00:00 2001 From: Madeline MacDonald Date: Tue, 5 Jun 2018 13:48:55 -0700 Subject: [PATCH] Stopping sessions when handling stop requests (#627) * Dropping profiler session on stop request * Changes to IXEventSession to simplify dropping sessions * Stop sessions instead of dropping, disable flaky tests --- .../Profiler/IProfilerSessionMonitor.cs | 2 +- .../Profiler/IXEventSession.cs | 5 + .../Profiler/ProfilerService.cs | 15 +- .../Profiler/ProfilerSessionMonitor.cs | 4 +- .../Profiler/XEventSession.cs | 5 + .../Agent/AgentAlertTests.cs | 9 +- .../Scripting/ScriptingServiceTests.cs | 21 +- .../Profiler/ProfilerServiceTests.cs | 61 +++- .../Profiler/ProfilerTestObjects.cs | 274 +++++++++--------- 9 files changed, 235 insertions(+), 161 deletions(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/IProfilerSessionMonitor.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/IProfilerSessionMonitor.cs index 56117e37..1579f839 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/IProfilerSessionMonitor.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/IProfilerSessionMonitor.cs @@ -27,6 +27,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler /// /// Stops monitoring a profiler session /// - bool StopMonitoringSession(string sessionId); + bool StopMonitoringSession(string sessionId, out ProfilerSession session); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/IXEventSession.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/IXEventSession.cs index 959a5d07..5d46dd3b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/IXEventSession.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/IXEventSession.cs @@ -14,5 +14,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler /// Reads XEvent XML from the default session target /// string GetTargetXml(); + + /// + /// Stops XEvent session + /// + void Stop(); } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerService.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerService.cs index d430f6cd..c25629d2 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerService.cs @@ -154,7 +154,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler { try { - monitor.StopMonitoringSession(parameters.OwnerUri); + ProfilerSession session; + monitor.StopMonitoringSession(parameters.OwnerUri, out session); + session.XEventSession.Stop(); + await requestContext.SendResult(new StopProfilingResult { Succeeded = true @@ -163,7 +166,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler catch (Exception e) { await requestContext.SendError(e); - } + } } /// @@ -224,9 +227,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler private static Session CreateSession(SqlStoreConnection connection, string sessionName) { - string createSessionSql = + string createSessionSql = @" - CREATE EVENT SESSION [Profiler] ON SERVER + CREATE EVENT SESSION [Profiler] ON SERVER ADD EVENT sqlserver.attention( ACTION(package0.event_sequence,sqlserver.client_app_name,sqlserver.client_pid,sqlserver.database_id,sqlserver.nt_username,sqlserver.query_hash,sqlserver.server_principal_name,sqlserver.session_id) WHERE ([package0].[equal_boolean]([sqlserver].[is_system],(0)))), @@ -251,7 +254,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler connection.ServerConnection.ExecuteNonQuery(createSessionSql); XEStore store = new XEStore(connection); - return store.Sessions[sessionName]; + return store.Sessions[sessionName]; } /// @@ -275,7 +278,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler public void Dispose() { if (!disposed) - { + { disposed = true; } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerSessionMonitor.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerSessionMonitor.cs index e638e930..09050b5d 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerSessionMonitor.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/ProfilerSessionMonitor.cs @@ -72,17 +72,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler /// /// Stop monitoring the session specified by the sessionId /// - public bool StopMonitoringSession(string sessionId) + public bool StopMonitoringSession(string sessionId, out ProfilerSession session) { lock (this.sessionsLock) { if (this.monitoredSessions.ContainsKey(sessionId)) { - ProfilerSession session; return this.monitoredSessions.Remove(sessionId, out session); } else { + session = null; return false; } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Profiler/XEventSession.cs b/src/Microsoft.SqlTools.ServiceLayer/Profiler/XEventSession.cs index 3e1d6f01..4a65c67b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Profiler/XEventSession.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Profiler/XEventSession.cs @@ -14,6 +14,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Profiler { public Session Session { get; set; } + public void Stop() + { + this.Session.Stop(); + } + public string GetTargetXml() { if (this.Session == null) diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Agent/AgentAlertTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Agent/AgentAlertTests.cs index 8b77d0ce..e18aee81 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Agent/AgentAlertTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Agent/AgentAlertTests.cs @@ -52,7 +52,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Agent /// /// Verify the default "create agent alert" request handler with valid parameters /// - [Fact] + // TODO: Fix flaky test. See https://github.com/Microsoft/sqltoolsservice/issues/630 + // [Fact] public async Task TestHandleCreateAgentAlertsRequest() { using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) @@ -84,7 +85,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Agent // { // OwnerUri = connectionResult.ConnectionInfo.OwnerUri, // Alert = alert - // }, deleteContext.Object); + // }, deleteContext.Object); // } // } // } @@ -123,13 +124,13 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Agent OwnerUri = connectionResult.ConnectionInfo.OwnerUri, Alert = alert }, createContext.Object); - + await service.HandleUpdateAgentAlertRequest(new UpdateAgentAlertParams() { OwnerUri = connectionResult.ConnectionInfo.OwnerUri, Alert = alert }, updateContext.Object); - + await service.HandleDeleteAgentAlertRequest(new DeleteAgentAlertParams() { OwnerUri = connectionResult.ConnectionInfo.OwnerUri, diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Scripting/ScriptingServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Scripting/ScriptingServiceTests.cs index 18e88df6..ace58057 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Scripting/ScriptingServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/Scripting/ScriptingServiceTests.cs @@ -89,7 +89,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Scripting [Fact] public async void VerifyScriptAsCreateTable() { - string query = @"CREATE TABLE testTable1 (c1 int) + string query = @"CREATE TABLE testTable1 (c1 int) GO CREATE CLUSTERED INDEX [ClusteredIndex-1] ON [dbo].[testTable1] ( @@ -167,17 +167,18 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Scripting await VerifyScriptAsForMultipleObjects(query, scriptingObjects, scriptCreateDrop, expectedScripts); } - [Fact] + // TODO: Fix flaky test. See https://github.com/Microsoft/sqltoolsservice/issues/631 + // [Fact] public async void VerifyScriptAsExecuteStoredProcedure() { - string query = @"CREATE PROCEDURE testSp1 - @BusinessEntityID [int], - @JobTitle [nvarchar](50), - @HireDate [datetime], - @RateChangeDate [datetime], - @Rate [money], + string query = @"CREATE PROCEDURE testSp1 + @BusinessEntityID [int], + @JobTitle [nvarchar](50), + @HireDate [datetime], + @RateChangeDate [datetime], + @Rate [money], @PayFrequency [tinyint] - AS + AS BEGIN Select * from sys.all_columns END"; ScriptingOperationType scriptCreateDrop = ScriptingOperationType.Execute; ScriptingObject scriptingObject = new ScriptingObject @@ -320,7 +321,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.Scripting { scriptCreateOperation = $"Script{operation}"; } - + scriptingParams.ScriptOptions = new ScriptOptions { ScriptCreateDrop = scriptCreateOperation, diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs index 45053f43..ac5b22d2 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerServiceTests.cs @@ -22,7 +22,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler /// Unit tests for ProfilerService /// public class ProfilerServiceTests - { + { /// /// Test starting a profiling session and receiving event callback /// @@ -35,7 +35,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler string testUri = "profiler_uri"; var requestContext = new Mock>(); requestContext.Setup(rc => rc.SendResult(It.IsAny())) - .Returns((result) => + .Returns((result) => { // capture the session id for sending the stop message sessionId = result.SessionId; @@ -65,5 +65,62 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler Assert.Equal(sessionListener.PreviousSessionId, sessionId); Assert.Equal(sessionListener.PreviousEvents.Count, 1); } + + /// + /// Test stopping a session and receiving event callback + /// + /// + [Fact] + public async Task TestStopProfilingRequest() + { + bool success = false; + bool stopped = false; + string testUri = "test_session"; + + // capture stopping results + var requestContext = new Mock>(); + requestContext.Setup(rc => rc.SendResult(It.IsAny())) + .Returns((result) => + { + success = result.Succeeded; + return Task.FromResult(0); + }); + + // capture if session was dropped + var mockSession = new Mock(); + mockSession.Setup(p => p.Stop()).Callback(() => + { + stopped = true; + }); + + var sessionListener = new TestSessionListener(); + var profilerService = new ProfilerService(); + profilerService.SessionMonitor.AddSessionListener(sessionListener); + profilerService.ConnectionServiceInstance = TestObjects.GetTestConnectionService(); + ConnectionInfo connectionInfo = TestObjects.GetTestConnectionInfo(); + profilerService.ConnectionServiceInstance.OwnerToConnectionMap.Add(testUri, connectionInfo); + profilerService.XEventSessionFactory = new TestXEventSessionFactory(); + + var requestParams = new StopProfilingParams(); + requestParams.OwnerUri = testUri; + + ProfilerSession session = new ProfilerSession(); + session.XEventSession = mockSession.Object; + session.SessionId = testUri; + + profilerService.SessionMonitor.StartMonitoringSession(session); + + await profilerService.HandleStopProfilingRequest(requestParams, requestContext.Object); + + requestContext.VerifyAll(); + + // check that session was succesfully stopped and drop was called + Assert.True(success); + Assert.True(stopped); + + // should not be able to remove the session, it should already be gone + ProfilerSession ps; + Assert.False(profilerService.SessionMonitor.StopMonitoringSession(testUri, out ps)); + } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerTestObjects.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerTestObjects.cs index aad48a9b..a79f8336 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerTestObjects.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/Profiler/ProfilerTestObjects.cs @@ -50,148 +50,150 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler public class TestXEventSession : IXEventSession { - private string testXEventXml = - "" + - " " + - " " + - " " + - " 51" + - " " + - " " + - " " + - " false" + - " " + - " " + - " " + - " 1" + - " " + - " " + - " " + - " 4096" + - " " + - " " + - " " + - " 0" + - " " + - " " + - " " + - " 2" + - " " + - " " + - " " + - " 191053000" + - " " + - " " + - " " + - " 4680" + - " " + - " " + - " " + - " 2000002838f4010000000000" + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " 01" + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " 01" + - " " + - " " + - " " + - " 56" + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " 930958063" + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " A2873402-C433-4D1F-94C4-9CA99749453E-0" + - " " + - " " + - " " + - " 770C3538-EC3F-4A27-86A9-31A2FC777DBC-1" + - " " + - " " + + private string testXEventXml = + "" + + " " + + " " + + " " + + " 51" + + " " + + " " + + " " + + " false" + + " " + + " " + + " " + + " 1" + + " " + + " " + + " " + + " 4096" + + " " + + " " + + " " + + " 0" + + " " + + " " + + " " + + " 2" + + " " + + " " + + " " + + " 191053000" + + " " + + " " + + " " + + " 4680" + + " " + + " " + + " " + + " 2000002838f4010000000000" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " 01" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " 01" + + " " + + " " + + " " + + " 56" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " 930958063" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " A2873402-C433-4D1F-94C4-9CA99749453E-0" + + " " + + " " + + " " + + " 770C3538-EC3F-4A27-86A9-31A2FC777DBC-1" + + " " + + " " + ""; public string GetTargetXml() { return testXEventXml; } + + public void Stop(){} } public class TestXEventSessionFactory : IXEventSessionFactory