From 367d721212f8f57d86c0a705da479e5ed2df80ec Mon Sep 17 00:00:00 2001 From: timtay-microsoft Date: Mon, 23 Apr 2018 13:32:51 -0700 Subject: [PATCH] fix(iot-service): Fix bug where setting desired properties to null didn't delete them from the device Github Bug #221 --- .../azure/sdk/iot/deps/twin/TwinState.java | 12 +++++- .../sdk/iot/deps/twin/TwinStateTest.java | 41 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/twin/TwinState.java b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/twin/TwinState.java index a91a3e6ea4..15cd9077a0 100644 --- a/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/twin/TwinState.java +++ b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/twin/TwinState.java @@ -175,7 +175,17 @@ public JsonElement toJsonElement() /* SRS_TWIN_STATE_21_003: [If the tags is null, the toJsonElement shall not include the `tags` in the final JSON.] */ /* SRS_TWIN_STATE_21_004: [If the property is null, the toJsonElement shall not include the `properties` in the final JSON.] */ Gson gson = new GsonBuilder().disableHtmlEscaping().create(); - return gson.toJsonTree(this).getAsJsonObject(); + JsonElement json = gson.toJsonTree(this).getAsJsonObject(); + + //since null values are lost when building the json tree, need to manually re-add properties as reported properties + // may have contained a property with a null value. Those must be preserved so users can delete properties + if (json != null && this.properties != null) + { + //Codes_SRS_TWIN_STATE_34_024: [The json element shall include all null desired and reported properties.] + json.getAsJsonObject().add("properties", this.properties.toJsonElement()); + } + + return json; } /** diff --git a/deps/src/test/java/tests/unit/com/microsoft/azure/sdk/iot/deps/twin/TwinStateTest.java b/deps/src/test/java/tests/unit/com/microsoft/azure/sdk/iot/deps/twin/TwinStateTest.java index 3cdbb1bed6..3c3f87c461 100644 --- a/deps/src/test/java/tests/unit/com/microsoft/azure/sdk/iot/deps/twin/TwinStateTest.java +++ b/deps/src/test/java/tests/unit/com/microsoft/azure/sdk/iot/deps/twin/TwinStateTest.java @@ -12,9 +12,7 @@ import org.junit.Test; import tests.unit.com.microsoft.azure.sdk.iot.deps.Helpers; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.*; /** * Unit tests for the TwinState @@ -40,6 +38,15 @@ public class TwinStateTest } }; + private final static TwinCollection PROPERTIES_WITH_NULL_VALUES = new TwinCollection() + { + { + put("prop1", null); + put("prop2", null); + put("prop3", null); + } + }; + private final static String REGISTER_MANAGER_SAMPLE = "\"deviceId\":\"validDeviceId\"," + "\"generationId\":\"validGenerationId\"," + @@ -222,6 +229,34 @@ public void toJsonElementReturnsEmptyJson() Helpers.assertJson(jsonElement.toString(), "{}"); } + //Tests_SRS_TWIN_STATE_34_024: [The json element shall include all null desired and reported properties.] + @Test + public void toJsonElementPreservesNullDesiredProperties() + { + // arrange + TwinState twinState = new TwinState(null, PROPERTIES_WITH_NULL_VALUES, PROPERTIES); + + // act + JsonElement jsonElement = Deencapsulation.invoke(twinState, "toJsonElement"); + + // assert + assertTrue(jsonElement.toString().contains(PROPERTIES_WITH_NULL_VALUES.toString())); + } + + //Tests_SRS_TWIN_STATE_34_024: [The json element shall include all null desired and reported properties.] + @Test + public void toJsonElementPreservesNullReportedProperties() + { + // arrange + TwinState twinState = new TwinState(null, PROPERTIES, PROPERTIES_WITH_NULL_VALUES); + + // act + JsonElement jsonElement = Deencapsulation.invoke(twinState, "toJsonElement"); + + // assert + assertTrue(jsonElement.toString().contains(PROPERTIES_WITH_NULL_VALUES.toString())); + } + /* SRS_TWIN_STATE_21_005: [The getTags shall return a TwinCollection with the stored tags.] */ /* SRS_TWIN_STATE_21_006: [The getDesiredProperty shall return a TwinCollection with the stored desired property.] */ /* SRS_TWIN_STATE_21_007: [The getReportedProperty shall return a TwinCollection with the stored reported property.] */