Adding pausing functionality for the profiler (#634)

* Dropping profiler session on stop request

* Changes to IXEventSession to simplify dropping sessions

* Stop sessions instead of dropping, disable flaky tests

* Initial framework for profiler pause requests

* Restructuring profiler session monitoring

* Fixes to session monitor

* Testing for pause functionality

* Fixing comments from PR

* Changes to testing

* Commenting out flaky test

* Deleting leftover testing code
This commit is contained in:
Madeline MacDonald
2018-06-13 17:55:01 -07:00
committed by GitHub
parent aff0f1afae
commit f53e532225
12 changed files with 549 additions and 101 deletions

View File

@@ -7,6 +7,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.SqlServer.Management.XEvent;
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Connection;
@@ -32,6 +33,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler
public async Task TestStartProfilingRequest()
{
string sessionId = null;
bool recievedEvents = false;
string testUri = "profiler_uri";
var requestContext = new Mock<RequestContext<StartProfilingResult>>();
requestContext.Setup(rc => rc.SendResult(It.IsAny<StartProfilingResult>()))
@@ -42,10 +44,15 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler
return Task.FromResult(0);
});
var sessionListener = new TestSessionListener();
// capture listener event notifications
var mockListener = new Mock<IProfilerSessionListener>();
mockListener.Setup(p => p.EventsAvailable(It.IsAny<string>(), It.IsAny<List<ProfilerEvent>>())).Callback(() =>
{
recievedEvents = true;
});
var profilerService = new ProfilerService();
profilerService.SessionMonitor.AddSessionListener(sessionListener);
profilerService.SessionMonitor.AddSessionListener(mockListener.Object);
profilerService.ConnectionServiceInstance = TestObjects.GetTestConnectionService();
ConnectionInfo connectionInfo = TestObjects.GetTestConnectionInfo();
profilerService.ConnectionServiceInstance.OwnerToConnectionMap.Add(testUri, connectionInfo);
@@ -55,15 +62,33 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler
requestParams.OwnerUri = testUri;
requestParams.TemplateName = "Standard";
// start profiling session
await profilerService.HandleStartProfilingRequest(requestParams, requestContext.Object);
// wait a bit for profile sessions to be polled
Thread.Sleep(500);
profilerService.SessionMonitor.PollSession(1);
// simulate a short polling delay
Thread.Sleep(200);
profilerService.SessionMonitor.PollSession(1);
// wait for polling to finish, or for timeout
System.Timers.Timer pollingTimer = new System.Timers.Timer();
pollingTimer.Interval = 10000;
pollingTimer.Start();
bool timeout = false;
pollingTimer.Elapsed += new System.Timers.ElapsedEventHandler((s_, e_) => {timeout = true;});
while (sessionId == null && !timeout)
{
Thread.Sleep(250);
}
pollingTimer.Stop();
requestContext.VerifyAll();
Assert.Equal(sessionListener.PreviousSessionId, sessionId);
Assert.Equal(sessionListener.PreviousEvents.Count, 1);
// Check that the correct XEvent session was started
Assert.Equal(sessionId, "1");
// check that the proper owner Uri was used
Assert.True(recievedEvents);
}
/// <summary>
@@ -82,11 +107,11 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler
requestContext.Setup(rc => rc.SendResult(It.IsAny<StopProfilingResult>()))
.Returns<StopProfilingResult>((result) =>
{
success = result.Succeeded;
success = true;
return Task.FromResult(0);
});
// capture if session was dropped
// capture if session was stopped
var mockSession = new Mock<IXEventSession>();
mockSession.Setup(p => p.Stop()).Callback(() =>
{
@@ -104,17 +129,13 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler
var requestParams = new StopProfilingParams();
requestParams.OwnerUri = testUri;
ProfilerSession session = new ProfilerSession();
session.XEventSession = mockSession.Object;
session.SessionId = testUri;
profilerService.SessionMonitor.StartMonitoringSession(session);
profilerService.SessionMonitor.StartMonitoringSession(testUri, mockSession.Object);
await profilerService.HandleStopProfilingRequest(requestParams, requestContext.Object);
requestContext.VerifyAll();
// check that session was succesfully stopped and drop was called
// check that session was succesfully stopped and stop was called
Assert.True(success);
Assert.True(stopped);
@@ -122,5 +143,97 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler
ProfilerSession ps;
Assert.False(profilerService.SessionMonitor.StopMonitoringSession(testUri, out ps));
}
/// <summary>
/// Test pausing then resuming a session
/// </summary>
/// <returns></returns>
[Fact]
public async Task TestPauseProfilingRequest()
{
bool success = false;
string testUri = "test_session";
bool recievedEvents = false;
// capture pausing results
var requestContext = new Mock<RequestContext<PauseProfilingResult>>();
requestContext.Setup(rc => rc.SendResult(It.IsAny<PauseProfilingResult>()))
.Returns<PauseProfilingResult>((result) =>
{
success = true;
return Task.FromResult(0);
});
// capture listener event notifications
var mockListener = new Mock<IProfilerSessionListener>();
mockListener.Setup(p => p.EventsAvailable(It.IsAny<string>(), It.IsAny<List<ProfilerEvent>>())).Callback(() =>
{
recievedEvents = true;
});
// setup profiler service
var profilerService = new ProfilerService();
profilerService.SessionMonitor.AddSessionListener(mockListener.Object);
profilerService.ConnectionServiceInstance = TestObjects.GetTestConnectionService();
ConnectionInfo connectionInfo = TestObjects.GetTestConnectionInfo();
profilerService.ConnectionServiceInstance.OwnerToConnectionMap.Add(testUri, connectionInfo);
var requestParams = new PauseProfilingParams();
requestParams.OwnerUri = testUri;
// begin monitoring session
profilerService.SessionMonitor.StartMonitoringSession(testUri, new TestXEventSession1());
// poll the session
profilerService.SessionMonitor.PollSession(1);
Thread.Sleep(500);
profilerService.SessionMonitor.PollSession(1);
// wait for polling to finish, or for timeout
System.Timers.Timer pollingTimer = new System.Timers.Timer();
pollingTimer.Interval = 10000;
pollingTimer.Start();
bool timeout = false;
pollingTimer.Elapsed += new System.Timers.ElapsedEventHandler((s_, e_) => {timeout = true;});
while (!recievedEvents && !timeout)
{
Thread.Sleep(250);
}
pollingTimer.Stop();
// confirm that polling works
Assert.True(recievedEvents);
// pause viewer
await profilerService.HandlePauseProfilingRequest(requestParams, requestContext.Object);
Assert.True(success);
recievedEvents = false;
success = false;
profilerService.SessionMonitor.PollSession(1);
// confirm that no events were sent to paused listener
Assert.False(recievedEvents);
// unpause viewer
await profilerService.HandlePauseProfilingRequest(requestParams, requestContext.Object);
Assert.True(success);
profilerService.SessionMonitor.PollSession(1);
// wait for polling to finish, or for timeout
timeout = false;
pollingTimer.Start();
while (!recievedEvents && !timeout)
{
Thread.Sleep(250);
}
// check that events got sent to listener
Assert.True(recievedEvents);
requestContext.VerifyAll();
}
}
}

View File

@@ -188,19 +188,168 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Profiler
" </event>" +
"</RingBufferTarget>";
public int Id { get { return 51; } }
public void Start(){}
public void Stop(){}
public string GetTargetXml()
{
return testXEventXml;
}
}
public class TestXEventSession1 : IXEventSession
{
private const string testXEventXml_1 =
"<RingBufferTarget truncated=\"0\" processingTime=\"3\" totalEventsProcessed=\"1\" eventCount=\"1\" droppedCount=\"0\" memoryUsed=\"47996\">" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-09-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>1</value>" +
" </data>" +
" </event>" +
"</RingBufferTarget>";
private const string testXEventXml_2 =
"<RingBufferTarget truncated=\"0\" processingTime=\"3\" totalEventsProcessed=\"1\" eventCount=\"1\" droppedCount=\"0\" memoryUsed=\"47996\">" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-09-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>1</value>" +
" </data>" +
" </event>" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-10-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>1</value>" +
" </data>" +
" </event>" +
"</RingBufferTarget>";
private const string testXEventXml_3 =
"<RingBufferTarget truncated=\"0\" processingTime=\"3\" totalEventsProcessed=\"1\" eventCount=\"1\" droppedCount=\"0\" memoryUsed=\"47996\">" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-09-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>1</value>" +
" </data>" +
" </event>" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-10-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>1</value>" +
" </data>" +
" </event>" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-11-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>1</value>" +
" </data>" +
" </event>" +
"</RingBufferTarget>";
public int Id { get { return 1; } }
public void Start(){}
public void Stop(){}
private int pollCount = 0;
private string[] poll_returns = { testXEventXml_1, testXEventXml_2, testXEventXml_3 };
public string GetTargetXml()
{
string res = poll_returns[pollCount];
pollCount++;
pollCount = pollCount > 2 ? 0 : pollCount;
return res;
}
}
public class TestXEventSession2 : IXEventSession
{
private const string testXEventXml_1 =
"<RingBufferTarget truncated=\"0\" processingTime=\"3\" totalEventsProcessed=\"1\" eventCount=\"1\" droppedCount=\"0\" memoryUsed=\"47996\">" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-09-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>2</value>" +
" </data>" +
" </event>" +
"</RingBufferTarget>";
private const string testXEventXml_2 =
"<RingBufferTarget truncated=\"0\" processingTime=\"3\" totalEventsProcessed=\"1\" eventCount=\"1\" droppedCount=\"0\" memoryUsed=\"47996\">" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-09-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>2</value>" +
" </data>" +
" </event>" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-10-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>2</value>" +
" </data>" +
" </event>" +
"</RingBufferTarget>";
private const string testXEventXml_3 =
"<RingBufferTarget truncated=\"0\" processingTime=\"3\" totalEventsProcessed=\"1\" eventCount=\"1\" droppedCount=\"0\" memoryUsed=\"47996\">" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-09-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>2</value>" +
" </data>" +
" </event>" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-10-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>2</value>" +
" </data>" +
" </event>" +
" <event name=\"existing_connection\" package=\"sqlserver\" timestamp=\"2017-11-08T07:46:53.579Z\">" +
" <data name=\"session_id\">" +
" <type name=\"int16\" package=\"package0\"></type>" +
" <value>2</value>" +
" </data>" +
" </event>" +
"</RingBufferTarget>";
public int Id { get { return 2; } }
public void Start(){}
public void Stop(){}
private int pollCount = 0;
private string[] poll_returns = { testXEventXml_1, testXEventXml_2, testXEventXml_3 };
public string GetTargetXml()
{
string res = poll_returns[pollCount];
pollCount++;
pollCount = pollCount > 2 ? 0 : pollCount;
return res;
}
}
public class TestXEventSessionFactory : IXEventSessionFactory
{
public IXEventSession CreateXEventSession(ConnectionInfo connInfo)
private int sessionNum = 1;
public IXEventSession GetOrCreateXEventSession(string template, ConnectionInfo connInfo)
{
return new TestXEventSession();
if(sessionNum == 1)
{
sessionNum = 2;
return new TestXEventSession1();
}
else
{
sessionNum = 1;
return new TestXEventSession2();
}
}
}
}