diff --git a/qa/integration/src/test/resources/features/rest/parsingRequests/RestParsingRequestsContents.feature b/qa/integration/src/test/resources/features/rest/parsingRequests/RestParsingRequestsContents.feature index 6223347d3b4..f04de95dc76 100644 --- a/qa/integration/src/test/resources/features/rest/parsingRequests/RestParsingRequestsContents.feature +++ b/qa/integration/src/test/resources/features/rest/parsingRequests/RestParsingRequestsContents.feature @@ -52,9 +52,33 @@ Feature: REST API tests for parsing of requests api back-end parser (MOXy) should NOT spot error because we are trying to update a property with a "default" value Given Server with host "127.0.0.1" on port "8081" Given An authenticated user - #the json is a huge string but basically it's a complete set of properties for the CredentialService, where the "password.minLength" property we want to set has missing "type" and "value" fields (we want to set an unlimited value for it) + #the json is a huge string but basically it's a complete set of properties for the CredentialService, where the "password.minLength" property we want to set has a finite value (123) + When REST "PUT" call at "/v1/_/serviceConfigurations/org.eclipse.kapua.service.authentication.credential.CredentialService" with JSON "{\"id\": \"org.eclipse.kapua.service.authentication.credential.CredentialService\", \"properties\": {\"property\": [{\"name\": \"lockoutPolicy.resetAfter\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"3800\"]}, {\"name\": \"password.minLength\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"123\"]}, {\"name\": \"lockoutPolicy.lockDuration\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"10800\"]}, {\"name\": \"lockoutPolicy.enabled\", \"array\": false, \"encrypted\": false, \"type\": \"Boolean\", \"value\": [\"true\"]}, {\"name\": \"lockoutPolicy.maxFailures\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"3\"]}]}}" + Then REST response code is 204 + When REST "GET" call at "/v1/_/serviceConfigurations/org.eclipse.kapua.service.authentication.credential.CredentialService" with JSON "" + Then REST response containing text "{\"name\":\"password.minLength\",\"array\":false,\"encrypted\":false,\"type\":\"Integer\",\"value\":[\"123\"]}" + #the json is a huge string but basically it's a complete set of properties for the CredentialService, where the "password.minLength" property we want to set has missing "type" and "value" fields (we want to set an unlimited value for it) When REST "PUT" call at "/v1/_/serviceConfigurations/org.eclipse.kapua.service.authentication.credential.CredentialService" with JSON "{\"id\": \"org.eclipse.kapua.service.authentication.credential.CredentialService\", \"properties\": {\"property\": [{\"name\": \"lockoutPolicy.resetAfter\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"3800\"]}, {\"name\": \"password.minLength\", \"array\": false, \"encrypted\": false}, {\"name\": \"lockoutPolicy.lockDuration\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"10800\"]}, {\"name\": \"lockoutPolicy.enabled\", \"array\": false, \"encrypted\": false, \"type\": \"Boolean\", \"value\": [\"true\"]}, {\"name\": \"lockoutPolicy.maxFailures\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"3\"]}]}}" Then REST response code is 204 + #and now if I get the configuration there will be no value for the password.minLength (aka it's the default one) + When REST "GET" call at "/v1/_/serviceConfigurations/org.eclipse.kapua.service.authentication.credential.CredentialService" with JSON "" + Then REST response containing text "{\"name\":\"password.minLength\",\"array\":false,\"encrypted\":false},{" + + Scenario: Update of "credentialService" configuration using properly type but with a "" value cause I want to set a default value for a property. + Given Server with host "127.0.0.1" on port "8081" + Given An authenticated user + #this is the json above but in the password.minLength now I set type and a finite value (123) + When REST "PUT" call at "/v1/_/serviceConfigurations/org.eclipse.kapua.service.authentication.credential.CredentialService" with JSON "{\"id\": \"org.eclipse.kapua.service.authentication.credential.CredentialService\", \"properties\": {\"property\": [{\"name\": \"lockoutPolicy.resetAfter\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"3800\"]}, {\"name\": \"password.minLength\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"123\"]}, {\"name\": \"lockoutPolicy.lockDuration\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"10800\"]}, {\"name\": \"lockoutPolicy.enabled\", \"array\": false, \"encrypted\": false, \"type\": \"Boolean\", \"value\": [\"true\"]}, {\"name\": \"lockoutPolicy.maxFailures\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"3\"]}]}}" + Then REST response code is 204 + When REST "GET" call at "/v1/_/serviceConfigurations/org.eclipse.kapua.service.authentication.credential.CredentialService" with JSON "" + Then REST response containing text "{\"name\":\"password.minLength\",\"array\":false,\"encrypted\":false,\"type\":\"Integer\",\"value\":[\"123\"]}" + #this is the json above but in the password.minLength now I set type and a "" value to restore property to the default value + When REST "PUT" call at "/v1/_/serviceConfigurations/org.eclipse.kapua.service.authentication.credential.CredentialService" with JSON "{\"id\": \"org.eclipse.kapua.service.authentication.credential.CredentialService\", \"properties\": {\"property\": [{\"name\": \"lockoutPolicy.resetAfter\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"3800\"]}, {\"name\": \"password.minLength\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"\"]}, {\"name\": \"lockoutPolicy.lockDuration\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"10800\"]}, {\"name\": \"lockoutPolicy.enabled\", \"array\": false, \"encrypted\": false, \"type\": \"Boolean\", \"value\": [\"true\"]}, {\"name\": \"lockoutPolicy.maxFailures\", \"array\": false, \"encrypted\": false, \"type\": \"Integer\", \"value\": [\"3\"]}]}}" + Then REST response code is 204 + #and now if I get the configuration there will be no value for the password.minLength (aka it's the default one) + When REST "GET" call at "/v1/_/serviceConfigurations/org.eclipse.kapua.service.authentication.credential.CredentialService" with JSON "" + Then REST response containing text "{\"name\":\"password.minLength\",\"array\":false,\"encrypted\":false},{" + @teardown Scenario: Stop full docker environment diff --git a/service/api/src/main/java/org/eclipse/kapua/model/xml/adapters/XmlPropertiesAdapter.java b/service/api/src/main/java/org/eclipse/kapua/model/xml/adapters/XmlPropertiesAdapter.java index 4b2a8d52765..eb6ab54f302 100644 --- a/service/api/src/main/java/org/eclipse/kapua/model/xml/adapters/XmlPropertiesAdapter.java +++ b/service/api/src/main/java/org/eclipse/kapua/model/xml/adapters/XmlPropertiesAdapter.java @@ -22,6 +22,7 @@ import java.util.Optional; import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.HashMap; public class XmlPropertiesAdapter, V extends XmlPropertyAdapted> extends XmlAdapter> { private final Class propertyClass; @@ -47,16 +48,18 @@ public Map unmarshal(V[] properties) { } }) .filter(adaptedProp -> xmlPropertyAdapters.containsKey((adaptedProp.getType()))) - .collect(Collectors.toMap( - XmlPropertyAdapted::getName, - adaptedProp -> { - final XmlPropertyAdapter xmlPropertyAdapter = xmlPropertyAdapters.get(adaptedProp.getType()); - return xmlPropertyAdapter.unmarshallValues(adaptedProp); - })); + .collect(HashMap::new, + (adaptedPropMap, adaptedProp) -> adaptedPropMap.put(adaptedProp.getName(), extractValueFromXmlProperty(adaptedProp)), + HashMap::putAll); // This is a work-around for Collectors.toMap limitation on null values return unmarshalledProperties; } + private Object extractValueFromXmlProperty(V adaptedProp) { + final XmlPropertyAdapter xmlPropertyAdapter = xmlPropertyAdapters.get(adaptedProp.getType()); + return xmlPropertyAdapter.unmarshallValues(adaptedProp); + } + @Override public V[] marshal(Map props) { final List adaptedProperties = Optional.ofNullable(props) diff --git a/service/api/src/test/java/org/eclipse/kapua/model/xml/adapters/XmlPropertiesAdapterTest.java b/service/api/src/test/java/org/eclipse/kapua/model/xml/adapters/XmlPropertiesAdapterTest.java index a0776ecadf5..31826b8468d 100644 --- a/service/api/src/test/java/org/eclipse/kapua/model/xml/adapters/XmlPropertiesAdapterTest.java +++ b/service/api/src/test/java/org/eclipse/kapua/model/xml/adapters/XmlPropertiesAdapterTest.java @@ -260,4 +260,33 @@ public void testUnmarshallingMissingType() { new TestPropertyAdapted("anotherValue", null, "42") })); } + + //Scenario in which, for example, I update a device configuration with some properties set to the default value (null or "") and some to a defined valued + @Test + public void testUnmarshallingEmptyNullValuesFields() { + final StringPropertyAdapter stringAdapter = Mockito.spy(new StringPropertyAdapter()); + final BooleanPropertyAdapter booleanAdapter = Mockito.spy(new BooleanPropertyAdapter()); + final LongPropertyAdapter longAdapter = Mockito.spy(new LongPropertyAdapter()); + final HashMap adapters = new HashMap() { + { + put(TestTypes.First, stringAdapter); + put(TestTypes.Second, booleanAdapter); + put(TestTypes.Fourth, longAdapter); + } + }; + final XmlPropertiesAdapter instance = new TestPropertiesAdapter(adapters); + final Map got = instance.unmarshal(new TestPropertyAdapted[]{ + new TestPropertyAdapted("aString", TestTypes.First, "TheString"), + new TestPropertyAdapted("emptyValues", TestTypes.Second, "", ""), + new TestPropertyAdapted("emptyValue", TestTypes.Fourth, ""), + new TestPropertyAdapted("nullValue", TestTypes.Fourth, (String) null) + }); + Assert.assertNotNull(got); + Assert.assertEquals(4, got.keySet().size()); + Assert.assertNotNull(got.get("aString")); + Assert.assertArrayEquals(new Boolean[]{null, null}, (Boolean[]) got.get("emptyValues")); + Assert.assertNull(got.get("emptyValue")); + Assert.assertNull(got.get("nullValue")); + } + } \ No newline at end of file