Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 67B54200B32 for ; Wed, 8 Jun 2016 22:23:34 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 66EEF160A2E; Wed, 8 Jun 2016 20:23:34 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 3AA54160A5C for ; Wed, 8 Jun 2016 22:23:33 +0200 (CEST) Received: (qmail 38116 invoked by uid 500); 8 Jun 2016 20:23:32 -0000 Mailing-List: contact commits-help@brooklyn.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@brooklyn.apache.org Delivered-To: mailing list commits@brooklyn.apache.org Received: (qmail 38037 invoked by uid 99); 8 Jun 2016 20:23:32 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Jun 2016 20:23:32 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E4DB9E0995; Wed, 8 Jun 2016 20:23:31 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: aledsage@apache.org To: commits@brooklyn.apache.org Date: Wed, 08 Jun 2016 20:23:34 -0000 Message-Id: In-Reply-To: <855487a2c8b643999ad1288bfef0f5ac@git.apache.org> References: <855487a2c8b643999ad1288bfef0f5ac@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [4/8] brooklyn-server git commit: PublicNetworkFaceEnricher: mapping all-matching archived-at: Wed, 08 Jun 2016 20:23:34 -0000 PublicNetworkFaceEnricher: mapping all-matching And update sensor-naming convention. Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/b1dc7d05 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/b1dc7d05 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/b1dc7d05 Branch: refs/heads/master Commit: b1dc7d05cf08c2e7f621514d741f162ea5bf2348 Parents: 2066d4a Author: Aled Sage Authored: Tue Jun 7 14:35:31 2016 +0100 Committer: Aled Sage Committed: Tue Jun 7 14:35:31 2016 +0100 ---------------------------------------------------------------------- .../access/PublicNetworkFaceEnricher.java | 132 +++++++++++++++++-- .../access/PublicNetworkFaceEnricherTest.java | 127 ++++++++++++++++-- 2 files changed, 239 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b1dc7d05/core/src/main/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricher.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricher.java b/core/src/main/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricher.java index 1247930..449692b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricher.java +++ b/core/src/main/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricher.java @@ -28,6 +28,7 @@ import org.apache.brooklyn.api.entity.EntityLocal; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.location.MachineLocation; import org.apache.brooklyn.api.sensor.AttributeSensor; +import org.apache.brooklyn.api.sensor.Sensor; import org.apache.brooklyn.api.sensor.SensorEvent; import org.apache.brooklyn.api.sensor.SensorEventListener; import org.apache.brooklyn.config.ConfigKey; @@ -40,10 +41,15 @@ import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.net.Networking; +import org.apache.brooklyn.util.text.StringPredicates; +import org.apache.brooklyn.util.text.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Lists; import com.google.common.net.HostAndPort; @@ -109,22 +115,72 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { new TypeToken>>() {}, "sensors", "The multiple sensors whose mapped values are to be re-published (with suffix \"mapped.public\"); " - + "either 'sensor' or 'sensors' should be specified"); + + "if neither 'sensor' or 'sensors' is specified, defaults to 'mapAll'"); + + public static ConfigKey MAP_MATCHING = ConfigKeys.newStringConfigKey( + "mapMatching", + "Whether to map all, based on a sensor naming convention (re-published with suffix \"mapped.public\"); " + + "if neither 'sensor' or 'sensors' is specified, defaults to matchin case-insensitive suffix of " + + "'port', 'uri', 'url' or 'endpoint' ", + "(?i).*(port|uri|url|endpoint)"); + + @SuppressWarnings("serial") + public static ConfigKey> SENSOR_NAME_CONVERTER = ConfigKeys.newConfigKey( + new TypeToken>() {}, + "sensorNameConverter", + "The converter to use, to map from the original sensor name to the re-published sensor name", + new SensorNameConverter("public")); public static final ConfigKey PORT_FORWARD_MANAGER = ConfigKeys.newConfigKey( PortForwardManager.class, "portForwardManager", "The PortForwardManager storing the port-mappings; if null, the global instance will be used"); + public static class SensorNameConverter implements Function { + private final String network; + + public SensorNameConverter(String network) { + this.network = network; + } + + @Override + public String apply(String input) { + if (input == null) throw new NullPointerException("Sensor name must not be null"); + String lowerInput = input.toLowerCase(); + if (lowerInput.endsWith("uri")) { + return input + ".mapped." + network; + } else if (lowerInput.endsWith("url")) { + return input + ".mapped." + network; + } else if (lowerInput.endsWith("endpoint")) { + return input + ".mapped." + network; + } else if (lowerInput.endsWith("port")) { + String prefix = input.substring(0, input.length() - "port".length()); + if (prefix.endsWith(".")) prefix = prefix.substring(0, prefix.length() - 1); + return prefix + ".endpoint.mapped." + network; + } else { + return input + ".mapped." + network; + } + } + } + protected Collection> sensors; - protected PortForwardManager.AssociationListener listener; + protected Optional>> mapMatching; + protected Function sensorNameConverter; + protected PortForwardManager.AssociationListener pfmListener; @Override public void setEntity(final EntityLocal entity) { super.setEntity(entity); + checkConfig(); sensors = resolveSensorsConfig(); - + if (sensors.isEmpty()) { + mapMatching = Optional.of(resolveMapMatchingConfig()); + } else { + mapMatching = Optional.absent(); + } + sensorNameConverter = getRequiredConfig(SENSOR_NAME_CONVERTER); + /* * To find the transformed sensor value we need several things to be set. Therefore * subscribe to all of them, and re-compute whenever any of the change. These are: @@ -132,7 +188,7 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { * - The entity to have a machine location (so we can lookup the mapped port association). * - The relevant sensors to have a value, which includes the private port. */ - listener = new PortForwardManager.AssociationListener() { + pfmListener = new PortForwardManager.AssociationListener() { @Override public void onAssociationCreated(PortForwardManager.AssociationMetadata metadata) { Maybe machine = getMachine(); @@ -150,7 +206,7 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { // no-op } }; - getPortForwardManager().addAssociationListener(listener, Predicates.alwaysTrue()); + getPortForwardManager().addAssociationListener(pfmListener, Predicates.alwaysTrue()); subscriptions().subscribe(entity, AbstractEntity.LOCATION_ADDED, new SensorEventListener() { @Override public void onEvent(SensorEvent event) { @@ -166,6 +222,17 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { tryTransform((AttributeSensor)event.getSensor()); }}); } + if (mapMatching.isPresent()) { + Sensor wildcardSensor = null; + subscriptions().subscribe(entity, wildcardSensor, new SensorEventListener() { + @Override public void onEvent(SensorEvent event) { + if (mapMatching.get().apply(event.getSensor())) { + LOG.debug("{} attempting transformations, triggered by sensor-event {}->{}, to {}", + new Object[] {PublicNetworkFaceEnricher.this, event.getSensor().getName(), event.getValue(), entity}); + tryTransform((AttributeSensor)event.getSensor()); + } + }}); + } tryTransformAll(); } @@ -173,8 +240,8 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { @Override public void destroy() { try { - if (listener != null) { - getPortForwardManager().removeAssociationListener(listener); + if (pfmListener != null) { + getPortForwardManager().removeAssociationListener(pfmListener); } } finally { super.destroy(); @@ -182,6 +249,9 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { } protected void tryTransformAll() { + if (!isRunning()) { + return; + } Maybe machine = getMachine(); if (machine.isAbsent()) { return; @@ -195,9 +265,25 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { LOG.warn("Problem transforming sensor "+sensor+" of "+entity, e); } } + if (mapMatching.isPresent()) { + for (Sensor sensor : entity.getEntityType().getSensors()) { + if (sensor instanceof AttributeSensor && mapMatching.get().apply(sensor)) { + try { + tryTransform(machine.get(), (AttributeSensor)sensor); + } catch (Exception e) { + // TODO Avoid repeated logging + Exceptions.propagateIfFatal(e); + LOG.warn("Problem transforming sensor "+sensor+" of "+entity, e); + } + } + } + } } protected void tryTransform(AttributeSensor sensor) { + if (!isRunning()) { + return; + } Maybe machine = getMachine(); if (machine.isAbsent()) { return; @@ -214,7 +300,7 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { if (newVal.isAbsent()) { return; } - AttributeSensor mappedSensor = Sensors.newStringSensor(sensor.getName()+".mapped.public"); + AttributeSensor mappedSensor = Sensors.newStringSensor(sensorNameConverter.apply(sensor.getName())); if (newVal.get().equals(entity.sensors().get(mappedSensor))) { // ignore duplicate return; @@ -358,13 +444,27 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { return portForwardManager; } + protected void checkConfig() { + AttributeSensor sensor = getConfig(SENSOR); + Collection> sensors = getConfig(SENSORS); + Maybe rawMapMatching = config().getRaw(MAP_MATCHING); + String mapMatching = config().get(MAP_MATCHING); + + if (sensor != null && sensors != null && sensors.isEmpty()) { + throw new IllegalStateException(this+" must not have both 'sensor' and 'sensors' config"); + } else if (sensor == null && (sensors == null || sensors.isEmpty())) { + if (Strings.isBlank(mapMatching)) { + throw new IllegalStateException(this+" requires one of 'sensor' or 'sensors' config (when 'mapMatching' is explicitly blank)"); + } + } else if (rawMapMatching.isPresent()) { + throw new IllegalStateException(this+" must not have explicit 'mapMatching', and either of 'sensor' or 'sensors' config"); + } + } + protected Collection> resolveSensorsConfig() { AttributeSensor sensor = getConfig(SENSOR); Collection> sensors = getConfig(SENSORS); - if (!(sensor == null ^ (sensors == null || sensors.isEmpty()))) { - throw new IllegalStateException(this+" requires one of sensor or sensors config"); - } Collection> result = Lists.newArrayList(); if (sensor != null) { AttributeSensor typedSensor = (AttributeSensor) entity.getEntityType().getSensor(sensor.getName()); @@ -379,4 +479,14 @@ public class PublicNetworkFaceEnricher extends AbstractEnricher { } return result; } + + protected Predicate> resolveMapMatchingConfig() { + String regex = getConfig(MAP_MATCHING); + final Predicate namePredicate = StringPredicates.matchesRegex(regex); + return new Predicate>() { + @Override public boolean apply(Sensor input) { + return input != null && namePredicate.apply(input.getName()); + } + }; + } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b1dc7d05/core/src/test/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricherTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricherTest.java b/core/src/test/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricherTest.java index 7e9cf81..cb9226b 100644 --- a/core/src/test/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricherTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/location/access/PublicNetworkFaceEnricherTest.java @@ -18,8 +18,13 @@ */ package org.apache.brooklyn.core.location.access; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; + import java.net.URI; +import java.net.URL; import java.util.List; +import java.util.Map; import org.apache.brooklyn.api.entity.EntitySpec; import org.apache.brooklyn.api.location.LocationSpec; @@ -31,11 +36,13 @@ import org.apache.brooklyn.core.sensor.Sensors; import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.location.ssh.SshMachineLocation; +import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.time.Duration; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; @@ -61,17 +68,23 @@ public class PublicNetworkFaceEnricherTest extends BrooklynAppUnitTestSupport { @DataProvider(name = "variants") public static Object[][] provideVariants() { - AttributeSensor hostAndPortSensor = Sensors.newSensor(HostAndPort.class, "test.hostAndPort"); + AttributeSensor hostAndPortSensor = Sensors.newSensor(HostAndPort.class, "test.endpoint"); List result = Lists.newArrayList(); for (Timing setSensor : Timing.values()) { for (Timing createAssociation : Timing.values()) { for (Timing addLocation : Timing.values()) { - result.add(new Object[] {setSensor, createAssociation, addLocation, Attributes.MAIN_URI, URI.create("http://127.0.0.1:1234/my/path"), "http://mypublichost:5678/my/path"}); - result.add(new Object[] {setSensor, createAssociation, addLocation, TestEntity.NAME, "http://127.0.0.1:1234/my/path", "http://mypublichost:5678/my/path"}); - result.add(new Object[] {setSensor, createAssociation, addLocation, Attributes.HTTP_PORT, 1234, "mypublichost:5678"}); - result.add(new Object[] {setSensor, createAssociation, addLocation, TestEntity.NAME, "1234", "mypublichost:5678"}); - result.add(new Object[] {setSensor, createAssociation, addLocation, TestEntity.NAME, "127.0.0.1:1234", "mypublichost:5678"}); - result.add(new Object[] {setSensor, createAssociation, addLocation, hostAndPortSensor, HostAndPort.fromString("127.0.0.1:1234"), "mypublichost:5678"}); + result.add(new Object[] {setSensor, createAssociation, addLocation, Attributes.MAIN_URI, + URI.create("http://127.0.0.1:1234/my/path"), "main.uri.mapped.public", "http://mypublichost:5678/my/path"}); + result.add(new Object[] {setSensor, createAssociation, addLocation, TestEntity.NAME, + "http://127.0.0.1:1234/my/path", "test.name.mapped.public", "http://mypublichost:5678/my/path"}); + result.add(new Object[] {setSensor, createAssociation, addLocation, Attributes.HTTP_PORT, + 1234, "http.endpoint.mapped.public", "mypublichost:5678"}); + result.add(new Object[] {setSensor, createAssociation, addLocation, TestEntity.NAME, + "1234", "test.name.mapped.public", "mypublichost:5678"}); + result.add(new Object[] {setSensor, createAssociation, addLocation, TestEntity.NAME, + "127.0.0.1:1234", "test.name.mapped.public", "mypublichost:5678"}); + result.add(new Object[] {setSensor, createAssociation, addLocation, hostAndPortSensor, + HostAndPort.fromString("127.0.0.1:1234"), "test.endpoint.mapped.public", "mypublichost:5678"}); } } } @@ -103,7 +116,8 @@ public class PublicNetworkFaceEnricherTest extends BrooklynAppUnitTestSupport { * The sensorVal must include port 1234, so that it will be converted to mypublichost:5678 */ @Test(dataProvider = "variants") - public void testSensorTransformed(Timing setUri, Timing createAssociation, Timing addLocation, AttributeSensor sensor, T sensorVal, String expectedVal) throws Exception { + public void testSensorTransformed(Timing setUri, Timing createAssociation, Timing addLocation, + AttributeSensor sensor, T sensorVal, String targetSensorName, String expectedVal) throws Exception { entity.sensors().set(Attributes.SUBNET_ADDRESS, "127.0.0.1"); if (setUri == Timing.BEFORE) { entity.sensors().set(sensor, sensorVal); @@ -128,7 +142,7 @@ public class PublicNetworkFaceEnricherTest extends BrooklynAppUnitTestSupport { entity.addLocations(ImmutableList.of(machine)); } - EntityAsserts.assertAttributeEqualsEventually(entity, Sensors.newStringSensor(sensor.getName()+".mapped.public"), expectedVal); + EntityAsserts.assertAttributeEqualsEventually(entity, Sensors.newStringSensor(targetSensorName), expectedVal); EntityAsserts.assertAttributeEquals(entity, sensor, sensorVal); } @@ -211,4 +225,99 @@ public class PublicNetworkFaceEnricherTest extends BrooklynAppUnitTestSupport { EntityAsserts.assertAttributeEqualsContinually(ImmutableMap.of("timeout", VERY_SHORT_WAIT), entity, Sensors.newStringSensor(TestEntity.NAME.getName()+".mapped.public"), null); } + + @Test + public void testTransformsAllMatchingSensors() throws Exception { + AttributeSensor stronglyTypedUri = Sensors.newSensor(URI.class, "strongly.typed.uri"); + AttributeSensor stringUri = Sensors.newStringSensor("string.uri"); + AttributeSensor stronglyTypedUrl = Sensors.newSensor(URL.class, "strongly.typed.url"); + AttributeSensor stringUrl = Sensors.newStringSensor("string.url"); + AttributeSensor intPort = Sensors.newIntegerSensor("int.port"); + AttributeSensor stringPort = Sensors.newStringSensor("string.port"); + AttributeSensor hostAndPort = Sensors.newSensor(HostAndPort.class, "hostAndPort.endpoint"); + AttributeSensor stringHostAndPort = Sensors.newStringSensor("stringHostAndPort.endpoint"); + + entity.sensors().set(Attributes.SUBNET_ADDRESS, "127.0.0.1"); + entity.sensors().set(stronglyTypedUri, URI.create("http://127.0.0.1:1234/my/path")); + entity.sensors().set(stringUri, "http://127.0.0.1:1234/my/path"); + entity.sensors().set(stronglyTypedUrl, new URL("http://127.0.0.1:1234/my/path")); + entity.sensors().set(stringUrl, "http://127.0.0.1:1234/my/path"); + entity.sensors().set(intPort, 1234); + entity.sensors().set(stringPort, "1234"); + entity.sensors().set(hostAndPort, HostAndPort.fromParts("127.0.0.1", 1234)); + entity.sensors().set(stringHostAndPort, "127.0.0.1:1234"); + portForwardManager.associate("myPublicIp", HostAndPort.fromParts("mypublichost", 5678), machine, 1234); + entity.addLocations(ImmutableList.of(machine)); + + entity.enrichers().add(EnricherSpec.create(PublicNetworkFaceEnricher.class)); + + assertAttributeEqualsEventually("strongly.typed.uri.mapped.public", "http://mypublichost:5678/my/path"); + assertAttributeEqualsEventually("string.uri.mapped.public", "http://mypublichost:5678/my/path"); + assertAttributeEqualsEventually("strongly.typed.url.mapped.public", "http://mypublichost:5678/my/path"); + assertAttributeEqualsEventually("string.url.mapped.public", "http://mypublichost:5678/my/path"); + assertAttributeEqualsEventually("int.endpoint.mapped.public", "mypublichost:5678"); + assertAttributeEqualsEventually("string.endpoint.mapped.public", "mypublichost:5678"); + assertAttributeEqualsEventually("hostAndPort.endpoint.mapped.public", "mypublichost:5678"); + assertAttributeEqualsEventually("stringHostAndPort.endpoint.mapped.public", "mypublichost:5678"); + } + + @Test + public void testIgnoresNonMatchingSensors() throws Exception { + AttributeSensor sensor1 = Sensors.newSensor(URI.class, "my.different"); + AttributeSensor sensor2 = Sensors.newSensor(URL.class, "my.different2"); + AttributeSensor sensor3 = Sensors.newStringSensor("my.different3"); + AttributeSensor sensor4 = Sensors.newIntegerSensor("my.different4"); + AttributeSensor sensor5 = Sensors.newSensor(HostAndPort.class, "my.different5"); + + entity.sensors().set(Attributes.SUBNET_ADDRESS, "127.0.0.1"); + entity.sensors().set(sensor1, URI.create("http://127.0.0.1:1234/my/path")); + entity.sensors().set(sensor2, new URL("http://127.0.0.1:1234/my/path")); + entity.sensors().set(sensor3, "http://127.0.0.1:1234/my/path"); + entity.sensors().set(sensor4, 1234); + entity.sensors().set(sensor5, HostAndPort.fromParts("127.0.0.1", 1234)); + portForwardManager.associate("myPublicIp", HostAndPort.fromParts("mypublichost", 5678), machine, 1234); + entity.addLocations(ImmutableList.of(machine)); + + entity.enrichers().add(EnricherSpec.create(PublicNetworkFaceEnricher.class)); + + Asserts.succeedsContinually(ImmutableMap.of("timeout", VERY_SHORT_WAIT), new Runnable() { + @Override public void run() { + Map, Object> allSensors = entity.sensors().getAll(); + String errMsg = "sensors="+allSensors; + for (AttributeSensor sensor : allSensors.keySet()) { + String name = sensor.getName(); + assertFalse(name.startsWith("my.different") && sensor.getName().contains("public"), errMsg); + } + }}); + } + + protected void assertAttributeEqualsEventually(String sensorName, String expectedVal) throws Exception { + try { + EntityAsserts.assertAttributeEqualsEventually(entity, Sensors.newStringSensor(sensorName), expectedVal); + } catch (Exception e) { + throw new Exception("Failed assertion for sensor '"+sensorName+"'; attributes are "+entity.sensors().getAll(), e); + } + } + + @Test + public void testSensorNameConverter() throws Exception { + PublicNetworkFaceEnricher enricher = entity.enrichers().add(EnricherSpec.create(PublicNetworkFaceEnricher.class)); + Function converter = enricher.getConfig(PublicNetworkFaceEnricher.SENSOR_NAME_CONVERTER); + + Map testCases = ImmutableMap.builder() + .put("my.uri", "my.uri.mapped.public") + .put("myuri", "myuri.mapped.public") + .put("my.UrI", "my.UrI.mapped.public") + .put("my.url", "my.url.mapped.public") + .put("myurl", "myurl.mapped.public") + .put("my.endpoint", "my.endpoint.mapped.public") + .put("myendpoint", "myendpoint.mapped.public") + .put("my.port", "my.endpoint.mapped.public") + .put("myport", "my.endpoint.mapped.public") + .build(); + + for (Map.Entry entry : testCases.entrySet()) { + assertEquals(converter.apply(entry.getKey()), entry.getValue(), "input="+entry.getKey()); + } + } }