Skip to content

Commit

Permalink
Merge updates in previews/pnpApi to preview (#2014)
Browse files Browse the repository at this point in the history
* fix(iot-device): Fix enumerator implementation to return key-value pairs

* fix(iot-device): Make ClientOptions.PayloadConvention readonly

* fix(iot-device): Fix duplicate property declaration in TestDeviceCallbackHandler - merge issue
  • Loading branch information
abhipsaMisra authored Jun 8, 2021
1 parent 3c14656 commit 0b97aea
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 11 deletions.
7 changes: 4 additions & 3 deletions iothub/device/devdoc/Convention-based operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

```diff
public class ClientOptions {
+ public PayloadConvention PayloadConvention { get; set; }
+ public ClientOptions(PayloadConvention payloadConvention = null);
+ public PayloadConvention PayloadConvention { get; }
}

public class DeviceClient : IDisposable {
Expand Down Expand Up @@ -66,7 +67,7 @@ public class NewtonsoftJsonPayloadSerializer : PayloadSerializer {
public override bool TryGetNestedObjectValue<T>(object nestedObject, string propertyName, out T outValue);
}

public abstract class PayloadCollection : IEnumerable, IEnumerable<object> {
public abstract class PayloadCollection : IEnumerable, IEnumerable<KeyValuePair<string, object>> {
protected PayloadCollection();
public IDictionary<string, object> Collection { get; private set; }
public PayloadConvention Convention { get; internal set; }
Expand All @@ -75,7 +76,7 @@ public abstract class PayloadCollection : IEnumerable, IEnumerable<object> {
public virtual void AddOrUpdate(string key, object value);
public void ClearCollection();
public bool Contains(string key);
public IEnumerator<object> GetEnumerator();
public IEnumerator<KeyValuePair<string, object>> GetEnumerator();
public virtual byte[] GetPayloadObjectBytes();
public virtual string GetSerializedString();
protected void SetCollection(PayloadCollection payloadCollection);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,10 @@ private static async Task<DeviceRegistrationResult> ProvisionDeviceAsync(Paramet
// connection status changes.
private static DeviceClient InitializeDeviceClient(string deviceConnectionString)
{
var options = new ClientOptions
// Specify a custom System.Text.Json based PayloadConvention to be used.
var options = new ClientOptions(SystemTextJsonPayloadConvention.Instance)
{
ModelId = ModelId,

// Specify a custom System.Text.Json based PayloadConvention to be used.
PayloadConvention = SystemTextJsonPayloadConvention.Instance,
};

DeviceClient deviceClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, TransportType.Mqtt, options);
Expand Down
15 changes: 14 additions & 1 deletion iothub/device/src/ClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ namespace Microsoft.Azure.Devices.Client
/// </summary>
public class ClientOptions
{
/// <summary>
/// Initializes an instance of <see cref="ClientOptions"/>.
/// </summary>
/// <param name="payloadConvention">
/// The payload convention to be used to serialize and encode the messages for convention based methods.
/// The default value is set to <see cref="DefaultPayloadConvention"/> which uses the <see cref="NewtonsoftJsonPayloadSerializer"/> serializer
/// and <see cref="Utf8PayloadEncoder"/> encoder.
/// </param>
public ClientOptions(PayloadConvention payloadConvention = default)
{
PayloadConvention = payloadConvention ?? DefaultPayloadConvention.Instance;
}

/// <summary>
/// The DTDL model Id associated with the device or module client instance.
/// This feature is currently supported only over MQTT and AMQP.
Expand Down Expand Up @@ -67,6 +80,6 @@ public class ClientOptions
/// and <see cref="Utf8PayloadEncoder"/> encoder.
/// </para>
/// </remarks>
public PayloadConvention PayloadConvention { get; set; } = DefaultPayloadConvention.Instance;
public PayloadConvention PayloadConvention { get; }
}
}
6 changes: 3 additions & 3 deletions iothub/device/src/PayloadCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Microsoft.Azure.Devices.Client
/// This classes uses the <see cref="NewtonsoftJsonPayloadSerializer"/> and
/// <see cref="Utf8PayloadEncoder"/> based <see cref="DefaultPayloadConvention"/> by default.
/// </remarks>
public abstract class PayloadCollection : IEnumerable<object>
public abstract class PayloadCollection : IEnumerable<KeyValuePair<string, object>>
{
/// <summary>
/// The underlying collection for the payload.
Expand Down Expand Up @@ -166,9 +166,9 @@ public void ClearCollection()
}

/// <inheritdoc />
public IEnumerator<object> GetEnumerator()
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
foreach (object property in Collection)
foreach (KeyValuePair<string, object> property in Collection)
{
yield return property;
}
Expand Down
102 changes: 102 additions & 0 deletions iothub/device/tests/ClientPropertiesTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Text;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.Azure.Devices.Client.Tests
{
[TestClass]
[TestCategory("Unit")]
public class ClientPropertiesTests
{
private const string BoolPropertyName = "boolPropertyName";
private const string DoublePropertyName = "doublePropertyName";
private const string FloatPropertyName = "floatPropertyName";
private const string StringPropertyName = "stringPropertyName";
private const string ObjectPropertyName = "objectPropertyName";
private const string MapPropertyName = "mapPropertyName";

private const bool BoolPropertyValue = false;
private const double DoublePropertyValue = 1.001;
private const float FloatPropertyValue = 1.2f;
private const string StringPropertyValue = "propertyValue";

private const string ComponentName = "testableComponent";

private static readonly CustomClientProperty s_objectPropertyValue = new CustomClientProperty { Id = 123, Name = "testName" };

private static readonly Dictionary<string, object> s_mapPropertyValue = new Dictionary<string, object>
{
{ "key1", "value1" },
{ "key2", 123 },
{ "key3", s_objectPropertyValue }
};

[TestMethod]
public void ClientPropertyCollection_CanEnumerateClientProperties()
{
// arrange
var deviceReportedProperties = new ClientPropertyCollection();
deviceReportedProperties.AddRootProperty(StringPropertyName, StringPropertyValue);
deviceReportedProperties.AddRootProperty(ObjectPropertyName, s_objectPropertyValue);
deviceReportedProperties.AddComponentProperty(ComponentName, BoolPropertyName, BoolPropertyValue);

var serviceUpdateRequestedProperties = new ClientPropertyCollection();
serviceUpdateRequestedProperties.AddRootProperty(DoublePropertyName, DoublePropertyValue);
serviceUpdateRequestedProperties.AddRootProperty(MapPropertyName, s_mapPropertyValue);
serviceUpdateRequestedProperties.AddComponentProperty(ComponentName, FloatPropertyName, FloatPropertyValue);

// act
// The test makes a call to the internal constructor.
// The users will retrieve client properties by calling DeviceClient.GetClientProperties()/ ModuleClient.GetClientProperties().
var clientProperties = new ClientProperties(serviceUpdateRequestedProperties, deviceReportedProperties);

// assert
// These are the device reported property values.
foreach (var deviceReportedKeyValuePairs in clientProperties)
{
if (deviceReportedKeyValuePairs.Key.Equals(StringPropertyName))
{
deviceReportedKeyValuePairs.Value.Should().Be(StringPropertyValue);
}
else if (deviceReportedKeyValuePairs.Key.Equals(ObjectPropertyName))
{
deviceReportedKeyValuePairs.Value.Should().BeEquivalentTo(s_objectPropertyValue);
}
else if (deviceReportedKeyValuePairs.Key.Equals(ComponentName))
{
deviceReportedKeyValuePairs.Value.Should().BeOfType(typeof(Dictionary<string, object>));
var componentDictionary = deviceReportedKeyValuePairs.Value;

componentDictionary.As<Dictionary<string, object>>().TryGetValue(BoolPropertyName, out object outValue).Should().BeTrue();
outValue.Should().Be(BoolPropertyValue);
}
}

// These are the property values for which service has requested an update.
foreach (var updateRequestedKeyValuePairs in clientProperties.Writable)
{
if (updateRequestedKeyValuePairs.Key.Equals(DoublePropertyName))
{
updateRequestedKeyValuePairs.Value.Should().Be(DoublePropertyValue);
}
else if (updateRequestedKeyValuePairs.Key.Equals(MapPropertyName))
{
updateRequestedKeyValuePairs.Value.Should().BeEquivalentTo(s_mapPropertyValue);
}
else if (updateRequestedKeyValuePairs.Key.Equals(ComponentName))
{
updateRequestedKeyValuePairs.Value.Should().BeOfType(typeof(Dictionary<string, object>));
var componentDictionary = updateRequestedKeyValuePairs.Value;

componentDictionary.As<Dictionary<string, object>>().TryGetValue(FloatPropertyName, out object outValue).Should().BeTrue();
outValue.Should().Be(FloatPropertyValue);
}
}
}
}
}

0 comments on commit 0b97aea

Please sign in to comment.