Skip to content

Commit

Permalink
Merged PR 919368: EdgeHub: MethodInvocation response Payload should b…
Browse files Browse the repository at this point in the history
…e json object

EdgeHub was stringifying the method invocation response payload json.
This change is to return the payload as a json object instead (same like IotHub).
  • Loading branch information
varunpuranik committed Jun 23, 2018
1 parent 0237700 commit 7892a98
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// Copyright (c) Microsoft. All rights reserved.
// Copyright (c) Microsoft. All rights reserved.
namespace Microsoft.Azure.Devices.Edge.Hub.Http
{
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class MethodResult
{
[JsonProperty("status")]
public int Status { get; set; }

[JsonProperty("payload")]
public string Payload { get; set; }
public JRaw Payload { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Microsoft.Azure.Devices.Edge.Hub.Http.Controllers
using Microsoft.Azure.Devices.Edge.Hub.Core.Identity;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;

public class TwinsController : Controller
{
Expand Down Expand Up @@ -61,15 +62,26 @@ async Task<IActionResult> InvokeMethodAsync(DirectMethodRequest directMethodRequ
IEdgeHub edgeHub = await this.edgeHubGetter;
DirectMethodResponse directMethodResponse = await edgeHub.InvokeMethodAsync(this.identity.Id, directMethodRequest);
Events.ReceivedMethodCallResponse(directMethodRequest, this.identity);

var methodResult = new MethodResult
{
Status = directMethodResponse.Status,
Payload = directMethodResponse.Data != null ? Encoding.UTF8.GetString(directMethodResponse.Data) : string.Empty
Payload = GetRawJson(directMethodResponse.Data)
};
return this.Json(methodResult);
}

internal static JRaw GetRawJson(byte[] bytes)
{
if (bytes == null || bytes.Length == 0)
{
return null;
}

string json = Encoding.UTF8.GetString(bytes);
return new JRaw(json);
}

static class Events
{
static readonly ILogger Log = Logger.Factory.CreateLogger<TwinsController>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Microsoft.Azure.Devices.Edge.Hub.Http.Test
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -16,6 +17,7 @@ namespace Microsoft.Azure.Devices.Edge.Hub.Http.Test
using Microsoft.Azure.Devices.Edge.Hub.Http.Controllers;
using Microsoft.Azure.Devices.Edge.Util.Test.Common;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;

Expand Down Expand Up @@ -52,7 +54,7 @@ public async Task TestInvokeMethod()
var methodResult = jsonResult.Value as MethodResult;
Assert.NotNull(methodResult);
Assert.Equal(200, methodResult.Status);
Assert.Equal(string.Empty, methodResult.Payload);
Assert.Equal(null, methodResult.Payload);
}

[Fact]
Expand Down Expand Up @@ -86,7 +88,76 @@ public async Task TestInvokeMethodOnModule()
var methodResult = jsonResult.Value as MethodResult;
Assert.NotNull(methodResult);
Assert.Equal(200, methodResult.Status);
Assert.Equal(string.Empty, methodResult.Payload);
Assert.Equal(null, methodResult.Payload);
}

[Fact]
public async Task TestInvokeMethodWithResponse()
{
var identity = Mock.Of<IIdentity>(i => i.Id == "edgedevice/module1");
ActionExecutingContext actionExecutingContext = this.GetActionExecutingContextMock(identity);

string responsePayload = "{ \"resp1\" : \"respvalue1\" }";
var directMethodResponse = new DirectMethodResponse(Guid.NewGuid().ToString(), Encoding.UTF8.GetBytes(responsePayload), 200);
var edgeHub = new Mock<IEdgeHub>();
edgeHub.Setup(e => e.InvokeMethodAsync(It.Is<string>(i => i == identity.Id), It.IsAny<DirectMethodRequest>()))
.ReturnsAsync(directMethodResponse);

var validator = new Mock<IValidator<MethodRequest>>();
validator.Setup(v => v.Validate(It.IsAny<MethodRequest>()));

var testController = new TwinsController(Task.FromResult(edgeHub.Object), validator.Object);
testController.OnActionExecuting(actionExecutingContext);

string toDeviceId = "device1";
string command = "showdown";
string payload = "{ \"prop1\" : \"value1\" }";

var methodRequest = new MethodRequest { MethodName = command, Payload = new JRaw(payload) };
IActionResult actionResult = await testController.InvokeDeviceMethodAsync(toDeviceId, methodRequest);

Assert.NotNull(actionResult);
var jsonResult = actionResult as JsonResult;
Assert.NotNull(jsonResult);
var methodResult = jsonResult.Value as MethodResult;
Assert.NotNull(methodResult);
Assert.Equal(200, methodResult.Status);
Assert.Equal(new JRaw(responsePayload), methodResult.Payload);
}

[Fact]
public async Task TestInvokeMethodOnModuleWithResponse()
{
var identity = Mock.Of<IIdentity>(i => i.Id == "edgedevice/module1");
ActionExecutingContext actionExecutingContext = this.GetActionExecutingContextMock(identity);

string responsePayload = "{ \"resp1\" : \"respvalue1\" }";
var directMethodResponse = new DirectMethodResponse(Guid.NewGuid().ToString(), Encoding.UTF8.GetBytes(responsePayload), 200);
var edgeHub = new Mock<IEdgeHub>();
edgeHub.Setup(e => e.InvokeMethodAsync(It.Is<string>(i => i == identity.Id), It.IsAny<DirectMethodRequest>()))
.ReturnsAsync(directMethodResponse);

var validator = new Mock<IValidator<Http.MethodRequest>>();
validator.Setup(v => v.Validate(It.IsAny<Http.MethodRequest>()));

var testController = new TwinsController(Task.FromResult(edgeHub.Object), validator.Object);
testController.OnActionExecuting(actionExecutingContext);

string toDeviceId = "edgedevice";
string toModuleId = "module2";
string command = "showdown";
string payload = "{ \"prop1\" : \"value1\" }";

var methodRequest = new Http.MethodRequest { MethodName = command, Payload = new JRaw(payload) };
IActionResult actionResult = await testController.InvokeModuleMethodAsync(WebUtility.UrlEncode(toDeviceId), WebUtility.UrlEncode(toModuleId), methodRequest);

Assert.NotNull(actionResult);
var jsonResult = actionResult as JsonResult;
Assert.NotNull(jsonResult);
var methodResult = jsonResult.Value as MethodResult;
Assert.NotNull(methodResult);
Assert.Equal(200, methodResult.Status);
Assert.Equal(new JRaw(responsePayload), methodResult.Payload);
}

ActionExecutingContext GetActionExecutingContextMock(IIdentity identity)
Expand All @@ -101,5 +172,35 @@ ActionExecutingContext GetActionExecutingContextMock(IIdentity identity)
var actionExecutingContext = new ActionExecutingContext(actionContext, Mock.Of<IList<IFilterMetadata>>(), Mock.Of<IDictionary<string, object>>(), new object());
return actionExecutingContext;
}

static IEnumerable<object[]> GetRawJsonData()
{
yield return new object[] { null, null };

yield return new object[] { new byte[0], null};

object obj = new
{
prop1 = "foo",
prop2 = new
{
prop3 = 100
}
};
string json = JsonConvert.SerializeObject(obj);
yield return new object[] { Encoding.UTF8.GetBytes(json), new JRaw(json) };
}

[Unit]
[Theory]
[MemberData(nameof(GetRawJsonData))]
public void GetRawJsonTest(byte[] input, JRaw expectedOutput)
{
// Act
JRaw output = TwinsController.GetRawJson(input);

// Assert
Assert.Equal(expectedOutput, output);
}
}
}

0 comments on commit 7892a98

Please sign in to comment.