Commit 5191612a authored by Jason Williams's avatar Jason Williams
Browse files

Adding the FileExplorer API implementation.

Also adds unittests testing them against mocks, and adds the functionality to the XboxTestApp for further manual testing.
parent 1133ab57
Loading
Loading
Loading
Loading
+184 −0
Original line number Diff line number Diff line
//----------------------------------------------------------------------------------------------
// <copyright file="FileOperation.cs" company="Microsoft Corporation">
//     Licensed under the MIT License. See LICENSE.TXT in the project root license information.
// </copyright>
//----------------------------------------------------------------------------------------------

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Tools.WindowsDevicePortal;
using static Microsoft.Tools.WindowsDevicePortal.DevicePortal;

namespace TestApp
{
    /// <summary>
    /// Helper for file related operations
    /// </summary>
    internal class FileOperation
    {
        /// <summary>
        /// Usage message for this operation
        /// </summary>
        private const string XblFileUsageMessage = "Usage:\n" +
            "  /subop:knownfolders\n" +
            "        Lists all available known folder ids on the console\n" +
            "  /subop:dir /knownfolder:<knownfolderid> [/subpath:<subpath>] [/packagefullname:<packageFullName>]\n" +
            "        Lists the directory contents at the given knownfoldid and optionally subpath.\n" +
            "  /subop:download /knownfolder:<knownfolderid> /filename:<name of the file to download> /destination:<filepath for storing the file> [/subpath:<subpath>] [/packagefullname:<packageFullName>]\n" +
            "        Downloads the requested file to the desired destination.\n" +
            "  /subop:upload /knownfolder:<knownfolderid> /filepath:<filepath of the file to upload> [/subpath:<subpath>] [/packagefullname:<packageFullName>]\n" +
            "        Uploads a file to the requested folder.\n" +
            "  /subop:rename /knownfolder:<knownfolderid> /filename:<name of the file to rename> /newfilename:<new filename> [/subpath:<subpath>] [/packagefullname:<packageFullName>]\n" +
            "        Renames a given file.\n" +
            "  /subop:delete /knownfolder:<knownfolderid> /filename:<name of the file to delete> [/subpath:<subpath>] [/packagefullname:<packageFullName>]\n" +
            "        Deletes the given file.\n";

        /// <summary>
        /// Main entry point for handling a Setting operation
        /// </summary>
        /// <param name="portal">DevicePortal reference for communicating with the device.</param>
        /// <param name="parameters">Parsed command line parameters.</param>
        public static void HandleOperation(DevicePortal portal, ParameterHelper parameters)
        {
            if (parameters.HasFlag(ParameterHelper.HelpFlag))
            {
                Console.WriteLine(XblFileUsageMessage);
                return;
            }

            string operationType = parameters.GetParameterValue("subop");

            if (string.IsNullOrWhiteSpace(operationType))
            {
                Console.WriteLine("Missing subop parameter");
                Console.WriteLine();
                Console.WriteLine(XblFileUsageMessage);
                return;
            }

            operationType = operationType.ToLowerInvariant();

            string knownFolderId = parameters.GetParameterValue("knownfolderid");
            string subPath = parameters.GetParameterValue("subpath");
            string packageFullName = parameters.GetParameterValue("packagefullname");

            try
            {
                if (operationType.Equals("knownfolders"))
                {
                    Task<KnownFolders> getKnownFoldersTask = portal.GetKnownFolders();

                    getKnownFoldersTask.Wait();
                    Console.WriteLine(getKnownFoldersTask.Result);
                }
                else
                {
                    if (string.IsNullOrWhiteSpace(knownFolderId))
                    {
                        Console.WriteLine("Missing knownfolderid parameter");
                        Console.WriteLine();
                        Console.WriteLine(XblFileUsageMessage);
                        return;
                    }

                    if (operationType.Equals("dir"))
                    {
                        Task<FolderContents> getDirectoryContents = portal.GetFolderContents(knownFolderId, subPath, packageFullName);

                        getDirectoryContents.Wait();
                        Console.WriteLine(getDirectoryContents.Result);
                    }
                    else if (operationType.Equals("upload"))
                    {
                        string filepath = parameters.GetParameterValue("filepath");

                        if (string.IsNullOrWhiteSpace(filepath))
                        {
                            Console.WriteLine("Missing filepath parameter");
                            Console.WriteLine();
                            Console.WriteLine(XblFileUsageMessage);
                            return;
                        }

                        Task uploadFileTask = portal.UploadFile(knownFolderId, filepath, subPath, packageFullName);

                        uploadFileTask.Wait();
                        Console.WriteLine(string.Format("{0} uploaded.", filepath));
                    }
                    else
                    {
                        string filename = parameters.GetParameterValue("filename");

                        if (string.IsNullOrWhiteSpace(filename))
                        {
                            Console.WriteLine("Missing filename parameter");
                            Console.WriteLine();
                            Console.WriteLine(XblFileUsageMessage);
                            return;
                        }

                        if (operationType.Equals("download"))
                        {
                            string destination = parameters.GetParameterValue("destination");

                            if (string.IsNullOrWhiteSpace(destination))
                            {
                                Console.WriteLine("Missing destination parameter");
                                Console.WriteLine();
                                Console.WriteLine(XblFileUsageMessage);
                                return;
                            }

                            destination += "/" + filename;

                            Task<Stream> getFile = portal.GetFile(knownFolderId, filename, subPath, packageFullName);

                            getFile.Wait();

                            using (FileStream filestream = new FileStream(destination, FileMode.OpenOrCreate, FileAccess.Write))
                            {
                                getFile.Result.CopyTo(filestream);
                            }

                            Console.WriteLine(string.Format("Downloaded {0}.", destination));
                        }
                        else if (operationType.Equals("rename"))
                        {
                            string newfilename = parameters.GetParameterValue("newfilename");

                            if (string.IsNullOrWhiteSpace(newfilename))
                            {
                                Console.WriteLine("Missing newfilename parameter");
                                Console.WriteLine();
                                Console.WriteLine(XblFileUsageMessage);
                                return;
                            }

                            Task renameFileTask = portal.RenameFile(knownFolderId, filename, newfilename, subPath, packageFullName);

                            renameFileTask.Wait();
                            Console.WriteLine(string.Format("Renamed {0} to {1}.", filename, newfilename));
                        }
                        else if (operationType.Equals("delete"))
                        {
                            Task deleteFileTask = portal.DeleteFile(knownFolderId, filename, subPath, packageFullName);

                            deleteFileTask.Wait();
                            Console.WriteLine(string.Format("Deleted {0}.", filename));
                        }
                    }
                }
            }
            catch (AggregateException e)
            {
                if (e.InnerException != null && e.InnerException is DevicePortalException)
                {
                    DevicePortalException exception = e.InnerException as DevicePortalException;

                    Console.WriteLine(string.Format("HTTP Status: {0}, Hresult: 0x{1:X8}. {2}", exception.StatusCode, exception.HResult, exception.Message));
                }
            }
        }
    }
}
 No newline at end of file
+15 −1
Original line number Diff line number Diff line
@@ -81,6 +81,11 @@ namespace TestApp
            /// Get or set Xbox Settings
            /// </summary>
            XboxSettings,

            /// <summary>
            /// Does remote file operations.
            /// </summary>
            FileOperation,
        }

        /// <summary>
@@ -249,6 +254,10 @@ namespace TestApp
            {
                SettingOperation.HandleOperation(portal, parameters);
            }
            else if (operation == OperationType.FileOperation)
            {
                FileOperation.HandleOperation(portal, parameters);
            }
        }

        /// <summary>
@@ -286,6 +295,10 @@ namespace TestApp
            {
                return OperationType.XboxSettings;
            }
            else if (operation.Equals("file", StringComparison.OrdinalIgnoreCase))
            {
                return OperationType.FileOperation;
            }

            throw new Exception("Unknown Operation Type. Supported operations are the following:\n" +
                "info\n" +
@@ -294,7 +307,8 @@ namespace TestApp
                "reboot\n" +
                "processes\n" +
                "systemPerf\n" +
                "config\n");
                "config\n" +
                "file\n");
        }

        /// <summary>
+1 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
  <ItemGroup>
    <Compile Include="DevicePortalConnection.cs" />
    <Compile Include="NetworkShare.cs" />
    <Compile Include="Operations\FileOperation.cs" />
    <Compile Include="Operations\SettingOperation.cs" />
    <Compile Include="Operations\InstallOperation.cs" />
    <Compile Include="ParameterHelper.cs" />
+202 −0
Original line number Diff line number Diff line
//----------------------------------------------------------------------------------------------
// <copyright file="AppFileExplorerTests.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.IO;
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 OsInformation APIs
    /// </summary>
    [TestClass]
    public class AppFileExplorerTests : BaseTests
    {
        /// <summary>
        /// Simple test which gets a response with a couple of known folders
        /// and verifies they are returned correctly.
        /// </summary>
        [TestMethod]
        public void AppFileExplorerGetKnownFolderTest()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
            HttpContent content = new StringContent(
                "{\"KnownFolders\" : [\"KnownFolderOne\",\"KnownFolderTwo\",\"KnownFolderThree\"]}",
                System.Text.Encoding.UTF8,
                "application/json");

            response.Content = content;

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.KnownFoldersApi, response);

            Task<KnownFolders> getKnownFoldersTask = TestHelpers.Portal.GetKnownFolders();
            getKnownFoldersTask.Wait();

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

            List<string> knownFolders = getKnownFoldersTask.Result.Folders;

            // Check some known things about this response.
            Assert.AreEqual(3, knownFolders.Count);
            Assert.AreEqual("KnownFolderOne", knownFolders[0]);
            Assert.AreEqual("KnownFolderTwo", knownFolders[1]);
            Assert.AreEqual("KnownFolderThree", knownFolders[2]);
        }

        /// <summary>
        /// Tests getting the contents of a folder that is not for
        /// an application (eg developer folder, documents folder).
        /// </summary>
        [TestMethod]
        public void AppFileExplorerGetFolderContentsTest()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
            HttpContent content = new StringContent(
                "{ \"Items\" : [{\"CurrentDir\" : \"\", \"DateCreated\" : 131117780894053204, \"Id\" : \"FolderOne\", \"Name\" : \"FolderOne\", \"SubPath\" : \"\\\\FolderOne\", \"Type\" : 16}," +
                "{\"CurrentDir\" : \"\", \"DateCreated\" : 131098833024438070, \"Id\" : \"FolderTwo\", \"Name\" : \"FolderTwo\", \"SubPath\" : \"\\\\FolderTwo\", \"Type\" : 16}," +
                "{\"CurrentDir\" : \"\", \"DateCreated\" : 131117780895076062, \"FileSize\" : 2985, \"Id\" : \"fakefile.xml\", \"Name\" : \"fakefile.xml\", \"SubPath\" : \"\", \"Type\" : 32}]}",
                System.Text.Encoding.UTF8,
                "application/json");

            response.Content = content;

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.GetFilesApi, response);

            Task<FolderContents> getFolderContentsTask = TestHelpers.Portal.GetFolderContents("KnownFolderOne");
            getFolderContentsTask.Wait();

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

            List<FileOrFolderInformation> directoryContents = getFolderContentsTask.Result.Contents;

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

            Assert.AreEqual(string.Empty, directoryContents[0].CurrentDir);
            Assert.AreEqual(131117780894053204, directoryContents[0].DateCreated);
            Assert.AreEqual("FolderOne", directoryContents[0].Id);
            Assert.AreEqual("FolderOne", directoryContents[0].Name);
            Assert.AreEqual("\\FolderOne", directoryContents[0].SubPath);
            Assert.AreEqual(16, directoryContents[0].Type);

            Assert.AreEqual(string.Empty, directoryContents[1].CurrentDir);
            Assert.AreEqual(131098833024438070, directoryContents[1].DateCreated);
            Assert.AreEqual("FolderTwo", directoryContents[1].Id);
            Assert.AreEqual("FolderTwo", directoryContents[1].Name);
            Assert.AreEqual("\\FolderTwo", directoryContents[1].SubPath);
            Assert.AreEqual(16, directoryContents[1].Type);

            Assert.AreEqual(string.Empty, directoryContents[2].CurrentDir);
            Assert.AreEqual(131117780895076062, directoryContents[2].DateCreated);
            Assert.AreEqual("fakefile.xml", directoryContents[2].Id);
            Assert.AreEqual("fakefile.xml", directoryContents[2].Name);
            Assert.AreEqual(string.Empty, directoryContents[2].SubPath);
            Assert.AreEqual(32, directoryContents[2].Type);
            Assert.AreEqual(2985, directoryContents[2].SizeInBytes);
        }

        /// <summary>
        /// Tests download method for downloading a file.
        /// </summary>
        [TestMethod]
        public void AppFileExplorerDownloadFileTest()
        {
            Stream stream = new FileStream("MockData\\Defaults\\api_os_devicefamily_Default.dat", FileMode.Open, FileAccess.Read);
            long fileLength = stream.Length;

            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
            HttpContent content = new StreamContent(stream);
            response.Content = content;

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.GetFileApi, response);

            Task<Stream> getFileTask = TestHelpers.Portal.GetFile("knownfolder", "FileToDownload.txt", "SubFolder\\SubFolder2");
            getFileTask.Wait();

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

            Assert.AreEqual(fileLength, getFileTask.Result.Length);
        }

        /// <summary>
        /// Tests upload method for uploading a file.
        /// </summary>
        [TestMethod]
        public void AppFileExplorerUploadFileTest()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.GetFileApi, response);

            Task uploadFileTask = TestHelpers.Portal.UploadFile("knownfolder", "MockData\\Defaults\\api_os_devicefamily_Default.dat", "SubFolder\\SubFolder2");
            uploadFileTask.Wait();

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

        /// <summary>
        /// Tests failure of method for uploading a file when the file
        /// doesn't exist.
        /// </summary>
        [TestMethod]
        public void AppFileExplorerUploadFileTest_Failure()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.GetFileApi, response);

            try
            {
                Task uploadFileTask = TestHelpers.Portal.UploadFile("knownfolder", "NonExistentFilePath\\NonExistentFile.txt", "SubFolder\\SubFolder2");
                uploadFileTask.Wait();

                Assert.Fail("Should not have succeeded if uploading a file which doesn't exist.");
            }
            catch (AggregateException e)
            {
                Assert.IsInstanceOfType(e.InnerException, typeof(IOException));
            }
        }

        /// <summary>
        /// Tests delete method for deleting a file.
        /// </summary>
        [TestMethod]
        public void AppFileExplorerDeleteFileTest()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.GetFileApi, response);

            Task deleteFileTask = TestHelpers.Portal.DeleteFile("knownfolder", "FileToDelete.txt", "SubFolder\\SubFolder2");
            deleteFileTask.Wait();

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

        /// <summary>
        /// Tests rename method for renaming a file
        /// </summary>
        [TestMethod]
        public void AppFileExplorerRenameFileTest()
        {
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);

            TestHelpers.MockHttpResponder.AddMockResponse(DevicePortal.RenameFileApi, response);

            Task renameFileTask = TestHelpers.Portal.RenameFile("knownfolder", "FileToRename.txt", "NewFileName.txt", "SubFolder\\SubFolder2");
            renameFileTask.Wait();

            Assert.AreEqual(TaskStatus.RanToCompletion, renameFileTask.Status);
        }
    }
}
+125 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading