{"id":6103,"date":"2011-10-04T07:32:30","date_gmt":"2011-10-04T07:32:30","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudioalm\/2011\/10\/04\/a-custom-data-diagnostic-adapter-for-visual-studio-coded-ui-test-using-windows-psr\/"},"modified":"2019-02-14T18:00:37","modified_gmt":"2019-02-15T02:00:37","slug":"a-custom-data-diagnostic-adapter-for-visual-studio-coded-ui-test-using-windows-psr","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/a-custom-data-diagnostic-adapter-for-visual-studio-coded-ui-test-using-windows-psr\/","title":{"rendered":"A custom data diagnostic adapter for Visual Studio Coded UI Test using Windows PSR"},"content":{"rendered":"<p>&#160;<\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span><strong><font color=\"#0000ff\">This is a guest blog from the Windows Azure AppFabric team. They are using Visual Studio Coded UI Test and want to share an exciting idea for generating rich troubleshooting logs.<\/font><\/strong><\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span><\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>Hello, my name is Jerrin Elanjikal and I\u2019m a test developer with the Windows Azure AppFabric product group at Microsoft IDC. My team develops automated UI test frameworks and tools to ensure the quality of our user interface components. We deal a unique set of technical challenges around UI test automation and debugging, which is very different from both API test automation and manual UI testing. <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>Our product has multiple user interfaces including a Silverlight web portal, Visual Studio designer surfaces, WPF dialogs and a few legacy WinForms dialogs. We target 85% code coverage through automated UI test cases. And most of our UI automation is done using Coded UI, along with a mix of internal frameworks for specialized functions. <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>When one of these test fail and you have to debug or reproduce the failure, we run into a few common pain points that are unique to UI test automation:&#160; <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>1. <\/span><span>The average test takes a lot more time to run as compared to your typical API unit test. Our tests on average take about 10 minutes each.<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span><\/span><span>2. A<\/span><span>nd while a UI test is running, you cannot use your computer for anything else that involves user interaction. This means that you either keep a dedicated second machine for debugging UI test failures, or just sit back and watch.<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>3. <\/span><span>UI tests can fail randomly due to a number of external reasons &#8211; a pop up thrown by another application, someone accidently logging into the machine, flaky internal test frameworks and the list goes on. It\u2019s almost impossible to reproduce or debug such failures on your development machine. <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt 27pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>The standard solution to these problems involves diagnostic logs and video recording of the test automation, so that you can debug without having to re-run the test. Often logs alone are not sufficient. Video recordings take up a lot of disk space, typically a few MB per test case. And you spend a lot of time watching the video and looking out for something interesting to happen. <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>Fortunately, there is a better alternative. The &#8216;Problem Steps Recorder&#8217; is an awesome little tool that comes built in with Windows 7 and later. PSR was originally intended to help customers explain their problem scenario to tech support. What it does is take screenshots of each UI action and generate a zipped html report with images and descriptions. Looking at a PSR report is like watching the highlights of a match &#8211; short &amp; interesting. It\u2019s every UI developer&#8217;s dream come true!<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>So, what we did is plug PSR into our CodedUI tests by writing a custom diagnostics data adapter that essentially just invokes psr.exe with the right parameters.<span>&#160; <\/span>This MSDN article &lt; <\/span><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd286727.aspx\"><span><font color=\"#0000ff\">http:\/\/msdn.microsoft.com\/en-us\/library\/dd286727.aspx<\/font><\/span><\/a><span> &gt; describes how to write and install a custom diagnostics data adapter for Visual Studio. And the command line parameters for PSR are as follows:<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>psr.exe [\/start |\/stop][\/output &lt;fullfilepath&gt;] [\/sc (0|1)] [\/maxsc &lt;value&gt;]<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span><span>&#160;&#160;&#160; <\/span>[\/sketch (0|1)] [\/slides (0|1)] [\/gui (o|1)]<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span><span>&#160;&#160;&#160; <\/span>[\/arcetl (0|1)] [\/arcxml (0|1)] [\/arcmht (0|1)]<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span><span>&#160;&#160;&#160; <\/span>[\/stopevent &lt;eventname&gt;] [\/maxlogsize &lt;value&gt;] [\/recordpid &lt;pid&gt;]<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>&#160;<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/start&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Start Recording. (Outputpath flag SHOULD be specified)<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/stop&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Stop Recording.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/sc&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span>&#160;&#160; <\/span>:Capture screenshots for recorded steps.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/maxsc&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Maximum number of recent screen captures.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/maxlogsize&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Maximum log file size (in MB) before wrapping occurs.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/gui&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Display control GUI.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/arcetl&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Include raw ETW file in archive output.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/arcxml&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Include MHT file in archive output.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/recordpid&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Record all actions associated with given PID.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/sketch&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Sketch UI if no screenshot was saved.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/slides&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Create slide show HTML pages.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/output&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Store output of record session in given path.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>\/stopevent&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; :Event to signal after output files are generated.<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>To start PSR recording at the beginning of each test case, we invoke <b>psr.exe<\/b> with the parameters <b>\/start \/output &lt;PSRFileName&gt; \/gui 0 \/sc 1 \/sketch 1 \/maxsc 100<\/b> in the OnTestCaseStart event handler of our custom diagnostics data adapter. <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>To complete the PSR recording and generate the zipped report we invoke <b>psr.exe \/stop <\/b>in the OnTestCaseEnd event handler, with an appropriate delay to complete the report file creation.<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>But PSR records a screenshot only when a UI action is performed. If the test fails because a UI element was not found on screen, as is often the case, PSR will not record a screenshot at that point. So we add the following code to the OnTestCaseEnd event handler to take an extra screenshot at the point of failure.<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>Playback.Initialize();<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>Image img = UITestControl.Desktop.CaptureImage();<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>Playback.Cleanup();<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>img.Save(ScreenshotFileName, ImageFormat.Jpeg);<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>We then attach the PSR report and the final screenshot to the test case.<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>dataSink.SendFileAsync(e.Context, ScreenshotFileName, false);<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><i><span>dataSink.SendFileAsync(e.Context, PSRLogFile, false);<\/span><\/i><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>The complete code for the PSR diagnostics data collector is given below:<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span><font color=\"#0000ff\" face=\"Consolas\"><font style=\"font-size: 10pt\">using<\/font><\/font><\/span><font style=\"font-size: 10pt\"><font face=\"Consolas\"><span> System;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> System.Diagnostics;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> System.Drawing;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> System.Drawing.Imaging;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> System.IO;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> System.Threading;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> System.Xml;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> Microsoft.VisualStudio.TestTools.Common;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> Microsoft.VisualStudio.TestTools.Execution;          <br \/><\/span><span><font color=\"#0000ff\">using<\/font><\/span><\/font><font face=\"Consolas\"><span> Microsoft.VisualStudio.TestTools.UITesting;          <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">namespace<\/font><\/span><\/font><font face=\"Consolas\"><span> PSRDataCollector          <br \/>{           <br \/>&#160;&#160;&#160; <\/span><span><font color=\"#008000\">\/\/ Problem Screen Recorder diagnostic data adapter<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160; [<\/font><\/span><font face=\"Consolas\"><span><font color=\"#2b91af\">DataCollectorTypeUri<\/font><\/span><span>(<\/span><span><font color=\"#a31515\">&quot;datacollector:\/\/Microsoft\/PSRDataCollector\/1.0&quot;<\/font><\/span><\/font><font face=\"Consolas\"><span>)]          <br \/>&#160;&#160;&#160; [<\/span><span><font color=\"#2b91af\">DataCollectorFriendlyName<\/font><\/span><span>(<\/span><span><font color=\"#a31515\">&quot;Problem Screen Recorder&quot;<\/font><\/span><span>, <\/span><span><font color=\"#0000ff\">false<\/font><\/span><\/font><font face=\"Consolas\"><span>)]          <br \/>&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">public<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">class<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">PSRDataCollector<\/font><\/span><span> : <\/span><span><font color=\"#2b91af\">DataCollector<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160; {          <br \/><\/font><\/span><span><font color=\"#0000ff\" face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #region<\/font><\/span><font face=\"Consolas\"><span> Constants          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">const<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">string<\/font><\/span><span> PSRExe = <\/span><span><font color=\"#a31515\">&quot;psr.exe&quot;<\/font><\/span><\/font><font face=\"Consolas\"><span>;          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">const<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">int<\/font><\/span><\/font><font face=\"Consolas\"><span> SaveDelay = 5000;          <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #endregion<\/font><\/span><\/font><font face=\"Consolas\"><span> Constants          <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #region<\/font><\/span><\/font><font face=\"Consolas\"><span> Fields          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">DataCollectionEvents<\/font><\/span><\/font><font face=\"Consolas\"><span> dataEvents;          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">DataCollectionLogger<\/font><\/span><\/font><font face=\"Consolas\"><span> dataLogger;          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">DataCollectionSink<\/font><\/span><\/font><font face=\"Consolas\"><span> dataSink;          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">XmlElement<\/font><\/span><\/font><font face=\"Consolas\"><span> configurationSettings;          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">string<\/font><\/span><\/font><font face=\"Consolas\"><span> PSRLogFile;          <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #endregion<\/font><\/span><\/font><font face=\"Consolas\"><span> Fields          <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #region<\/font><\/span><\/font><font face=\"Consolas\"><span> DataCollector          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#008000\">\/\/ Required method called by the testing framework<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><font face=\"Consolas\"><span><font color=\"#0000ff\">public<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">override<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> Initialize(<\/span><span><font color=\"#2b91af\">XmlElement<\/font><\/span><\/font><font face=\"Consolas\"><span> configurationElement,          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">DataCollectionEvents<\/font><\/span><\/font><font face=\"Consolas\"><span> events,          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">DataCollectionSink<\/font><\/span><\/font><font face=\"Consolas\"><span> sink,          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">DataCollectionLogger<\/font><\/span><\/font><font face=\"Consolas\"><span> logger,          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">DataCollectionEnvironmentContext<\/font><\/span><\/font><font face=\"Consolas\"><span> environmentContext)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents = events; <\/span><span><font color=\"#008000\">\/\/ The test events<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataLogger = logger; <\/font><\/span><span><font color=\"#008000\" face=\"Consolas\">\/\/ The error and warning log<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataSink = sink;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#008000\" face=\"Consolas\">\/\/ Saves collected data<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#008000\" face=\"Consolas\">\/\/ Configuration from the test settings<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; configurationSettings = configurationElement;          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#008000\" face=\"Consolas\">\/\/ Register common events for the data collector<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#008000\" face=\"Consolas\">\/\/ Not all of the events are used in this class<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.SessionStart +=          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><font face=\"Consolas\"><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">SessionStartEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnSessionStart);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.SessionEnd +=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">SessionEndEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnSessionEnd);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.TestCaseStart +=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">TestCaseStartEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnTestCaseStart);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.TestCaseEnd +=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">TestCaseEndEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnTestCaseEnd);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.DataRequest +=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">DataRequestEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnDataRequest);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">protected<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">override<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> Dispose(<\/span><span><font color=\"#0000ff\">bool<\/font><\/span><\/font><font face=\"Consolas\"><span> disposing)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">if<\/font><\/span><\/font><font face=\"Consolas\"><span> (disposing)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.SessionStart -=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">SessionStartEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnSessionStart);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.SessionEnd -=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">SessionEndEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnSessionEnd);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.TestCaseStart -=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">TestCaseStartEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnTestCaseStart);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.TestCaseEnd -=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">TestCaseEndEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnTestCaseEnd);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataEvents.DataRequest -=           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">EventHandler<\/font><\/span><span>&lt;<\/span><span><font color=\"#2b91af\">DataRequestEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span>&gt;(OnDataRequest);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #endregion<\/font><\/span><\/font><font face=\"Consolas\"><span> DataCollector          <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #region<\/font><\/span><\/font><font face=\"Consolas\"><span> Event Handlers          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">public<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> OnSessionStart(<\/span><span><font color=\"#0000ff\">object<\/font><\/span><span> sender, <\/span><span><font color=\"#2b91af\">SessionStartEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span> e)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#008000\">\/\/ TODO: Provide implementation<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><font face=\"Consolas\"><span><font color=\"#0000ff\">public<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> OnSessionEnd(<\/span><span><font color=\"#0000ff\">object<\/font><\/span><span> sender, <\/span><span><font color=\"#2b91af\">SessionEndEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span> e)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#008000\">\/\/ TODO: Provide implementation<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><font face=\"Consolas\"><span><font color=\"#0000ff\">public<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> OnTestCaseStart(<\/span><span><font color=\"#0000ff\">object<\/font><\/span><span> sender, <\/span><span><font color=\"#2b91af\">TestCaseEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span> e)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">this<\/font><\/span><span>.PSRLogFile = <\/span><span><font color=\"#2b91af\">Path<\/font><\/span><span>.Combine(<\/span><span><font color=\"#2b91af\">Environment<\/font><\/span><span>.CurrentDirectory, e.TestCaseName + <\/span><span><font color=\"#a31515\">&quot;.psr.zip&quot;<\/font><\/span><\/font><font face=\"Consolas\"><span>);          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#008000\">\/\/ Kill all running PSR processes<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; TryKillProcess(PSRExe);          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#008000\" face=\"Consolas\">\/\/ Start PSR<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#0000ff\" face=\"Consolas\">try<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; InvokeProcess(PSRExe, <\/font><\/span><font face=\"Consolas\"><span><font color=\"#2b91af\">String<\/font><\/span><span>.Format(<\/span><span><font color=\"#a31515\">&quot;\/start \/output &quot;{0}&quot; \/gui 0 \/sc 1 \/sketch 1 \/maxsc 100&quot;<\/font><\/span><span>, <\/span><span><font color=\"#0000ff\">this<\/font><\/span><\/font><font face=\"Consolas\"><span>.PSRLogFile));          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">catch<\/font><\/span><span> (<\/span><span><font color=\"#2b91af\">Exception<\/font><\/span><\/font><font face=\"Consolas\"><span> exp)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataLogger.LogError(e.Context, <\/span><span><font color=\"#0000ff\">string<\/font><\/span><span>.Format(<\/span><span><font color=\"#a31515\">&quot;Unexpected exception while trying to start PSR process : {0}&quot;<\/font><\/span><\/font><font face=\"Consolas\"><span>, exp));          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">public<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> OnTestCaseEnd(<\/span><span><font color=\"#0000ff\">object<\/font><\/span><span> sender, <\/span><span><font color=\"#2b91af\">TestCaseEndEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span> e)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">try<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#008000\" face=\"Consolas\">\/\/ Save the PSR logs<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; InvokeProcess(PSRExe, <\/font><\/span><span><font color=\"#a31515\" face=\"Consolas\">@&quot;\/stop&quot;<\/font><\/span><font face=\"Consolas\"><span>).WaitForExit(60000);          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#008000\">\/\/ Sleep to ensure PSR completes file creation operation<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#2b91af\" face=\"Consolas\">Thread<\/font><\/span><font face=\"Consolas\"><span>.Sleep(SaveDelay);          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">if<\/font><\/span><span> (!<\/span><span><font color=\"#2b91af\">File<\/font><\/span><span>.Exists(<\/span><span><font color=\"#0000ff\">this<\/font><\/span><\/font><font face=\"Consolas\"><span>.PSRLogFile))          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataLogger.LogError(e.Context, <\/span><span><font color=\"#a31515\">&quot;No user actions were recorded by PSR!&quot;<\/font><\/span><\/font><font face=\"Consolas\"><span>);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">else<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">if<\/font><\/span><span> (e.TestOutcome != <\/span><span><font color=\"#2b91af\">TestOutcome<\/font><\/span><\/font><font face=\"Consolas\"><span>.Passed)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">string<\/font><\/span><span> ScreenshotFileName = <\/span><span><font color=\"#2b91af\">Path<\/font><\/span><span>.Combine(<\/span><span><font color=\"#2b91af\">Environment<\/font><\/span><span>.CurrentDirectory, e.TestCaseName + <\/span><span><font color=\"#a31515\">&quot;.screenshot.jpg&quot;<\/font><\/span><\/font><font face=\"Consolas\"><span>);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; CaptureScreenshot(ScreenshotFileName);           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataSink.SendFileAsync(e.Context, ScreenshotFileName, <\/span><span><font color=\"#0000ff\">false<\/font><\/span><\/font><font face=\"Consolas\"><span>);          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataSink.SendFileAsync(e.Context, <\/span><span><font color=\"#0000ff\">this<\/font><\/span><span>.PSRLogFile, <\/span><span><font color=\"#0000ff\">false<\/font><\/span><\/font><font face=\"Consolas\"><span>);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">else<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><font face=\"Consolas\"><span><font color=\"#2b91af\">File<\/font><\/span><span>.Delete(<\/span><span><font color=\"#0000ff\">this<\/font><\/span><\/font><font face=\"Consolas\"><span>.PSRLogFile);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">catch<\/font><\/span><span> (<\/span><span><font color=\"#2b91af\">Exception<\/font><\/span><\/font><font face=\"Consolas\"><span> exp)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; dataLogger.LogError(e.Context, <\/span><span><font color=\"#0000ff\">string<\/font><\/span><span>.Format(<\/span><span><font color=\"#a31515\">&quot;Unexpected exception while trying to stop PSR process : {0}&quot;<\/font><\/span><\/font><font face=\"Consolas\"><span>, exp));          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#008000\">\/\/ Kill all PSR processes<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; TryKillProcess(PSRExe);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><font face=\"Consolas\"><span><font color=\"#0000ff\">public<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> OnDataRequest(<\/span><span><font color=\"#0000ff\">object<\/font><\/span><span> sender, <\/span><span><font color=\"#2b91af\">DataRequestEventArgs<\/font><\/span><\/font><font face=\"Consolas\"><span> e)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#008000\">\/\/ TODO: Provide implementation<\/font><\/span><\/font><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><\/span><span><font color=\"#008000\" face=\"Consolas\">\/\/ Most likely this occurs because a bug is being filed<\/font><\/span><span>        <br \/><font face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; }          <br \/><span>&#160;<\/span>           <br \/><\/font><\/span><span><font color=\"#0000ff\" face=\"Consolas\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #endregion<\/font><\/span><font face=\"Consolas\"><span> Event Handlers          <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #region<\/font><\/span><\/font><font face=\"Consolas\"><span> Helpers          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">Process<\/font><\/span><span> InvokeProcess(<\/span><span><font color=\"#0000ff\">string<\/font><\/span><span> processName, <\/span><span><font color=\"#0000ff\">string<\/font><\/span><\/font><font face=\"Consolas\"><span> parameters)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">ProcessStartInfo<\/font><\/span><span> startInfo = <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">ProcessStartInfo<\/font><\/span><\/font><font face=\"Consolas\"><span>(processName, parameters);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; startInfo.WindowStyle = <\/span><span><font color=\"#2b91af\">ProcessWindowStyle<\/font><\/span><\/font><font face=\"Consolas\"><span>.Hidden;          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; startInfo.UseShellExecute = <\/span><span><font color=\"#0000ff\">true<\/font><\/span><\/font><font face=\"Consolas\"><span>;          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; startInfo.ErrorDialog = <\/span><span><font color=\"#0000ff\">false<\/font><\/span><\/font><font face=\"Consolas\"><span>;          <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">Process<\/font><\/span><span> proc = <\/span><span><font color=\"#0000ff\">new<\/font><\/span><span>&#160;<\/span><span><font color=\"#2b91af\">Process<\/font><\/span><\/font><font face=\"Consolas\"><span>();          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; proc.StartInfo = startInfo;           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; proc.Start();           <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">return<\/font><\/span><\/font><font face=\"Consolas\"><span> proc;          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> TryKillProcess(<\/span><span><font color=\"#0000ff\">string<\/font><\/span><\/font><font face=\"Consolas\"><span> processName)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">Process<\/font><\/span><span>[] processes = <\/span><span><font color=\"#2b91af\">Process<\/font><\/span><\/font><font face=\"Consolas\"><span>.GetProcessesByName(processName);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">foreach<\/font><\/span><span> (<\/span><span><font color=\"#2b91af\">Process<\/font><\/span><span> proc <\/span><span><font color=\"#0000ff\">in<\/font><\/span><\/font><font face=\"Consolas\"><span> processes)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">try<\/font><\/span><\/font><font face=\"Consolas\"><span> { proc.Kill(); }          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">catch<\/font><\/span><span> (<\/span><span><font color=\"#2b91af\">Exception<\/font><\/span><\/font><font face=\"Consolas\"><span> exp) { }          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/><span>&#160;<\/span>           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#0000ff\">private<\/font><\/span><span>&#160;<\/span><span><font color=\"#0000ff\">void<\/font><\/span><span> CaptureScreenshot(<\/span><span><font color=\"#0000ff\">string<\/font><\/span><\/font><font face=\"Consolas\"><span> ScreenshotFileName)          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {           <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">Playback<\/font><\/span><\/font><font face=\"Consolas\"><span>.Initialize();          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">Image<\/font><\/span><span> img = <\/span><span><font color=\"#2b91af\">UITestControl<\/font><\/span><\/font><font face=\"Consolas\"><span>.Desktop.CaptureImage();          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/span><span><font color=\"#2b91af\">Playback<\/font><\/span><\/font><font face=\"Consolas\"><span>.Cleanup();          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; img.Save(ScreenshotFileName, <\/span><span><font color=\"#2b91af\">ImageFormat<\/font><\/span><\/font><font face=\"Consolas\"><span>.Jpeg);          <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }           <br \/><span>&#160;<\/span>           <br \/><\/span><span><font color=\"#0000ff\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; #endregion<\/font><\/span><\/font><\/font><span><font face=\"Consolas\"><font style=\"font-size: 10pt\"> Helpers          <br \/>&#160;&#160;&#160; }           <br \/>}<\/font><\/font><\/span><span><\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>You can download the full project from <\/span><a href=\"http:\/\/psr4vs.codeplex.com\"><span><font color=\"#0000ff\">http:\/\/psr4vs.codeplex.com<\/font><\/span><\/a><span>. <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>To install the PSR data collector into Visual Studio, download and build this project. Copy PSRDataCollector.dll to %VSINSTALLDIR%Common7IDEPrivateAssembliesDataCollectors. <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>To enable PSR data collection, open test settings from Solution Explorer in your CodedUI test and enable \u2018Problem Screen Recorder\u2019 under the \u2018Data and Diagnostics\u2019 tab.<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span><\/span><span><\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><a href=\"https:\/\/devblogs.microsoft.com\/00\/00\/00\/45\/92\/metablogapi\/2742.image_35A86816.png\"><img decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2011\/10\/8688.image_thumb_24E0BD68.png\" width=\"628\" height=\"347\" \/><\/a><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>Run your CodedUI test again and let it fail. Wait for the test run session to complete. Now, you will find the PSR report and final screenshot attached to the test report.<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><a href=\"https:\/\/devblogs.microsoft.com\/00\/00\/00\/45\/92\/metablogapi\/5875.image_100EC4E8.png\"><img decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2011\/10\/7041.image_thumb_15110297.png\" width=\"556\" height=\"402\" \/><\/a><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span><\/span><span><\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>Debugging automated UI tests just got a whole lot easier! <\/span><\/p>\n<p style=\"line-height: normal;margin: 0in 0in 0pt\" class=\"MsoNormal\"><span>&#160;<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#160; This is a guest blog from the Windows Azure AppFabric team. They are using Visual Studio Coded UI Test and want to share an exciting idea for generating rich troubleshooting logs. Hello, my name is Jerrin Elanjikal and I\u2019m a test developer with the Windows Azure AppFabric product group at Microsoft IDC. My team [&hellip;]<\/p>\n","protected":false},"author":98,"featured_media":45953,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-6103","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"acf":[],"blog_post_summary":"<p>&#160; This is a guest blog from the Windows Azure AppFabric team. They are using Visual Studio Coded UI Test and want to share an exciting idea for generating rich troubleshooting logs. Hello, my name is Jerrin Elanjikal and I\u2019m a test developer with the Windows Azure AppFabric product group at Microsoft IDC. My team [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/6103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/98"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=6103"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/6103\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/45953"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=6103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=6103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=6103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}