From e6ebe4ff7aaf894800b3c65bdbb318494b42cc9b Mon Sep 17 00:00:00 2001 From: Jeff Mesnil Date: Thu, 14 Feb 2019 10:51:47 +0100 Subject: [PATCH 1/2] Support variable evaluation * Spec * Update specification with Variable Evaluation chapter * Introduce mp.config.evaluateVariables property to support previous behaviour. * Add a note about backwards compatibilty * API * add ConfigBuilder#evaluateVariables * TCK * Add VariableEvaluationTest to the TCK to validate variable evaluation Signed-off-by: Jeff Mesnil --- .../eclipse/microprofile/config/Config.java | 4 - .../config/ConfigAccessorBuilder.java | 2 +- .../config/inject/ConfigProperty.java | 2 +- .../config/spi/ConfigBuilder.java | 13 + .../microprofile-config-spec.asciidoc | 2 + spec/src/main/asciidoc/release_notes.asciidoc | 11 +- .../asciidoc/variable-evaluation.asciidoc | 123 ++++++++ .../config/tck/ConfigAccessorTest.java | 5 +- .../config/tck/VariableEvaluationTest.java | 270 ++++++++++++++++++ .../configsources/KeyValuesConfigSource.java | 62 ++++ 10 files changed, 481 insertions(+), 13 deletions(-) create mode 100644 spec/src/main/asciidoc/variable-evaluation.asciidoc create mode 100644 tck/src/main/java/org/eclipse/microprofile/config/tck/VariableEvaluationTest.java create mode 100644 tck/src/main/java/org/eclipse/microprofile/config/tck/configsources/KeyValuesConfigSource.java diff --git a/api/src/main/java/org/eclipse/microprofile/config/Config.java b/api/src/main/java/org/eclipse/microprofile/config/Config.java index 6d684ed3..3bba30ac 100644 --- a/api/src/main/java/org/eclipse/microprofile/config/Config.java +++ b/api/src/main/java/org/eclipse/microprofile/config/Config.java @@ -102,8 +102,6 @@ public interface Config { * * If this method gets used very often then consider to locally store the configured value. * - *

Note that no variable replacement like in {@link ConfigAccessorBuilder#evaluateVariables(boolean)} will be performed! - * * @param the property type * @param propertyName * The configuration propertyName. @@ -121,8 +119,6 @@ public interface Config { * * If this method is used very often then consider to locally store the configured value. * - *

Note that no variable replacement like in {@link ConfigAccessorBuilder#evaluateVariables(boolean)} will be performed! - * * @param the property type * @param propertyName * The configuration propertyName. diff --git a/api/src/main/java/org/eclipse/microprofile/config/ConfigAccessorBuilder.java b/api/src/main/java/org/eclipse/microprofile/config/ConfigAccessorBuilder.java index bbd6a708..92dfb3ad 100644 --- a/api/src/main/java/org/eclipse/microprofile/config/ConfigAccessorBuilder.java +++ b/api/src/main/java/org/eclipse/microprofile/config/ConfigAccessorBuilder.java @@ -98,7 +98,7 @@ public interface ConfigAccessorBuilder { * {@code "mycompany.some.url"} would be: * {@code "http://localhost:8081/some/path"} * - *

ATTENTION: This defaults to {@code true}! That means variable replacement is enabled by default!

+ * ATTENTION: This defaults to {@code true}! That means variable evaluation is enabled by default! * * @param evaluateVariables whether to evaluate variables in values or not * diff --git a/api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperty.java b/api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperty.java index e8d36511..2fa4caf3 100644 --- a/api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperty.java +++ b/api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperty.java @@ -140,7 +140,7 @@ /** * @see org.eclipse.microprofile.config.ConfigAccessorBuilder#evaluateVariables(boolean) - * @return whether variable replacement is enabled. Defaults to {@code true}. + * @return whether variable evaluation is enabled. Defaults to {@code true}. */ @Nonbinding boolean evaluateVariables() default true; diff --git a/api/src/main/java/org/eclipse/microprofile/config/spi/ConfigBuilder.java b/api/src/main/java/org/eclipse/microprofile/config/spi/ConfigBuilder.java index 4ab84053..c2fc64da 100644 --- a/api/src/main/java/org/eclipse/microprofile/config/spi/ConfigBuilder.java +++ b/api/src/main/java/org/eclipse/microprofile/config/spi/ConfigBuilder.java @@ -95,6 +95,19 @@ public interface ConfigBuilder { */ ConfigBuilder withConverters(Converter... converters); + /** + * Determines whether variable evaluation is enabled. + * + * This enables variable evaluation globally for any configuration values retrieved using the + * {@link Config#getValue(String, Class)} and {@link Config#getOptionalValue(String, Class)} methods + * on `Config` built by this builder. + * + * This setting has no impact on {@link org.eclipse.microprofile.config.ConfigAccessorBuilder#evaluateVariables(boolean)}. + * + * @param evaluateVariables {@code true} to evaluate variables + * @return the ConfigBuilder + */ + ConfigBuilder evaluateVariables(boolean evaluateVariables); /** * Add the specified {@link Converter} for the given type. diff --git a/spec/src/main/asciidoc/microprofile-config-spec.asciidoc b/spec/src/main/asciidoc/microprofile-config-spec.asciidoc index 61932d89..1ad783b9 100644 --- a/spec/src/main/asciidoc/microprofile-config-spec.asciidoc +++ b/spec/src/main/asciidoc/microprofile-config-spec.asciidoc @@ -44,6 +44,8 @@ include::configprovider.asciidoc[] include::configsources.asciidoc[] +include::variable-evaluation.asciidoc[] + include::converters.asciidoc[] include::configaccessor.asciidoc[] diff --git a/spec/src/main/asciidoc/release_notes.asciidoc b/spec/src/main/asciidoc/release_notes.asciidoc index 961935e6..b45d1ba9 100644 --- a/spec/src/main/asciidoc/release_notes.asciidoc +++ b/spec/src/main/asciidoc/release_notes.asciidoc @@ -112,16 +112,19 @@ Java2 security related change (link:https://github.com/eclipse/microprofile-conf [[release_notes_14]] == Release Notes for MicroProfile Config 1.4 -The following changes occurred in the 1.4 release, compared to 1.2 +The following changes occurred in the 1.4 release, compared to 1.3 -A full list of changes may be found on the link:https://github.com/eclipse/microprofile-config/milestone/5?closed=1[MicroProfile Config 1.4 Milestone] +A full list of changes may be found on the link:https://github.com/eclipse/microprofile-config/milestone/7[MicroProfile Config 1.4 Milestone] === API/SPI Changes -MicroProfile 1.4 introduced a way to deal with dynamic values. +MicroProfile Config 1.4 introduced a way to deal with dynamic values. To support this feature from the user side we introduced the `ConfigAccessor`. + We also introduced a way to have `ConfigSources` notify the `Config` about an underlying attribute change. +MicroProfile Config now supports variable evaluation so that a Config property value can refer to other config properties. + === Functional Changes -OSGi compatibility got improved. \ No newline at end of file +OSGi compatibility got improved. diff --git a/spec/src/main/asciidoc/variable-evaluation.asciidoc b/spec/src/main/asciidoc/variable-evaluation.asciidoc new file mode 100644 index 00000000..829c65e5 --- /dev/null +++ b/spec/src/main/asciidoc/variable-evaluation.asciidoc @@ -0,0 +1,123 @@ +// +// Copyright (c) 2016-2019 Contributors to the Eclipse Foundation +// +// See the NOTICE file(s) distributed with this work for additional +// information regarding copyright ownership. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +[[variable-evaluation]] +== Variable Evaluation + +The value of a configuration property can contains a variable corresponding to another configuration property. +This variable is _evaluated_ to be replaced by its own value when the original property is returned. + +For example, let's define a `server.url` property: + +[source] +---- +server.url=http://${server.host}:{server.port}/endpoint +---- + +When the Config API returns the value of `server.url`, it evaluates any variable (such as `server.host` and `server.port`) to replace +them with their value. + +If these properties are also defined: + +[source] +---- +server.host=example.org +server.port=8080 +---- + +The `server.url` value returned by the Config API is `http://example.org:8080/endpoint`. + +[NOTE] +==== +Backwards Compatibility + +Variable evaluation is not backwards compatible. +Previous version of MicroProfile Config would not evalute the variables and would return the value `http://${server.host}:{server.port}/endpoint`. + +Implementation of MicroProfile Config MUST provide a way to disable variable evaluation to provide backwards compatibility. + +The property `mp.config.evaluateVariables` can be configured as a boolean in one of the 3 default `ConfigSource` (environment variables, system properties, +`META-INF/microprofile-config.properties`). Its value will be used by the MicroProfile Config implementation to _globally_ enable or disable variable evaluation. +In the absence of this property, variable evaluation is enabled. +==== + +--- + + +=== Variable Syntax + +The syntax to use a variable is `${key}` for a _required_ config property and `${:}` for +an _optional_ config property. + +If the variable is required , by using `${key}`, a config property with the name `key` MUST be present in the Config to be evaluated, otherwise, the +Config API will throw a `NoSuchElementException` (or an `Optional.empty()` value). + +For example, let's define the configuration properties: + +[source] +---- +server.url=http://${server.host}:{server.port}/endpoint +server.host=example.org +---- + +A call to `Config.getValue("server.url", String.class)` will throw a `NoSuchElementException` since the +`server.port` property is not configured. +Likewise, a call to `Config.getOptionalValue("server.url", String.class)` will return an `Optional.empty()`. + +==== Default value + +A variable can define a _default_ value to be evaluated if the corresponding config property is not present. + +For example, let's define the configuration properties: + +[source] +---- +server.url=http://${server.host:example.org}:{server.port:8080}/endpoint +---- + +If neither `server.host` nor `server.port` config properties are present, the Config API will use the variable's default values and will return +`http://example.org:8080/endpoint` for the `server.url`. + +It is possible to define an empty default value for a variable. +If the key is not present in the Config, it will not be evaluated. + +For example, let's define the configuration properties: + +[source] +---- +server.url=http://example.org:8080/endpoint#${server.anchor:} +---- + +When the `server.anchor` configuration property is not present, the Config API will return +`http://example.org:8080/endpoint#` for the `server.url`. + +If the `server.anchor` is configured with the value `id123`, the Config API will return +`http://example.org:8080/endpoint#id123` for the `server.url`. + +A default value does not support variable evaluation (a default value is _raw_). + +For example, let's define the configuration properties: + +[source] +---- +foo.one=Hello +foo.two=${foo.three:${foo.one}} +---- + +`foo.two` defines a variable which key is `foo.three` and which default value is `${foo.one}`. +If the config property `foo.three` is not present, the Config API will return `${foo.one}` for the `foo.two` config property. diff --git a/tck/src/main/java/org/eclipse/microprofile/config/tck/ConfigAccessorTest.java b/tck/src/main/java/org/eclipse/microprofile/config/tck/ConfigAccessorTest.java index 546979e2..9bc8148b 100644 --- a/tck/src/main/java/org/eclipse/microprofile/config/tck/ConfigAccessorTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/config/tck/ConfigAccessorTest.java @@ -101,12 +101,11 @@ public void testVariableReplacement() { Assert.assertEquals(config.access("tck.config.variable.secondEndpoint", String.class).build().getValue(), "http://some.host.name/endpointTwo"); - // variables in Config.getValue and getOptionalValue do not get evaluated otoh Assert.assertEquals(config.getValue("tck.config.variable.firstEndpoint", String.class), - "http://${tck.config.variable.baseHost}/endpointOne"); + "http://some.host.name/endpointOne"); Assert.assertEquals(config.getOptionalValue("tck.config.variable.firstEndpoint", String.class).get(), - "http://${tck.config.variable.baseHost}/endpointOne"); + "http://some.host.name/endpointOne"); } @Test diff --git a/tck/src/main/java/org/eclipse/microprofile/config/tck/VariableEvaluationTest.java b/tck/src/main/java/org/eclipse/microprofile/config/tck/VariableEvaluationTest.java new file mode 100644 index 00000000..baffbe78 --- /dev/null +++ b/tck/src/main/java/org/eclipse/microprofile/config/tck/VariableEvaluationTest.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2016-2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.eclipse.microprofile.config.tck; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.fail; + +import java.util.NoSuchElementException; + +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.spi.ConfigProviderResolver; +import org.eclipse.microprofile.config.tck.base.AbstractTest; +import org.eclipse.microprofile.config.tck.configsources.KeyValuesConfigSource; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.testng.Arquillian; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.testng.annotations.Test; + +public class VariableEvaluationTest extends Arquillian { + + @Deployment + public static WebArchive deploy() { + JavaArchive testJar = ShrinkWrap + .create(JavaArchive.class, "VariableEvaluationTest.jar") + .addPackage(AbstractTest.class.getPackage()) + .addClass(KeyValuesConfigSource.class) + .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml") + .as(JavaArchive.class); + + WebArchive war = ShrinkWrap + .create(WebArchive.class, "VariableEvaluationTest.war") + .addAsLibrary(testJar); + return war; + } + + @Test + public void testDefaultVariableEvaluation() { + Config config = buildConfig( + "foo.one", "value", + "foo.two", "${foo.one}", + "foo.three", "+${foo.two}+"); + + assertEquals(config.getValue("foo.one", String.class), "value"); + + assertEquals(config.getValue("foo.two", String.class), "value"); + assertEquals(config.access("foo.two", String.class).build().getValue(), "value"); + assertEquals(config.access("foo.two", String.class).evaluateVariables(false).build().getValue(), "${foo.one}"); + + assertEquals(config.getValue("foo.three", String.class), "+value+"); + assertEquals(config.access("foo.three", String.class).build().getValue(), "+value+"); + assertEquals(config.access("foo.three", String.class).evaluateVariables(false).build().getValue(), "+${foo.two}+"); + + } + + @Test + public void testVariableEvaluationWithDefaults() { + Config config = buildConfig( + "foo.two", "${foo.one:value}", + "foo.three", "+${foo.two}+"); + + assertFalse(config.getOptionalValue("foo.one", String.class).isPresent()); + + assertEquals(config.getValue("foo.two", String.class), "value"); + assertEquals(config.access("foo.two", String.class).build().getValue(), "value"); + assertEquals(config.access("foo.two", String.class).evaluateVariables(false).build().getValue(), "${foo.one:value}"); + + assertEquals(config.getValue("foo.three", String.class), "+value+"); + assertEquals(config.access("foo.three", String.class).build().getValue(), "+value+"); + assertEquals(config.access("foo.three", String.class).evaluateVariables(false).build().getValue(), "+${foo.two}+"); + } + + @Test + public void testVariableEvaluationWithMissingProperty() { + Config config = buildConfig( + "foo.two", "${foo.one}suffix", + "foo.three", "+${foo.two}+"); + + assertFalse(config.getOptionalValue("foo.two", String.class).isPresent()); + try { + config.getValue("foo.two", String.class); + fail("Expected exception"); + } + catch (NoSuchElementException expected) { + // OK + } + try { + config.access("foo.two", String.class).build().getValue(); + fail("Expected exception"); + } + catch (NoSuchElementException expected) { + // OK + } + assertEquals(config.access("foo.two", String.class).evaluateVariables(false).build().getValue(), "${foo.one}suffix"); + + + assertFalse(config.getOptionalValue("foo.three", String.class).isPresent()); + try { + config.getValue("foo.three", String.class); + fail("Expected exception"); + } + catch (NoSuchElementException expected) { + // OK + } + try { + config.access("foo.tree", String.class).build().getValue(); + fail("Expected exception"); + } + catch (NoSuchElementException expected) { + // OK + } + assertEquals(config.access("foo.three", String.class).evaluateVariables(false).build().getValue(), "+${foo.two}+"); + + } + + @Test + public void testVariableEvaluationWithMissingOptionalProperty() { + Config config = buildConfig( + "foo.two", "${foo.one:}suffix", + "foo.three", "+${foo.two}+"); + + assertFalse(config.getOptionalValue("foo.one", String.class).isPresent()); + + assertEquals(config.getValue("foo.two", String.class), "suffix"); + assertEquals(config.access("foo.two", String.class).build().getValue(), "suffix"); + assertEquals(config.access("foo.two", String.class).evaluateVariables(false).build().getValue(), "${foo.one:}suffix"); + + assertEquals(config.getValue("foo.three", String.class), "+suffix+"); + assertEquals(config.access("foo.three", String.class).build().getValue(), "+suffix+"); + assertEquals(config.access("foo.three", String.class).evaluateVariables(false).build().getValue(), "+${foo.two}+"); + } + + @Test + public void testVariableEvaluationWithOptionalProperty() { + Config config = buildConfig( + "foo.one", "value", + "foo.two", "${foo.one:}_suffix", + "foo.three", "+value_suffix+"); + + assertEquals(config.getValue("foo.two", String.class), "value_suffix"); + assertEquals(config.access("foo.two", String.class).build().getValue(), "value_suffix"); + assertEquals(config.access("foo.two", String.class).evaluateVariables(false).build().getValue(), "${foo.one:}_suffix"); + + assertEquals(config.getValue("foo.three", String.class), "+value_suffix+"); + assertEquals(config.access("foo.three", String.class).build().getValue(), "+value_suffix+"); + assertEquals(config.access("foo.three", String.class).evaluateVariables(false).build().getValue(), "+value_suffix+"); + } + + @Test + public void testVariableEvaluationWithOptionalPropertyAndDefault() { + Config config = buildConfig( + "foo.two", "${foo.one:value}_suffix", + "foo.three", "+${foo.two}+"); + + assertFalse(config.getOptionalValue("foo.one", String.class).isPresent()); + + assertEquals(config.getValue("foo.two", String.class), "value_suffix"); + assertEquals(config.access("foo.two", String.class).build().getValue(), "value_suffix"); + assertEquals(config.access("foo.two", String.class).evaluateVariables(false).build().getValue(), "${foo.one:value}_suffix"); + + assertEquals(config.getValue("foo.three", String.class), "+value_suffix+"); + assertEquals(config.access("foo.three", String.class).build().getValue(), "+value_suffix+"); + assertEquals(config.access("foo.three", String.class).evaluateVariables(false).build().getValue(), "+${foo.two}+"); + } + + @Test + public void testRecursiveVariableEvaluation() { + Config config = buildConfig( + "foo.one", "${foo.two}", + "foo.two", "${foo.one}"); + + try { + config.getOptionalValue("foo.one", String.class); + fail("Expected exception"); + } + catch (IllegalArgumentException expected) { + // OK + } + + try { + config.getValue("foo.one", String.class); + fail("Expected exception"); + } + catch (IllegalArgumentException expected) { + // OK + } + try { + config.access("foo.one", String.class).build().getValue(); + fail("Expected exception"); + } + catch (IllegalArgumentException expected) { + // OK + } + assertEquals(config.access("foo.one", String.class).evaluateVariables(false).build().getValue(), "${foo.two}"); + + + try { + config.getOptionalValue("foo.two", String.class); + fail("Expected exception"); + } + catch (IllegalArgumentException expected) { + // OK + } + try { + config.getValue("foo.two", String.class); + fail("Expected exception"); + } + catch (IllegalArgumentException expected) { + // OK + } + try { + config.access("foo.two", String.class).build().getValue(); + fail("Expected exception"); + } + catch (IllegalArgumentException expected) { + // OK + } + assertEquals(config.access("foo.two", String.class).evaluateVariables(false).build().getValue(), "${foo.one}"); + } + + @Test + public void testDefaultValueIsNotEvaluated() { + Config config = buildConfig( + "foo.one", "value", + "foo.two", "${foo.three:${foo.one}}"); + + assertEquals(config.getValue("foo.two", String.class), "${foo.one}"); + assertEquals(config.access("foo.two", String.class).build().getValue(), "${foo.one}"); + assertEquals(config.access("foo.two", String.class).evaluateVariables(false).build().getValue(), "${foo.three:${foo.one}}"); + + } + + @Test + public void testConfigBuilderDisableVariableEvaluation() { + Config config = ConfigProviderResolver.instance().getBuilder() + .evaluateVariables(false) + .withSources(KeyValuesConfigSource.config( + "foo.one", "value", + "foo.two", "${foo.one}" + )) + .build(); + + assertEquals(config.getValue("foo.two", String.class), "${foo.one}"); + } + + private static Config buildConfig(String... keyValues) { + return ConfigProviderResolver.instance().getBuilder() + .withSources(KeyValuesConfigSource.config(keyValues)) + .build(); + } +} diff --git a/tck/src/main/java/org/eclipse/microprofile/config/tck/configsources/KeyValuesConfigSource.java b/tck/src/main/java/org/eclipse/microprofile/config/tck/configsources/KeyValuesConfigSource.java new file mode 100644 index 00000000..b186e272 --- /dev/null +++ b/tck/src/main/java/org/eclipse/microprofile/config/tck/configsources/KeyValuesConfigSource.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016-2019 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.eclipse.microprofile.config.tck.configsources; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.microprofile.config.spi.ConfigSource; + +public class KeyValuesConfigSource implements ConfigSource { + + + private final Map properties = new HashMap<>(); + + private KeyValuesConfigSource(Map properties) { + this.properties.putAll(properties); + } + + @Override + public Map getProperties() { + return Collections.unmodifiableMap(properties); + } + + @Override + public String getValue(String propertyName) { + return properties.get(propertyName); + } + + @Override + public String getName() { + return "PropertiesConfigSource"; + } + + public static ConfigSource config(String... keyValues) { + if (keyValues.length %2 != 0) { + throw new IllegalArgumentException("keyValues array must be a multiple of 2"); + } + + Map props = new HashMap<>(); + for (int i = 0; i < keyValues.length; i += 2) { + props.put(keyValues[i], keyValues[i+1]); + } + return new KeyValuesConfigSource(props); + } +} From 73ca146ffa58c435e417b6b1a33345d3c5a8fca0 Mon Sep 17 00:00:00 2001 From: Jeff Mesnil Date: Fri, 22 Mar 2019 09:54:02 +0100 Subject: [PATCH 2/2] [TCK] Support Variable Evaluation * Add VariableEvaluationTest#testMPConfigEvaluateVariablesProperty to check that an implement does *not* evaluate variables if the mp.config.evaluateVariabes config property is set to false. --- .../config/tck/VariableEvaluationTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tck/src/main/java/org/eclipse/microprofile/config/tck/VariableEvaluationTest.java b/tck/src/main/java/org/eclipse/microprofile/config/tck/VariableEvaluationTest.java index baffbe78..3e18e814 100644 --- a/tck/src/main/java/org/eclipse/microprofile/config/tck/VariableEvaluationTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/config/tck/VariableEvaluationTest.java @@ -53,6 +53,30 @@ public static WebArchive deploy() { return war; } + @Test + public void testMPConfigEvaluateVariablesProperty() { + final String previousValue = System.getProperty("mp.config.evaluateVariables"); + + try { + System.setProperty("mp.config.evaluateVariables", "false"); + + Config config = buildConfig( + "foo.one", "value", + "foo.two", "${foo.one}", + "foo.three", "+${foo.two}+"); + assertEquals(config.getValue("foo.two", String.class), "${foo.one}"); + assertEquals(config.getValue("foo.three", String.class), "+${foo.two}+"); + } + finally { + if (previousValue != null) { + System.setProperty("mp.config.evaluateVariables", previousValue); + } + else { + System.clearProperty("mp.config.evaluateVariables"); + } + } + } + @Test public void testDefaultVariableEvaluation() { Config config = buildConfig( @@ -264,6 +288,7 @@ public void testConfigBuilderDisableVariableEvaluation() { private static Config buildConfig(String... keyValues) { return ConfigProviderResolver.instance().getBuilder() + .addDefaultSources() .withSources(KeyValuesConfigSource.config(keyValues)) .build(); }