Commit 5a7a85d7 authored by David Kline's avatar David Kline Committed by GitHub
Browse files

Merge pull request #223 from Microsoft/master

V0.9.3 release - ETW streaming and refactoring of aync usage
parents 0f7f95c8 4fd8709b
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -71,6 +71,17 @@ Address any review comments, force push to your topic branch, and post a comment

If the pull request review goes well, a project maintainer will merge your changes. Thank you for helping improve the Windows Device Portal Wrapper!

# NuGet release and versioning

**For maintainers**

When creating a new NuGet and GitHub release, the following steps should be taken:
1. Bump the version number as appropriate in master (after 1.0, WDP Wrapper will correctly use semver)
2. Merge from Master to Release, with a PR appropriately named ("v1.2.3 release")
3. Squash and merge commits, leaving major feature entries and fixes in the description. 
4. Compile release builds of the .NET and UWP libraries, sign them, and upload to NuGet 
5. Cut a new release on GitHub using the same version number ("v1.2.3") and attach the signed libraries to the release. 
6. Update code documentation. 

# Updating code documentation

+146 −259
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ namespace SampleWdpClient.UniversalWindows
        /// </summary>
        /// <param name="sender">The caller of this method.</param>
        /// <param name="e">The arguments associated with this event.</param>
        private void ConnectToDevice_Click(object sender, RoutedEventArgs e)
        private async void ConnectToDevice_Click(object sender, RoutedEventArgs e)
        {
            this.EnableConnectionControls(false);
            this.EnableDeviceControls(false);
@@ -78,12 +78,10 @@ namespace SampleWdpClient.UniversalWindows
                    this.password.Password));

            StringBuilder sb = new StringBuilder();
            Task connectTask = new Task(
                async () =>
                {
                    sb.Append(this.MarshalGetCommandOutput());

            sb.Append(this.commandOutput.Text);
            sb.AppendLine("Connecting...");
                    this.MarshalUpdateCommandOutput(sb.ToString());
            this.commandOutput.Text = sb.ToString();
            portal.ConnectionStatus += (portal, connectArgs) =>
            {
                if (connectArgs.Status == DeviceConnectionStatus.Connected)
@@ -122,17 +120,9 @@ namespace SampleWdpClient.UniversalWindows
                sb.AppendLine(exception.Message);
            }

                    this.MarshalUpdateCommandOutput(sb.ToString());
                });

            Task continuationTask = connectTask.ContinueWith(
                (t) =>
                {
                    this.MarshalEnableDeviceControls(true);
                    this.MarshalEnableConnectionControls(true);
                });

            connectTask.Start();
            this.commandOutput.Text = sb.ToString();
            EnableDeviceControls(true);
            EnableConnectionControls(true);
        }

        /// <summary>
@@ -179,19 +169,16 @@ namespace SampleWdpClient.UniversalWindows
        /// </summary>
        /// <param name="sender">The caller of this method.</param>
        /// <param name="e">The arguments associated with this event.</param>
        private void GetIPConfig_Click(object sender, RoutedEventArgs e)
        private async void GetIPConfig_Click(object sender, RoutedEventArgs e)
        {
            this.ClearOutput();
            this.EnableConnectionControls(false);
            this.EnableDeviceControls(false);

            StringBuilder sb = new StringBuilder();
            Task getTask = new Task(
                async () =>
                {
                    sb.Append(this.MarshalGetCommandOutput());
            sb.Append(commandOutput.Text);
            sb.AppendLine("Getting IP configuration...");
                    this.MarshalUpdateCommandOutput(sb.ToString());
            commandOutput.Text = sb.ToString();

            try
            {
@@ -217,17 +204,10 @@ namespace SampleWdpClient.UniversalWindows
                sb.AppendLine("Failed to get IP config info.");
                sb.AppendLine(ex.GetType().ToString() + " - " + ex.Message);
            }
                });

            Task continuationTask = getTask.ContinueWith(
                (t) =>
                {
                    this.MarshalUpdateCommandOutput(sb.ToString());
                    this.MarshalEnableDeviceControls(true);
                    this.MarshalEnableConnectionControls(true);
                });

            getTask.Start();
            commandOutput.Text = sb.ToString();
            EnableDeviceControls(true);
            EnableConnectionControls(true);
        }

        /// <summary>
@@ -235,19 +215,17 @@ namespace SampleWdpClient.UniversalWindows
        /// </summary>
        /// <param name="sender">The caller of this method.</param>
        /// <param name="e">The arguments associated with this event.</param>
        private void GetWifiInfo_Click(object sender, RoutedEventArgs e)
        private async void GetWifiInfo_Click(object sender, RoutedEventArgs e)
        {
            this.ClearOutput();
            this.EnableConnectionControls(false);
            this.EnableDeviceControls(false);

            StringBuilder sb = new StringBuilder();
            Task getTask = new Task(
                async () =>
                {
                    sb.Append(this.MarshalGetCommandOutput());

            sb.Append(commandOutput.Text);
            sb.AppendLine("Getting WiFi interfaces and networks...");
                    this.MarshalUpdateCommandOutput(sb.ToString());
            commandOutput.Text = sb.ToString();

            try
            {
@@ -284,81 +262,10 @@ namespace SampleWdpClient.UniversalWindows
                sb.AppendLine("Failed to get WiFi info.");
                sb.AppendLine(ex.GetType().ToString() + " - " + ex.Message);
            }
                });

            Task continuationTask = getTask.ContinueWith(
                (t) =>
                {
                    this.MarshalUpdateCommandOutput(sb.ToString());
                    this.MarshalEnableDeviceControls(true);
                    this.MarshalEnableConnectionControls(true);
                });

            getTask.Start();
        }

        /// <summary>
        /// Executes the EnabledConnectionControls method on the UI thread.
        /// </summary>
        /// <param name="enable">True to enable the controls, false to disable them.</param>
        private void MarshalEnableConnectionControls(bool enable)
        {
            Task t = this.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal,
                () =>
                {
                    this.EnableConnectionControls(enable);
                }).AsTask();
            t.Wait();
        }

        /// <summary>
        /// Executes the EnabledDeviceControls method on the UI thread.
        /// </summary>
        /// <param name="enable">True to enable the controls, false to disable them.</param>
        private void MarshalEnableDeviceControls(bool enable)
        {
            Task t = this.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal,
                () =>
                {
                    this.EnableDeviceControls(enable);
                }).AsTask();
            t.Wait();
        }

        /// <summary>
        /// Executes the fetching of the text displayed in the command output UI element on the UI thread.
        /// </summary>
        /// <returns>The contents of the command output UI element.</returns>
        private string MarshalGetCommandOutput()
        {
            string output = string.Empty;

            Task t = this.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal,
                () =>
                {
                    output = this.commandOutput.Text;
                }).AsTask();
            t.Wait();

            return output;
        }

        /// <summary>
        /// Executes the update of the text displayed in the command output UI element ont he UI thread.
        /// </summary>
        /// <param name="output">The text to display in the command output UI element.</param>
        private void MarshalUpdateCommandOutput(string output)
        {
            Task t = this.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal,
                () =>
                {
                    this.commandOutput.Text = output;
                }).AsTask();
            t.Wait();
            commandOutput.Text = sb.ToString();
            EnableDeviceControls(true);
            EnableConnectionControls(true);
        }

        /// <summary>
@@ -376,7 +283,7 @@ namespace SampleWdpClient.UniversalWindows
        /// </summary>
        /// <param name="sender">The caller of this method.</param>
        /// <param name="e">The arguments associated with this event.</param>
        private void RebootDevice_Click(object sender, RoutedEventArgs e)
        private async void RebootDevice_Click(object sender, RoutedEventArgs e)
        {
            bool reenableDeviceControls = false;

@@ -385,12 +292,10 @@ namespace SampleWdpClient.UniversalWindows
            this.EnableDeviceControls(false);

            StringBuilder sb = new StringBuilder();
            Task rebootTask = new Task(
                async () =>
                {
                    sb.Append(this.MarshalGetCommandOutput());

            sb.Append(commandOutput.Text);
            sb.AppendLine("Rebooting the device");
                    this.MarshalUpdateCommandOutput(sb.ToString());
            commandOutput.Text = sb.ToString();

            try
            {
@@ -402,17 +307,10 @@ namespace SampleWdpClient.UniversalWindows
                sb.AppendLine(ex.GetType().ToString() + " - " + ex.Message);
                reenableDeviceControls = true;
            }
                });

            Task continuationTask = rebootTask.ContinueWith(
                (t) =>
                {
                    this.MarshalUpdateCommandOutput(sb.ToString());
                    this.MarshalEnableDeviceControls(reenableDeviceControls);
                    this.MarshalEnableConnectionControls(true);
                });

            rebootTask.Start();
            commandOutput.Text = sb.ToString();
            EnableDeviceControls(reenableDeviceControls);
            EnableConnectionControls(true);
        }

        /// <summary>
@@ -420,7 +318,7 @@ namespace SampleWdpClient.UniversalWindows
        /// </summary>
        /// <param name="sender">The caller of this method.</param>
        /// <param name="e">The arguments associated with this event.</param>
        private void ShutdownDevice_Click(object sender, RoutedEventArgs e)
        private async void ShutdownDevice_Click(object sender, RoutedEventArgs e)
        {
            bool reenableDeviceControls = false;

@@ -429,13 +327,9 @@ namespace SampleWdpClient.UniversalWindows
            this.EnableDeviceControls(false);

            StringBuilder sb = new StringBuilder();
            Task shutdownTask = new Task(
                async () =>
                {
                    sb.Append(this.MarshalGetCommandOutput());
            sb.Append(commandOutput.Text);
            sb.AppendLine("Shutting down the device");
                    this.MarshalUpdateCommandOutput(sb.ToString());

            commandOutput.Text = sb.ToString();
            try
            {
                await portal.ShutdownAsync();
@@ -446,17 +340,10 @@ namespace SampleWdpClient.UniversalWindows
                sb.AppendLine(ex.GetType().ToString() + " - " + ex.Message);
                reenableDeviceControls = true;
            }
                });

            Task continuationTask = shutdownTask.ContinueWith(
                (t) =>
                {
                    this.MarshalUpdateCommandOutput(sb.ToString());
                    this.MarshalEnableDeviceControls(reenableDeviceControls);
                    this.MarshalEnableConnectionControls(true);
                });

            shutdownTask.Start();
            commandOutput.Text = sb.ToString();
            EnableDeviceControls(reenableDeviceControls);
            EnableConnectionControls(true);
        }

        /// <summary>
+3 −0
Original line number Diff line number Diff line
@@ -40,8 +40,11 @@ namespace MockDataGenerator
            new Endpoint(HttpMethods.Get, DevicePortal.IpConfigApi),
            new Endpoint(HttpMethods.Get, DevicePortal.SystemPerfApi),
            new Endpoint(HttpMethods.Get, DevicePortal.RunningProcessApi),
            new Endpoint(HttpMethods.Get, DevicePortal.CustomEtwProvidersApi),
            new Endpoint(HttpMethods.Get, DevicePortal.EtwProvidersApi),
            new Endpoint(HttpMethods.WebSocket, DevicePortal.SystemPerfApi),
            new Endpoint(HttpMethods.WebSocket, DevicePortal.RunningProcessApi),
            new Endpoint(HttpMethods.WebSocket, DevicePortal.RealtimeEtwSessionApi),

            // HoloLens specific endpoints
            new Endpoint(HttpMethods.Get, DevicePortal.HolographicIpdApi),
+109 −0
Original line number Diff line number Diff line
//----------------------------------------------------------------------------------------------
// <copyright file="EtwTests.cs" company="Microsoft Corporation">
//     Licensed under the MIT License. See LICENSE.TXT in the project root license information.
// </copyright>
//----------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
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 ETW APIs.
    /// </summary>
    [TestClass]
    public class EtwTests : BaseTests
    {
        /// <summary>
        /// Basic test of GET method for getting a list of custom registered ETW providers.
        /// </summary>
        [TestMethod]
        public void GetCustomEtwProvidersTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.CustomEtwProvidersApi, HttpMethods.Get);

            Task<EtwProviders> getCustomEtwProvidersTask = TestHelpers.Portal.GetCustomEtwProvidersAsync();
            getCustomEtwProvidersTask.Wait();

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

            ValidateEtwProviders(getCustomEtwProvidersTask.Result);
        }

        /// <summary>
        /// Basic test of GET method for getting a list of registered ETW providers.
        /// </summary>
        [TestMethod]
        public void GetEtwProvidersTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.EtwProvidersApi, HttpMethods.Get);

            Task<EtwProviders> getEtwProvidersTask = TestHelpers.Portal.GetEtwProvidersAsync();
            getEtwProvidersTask.Wait();

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

            ValidateEtwProviders(getEtwProvidersTask.Result);
        }

        [TestMethod]
        public void GetEtwEventsTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.RealtimeEtwSessionApi, HttpMethods.WebSocket);

            ManualResetEvent etwEventsReceived = new ManualResetEvent(false);
            EtwEvents etwEvents = null;

            WindowsDevicePortal.WebSocketMessageReceivedEventHandler<EtwEvents> etwEventsReceivedHandler =
                delegate (DevicePortal sender, WebSocketMessageReceivedEventArgs<EtwEvents> args)
                {
                    if (args.Message != null)
                    {
                        etwEvents = args.Message;
                        etwEventsReceived.Set();
                    }
                };

            TestHelpers.Portal.RealtimeEventsMessageReceived += etwEventsReceivedHandler;

            Task startListeningForEtwEventsTask = TestHelpers.Portal.StartListeningForEtwEventsAsync();
            startListeningForEtwEventsTask.Wait();
            Assert.AreEqual(TaskStatus.RanToCompletion, startListeningForEtwEventsTask.Status);

            etwEventsReceived.WaitOne();

            Task stopListeningForEtwEventsTask = TestHelpers.Portal.StopListeningForEtwEventsAsync();
            stopListeningForEtwEventsTask.Wait();
            Assert.AreEqual(TaskStatus.RanToCompletion, stopListeningForEtwEventsTask.Status);

            TestHelpers.Portal.RealtimeEventsMessageReceived -= etwEventsReceivedHandler;

            ValidateEtwEvents(etwEvents);
        }

        /// <summary>
        /// Validate the <see cref="EtwEvents"/>  returned from the tests.
        /// </summary>
        /// <param name="etwEvents">The <see cref="EtwEvents"/> to validate.</param>
        private static void ValidateEtwEvents(EtwEvents etwEvents)
        {
            Assert.IsNotNull(etwEvents);
        }
        
        /// <summary>
        /// Validate the <see cref="EtwProviders"/> returned from the tests. 
        /// </summary>
        /// <param name="etw">The <see cref="EtwProviders"/> to validate.</param>
        private static void ValidateEtwProviders(EtwProviders etw)
        {
            Assert.IsTrue(etw.Providers.Count > 0);
            Assert.IsTrue(etw.Providers.All(etwProvider => !string.IsNullOrEmpty(etwProvider.Name)));
        }
    }
}
+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);
            });
        }
    }
}
Loading