From db8462cf1979ae1412c6092ee567ddf54f0bd9e3 Mon Sep 17 00:00:00 2001 From: Matteo Maiero Date: Sat, 11 Jan 2025 09:38:09 +0100 Subject: [PATCH] feat: Set default web ports for console and rest (#5624) * feat: Set default web ports for console and rest Signed-off-by: MMaiero * Additional changes Signed-off-by: MMaiero * Added defaults Signed-off-by: MMaiero * More changes Signed-off-by: MMaiero * fix: tentative test update Signed-off-by: MMaiero * WIP: refactor configuration service for the self configuring part Signed-off-by: MMaiero * Further cleaning Signed-off-by: MMaiero * Improvement on corner cases Signed-off-by: MMaiero * Added more coverage Signed-off-by: MMaiero * Test updated following comment Signed-off-by: MMaiero --------- Signed-off-by: MMaiero --- .../ConfigurationServiceImpl.java | 179 +++++++++--------- .../rest/configuration/api/PropertyDTO.java | 45 +++-- ...ura.internal.rest.provider.RestService.xml | 1 + .../org/eclipse/kura/web/ConsoleOptions.java | 1 + .../web/SelfConfiguringComponentProperty.java | 74 +++++--- .../requesthandler/RestTransport.java | 27 ++- .../test/ConfigurationRestServiceTest.java | 41 ++++ 7 files changed, 230 insertions(+), 138 deletions(-) diff --git a/kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceImpl.java b/kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceImpl.java index f43103b5bf3..f8e3f9144de 100644 --- a/kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceImpl.java +++ b/kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others + * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.kura.core.configuration; +import static java.util.Objects.isNull; import static java.util.Objects.requireNonNull; import java.io.File; @@ -64,6 +65,7 @@ import org.eclipse.kura.marshalling.Marshaller; import org.eclipse.kura.marshalling.Unmarshaller; import org.eclipse.kura.system.SystemService; +import org.eclipse.kura.util.service.ServiceUtil; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -1232,103 +1234,99 @@ private ComponentConfiguration getConfigurableComponentConfiguration(String pid) private ComponentConfiguration getSelfConfiguringComponentConfiguration(String pid) { ComponentConfiguration cc = null; + final ServiceReference[] refs = ServiceUtil.getServiceReferences(this.bundleContext, + SelfConfiguringComponent.class, null); + try { - ServiceReference[] refs = this.ctx.getBundleContext().getServiceReferences((String) null, null); - if (refs != null) { - for (ServiceReference ref : refs) { - String ppid = (String) ref.getProperty(KURA_SERVICE_PID); - if (pid.equals(ppid)) { - Object obj = this.ctx.getBundleContext().getService(ref); - try { - if (obj instanceof SelfConfiguringComponent) { - SelfConfiguringComponent selfConfigComp = null; - selfConfigComp = (SelfConfiguringComponent) obj; - try { - cc = selfConfigComp.getConfiguration(); - if (cc.getPid() == null || !cc.getPid().equals(pid)) { - logger.error( - "Invalid pid for returned Configuration of SelfConfiguringComponent with pid: " - + pid + ". Ignoring it."); - return null; - } - - OCD ocd = cc.getDefinition(); - if (ocd != null) { - List ads = ocd.getAD(); - - if (ads != null) { - for (AD ad : ads) { - String adId = ad.getId(); - String adType = ad.getType().value(); - - if (adId == null) { - logger.error( - "null required id for AD for returned Configuration of SelfConfiguringComponent with pid: {}", - pid); - return null; - } - if (adType == null) { - logger.error( - "null required type for AD id: {} for returned Configuration of SelfConfiguringComponent with pid: {}", - adId, pid); - return null; - } - - Map props = cc.getConfigurationProperties(); - if (props != null) { - Object value = props.get(adId); - if (value != null) { - String propType; - if (!value.getClass().isArray()) { - propType = value.getClass().getSimpleName(); - } else { - propType = value.getClass().getComponentType() - .getSimpleName(); - } - - try { - logger.debug( - "pid: {}, property name: {}, type: {}, value: {}", - pid, adId, propType, value); - Scalar propertyScalar = Scalar.fromValue(propType); - Scalar adScalar = Scalar.fromValue(adType); - if (propertyScalar != adScalar) { - logger.error( - "Type: {} for property named: {} does not match the AD type: {} for returned Configuration of SelfConfiguringComponent with pid: {}", - new Object[] { propType, adId, adType, pid }); - return null; - } - } catch (IllegalArgumentException e) { - logger.error( - "Invalid class: {} for property named: {} for returned Configuration of SelfConfiguringComponent with pid: " - + pid, - propType, adId); - return null; - } - } - } - } - } - } - } catch (KuraException e) { - logger.error(GETTING_CONFIGURATION_ERROR, pid, e); - } - } else { - logger.error("Component {} is not a SelfConfiguringComponent. Ignoring it.", obj); - } - } finally { - this.ctx.getBundleContext().ungetService(ref); - } + for (ServiceReference ref : refs) { + String ppid = (String) ref.getProperty(KURA_SERVICE_PID); + final SelfConfiguringComponent selfConfigComp = (SelfConfiguringComponent) this.bundleContext + .getService(ref); + if (pid.equals(ppid)) { + + cc = selfConfigComp.getConfiguration(); + if (!isValidSelfConfiguringComponent(pid, cc)) { + return null; } } } - } catch (InvalidSyntaxException e) { + } catch (KuraException e) { logger.error(GETTING_CONFIGURATION_ERROR, pid, e); + } finally { + ServiceUtil.ungetServiceReferences(this.bundleContext, refs); } return cc; } + private boolean isValidSelfConfiguringComponent(String pid, ComponentConfiguration cc) { + + if (isNull(cc) || cc.getPid() == null || !cc.getPid().equals(pid)) { + logger.error( + "Invalid pid for returned Configuration of SelfConfiguringComponent with pid: {}. Ignoring it.", + pid); + return false; + } + + OCD ocd = cc.getDefinition(); + if (isNull(ocd) || isNull(ocd.getAD())) { + return false; + } + + List ads = ocd.getAD(); + + for (AD ad : ads) { + String adId = ad.getId(); + String adType = ad.getType().value(); + + if (isNull(adId) || isNull(adType)) { + logger.error( + "null required type for AD id: {} for returned Configuration of SelfConfiguringComponent with pid: {}", + adId, pid); + return false; + } + + Map props = cc.getConfigurationProperties(); + if (!isNull(props) && !isNull(props.get(adId)) && !isMatchingADType(pid, adId, adType, props.get(adId))) { + return false; + } + } + return true; + } + + private boolean isMatchingADType(String pid, String adId, String adType, Object value) { + boolean result = false; + try { + logger.debug("pid: {}, property name: {}, value: {}", pid, adId, value); + Scalar propertyScalar = getScalarFromObject(value); + Scalar adScalar = Scalar.fromValue(adType); + if (propertyScalar != adScalar) { + logger.error( + "Type: {} for property named: {} does not match the AD type: {} for returned Configuration of SelfConfiguringComponent with pid: {}", + propertyScalar.name(), adId, adType, pid); + } + result = true; + } catch (IllegalArgumentException e) { + logger.error( + "Invalid class for property named: {} for returned Configuration of SelfConfiguringComponent with pid: {}", + adId, pid); + } + return result; + } + + private Scalar getScalarFromObject(Object p) { + Class clazz = p.getClass(); + if (clazz.isArray()) { + Object[] tempArray = (Object[]) p; + if (tempArray.length > 0 && tempArray[0] != null) { + clazz = tempArray[0].getClass(); + } else { + clazz = clazz.getComponentType(); + } + } + return Scalar.fromValue(clazz.getSimpleName()); + } + private TreeSet getSnapshotsInternal() { // keeps the list of snapshots ordered TreeSet ids = new TreeSet<>(); @@ -1901,10 +1899,7 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { + if (obj == null || getClass() != obj.getClass()) { return false; } TrackedComponentFactory other = (TrackedComponentFactory) obj; diff --git a/kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/PropertyDTO.java b/kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/PropertyDTO.java index bcb5261da50..a197879d2fb 100644 --- a/kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/PropertyDTO.java +++ b/kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/PropertyDTO.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others - * + * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others + * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ - * + * * SPDX-License-Identifier: EPL-2.0 - * + * * Contributors: * Eurotech *******************************************************************************/ @@ -45,10 +45,10 @@ public Object getValue() { public void validate() { FailureHandler.requireParameter(this.type, "type"); - if (value instanceof List) { - validateArrayProperty(type, (List) value); + if (this.value instanceof List) { + validateArrayProperty(this.type, (List) this.value); } else { - validateSingletonProperty(type, value); + validateSingletonProperty(this.type, this.value); } } @@ -96,22 +96,35 @@ private static void validateSingletonProperty(final Scalar type, final Object va public static Optional fromConfigurationProperty(final Object property) { - return Optional.ofNullable(property).flatMap(p -> scalarFromClass(p.getClass())) + return Optional.ofNullable(property).flatMap(PropertyDTO::getScalarFromObject) .map(type -> new PropertyDTO(configurationPropertyToDTOProperty(property), type)); } + private static Optional getScalarFromObject(Object p) { + Class clazz = p.getClass(); + if (clazz.isArray()) { + Object[] tempArray = (Object[]) p; + if (tempArray.length > 0 && tempArray[0] != null) { + clazz = tempArray[0].getClass(); + } else { + clazz = clazz.getComponentType(); + } + } + return scalarFromSingletonClass(clazz); + } + public Optional toConfigurationProperty() { - if (value == null) { + if (this.value == null) { return Optional.empty(); } - final Optional asSingleton = singletonToProperty(value, type); + final Optional asSingleton = singletonToProperty(this.value, this.type); if (asSingleton.isPresent()) { return asSingleton; } - return arrayToProperty(value, type); + return arrayToProperty(this.value, this.type); } @SuppressWarnings("unchecked") @@ -233,7 +246,7 @@ private static Optional arrayToProperty(final Object propertyValue, fina } } - public static Optional scalarFormSingletonClass(final Class clazz) { + public static Optional scalarFromSingletonClass(final Class clazz) { final Scalar result; if (clazz == Boolean.class) { @@ -263,14 +276,6 @@ public static Optional scalarFormSingletonClass(final Class clazz) { return Optional.of(result); } - public static Optional scalarFromClass(final Class clazz) { - if (clazz.isArray()) { - return scalarFormSingletonClass(clazz.getComponentType()); - } else { - return scalarFormSingletonClass(clazz); - } - } - private static Object configurationPropertyToDTOProperty(final Object property) { if (property instanceof Password) { return new String(((Password) property).getPassword()); diff --git a/kura/org.eclipse.kura.rest.provider/OSGI-INF/metatype/org.eclipse.kura.internal.rest.provider.RestService.xml b/kura/org.eclipse.kura.rest.provider/OSGI-INF/metatype/org.eclipse.kura.internal.rest.provider.RestService.xml index 84dc1b87d3b..5370f1203de 100644 --- a/kura/org.eclipse.kura.rest.provider/OSGI-INF/metatype/org.eclipse.kura.internal.rest.provider.RestService.xml +++ b/kura/org.eclipse.kura.rest.provider/OSGI-INF/metatype/org.eclipse.kura.internal.rest.provider.RestService.xml @@ -19,6 +19,7 @@ type="Integer" cardinality="3" required="false" + default="443,4443" min="1" max="65535" description="If set to a non empty list, REST API access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. Please make sure that the allowed ports are open in HttpService and Firewall configuration."> diff --git a/kura/org.eclipse.kura.web2/src/main/java/org/eclipse/kura/web/ConsoleOptions.java b/kura/org.eclipse.kura.web2/src/main/java/org/eclipse/kura/web/ConsoleOptions.java index 1d5b30cbf96..4fe76fc314f 100644 --- a/kura/org.eclipse.kura.web2/src/main/java/org/eclipse/kura/web/ConsoleOptions.java +++ b/kura/org.eclipse.kura.web2/src/main/java/org/eclipse/kura/web/ConsoleOptions.java @@ -101,6 +101,7 @@ public class ConsoleOptions { new AdBuilder("allowed.ports", "Allowed ports", Tscalar.INTEGER) // .setRequired(false) // .setCardinality(3) // + .setDefault("443,4443") // .setDescription( "If set to a non empty list, Web Console access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. Please make sure that the allowed ports are open in HttpService and Firewall configuration.") // .build(), // diff --git a/kura/org.eclipse.kura.web2/src/main/java/org/eclipse/kura/web/SelfConfiguringComponentProperty.java b/kura/org.eclipse.kura.web2/src/main/java/org/eclipse/kura/web/SelfConfiguringComponentProperty.java index f271ea17d0f..8dec9e2c40e 100644 --- a/kura/org.eclipse.kura.web2/src/main/java/org/eclipse/kura/web/SelfConfiguringComponentProperty.java +++ b/kura/org.eclipse.kura.web2/src/main/java/org/eclipse/kura/web/SelfConfiguringComponentProperty.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright (c) 2020 Eurotech and/or its affiliates and others - * + * Copyright (c) 2020, 2024 Eurotech and/or its affiliates and others + * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ - * + * * SPDX-License-Identifier: EPL-2.0 - * + * * Contributors: * Eurotech *******************************************************************************/ @@ -52,15 +52,15 @@ private SelfConfiguringComponentProperty(final Tad ad, final Class classz, } public Tad getAd() { - return ad; + return this.ad; } public void fillValue(final Map properties) { - if (value.isPresent() && !properties.containsKey(ad.getId())) { - if (ad.getType() == Scalar.PASSWORD) { - properties.put(this.ad.getId(), new Password(value.get().toString().toCharArray())); + if (this.value.isPresent() && !properties.containsKey(this.ad.getId())) { + if (this.ad.getType() == Scalar.PASSWORD) { + properties.put(this.ad.getId(), new Password(this.value.get().toString().toCharArray())); } else { - properties.put(this.ad.getId(), value.get()); + properties.put(this.ad.getId(), this.value.get()); } } } @@ -74,16 +74,16 @@ public void update(final Map properties) { } else if (this.ad.getType() == Scalar.PASSWORD && providedValue instanceof Password) { final Password providedPassword = (Password) providedValue; - this.value = Optional.of((T) new String((providedPassword.getPassword()))); + this.value = Optional.of((T) new String(providedPassword.getPassword())); } } public T get() { - return value.orElseThrow(() -> new IllegalStateException("property value has not been set")); + return this.value.orElseThrow(() -> new IllegalStateException("property value has not been set")); } public Optional getOptional() { - return value; + return this.value; } private static void check(final Scalar scalar, final int cardinality, final Class clazz) { @@ -130,19 +130,19 @@ private static void check(final Scalar scalar, final int cardinality, final Clas private Object extractScalar(final Scalar scalar, final String value) { if (scalar == Scalar.BOOLEAN) { - return (Boolean) Boolean.parseBoolean(value); + return Boolean.parseBoolean(value); } else if (scalar == Scalar.BYTE) { - return (Boolean) Boolean.parseBoolean(value); + return Byte.parseByte(value); } else if (scalar == Scalar.CHAR) { - return (Character) value.charAt(0); + return value.charAt(0); } else if (scalar == Scalar.DOUBLE) { - return (Double) Double.parseDouble(value); + return Double.parseDouble(value); } else if (scalar == Scalar.FLOAT) { - return (Float) Float.parseFloat(value); + return Float.parseFloat(value); } else if (scalar == Scalar.INTEGER) { - return (Integer) Integer.parseInt(value); + return Integer.parseInt(value); } else if (scalar == Scalar.LONG) { - return (Long) Long.parseLong(value); + return Long.parseLong(value); } else if (scalar == Scalar.PASSWORD) { try { return new String(unwrapCryptoService().encryptAes(value.toCharArray())); @@ -150,20 +150,44 @@ private Object extractScalar(final Scalar scalar, final String value) { throw new IllegalStateException("failed to encrypt password", e); } } else if (scalar == Scalar.SHORT) { - return (Short) Short.parseShort(value); + return Short.parseShort(value); } else if (scalar == Scalar.STRING) { - return (String) value; + return value; + } else { + throw new IllegalArgumentException(scalar == null ? null : scalar.toString()); + } + } + + private Object createScalarArray(final Scalar scalar) { + if (scalar == Scalar.BOOLEAN) { + return new Boolean[0]; + } else if (scalar == Scalar.BYTE) { + return new Byte[0]; + } else if (scalar == Scalar.CHAR) { + return new Character[0]; + } else if (scalar == Scalar.DOUBLE) { + return new Double[0]; + } else if (scalar == Scalar.FLOAT) { + return new Float[0]; + } else if (scalar == Scalar.INTEGER) { + return new Integer[0]; + } else if (scalar == Scalar.LONG) { + return new Long[0]; + } else if (scalar == Scalar.SHORT) { + return new Short[0]; + } else if (scalar == Scalar.STRING || scalar == Scalar.PASSWORD) { + return new String[0]; } else { throw new IllegalArgumentException(scalar == null ? null : scalar.toString()); } } private CryptoService unwrapCryptoService() { - if (!cryptoService.isPresent()) { + if (!this.cryptoService.isPresent()) { throw new IllegalArgumentException("CryptoService is required for defining a password property"); } - return cryptoService.get(); + return this.cryptoService.get(); } private Optional extractDefault(final AD ad) { @@ -180,10 +204,10 @@ private Optional extractDefault(final AD ad) { if (cardinality == 0) { return Optional.of((T) extractScalar(scalar, defaultValue)); } else { - final List result = COMMA.splitAsStream(defaultValue).map(String::trim).filter(String::isEmpty) + final List result = COMMA.splitAsStream(defaultValue).map(String::trim).filter(s -> !s.isEmpty()) .map(s -> extractScalar(scalar, s)).collect(Collectors.toList()); - return Optional.of((T) result.toArray()); + return Optional.of((T) result.toArray((T[]) createScalarArray(scalar))); } } diff --git a/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/RestTransport.java b/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/RestTransport.java index d2e11c95f27..6170ea823c9 100644 --- a/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/RestTransport.java +++ b/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/RestTransport.java @@ -28,14 +28,18 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Optional; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import org.apache.commons.io.IOUtils; +import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.ConfigurableComponent; +import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.core.testutil.service.ServiceUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,6 +74,12 @@ public void init() { } try { + final ConfigurationService configurationService = trackService(ConfigurationService.class); + Map restServiceConfiguration = initialRestServiceConfiguration(); + + ServiceUtil.updateComponentConfiguration(configurationService, "org.eclipse.kura.internal.rest.provider.RestService", restServiceConfiguration).get(30, + TimeUnit.SECONDS); + waitPortOpen("localhost", 8080, 3, TimeUnit.MINUTES); ServiceUtil @@ -78,7 +88,7 @@ public void init() { .get(1, TimeUnit.MINUTES); Thread.sleep(1000); - + initialized = true; } catch (final InterruptedException e) { Thread.currentThread().interrupt(); @@ -87,6 +97,21 @@ public void init() { throw new IllegalStateException(e); } } + + private T trackService(final Class classz) + throws InterruptedException, ExecutionException, TimeoutException { + return ServiceUtil + .trackService(classz, Optional.empty()).get(30, TimeUnit.SECONDS); + } + + private Map initialRestServiceConfiguration() { + + final Map restServiceConfiguration = new HashMap<>(); + + restServiceConfiguration.put("allowed.ports", new Integer[0]); + + return restServiceConfiguration; + } public static void waitPortOpen(final String host, final int port, final long timeout, final TimeUnit timeoutUnit) throws InterruptedException { diff --git a/kura/test/org.eclipse.kura.rest.configuration.provider.test/src/main/java/org/eclipse/kura/rest/configuration/provider/test/ConfigurationRestServiceTest.java b/kura/test/org.eclipse.kura.rest.configuration.provider.test/src/main/java/org/eclipse/kura/rest/configuration/provider/test/ConfigurationRestServiceTest.java index b71ea446e3e..a5960c44373 100644 --- a/kura/test/org.eclipse.kura.rest.configuration.provider.test/src/main/java/org/eclipse/kura/rest/configuration/provider/test/ConfigurationRestServiceTest.java +++ b/kura/test/org.eclipse.kura.rest.configuration.provider.test/src/main/java/org/eclipse/kura/rest/configuration/provider/test/ConfigurationRestServiceTest.java @@ -257,6 +257,17 @@ public void testGetIntegerProperty() throws KuraException { thenTestPropertyTypeIs(Json.value("INTEGER")); thenTestPropertyValueIs(Json.value(123)); } + + @Test + public void testGetShortProperty() throws KuraException { + givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.SHORT, (short) 123); + + whenRequestIsPerformed(new MethodSpec("GET"), "/configurableComponents/configurations"); + + thenRequestSucceeds(); + thenTestPropertyTypeIs(Json.value("SHORT")); + thenTestPropertyValueIs(Json.value(123)); + } @Test public void testGetLongProperty() throws KuraException { @@ -408,6 +419,17 @@ public void testGetIntegerArrayProperty() throws KuraException { thenTestPropertyTypeIs(Json.value("INTEGER")); thenTestPropertyValueIs(Json.array(1, 2, 3)); } + + @Test + public void testGetShortArrayProperty() throws KuraException { + givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.SHORT, new Short[] { 1, 2, 3 }); + + whenRequestIsPerformed(new MethodSpec("GET"), "/configurableComponents/configurations"); + + thenRequestSucceeds(); + thenTestPropertyTypeIs(Json.value("SHORT")); + thenTestPropertyValueIs(Json.array(1, 2, 3)); + } @Test public void testGetLongArrayProperty() throws KuraException { @@ -510,6 +532,15 @@ public void testUpdateIntegerProperty() throws KuraException { thenRequestSucceeds(); thenReceivedPropertiesForPidContains("foo", "testProp", 123); } + + @Test + public void testUpdateShortProperty() throws KuraException { + whenRequestIsPerformed(new MethodSpec("PUT"), "/configurableComponents/configurations/_update", "{\"configs\":[" + + "{\"pid\":\"foo\"," + "properties: {\"testProp\":{\"type\":\"SHORT\",\"value\":123}}" + "}" + "]}"); + + thenRequestSucceeds(); + thenReceivedPropertiesForPidContains("foo", "testProp", (short) 123); + } @Test public void testUpdateLongProperty() throws KuraException { @@ -600,6 +631,16 @@ public void testUpdateIntegerArrayProperty() throws KuraException { thenRequestSucceeds(); thenReceivedPropertiesForPidContainsArray("foo", "testProp", new Integer[] { 1, 2, 3 }); } + + @Test + public void testUpdateShortArrayProperty() throws KuraException { + whenRequestIsPerformed(new MethodSpec("PUT"), "/configurableComponents/configurations/_update", + "{\"configs\":[" + "{\"pid\":\"foo\"," + + "properties: {\"testProp\":{\"type\":\"SHORT\",\"value\":[1,2,3]}}" + "}" + "]}"); + + thenRequestSucceeds(); + thenReceivedPropertiesForPidContainsArray("foo", "testProp", new Short[] { 1, 2, 3 }); + } @Test public void testUpdateLongArrayProperty() throws KuraException {