Commit 0a6cc307 authored by Jason Williams's avatar Jason Williams
Browse files

Add the ability while generating a mock to specify a file to use as the request body

This was the last real hole in the mock generation--you should now be able to generate a response for whatever endpoint you want with whatever request body and parameters you desire.
parent 48390b60
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -112,13 +112,15 @@ MockDataGenerator.exe, from the MockDataGenerator project, is used to target a W
### MockDataGenerator Parameters

| Parameter                  | Purpose                                        |
|-------------------------|------------------------------------------------|
|----------------------------|------------------------------------------------|
| /Address                   | URL for device (eg. https://10.0.0.1:11443)    |
| /User                      | WDP username                                   |
| /Pwd                       | WDP password                                   |
| /Endpoint                  | API to call (default is all endoints in program.cs)   |
| /Method                    | HTTP method to use (default is GET)            |
| /Directory                 | Directory to save mock data file(s) (default is .\MockData) |
| /requestBody               | File to use for the request body. Only applicable when /Endpoint is present. |
| /requestBodyMultiPartFile  | Normally the requestBody file is considered JSON and provided as is. Specify this parameter to include it as a multipart file instead. |

### MockDataGenerator File Name Format

@@ -151,6 +153,12 @@ All examples connect to 10.0.0.1:11443 with username TestUser and password Super
  MockDataGenerator.exe  /ip: 10.0.0.1:11443/user:TestUser /pwd:SuperSecret /endpoint:api/resourcemanager/systemperf /method:WebSocket
  ```

* Generate mock for a POST call to upload a file, specifying the file to use for the request body.

    ```shell
  MockDataGenerator.exe  /ip: 10.0.0.1:11443/user:TestUser /pwd:SuperSecret /endpoint:api/filesystem/apps/file?knownfolderid=LocalAppData&packagefullname=MyTestPackage_Fullname /method:Post /requestBody:myfile.txt /requestBodyMultiPartFile
  ```
  
  ## Adding Mock Data to the Solution
  
  1. Mock data should be added to the UnitTestProject in the MockData directory. 
+69 −3
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Tools.WindowsDevicePortal;
@@ -23,7 +24,7 @@ namespace MockDataGenerator
        /// <summary>
        /// Usage string
        /// </summary>
        private const string GeneralUsageMessage = "Usage: /address:<URL for device (eg. https://10.0.0.1:11443)> /user:<WDP username> /pwd:<WDP password> [/endpoint:<api to call>] [/directory:<directory to save mock data file(s)>";
        private const string GeneralUsageMessage = "Usage: /address:<URL for device (eg. https://10.0.0.1:11443)> /user:<WDP username> /pwd:<WDP password> [/endpoint:<api to call> [/method:<http method>] [/requestBody:<path to file for requestBody (PUT and POST only)>] [/requestBodyMultiPartFile (otherwise defaults to application/json] [/directory:<directory to save mock data file(s)>";

        /// <summary>
        /// Endpoints for REST calls to populate. Feel free to override this list (especially locally) to
@@ -137,9 +138,48 @@ namespace MockDataGenerator

                string endpoint = parameters.GetParameterValue("endpoint");

                string requestBodyFile = parameters.GetParameterValue("requestbody");

                if (!string.IsNullOrEmpty(requestBodyFile))
                {
                    if (parameters.HasFlag("requestbodymultipartfile"))
                    {
                        string boundaryString = Guid.NewGuid().ToString();

                        using (MemoryStream dataStream = new MemoryStream())
                        {
                            byte[] data;

                            FileInfo fi = new FileInfo(requestBodyFile);
                            data = Encoding.ASCII.GetBytes(string.Format("\r\n--{0}\r\n", boundaryString));
                            dataStream.Write(data, 0, data.Length);
                            CopyFileToRequestStream(fi, dataStream);

                            // Close the multipart request data.
                            data = Encoding.ASCII.GetBytes(string.Format("\r\n--{0}--\r\n", boundaryString));
                            dataStream.Write(data, 0, data.Length);

                            dataStream.Position = 0;
                            string contentType = string.Format("multipart/form-data; boundary={0}", boundaryString);

                            Task saveResponseTask = portal.SaveEndpointResponseToFile(endpoint, directory, httpMethod, dataStream, contentType);
                            saveResponseTask.Wait();
                        }
                    }
                    else
                    {
                        Stream fileStream = new FileStream(requestBodyFile, FileMode.Open);

                        Task saveResponseTask = portal.SaveEndpointResponseToFile(endpoint, directory, httpMethod, fileStream, "application/json");
                        saveResponseTask.Wait();
                    }
                }
                else
                {
                    Task saveResponseTask = portal.SaveEndpointResponseToFile(endpoint, directory, httpMethod);
                    saveResponseTask.Wait();
                }
            }
            else
            {
                foreach (Endpoint endpoint in Endpoints)
@@ -184,6 +224,32 @@ namespace MockDataGenerator
            }
        }

        /// <summary>
        /// Copies a file to the specified stream and prepends the necessary content information
        /// required to be part of a multipart form data request.
        /// </summary>
        /// <param name="file">The file to be copied.</param>
        /// <param name="stream">The stream to which the file will be copied.</param>
        private static void CopyFileToRequestStream(
            FileInfo file,
            Stream stream)
        {
            byte[] data;
            string contentDisposition = string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n", file.Name, file.Name);
            string contentType = "Content-Type: application/octet-stream\r\n\r\n";

            data = Encoding.ASCII.GetBytes(contentDisposition);
            stream.Write(data, 0, data.Length);

            data = Encoding.ASCII.GetBytes(contentType);
            stream.Write(data, 0, data.Length);

            using (FileStream fs = File.OpenRead(file.FullName))
            {
                fs.CopyTo(stream);
            }
        }

        /// <summary>
        /// Encapsulation of an endpoint and its HTTP method.
        /// </summary>
+31 −3
Original line number Diff line number Diff line
@@ -5,9 +5,12 @@
//----------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.IO;
#if !WINDOWS_UWP
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
#endif // !WINDOWS_UWP
#if WINDOWS_UWP
using System.Runtime.InteropServices.WindowsRuntime;
@@ -20,6 +23,7 @@ using System.Threading.Tasks;
#if WINDOWS_UWP
using Windows.Security.Cryptography.Certificates;
using Windows.Web.Http;
using Windows.Web.Http.Headers;
#endif // WINDOWS_UWP

namespace Microsoft.Tools.WindowsDevicePortal
@@ -305,8 +309,15 @@ namespace Microsoft.Tools.WindowsDevicePortal
        /// <param name="endpoint">API endpoint we are calling.</param>
        /// <param name="directory">Directory to store our file.</param>
        /// <param name="httpMethod">The http method to be performed.</param>
        /// <param name="requestBody">An optional stream to use for the request body content.</param>
        /// <param name="requestBodyContentType">The content type of the request stream.</param>
        /// <returns>Task waiting for HTTP call to return and file copy to complete.</returns>
        public async Task SaveEndpointResponseToFile(string endpoint, string directory, HttpMethods httpMethod)
        public async Task SaveEndpointResponseToFile(
            string endpoint,
            string directory,
            HttpMethods httpMethod,
            Stream requestBody = null,
            string requestBodyContentType = null)
        {
            Uri uri = new Uri(this.deviceConnection.Connection, endpoint);

@@ -376,7 +387,24 @@ namespace Microsoft.Tools.WindowsDevicePortal
            }
            else if (HttpMethods.Put == httpMethod)
            {
                using (Stream dataStream = await this.Put(uri))
#if WINDOWS_UWP
                HttpStreamContent streamContent = null;
#else
                StreamContent streamContent = null;
#endif // WINDOWS_UWP

                if (requestBody != null)
                {
#if WINDOWS_UWP
                streamContent = new HttpStreamContent(requestBody.AsInputStream());
                streamContent.Headers.ContentType = new HttpMediaTypeHeaderValue(requestBodyContentType);
#else
                    streamContent = new StreamContent(requestBody);
                    streamContent.Headers.ContentType = new MediaTypeHeaderValue(requestBodyContentType);
#endif // WINDOWS_UWP
                }

                using (Stream dataStream = await this.Put(uri, streamContent))
                {
                    using (var fileStream = File.Create(filepath))
                    {
@@ -387,7 +415,7 @@ namespace Microsoft.Tools.WindowsDevicePortal
            }
            else if (HttpMethods.Post == httpMethod)
            {
                using (Stream dataStream = await this.Post(uri))
                using (Stream dataStream = await this.Post(uri, requestBody, requestBodyContentType))
                {
                    using (var fileStream = File.Create(filepath))
                    {