Commit 23d98f72 authored by Jason Williams's avatar Jason Williams Committed by GitHub
Browse files

Merge pull request #113 from WilliamsJason/master

Adds the folder upload method for loose deployment
parents b30d19af 8a362114
Loading
Loading
Loading
Loading
+128 −61
Original line number Diff line number Diff line
@@ -30,8 +30,10 @@ namespace XboxWdpDriver
        private const string XblInstallUsageMessage = "Usage:\n" +
            "  /appx:<path to Appx> [/depend:<path to dependency1>;<path to dependency2> /cer:<path to certificate>]\n" +
            "        Installs the given AppX package, along with any given dependencies.\n" +
            "  /folder:<path to loose folder> [/depend:<path to dependency1>;<path to dependency2> /cer:<path to certificate>]\n" +
            "        Installs the appx from a loose folder, along with any given dependencies.\n";
            "  /folder:<path to loose folder> [/depend:<path to dependency1>;<path to dependency2> /cer:<path to certificate> /transfer:<SMB or HTTP, SMB is the default> /destfoldername:<folder name, defaults to the same as the loose folder>]\n" +
            "        Installs the appx from a loose folder, along with any given dependencies.\n" +
            "  /register:<subpath on DevelopmentFiles\\LooseFolder to app to register>\n" +
            "        Registers a loose folder that is already present on the device.\n";

        /// <summary>
        /// Event used to indicate that the application install process is complete.
@@ -48,6 +50,20 @@ namespace XboxWdpDriver
        /// </summary>
        private bool verbose;

        /// <summary>
        /// Reference to our portal object.
        /// </summary>
        private DevicePortal portal;

        /// <summary>
        /// Initializes a new instance of the <see cref="InstallOperation"/> class. 
        /// </summary>
        /// <param name="portal">Reference to the device portal object.</param>
        public InstallOperation(DevicePortal portal)
        {
            this.portal = portal;
        }

        /// <summary>
        /// Main entry point for handling an install operation
        /// </summary>
@@ -61,7 +77,7 @@ namespace XboxWdpDriver
                return;
            }

            InstallOperation operation = new InstallOperation();
            InstallOperation operation = new InstallOperation(portal);
            portal.AppInstallStatus += operation.AppInstallStatusHandler;

            if (parameters.HasFlag(ParameterHelper.VerboseFlag))
@@ -81,7 +97,10 @@ namespace XboxWdpDriver

            string appxFile = parameters.GetParameterValue("appx");
            string folderPath = parameters.GetParameterValue("folder");
            string registerPath = parameters.GetParameterValue("register");

            try
            {
                if (!string.IsNullOrEmpty(appxFile))
                {
                    operation.mreAppInstall.Reset();
@@ -98,8 +117,6 @@ namespace XboxWdpDriver
                    }
                }
                else if (!string.IsNullOrEmpty(folderPath))
            {
                try
                {
                    // Install all dependencies one at a time (loose folder doesn't handle dependencies well).
                    foreach (string dependency in dependencies)
@@ -123,13 +140,26 @@ namespace XboxWdpDriver
                        folderPath = folderPath.Remove(folderPath.Length - 1);
                    }

                    string destinationFolderName = parameters.GetParameterValue("destfoldername");

                    if (string.IsNullOrEmpty(destinationFolderName))
                    {
                        // Get just the folder name
                        string folderName = folderPath.Substring(folderPath.LastIndexOf('\\') + 1);

                        destinationFolderName = folderName;
                    }

                    string transferType = parameters.GetParameterValue("transfer");

                    if (string.IsNullOrEmpty(transferType) || string.Equals(transferType, "smb", StringComparison.OrdinalIgnoreCase))
                    {
                        string shareName = Path.Combine("\\\\", parameters.GetParameterValue(ParameterHelper.IpOrHostname), "DevelopmentFiles");
                        string destinationFolder = Path.Combine(shareName, "LooseApps", destinationFolderName);

                        try
                        {
                        operation.CopyDirectory(folderPath, Path.Combine(shareName, "LooseApps", folderName));
                            operation.CopyDirectory(folderPath, destinationFolder);
                        }
                        catch (IOException e)
                        {
@@ -148,7 +178,7 @@ namespace XboxWdpDriver
                                    return;
                                }

                            operation.CopyDirectory(folderPath, Path.Combine(shareName, "LooseApps", folderName));
                                operation.CopyDirectory(folderPath, destinationFolder);

                                NetworkShare.DisconnectFromShare(shareName, false);
                            }
@@ -158,19 +188,44 @@ namespace XboxWdpDriver
                                return;
                            }
                        }
                    }
                    else if (string.Equals(transferType, "http", StringComparison.OrdinalIgnoreCase))
                    {
                        operation.UploadDirectoryOverHttp(folderPath, destinationFolderName);
                    }
                    else
                    {
                        Console.WriteLine(string.Format("Unexpected transfer type received: {0}. Expecting one of SMB or HTTP.", transferType));
                        return;
                    }

                    Task registerTask = portal.RegisterApplication(folderName);
                    Task registerTask = portal.RegisterApplication(destinationFolderName);
                    registerTask.Wait();

                    Console.WriteLine("Install complete.");
                }
                else if (!string.IsNullOrEmpty(registerPath))
                {
                    Task registerTask = portal.RegisterApplication(registerPath);
                    registerTask.Wait();

                    Console.WriteLine("Registration complete.");
                }
                else
                {
                    Console.WriteLine("Must provide an appx package, loose folder, or path to register.");
                    Console.WriteLine();
                    Console.WriteLine(XblInstallUsageMessage);
                    return;
                }
            }
            catch (AggregateException e)
            {
                if (e.InnerException is DevicePortalException)
                {
                    DevicePortalException innerException = e.InnerException as DevicePortalException;

                        Console.WriteLine(string.Format("Exception encountered: 0x{0:X} : {1}", innerException.HResult, innerException.Reason));
                    Console.WriteLine(string.Format("Exception encountered: {0}, hr = 0x{1:X} : {2}", innerException.StatusCode, innerException.HResult, innerException.Reason));
                }
                else if (e.InnerException is OperationCanceledException)
                {
@@ -184,14 +239,6 @@ namespace XboxWdpDriver
                return;
            }
        }
            else
            {
                Console.WriteLine("Must provide an appx package or a loose folder.");
                Console.WriteLine();
                Console.WriteLine(XblInstallUsageMessage);
                return;
            }
        }

        /// <summary>
        /// Cleans up the object's data.
@@ -215,6 +262,26 @@ namespace XboxWdpDriver
            }
        }

        /// <summary>
        /// Recursively uploads a source directory to the console.
        /// </summary>
        /// <param name="folderPath">The source directory.</param>
        /// <param name="relativeDestination">The relative destination directory.</param>
        private void UploadDirectoryOverHttp(string folderPath, string relativeDestination)
        {
            Task uploadTask = this.portal.UploadPackageFolder(folderPath, relativeDestination);
            uploadTask.Wait();

            foreach (string subDir in Directory.GetDirectories(folderPath))
            {
                // Get just the folder name
                string subDirName = subDir.Substring(subDir.LastIndexOf('\\') + 1);
                string destSubDir = Path.Combine(relativeDestination, subDirName);
                
                this.UploadDirectoryOverHttp(subDir, destSubDir);
            }
        }

        /// <summary>
        /// Recursively copies a source directory to a destination directory.
        /// </summary>
+3 −0
Original line number Diff line number Diff line
@@ -236,6 +236,9 @@ namespace XboxWdpDriver
                }
                else if (operation == OperationType.InstallOperation)
                {
                    // Ensure we have an IP since SMB might need it for path generation.
                    parameters.AddParameter(ParameterHelper.IpOrHostname, targetConsole);

                    InstallOperation.HandleOperation(portal, parameters);
                }
                else if (operation == OperationType.RebootOperation)
+221 −0
Original line number Diff line number Diff line
@@ -4,7 +4,11 @@
// </copyright>
//----------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -362,6 +366,223 @@ namespace Microsoft.Tools.WindowsDevicePortal.Tests
            ValidateSystemPerm(systemPerfInfo);
        }

        /// <summary>
        /// Basic test of the register API.
        /// </summary>
        [TestMethod]
        public void XboxAppRegisterTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.RegisterPackageApi, HttpMethods.Post);

            Task registerTask = TestHelpers.Portal.RegisterApplication("SomeLooseFolder");
            registerTask.Wait();

            Assert.AreEqual(TaskStatus.RanToCompletion, registerTask.Status);
        }

        /// <summary>
        /// Basic test of the folder upload API.
        /// </summary>
        [TestMethod]
        public void XboxAppUploadFolderTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.UploadPackageFolderApi, HttpMethods.Post);

            Task uploadTask = TestHelpers.Portal.UploadPackageFolder("MockData\\XboxOne", "DestinationLooseFolder");
            uploadTask.Wait();

            Assert.AreEqual(TaskStatus.RanToCompletion, uploadTask.Status);
        }

        /// <summary>
        /// Basic test of the GET method. Gets a mock list of users
        /// and verifies it comes back as expected from the raw response
        /// content.
        /// </summary>
        [TestMethod]
        public void GetXboxLiveUserListTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.XboxLiveUserApi, HttpMethods.Get);

            Task<UserList> getUserTask = TestHelpers.Portal.GetXboxLiveUsers();
            getUserTask.Wait();

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

            List<UserInfo> users = getUserTask.Result.Users;

            // Check some known things about this response.
            Assert.AreEqual(2, users.Count);

            Assert.AreEqual("fakeMsa@fakedomain.com", users[0].EmailAddress);
            Assert.AreEqual("fakeGamertag", users[0].Gamertag);
            Assert.AreEqual(16u, users[0].UserId);
            Assert.AreEqual("12345667890123456", users[0].XboxUserId);
            Assert.AreEqual(true, users[0].SignedIn);
            Assert.AreEqual(false, users[0].AutoSignIn);

            Assert.IsNull(users[1].EmailAddress);
            Assert.AreEqual("fakeGamertag(1)", users[1].Gamertag);
            Assert.AreEqual(1u, users[1].UserId);
            Assert.AreEqual("7036874539097560", users[1].XboxUserId);
            Assert.AreEqual(true, users[1].SponsoredUser);
            Assert.AreEqual(true, users[1].SignedIn);
        }

        /// <summary>
        /// Basic test of the PUT method. Creates a UserList
        /// object and passes that to the server.
        /// </summary>
        [TestMethod]
        public void UpdateXboxLiveUsersTest()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NoContent);
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.XboxLiveUserApi, response, HttpMethods.Put);

            UserList users = new UserList();
            UserInfo user = new UserInfo();
            user.EmailAddress = "fakeMsa@fakeDomain.com";
            user.Password = "someFakePassword!";
            user.SignedIn = true;
            users.Add(user);

            Task updateUsersTask = TestHelpers.Portal.UpdateXboxLiveUsers(users);
            updateUsersTask.Wait();

            Assert.AreEqual(TaskStatus.RanToCompletion, updateUsersTask.Status);
        }

        /// <summary>
        /// Tests the failure case of trying to add a sponsored user
        /// when the maximum number is already on the console.
        /// </summary>
        [TestMethod]
        public void AddSponsoredUserTest_Failure()
        {
            HttpResponseMessage response = new HttpResponseMessage((HttpStatusCode)422);
            HttpContent content = new StringContent(
                "{\"ErrorCode\":-2136866553,\"ErrorMessage\":\"The maximum number of sponsored users is already signed in.\"}",
                System.Text.Encoding.UTF8,
                "application/json");

            response.Content = content;

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.XboxLiveUserApi, response, HttpMethods.Put);

            UserList users = new UserList();
            UserInfo user = new UserInfo();
            user.SponsoredUser = true;
            users.Add(user);

            try
            {
                Task updateUsersTask = TestHelpers.Portal.UpdateXboxLiveUsers(users);
                updateUsersTask.Wait();

                Assert.Fail("Expected an exception due to mock responder returning failure HRESULT.");
            }
            catch (Exception e)
            {
                Assert.IsTrue(e is AggregateException);
                Assert.IsNotNull(e.InnerException);
                Assert.IsTrue(e.InnerException is DevicePortalException);

                DevicePortalException exception = e.InnerException as DevicePortalException;

                Assert.AreEqual(-2136866553, exception.HResult);
                Assert.AreEqual("The maximum number of sponsored users is already signed in.", exception.Reason);
            }
        }

        /// <summary>
        /// Basic test of the GET method. Gets a mock list of settings
        /// and verifies it comes back as expected from the raw response
        /// content.
        /// </summary>
        [TestMethod]
        public void GetXboxSettingsTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.XboxSettingsApi, HttpMethods.Get);

            Task<XboxSettingList> getSettingsTask = TestHelpers.Portal.GetXboxSettings();
            getSettingsTask.Wait();

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

            List<XboxSetting> settings = getSettingsTask.Result.Settings;

            // Check some known things about this response.
            Assert.AreEqual(8, settings.Count);

            Assert.AreEqual("AudioBitstreamFormat", settings[0].Name);
            Assert.AreEqual("DTS", settings[0].Value);
            Assert.AreEqual("Audio", settings[0].Category);
            Assert.AreEqual("No", settings[0].RequiresReboot);

            Assert.AreEqual("ColorDepth", settings[1].Name);
            Assert.AreEqual("24 bit", settings[1].Value);
            Assert.AreEqual("Video", settings[1].Category);
            Assert.AreEqual("Yes", settings[1].RequiresReboot);

            Assert.AreEqual("TVResolution", settings[7].Name);
            Assert.AreEqual("720p", settings[7].Value);
            Assert.AreEqual("Video", settings[7].Category);
            Assert.AreEqual("No", settings[7].RequiresReboot);
        }

        /// <summary>
        /// Basic test of the GET method when called for a
        /// single setting.
        /// </summary>
        [TestMethod]
        public void GetSingleXboxSettingTest()
        {
            string settingName = "TVResolution";
            TestHelpers.MockHttpResponder.AddMockResponse(Path.Combine(DevicePortal.XboxSettingsApi, settingName), HttpMethods.Get);

            Task<XboxSetting> getSettingTask = TestHelpers.Portal.GetXboxSetting(settingName);
            getSettingTask.Wait();

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

            XboxSetting setting = getSettingTask.Result;

            // Check some known things about this response.
            Assert.AreEqual(settingName, setting.Name);
            Assert.AreEqual("720p", setting.Value);
            Assert.AreEqual("Video", setting.Category);
            Assert.AreEqual("No", setting.RequiresReboot);
        }

        /// <summary>
        /// Basic test of the PUT method. Creates a XboxSettingList
        /// object and passes that to the server.
        /// </summary>
        [TestMethod]
        public void UpdateXboxSettingsTest()
        {
            XboxSetting setting = new XboxSetting();
            setting.Name = "TVResolution";
            setting.Value = "1080p";

            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NoContent);
            TestHelpers.MockHttpResponder.AddMockResponse(Path.Combine(DevicePortal.XboxSettingsApi, setting.Name), HttpMethods.Put);

            Task<XboxSetting> updateSettingsTask = TestHelpers.Portal.UpdateXboxSetting(setting);
            updateSettingsTask.Wait();

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

            XboxSetting recievedSetting = updateSettingsTask.Result;

            // Check some known things about this response.
            Assert.AreEqual(setting.Name, recievedSetting.Name);

            Assert.AreEqual("1080p", recievedSetting.Value);
            Assert.AreEqual("Video", recievedSetting.Category);
            Assert.AreEqual("No", recievedSetting.RequiresReboot);
        }

        /// <summary>
        /// Validate the <see cref="RunningProcesses" /> returned from the tests.
        /// </summary>
+1 −4
Original line number Diff line number Diff line
@@ -77,9 +77,6 @@
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="TestHelpers.cs" />
    <Compile Include="WDPMockImplementations\WebSocket.cs" />
    <Compile Include="Xbox\UserManagementTests.cs" />
    <Compile Include="Xbox\XboxAppDeploymentTests.cs" />
    <Compile Include="Xbox\XboxSettingsTests.cs" />
  </ItemGroup>
  <ItemGroup>
    <WCFMetadata Include="Service References\" />
+0 −123
Original line number Diff line number Diff line
//----------------------------------------------------------------------------------------------
// <copyright file="UserManagementTests.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.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static Microsoft.Tools.WindowsDevicePortal.DevicePortal;

namespace Microsoft.Tools.WindowsDevicePortal.Tests
{
    /// <summary>
    /// Test class for UserManagement APIs
    /// </summary>
    [TestClass]
    public class UserManagementTests : BaseTests
    {
        /// <summary>
        /// Basic test of the GET method. Gets a mock list of users
        /// and verifies it comes back as expected from the raw response
        /// content.
        /// </summary>
        [TestMethod]
        public void GetXboxLiveUserListTest()
        {
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.XboxLiveUserApi, HttpMethods.Get);

            Task<UserList> getUserTask = TestHelpers.Portal.GetXboxLiveUsers();
            getUserTask.Wait();

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

            List<UserInfo> users = getUserTask.Result.Users;

            // Check some known things about this response.
            Assert.AreEqual(2, users.Count);

            Assert.AreEqual("fakeMsa@fakedomain.com", users[0].EmailAddress);
            Assert.AreEqual("fakeGamertag", users[0].Gamertag);
            Assert.AreEqual(16u, users[0].UserId);
            Assert.AreEqual("12345667890123456", users[0].XboxUserId);
            Assert.AreEqual(true, users[0].SignedIn);
            Assert.AreEqual(false, users[0].AutoSignIn);

            Assert.IsNull(users[1].EmailAddress);
            Assert.AreEqual("fakeGamertag(1)", users[1].Gamertag);
            Assert.AreEqual(1u, users[1].UserId);
            Assert.AreEqual("7036874539097560", users[1].XboxUserId);
            Assert.AreEqual(true, users[1].SponsoredUser);
            Assert.AreEqual(true, users[1].SignedIn);
        }

        /// <summary>
        /// Basic test of the PUT method. Creates a UserList
        /// object and passes that to the server.
        /// </summary>
        [TestMethod]
        public void UpdateXboxLiveUsersTest()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.NoContent);
            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.XboxLiveUserApi, response, HttpMethods.Put);

            UserList users = new UserList();
            UserInfo user = new UserInfo();
            user.EmailAddress = "fakeMsa@fakeDomain.com";
            user.Password = "someFakePassword!";
            user.SignedIn = true;
            users.Add(user);

            Task updateUsersTask = TestHelpers.Portal.UpdateXboxLiveUsers(users);
            updateUsersTask.Wait();

            Assert.AreEqual(TaskStatus.RanToCompletion, updateUsersTask.Status);
        }

        /// <summary>
        /// Tests the failure case of trying to add a sponsored user
        /// when the maximum number is already on the console.
        /// </summary>
        [TestMethod]
        public void AddSponsoredUserTest_Failure()
        {
            HttpResponseMessage response = new HttpResponseMessage((HttpStatusCode)422);
            HttpContent content = new StringContent(
                "{\"ErrorCode\":-2136866553,\"ErrorMessage\":\"The maximum number of sponsored users is already signed in.\"}", 
                System.Text.Encoding.UTF8, 
                "application/json");

            response.Content = content;

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.XboxLiveUserApi, response, HttpMethods.Put);

            UserList users = new UserList();
            UserInfo user = new UserInfo();
            user.SponsoredUser = true;
            users.Add(user);

            try
            {
                Task updateUsersTask = TestHelpers.Portal.UpdateXboxLiveUsers(users);
                updateUsersTask.Wait();

                Assert.Fail("Expected an exception due to mock responder returning failure HRESULT.");
            }
            catch (Exception e)
            {
                Assert.IsTrue(e is AggregateException);
                Assert.IsNotNull(e.InnerException);
                Assert.IsTrue(e.InnerException is DevicePortalException);

                DevicePortalException exception = e.InnerException as DevicePortalException;

                Assert.AreEqual(-2136866553, exception.HResult);
                Assert.AreEqual("The maximum number of sponsored users is already signed in.", exception.Reason);
            }
        }
    }
}
Loading