Commit faa6f8bd authored by Chris Baudin's avatar Chris Baudin Committed by Hirsch Singhal
Browse files

Issue #29: WindowsErrorReporting is unimplemented (#224)

* Fix unit test build break.

* WindowsErrorReporting is unimplemented (Issue #29)

* Convenience accessor for SYSTEM reports 

I had to dig into behavior to figure this out and test across multiple devices to figure out how this API actually worked - hopefully this helps other developers not have to do the same thing
parent b7c5300e
Loading
Loading
Loading
Loading
+78 −0
Original line number Diff line number Diff line
//----------------------------------------------------------------------------------------------
// <copyright file="WindowsErrorReportingTests.cs" company="Microsoft Corporation">
//     Licensed under the MIT License. See LICENSE.TXT in the project root license information.
// </copyright>
//----------------------------------------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static Microsoft.Tools.WindowsDevicePortal.DevicePortal;

namespace Microsoft.Tools.WindowsDevicePortal.Tests.Core
{
    /// <summary>
    /// Test class for Windows Error Reporting (WER) APIs.
    /// </summary>
    [TestClass]
    public class WindowsErrorReportingTests : BaseTests
    {
        /// <summary>
        /// Basic test of GET method for getting a list of Windows Error Reporting (WER) reports.
        /// </summary>
        [TestMethod]
        public void GetWindowsErrorReportsTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.WindowsErrorReportsApi, HttpMethods.Get);

            Task<WerDeviceReports> getWerReportsTask = TestHelpers.Portal.GetWindowsErrorReportsAsync();
            getWerReportsTask.Wait();

            Assert.AreEqual(TaskStatus.RanToCompletion, getWerReportsTask.Status);

            List<WerUserReports> deviceReports = getWerReportsTask.Result.UserReports;
            Assert.AreEqual(6, deviceReports.Count);
            deviceReports.ForEach(userReport =>
            {
                Assert.IsFalse(string.IsNullOrWhiteSpace(userReport.UserName));
                userReport.Reports.ForEach(report =>
                {
                    Assert.AreNotEqual(0, report.CreationTime);
                    Assert.IsFalse(string.IsNullOrWhiteSpace(report.Name));
                    switch (report.Type.ToLower())
                    {
                        case "queue":
                        case "archive":
                            break;
                        default:
                            Assert.Fail($"Expected the report type to be 'Queue' or 'Archive'. Actual value is '{report.Type}'.");
                            break;
                    }
                });
            });
        }

        /// <summary>
        /// Basic test of GET method for getting a list of Windows Error Reporting (WER) report files.
        /// </summary>
        [TestMethod]
        public void GetWindowsErrorReportFilesTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.WindowsErrorReportingFilesApi, HttpMethods.Get);

            Task<WerFiles> getWerReportingFilesTask = TestHelpers.Portal.GetWindowsErrorReportingFileListAsync(string.Empty, string.Empty, string.Empty);
            getWerReportingFilesTask.Wait();

            Assert.AreEqual(TaskStatus.RanToCompletion, getWerReportingFilesTask.Status);

            List<WerFileInformation> list = getWerReportingFilesTask.Result.Files;
            Assert.AreEqual(2, list.Count);
            list.ForEach(file =>
            {
                Assert.IsFalse(string.IsNullOrWhiteSpace(file.Name));
                Assert.AreNotEqual(0, file.Size);
            });
        }
    }
}
+1 −0
Original line number Diff line number Diff line
{"Files" : [{"Name" : "DMI59C3.tmp.log.xml", "Size" : 17490},{"Name" : "Report.wer", "Size" : 2354}]}
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
{"WerReports" : [{"User" : "All Users", "Reports" : []},{"User" : "Default", "Reports" : []},{"User" : "Default User", "Reports" : []},{"User" : "defaultuser0", "Reports" : []},{"User" : "Public", "Reports" : []},{"User" : "SYSTEM", "Reports" : [{"CreationTime" : 131318340058889142, "Name" : "NonCritical_x64_7929388dba23a244febb598fddbb379b5a87d15_00000000_cab_03f96433", "Type" : "Queue"},{"CreationTime" : 131318340058732887, "Name" : "NonCritical_x64_bf8ef24cbbad37c50f759d68f2292f1f2b0e7df_00000000_cab_03f96423", "Type" : "Queue"},{"CreationTime" : 131318550054539960, "Name" : "NonCritical_x64_f52a5825f740cca45c7b0c8078746ec73beaac_00000000_18add298", "Type" : "Archive"},{"CreationTime" : 131318340063576709, "Name" : "NonCritical_x64_f728cd6f9e9f34997130a4d3dd3d855648a6f_00000000_0ca56608", "Type" : "Archive"}]}]}
 No newline at end of file
+7 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@
  <ItemGroup>
    <Compile Include="BaseTests.cs" />
    <Compile Include="Core\AppFileExplorerTests.cs" />
    <Compile Include="Core\WindowsErrorReportingTests.cs" />
    <Compile Include="Core\EtwTests.cs" />
    <Compile Include="Core\PerformanceDataTests.cs" />
    <Compile Include="Device-VersionTests\HoloLens\HoloLensHelpers.cs" />
@@ -86,6 +87,12 @@
    <WCFMetadata Include="Service References\" />
  </ItemGroup>
  <ItemGroup>
    <None Include="MockData\Defaults\api_wer_report_files_Default.dat">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Include="MockData\Defaults\api_wer_reports_Default.dat">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Include="MockData\Defaults\WebSocket_api_etw_session_realtime_Default.dat">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
+184 −0
Original line number Diff line number Diff line
@@ -6,6 +6,12 @@

namespace Microsoft.Tools.WindowsDevicePortal
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Threading.Tasks;

    /// <content>
    /// Wrappers for DNS methods
    /// </content>
@@ -25,5 +31,183 @@ namespace Microsoft.Tools.WindowsDevicePortal
        /// API for getting the list of Windows error reports.
        /// </summary>
        public static readonly string WindowsErrorReportsApi = "api/wer/reports";

        /// <summary>
        /// Gets the list of Windows Error Reporting (WER) reports.
        /// </summary>
        /// <returns>The list of Windows Error Reporting (WER) reports.</returns>
        public async Task<WerDeviceReports> GetWindowsErrorReportsAsync()
        {
            this.CheckPlatformSupport();

            return await this.GetAsync<WerDeviceReports>(WindowsErrorReportsApi);
        }

        /// <summary>
        /// Gets the list of files in a Windows Error Reporting (WER) report.
        /// </summary>
        /// <param name="user">The user associated with the report.</param>
        /// <param name="type">The type of report. This can be either 'queried' or 'archived'.</param>
        /// <param name="name">The name of the report.</param>
        /// <returns>The list of files.</returns>
        public async Task<WerFiles> GetWindowsErrorReportingFileListAsync(string user, string type, string name)
        {
            this.CheckPlatformSupport();

            Dictionary<string, string> payload = new Dictionary<string, string>();
            payload.Add("user", user);
            payload.Add("type", type);
            payload.Add("name", Utilities.Hex64Encode(name));

            return await this.GetAsync<WerFiles>(WindowsErrorReportingFilesApi, Utilities.BuildQueryString(payload));
        }

        /// <summary>
        /// Gets the specified file from a Windows Error Reporting (WER) report.
        /// </summary>
        /// <param name="user">The user associated with the report.</param>
        /// <param name="type">The type of report. This can be either 'queried' or 'archived'.</param>
        /// <param name="name">The name of the report.</param>
        /// <param name="file">The name of the file to download from the report.</param>
        /// <returns>Byte array containing the file data</returns>
        public async Task<byte[]> GetWindowsErrorReportingFileAsync(string user, string type, string name, string file)
        {
            this.CheckPlatformSupport();

            Dictionary<string, string> payload = new Dictionary<string, string>();
            payload.Add("user", user);
            payload.Add("type", type);
            payload.Add("name", Utilities.Hex64Encode(name));
            payload.Add("file", Utilities.Hex64Encode(file));

            Uri uri = Utilities.BuildEndpoint(
                this.deviceConnection.Connection,
                WindowsErrorReportingFileApi,
                Utilities.BuildQueryString(payload));

            byte[] werFile = null;
            using (Stream stream = await this.GetAsync(uri))
            {
                werFile = new byte[stream.Length];
                stream.Read(werFile, 0, werFile.Length);
            }

            return werFile;
        }

        /// <summary>
        /// Checks if the Windows Error Reporting (WER) APIs are being called on a supported platform.
        /// </summary>
        private void CheckPlatformSupport()
        {
            switch (this.Platform)
            {
                case DevicePortalPlatforms.Mobile:
                case DevicePortalPlatforms.XboxOne:
                    throw new NotSupportedException("This method is only supported on Windows Desktop, HoloLens and IoT platforms.");
            }
        }

        /// <summary>
        /// A list of all files contained within a Windows Error Reporting (WER) report.
        /// </summary>
        [DataContract]
        public class WerFiles
        {
            /// <summary>
            /// Gets a list of all files contained within a Windows Error Reporting (WER) report.
            /// </summary>
            [DataMember(Name = "Files")]
            public List<WerFileInformation> Files { get; private set; }
        }

        /// <summary>
        /// Information about a Windows Error Reporting (WER) report file.
        /// </summary>
        [DataContract]
        public class WerFileInformation
        {
            /// <summary>
            /// Gets the name of the file.
            /// </summary>
            [DataMember(Name = "Name")]
            public string Name { get; private set; }

            /// <summary>
            /// Gets the size of the file (in bytes).
            /// </summary>
            [DataMember(Name = "Size")]
            public int Size { get; private set; }
        }

        /// <summary>
        /// A list of all Windows Error Reporting (WER) reports on a device.
        /// </summary>
        [DataContract]
        public class WerDeviceReports
        {
            /// <summary>
            ///  Gets a list of all Windows Error Reporting (WER) reports on a 
            ///  device.  The SYSTEM user account usually holds the bulk of the 
            ///  error reports. 
            /// </summary>
            [DataMember(Name = "WerReports")]
            public List<WerUserReports> UserReports { get; private set; }

            /// <summary>
            /// Convenience accessor for the System error reports - this is 
            /// where most error reports end up. 
            /// </summary>
            public WerUserReports SystemErrorReports {
                get
                {
                    return UserReports.First(x => x.UserName == "SYSTEM");
                }
            }
        }

        /// <summary>
        /// A list of Windows Error Reporting (WER) reports for a specific user.
        /// </summary>
        [DataContract]
        public class WerUserReports
        {
            /// <summary>
            /// Gets the user name.
            /// </summary>
            [DataMember(Name = "User")]
            public string UserName { get; private set; }

            /// <summary>
            /// Gets a list of Windows Error Reporting (WER) reports
            /// </summary>
            [DataMember(Name = "Reports")]
            public List<WerReportInformation> Reports { get; private set; }
        }

        /// <summary>
        /// Information about a Windows Error Reporting (WER) report.
        /// </summary>
        [DataContract]
        public class WerReportInformation
        {
            /// <summary>
            /// Gets the creation time.
            /// </summary>
            [DataMember(Name = "CreationTime")]
            public ulong CreationTime { get; private set; }

            /// <summary>
            /// Gets the report name (not base64 encoded).
            /// </summary>
            [DataMember(Name = "Name")]
            public string Name { get; private set; }

            /// <summary>
            /// Gets the report type ("Queue" or "Archive").
            /// </summary>
            [DataMember(Name = "Type")]
            public string Type { get; private set; }
        }
    }
}