Skip to content

Commit

Permalink
Support multiple profile names in dynamic property names (#1080)
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Jan 11, 2024
1 parent 6d41f17 commit 9abb6e1
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,48 @@ public String[] getProfiles() {

public String normalizeName(final String name) {
if (name.length() > 0 && name.charAt(0) == '%') {
for (String profile : profiles) {
if (name.startsWith(profile + ".", 1)) {
return name.substring(profile.length() + 2);
int profilesEnd = name.indexOf('.', 1);
int multipleSplit = -1;
for (int i = 1; i < profilesEnd; i++) {
if (name.charAt(i) == ',') {
multipleSplit = i;
break;
}
}

if (multipleSplit == -1) {
// Single profile property name (%profile.foo.bar)
for (String profile : profiles) {
if (profilesEnd == profile.length() + 1 && name.regionMatches(1, profile, 0, profile.length())) {
return name.substring(profilesEnd + 1);
}
}
} else {
// Multiple profile property name (%profile,another.foo.bar)
int nextSplit = multipleSplit;
int toOffset = 1;
while (nextSplit != -1) {
for (String profile : profiles) {
char expectedEnd = name.charAt(toOffset + profile.length());
if ((expectedEnd == '.' || expectedEnd == ',') &&
name.regionMatches(toOffset, profile, 0, profile.length())) {
return name.substring(profilesEnd + 1);
}
}

toOffset = nextSplit + 1;
nextSplit = -1;

for (int i = toOffset; i < profilesEnd; i++) {
if (name.charAt(i) == ',') {
nextSplit = i;
break;
}
}

if (toOffset < profilesEnd && nextSplit == -1) {
nextSplit = profilesEnd;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,10 @@ public List<InterceptorWithPriority> getInterceptors() {
return interceptors;
}

public List<String> getProfiles() {
return profiles;
}

public ConfigValidator getValidator() {
if (isAddDiscoveredValidator()) {
this.validator = discoverValidator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.NoSuchElementException;
import java.util.OptionalInt;
import java.util.Set;
import java.util.stream.StreamSupport;

import org.eclipse.microprofile.config.Config;
import org.junit.jupiter.api.Test;
Expand All @@ -30,7 +31,7 @@
class ProfileConfigSourceInterceptorTest {
@Test
void profile() {
final Config config = buildConfig("my.prop", "1", "%prof.my.prop", "2", SMALLRYE_CONFIG_PROFILE, "prof");
SmallRyeConfig config = buildConfig("my.prop", "1", "%prof.my.prop", "2", SMALLRYE_CONFIG_PROFILE, "prof");

assertEquals("2", config.getValue("my.prop", String.class));

Expand All @@ -41,28 +42,28 @@ void profile() {

@Test
void profileOnly() {
final Config config = buildConfig("%prof.my.prop", "2", SMALLRYE_CONFIG_PROFILE, "prof");
SmallRyeConfig config = buildConfig("%prof.my.prop", "2", SMALLRYE_CONFIG_PROFILE, "prof");

assertEquals("2", config.getValue("my.prop", String.class));
}

@Test
void fallback() {
final Config config = buildConfig("my.prop", "1", SMALLRYE_CONFIG_PROFILE, "prof");
SmallRyeConfig config = buildConfig("my.prop", "1", SMALLRYE_CONFIG_PROFILE, "prof");

assertEquals("1", config.getValue("my.prop", String.class));
}

@Test
void expressions() {
final Config config = buildConfig("my.prop", "1", "%prof.my.prop", "${my.prop}", SMALLRYE_CONFIG_PROFILE, "prof");
SmallRyeConfig config = buildConfig("my.prop", "1", "%prof.my.prop", "${my.prop}", SMALLRYE_CONFIG_PROFILE, "prof");

assertThrows(IllegalArgumentException.class, () -> config.getValue("my.prop", String.class));
}

@Test
void profileExpressions() {
final Config config = buildConfig("my.prop", "1",
SmallRyeConfig config = buildConfig("my.prop", "1",
"%prof.my.prop", "${%prof.my.prop.profile}",
"%prof.my.prop.profile", "2",
SMALLRYE_CONFIG_PROFILE, "prof");
Expand All @@ -72,7 +73,7 @@ void profileExpressions() {

@Test
void cannotExpand() {
final Config config = new SmallRyeConfigBuilder()
SmallRyeConfig config = new SmallRyeConfigBuilder()
.addDefaultInterceptors()
.withSources(config("my.prop", "${another.prop}", SMALLRYE_CONFIG_PROFILE, "prof", "config_ordinal", "1000"))
.withSources(config("my.prop", "${another.prop}", "%prof.my.prop", "2", SMALLRYE_CONFIG_PROFILE, "prof"))
Expand All @@ -83,8 +84,8 @@ void cannotExpand() {

@Test
void customConfigProfile() {
final String[] configs = { "my.prop", "1", "%prof.my.prop", "2", "config.profile", "prof" };
final Config config = new SmallRyeConfigBuilder()
String[] configs = { "my.prop", "1", "%prof.my.prop", "2", "config.profile", "prof" };
SmallRyeConfig config = new SmallRyeConfigBuilder()
.addDefaultSources()
.addDiscoveredInterceptors()
.withSources(config(configs))
Expand All @@ -95,8 +96,8 @@ void customConfigProfile() {

@Test
void noConfigProfile() {
final String[] configs = { "my.prop", "1", "%prof.my.prop", "2" };
final Config config = new SmallRyeConfigBuilder()
String[] configs = { "my.prop", "1", "%prof.my.prop", "2" };
SmallRyeConfig config = new SmallRyeConfigBuilder()
.addDefaultInterceptors()
.withSources(config(configs))
.build();
Expand All @@ -106,7 +107,7 @@ void noConfigProfile() {

@Test
void priorityProfile() {
final Config config = new SmallRyeConfigBuilder()
SmallRyeConfig config = new SmallRyeConfigBuilder()
.addDefaultInterceptors()
.withProfile("prof")
.withSources(
Expand All @@ -130,7 +131,7 @@ void priorityProfile() {

@Test
void priorityOverrideProfile() {
final Config config = new SmallRyeConfigBuilder()
SmallRyeConfig config = new SmallRyeConfigBuilder()
.addDefaultInterceptors()
.withSources(
new MapBackedConfigSource("higher", new HashMap<String, String>() {
Expand All @@ -153,7 +154,7 @@ void priorityOverrideProfile() {

@Test
void priorityProfileOverOriginal() {
final Config config = new SmallRyeConfigBuilder()
SmallRyeConfig config = new SmallRyeConfigBuilder()
.addDefaultInterceptors()
.withProfile("prof")
.withSources(
Expand All @@ -178,30 +179,36 @@ void priorityProfileOverOriginal() {

@Test
void propertyNames() {
final Config config = buildConfig("my.prop", "1", "%prof.my.prop", "2", "%prof.prof.only", "1",
SmallRyeConfig config = buildConfig(
"my.prop", "1",
"%prof.my.prop", "2",
"%prof.prof.only", "1",
"%inactive.prop", "1",
SMALLRYE_CONFIG_PROFILE, "prof");

assertEquals("2", config.getConfigValue("my.prop").getValue());
assertEquals("1", config.getConfigValue("prof.only").getValue());

final List<String> properties = stream(config.getPropertyNames().spliterator(), false).collect(toList());
List<String> properties = stream(config.getPropertyNames().spliterator(), false).collect(toList());
assertFalse(properties.contains("%prof.my.prop"));
assertTrue(properties.contains("my.prop"));
assertTrue(properties.contains("prof.only"));
// Inactive profile properties are included. We may need to revise this
assertTrue(properties.contains("%inactive.prop"));
}

@Test
void excludePropertiesFromInactiveProfiles() {
final Config config = buildConfig("%prof.my.prop", "1", "%foo.another", "2");
SmallRyeConfig config = buildConfig("%prof.my.prop", "1", "%foo.another", "2");

final List<String> properties = stream(config.getPropertyNames().spliterator(), false).collect(toList());
List<String> properties = stream(config.getPropertyNames().spliterator(), false).collect(toList());
assertTrue(properties.contains("my.prop"));
assertFalse(properties.contains("another"));
}

@Test
void profileName() {
final SmallRyeConfig config = new SmallRyeConfigBuilder()
SmallRyeConfig config = new SmallRyeConfigBuilder()
.withSources(config("my.prop", "1", "%prof.my.prop", "2"))
.withProfile("prof")
.build();
Expand Down Expand Up @@ -371,7 +378,7 @@ void parentProfileInActiveProfileWithRelocate() {
SmallRyeConfig config = new SmallRyeConfigBuilder()
.withInterceptorFactories(new ConfigSourceInterceptorFactory() {
@Override
public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorContext context) {
public ConfigSourceInterceptor getInterceptor(ConfigSourceInterceptorContext context) {
Map<String, String> relocations = new HashMap<>();
relocations.put(SMALLRYE_CONFIG_PROFILE_PARENT, "quarkus.config.profile.parent");

Expand Down Expand Up @@ -482,7 +489,8 @@ void multipleProfileProperty() {
.withSources(config("%prod,dev.my.prop", "value", "%prod,dev.my.override", "value", "config_ordinal", "100"))
.withSources(config("%dev.my.prop", "minimal", "config_ordinal", "0"))
.withSources(config("%prod,dev.another.prop", "multi", "%prod.another.prop", "single"))
.withSources(config("%common,prod,dev.triple.prop", "triple", "%common,prod.triple.prop", "double"));
.withSources(config("%common,prod,dev.triple.prop", "triple", "%common,prod.triple.prop", "double"))
.withSources(config("%commonone,prodone,devone.prop.start.with", "1"));

SmallRyeConfig prod = builder.withProfile("prod").build();
assertEquals("value", prod.getRawValue("my.prop"));
Expand All @@ -491,16 +499,35 @@ void multipleProfileProperty() {
assertEquals("override", prod.getRawValue("%prod.my.override"));
assertEquals("single", prod.getRawValue("another.prop"));
assertEquals("double", prod.getRawValue("triple.prop"));
Set<String> prodNames = StreamSupport.stream(prod.getPropertyNames().spliterator(), false).collect(toSet());
assertTrue(prodNames.contains("my.prop"));
assertTrue(prodNames.contains("my.override"));
assertTrue(prodNames.contains("another.prop"));
assertTrue(prodNames.contains("triple.prop"));
assertFalse(prodNames.contains("prop.start.with"));
builder.getProfiles().clear();

SmallRyeConfig dev = builder.withProfile("dev").build();
assertEquals("value", dev.getRawValue("my.prop"));
assertEquals("value", dev.getRawValue("%dev.my.prop"));
assertEquals("value", dev.getRawValue("my.override"));
assertEquals("value", dev.getRawValue("%dev.my.override"));
assertEquals("triple", dev.getRawValue("triple.prop"));
Set<String> devNames = StreamSupport.stream(dev.getPropertyNames().spliterator(), false).collect(toSet());
assertTrue(devNames.contains("my.prop"));
assertTrue(devNames.contains("my.override"));
assertTrue(devNames.contains("another.prop"));
assertTrue(devNames.contains("triple.prop"));
assertFalse(devNames.contains("prop.start.with"));
builder.getProfiles().clear();

SmallRyeConfig common = builder.withProfile("common").build();
assertEquals("double", common.getRawValue("triple.prop"));
Set<String> commonNames = StreamSupport.stream(common.getPropertyNames().spliterator(), false).collect(toSet());
assertTrue(commonNames.contains("triple.prop"));
assertFalse(commonNames.contains("my.prop"));
assertFalse(commonNames.contains("prop.start.with"));
builder.getProfiles().clear();
}

@Test
Expand Down

0 comments on commit 9abb6e1

Please sign in to comment.