Skip to content

Commit

Permalink
Adopt SmallRye Config
Browse files Browse the repository at this point in the history
Closes stevespringett#695

Signed-off-by: nscuro <[email protected]>
  • Loading branch information
nscuro committed Jan 2, 2025
1 parent b2b1aac commit 2cb2585
Show file tree
Hide file tree
Showing 17 changed files with 690 additions and 131 deletions.
4 changes: 4 additions & 0 deletions alpine-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.config</groupId>
<artifactId>smallrye-config-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
Expand Down
241 changes: 125 additions & 116 deletions alpine-common/src/main/java/alpine/Config.java

Large diffs are not rendered by default.

166 changes: 154 additions & 12 deletions alpine-common/src/test/java/alpine/ConfigTest.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,56 @@
package alpine;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.SmallRyeConfigBuilderCustomizer;
import io.smallrye.config.WithDefault;
import org.eclipse.microprofile.config.ConfigValue;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junitpioneer.jupiter.RestoreEnvironmentVariables;
import org.junitpioneer.jupiter.RestoreSystemProperties;
import org.junitpioneer.jupiter.SetEnvironmentVariable;
import org.junitpioneer.jupiter.SetSystemProperty;

import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Map;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

public class ConfigTest {

@AfterEach
public void tearDown() {
Config.reset();
@AfterAll
public static void tearDown() {
Config.reload(); // Ensure we're not affecting other tests
}

@AfterAll
public static void tearDownClass() {
Config.getInstance().init(); // Ensure we're not affecting other tests
@Test
@RestoreEnvironmentVariables
@SetEnvironmentVariable(key = "ALPINE_NO_PROXY", value = "foo, bar, baz")
void testGetPropertyAsList() {
Config.reload();

assertThat(Config.getInstance().getPropertyAsList(Config.AlpineKey.NO_PROXY)).containsExactly("foo", "bar", "baz");
}

@Test
void testGetProperty() {
Config.reload();

// Property with default value.
assertThat(Config.getInstance().getProperty(Config.AlpineKey.DATABASE_URL)).isEqualTo("jdbc:h2:mem:alpine");

// Property without default value.
assertThat(Config.getInstance().getProperty(Config.AlpineKey.SECRET_KEY_PATH)).isNull();
}

@Test
public void testGetPassThroughPropertiesEmpty() {
Config.getInstance().init();
Config.reload();

assertThat(Config.getInstance().getPassThroughProperties("datanucleus")).isEmpty();
}
Expand All @@ -43,21 +67,139 @@ public void testGetPassThroughPropertiesEmpty() {
@SetEnvironmentVariable(key = "ALPINE_DATANUCLEUS_FROM_ENV", value = "fromEnv7")
@SetEnvironmentVariable(key = "alpine_datanucleus_from_env_lowercase", value = "fromEnv8")
@SetEnvironmentVariable(key = "Alpine_DataNucleus_From_Env_MixedCase", value = "fromEnv9")
public void testGetPassThroughProperties() {
@SetEnvironmentVariable(key = "ALPINE_DATANUCLEUS_EXPRESSION_FROM_ENV", value = "${alpine.datanucleus.from.env}")
public void testGetPassThroughProperties() throws Exception {
final URL propertiesUrl = ConfigTest.class.getResource("/Config_testGetPassThroughProperties.properties");
assertThat(propertiesUrl).isNotNull();

System.setProperty("alpine.application.properties", propertiesUrl.getPath());
final Path tmpPropertiesFile = Files.createTempFile(null, ".properties");
Files.copy(propertiesUrl.openStream(), tmpPropertiesFile, StandardCopyOption.REPLACE_EXISTING);

System.setProperty("alpine.application.properties", tmpPropertiesFile.toUri().toString());

Config.getInstance().init();
Config.reload();

assertThat(Config.getInstance().getPassThroughProperties("datanucleus"))
.containsExactlyInAnyOrderEntriesOf(Map.of(
"datanucleus.foo", "fromEnv3", // ENV takes precedence over properties
"datanucleus.foo.bar", "fromEnv4", // ENV takes precedence over properties
"datanucleus.from.env", "fromEnv7",
"datanucleus.from.props", "fromProps7"
"datanucleus.from.props", "fromProps7",
"datanucleus.from.env.lowercase", "fromEnv8",
"datanucleus.from.env.mixedcase", "fromEnv9",
"datanucleus.expression.from.props", "fromEnv3",
"datanucleus.expression.from.env", "fromEnv7"
));
}

@ConfigMapping(prefix = "alpine")
public interface TestConfig {

DatabaseConfig database();

interface DatabaseConfig {

Optional<String> url();

@WithDefault("testUser")
String username();

Map<String, String> pool();

}

}

public static class ConfigBuilderCustomizer implements SmallRyeConfigBuilderCustomizer {

@Override
public void configBuilder(final SmallRyeConfigBuilder configBuilder) {
configBuilder
.withMapping(TestConfig.class)
.withValidateUnknown(false);
}

}

@Test
@RestoreEnvironmentVariables
@SetEnvironmentVariable(key = "ALPINE_DATABASE_URL", value = "jdbc:h2:mem:alpine")
@SetEnvironmentVariable(key = "ALPINE_DATABASE_POOL_MAX_SIZE", value = "666")
void testGetMapping() {
Config.reload();

final var testConfig = Config.getInstance().getMapping(TestConfig.class);
assertThat(testConfig).isNotNull();
assertThat(testConfig.database().url()).contains("jdbc:h2:mem:alpine");
assertThat(testConfig.database().username()).isEqualTo("testUser");
assertThat(testConfig.database().pool())
.containsExactlyInAnyOrderEntriesOf(Map.of("max.size", "666"));
}

@Test
@RestoreEnvironmentVariables
@SetEnvironmentVariable(key = "ALPINE_CONFIG_PROFILE", value = "dev")
@SetEnvironmentVariable(key = "ALPINE_DATABASE_URL", value = "defaultUrl")
@SetEnvironmentVariable(key = "_DEV_ALPINE_DATABASE_URL", value = "devUrl")
@SetEnvironmentVariable(key = "ALPINE_DATABASE_USERNAME", value = "defaultUser")
void testProfiles() {
Config.reload();

assertThat(Config.getInstance().getProperty(Config.AlpineKey.DATABASE_URL)).isEqualTo("devUrl");
assertThat(Config.getInstance().getProperty(Config.AlpineKey.DATABASE_USERNAME)).isEqualTo("defaultUser");
}

@Test
@RestoreEnvironmentVariables
@SetEnvironmentVariable(key = "ALPINE_DATABASE_URL", value = "defaultUrl")
@SetEnvironmentVariable(key = "_PROD_ALPINE_DATABASE_URL", value = "prodUrl")
@SetEnvironmentVariable(key = "ALPINE_DATABASE_USERNAME", value = "defaultUser")
void testDefaultProfile() {
Config.reload();

assertThat(Config.getInstance().getProperty(Config.AlpineKey.DATABASE_URL)).isEqualTo("prodUrl");
assertThat(Config.getInstance().getProperty(Config.AlpineKey.DATABASE_USERNAME)).isEqualTo("defaultUser");
}

@Test
@RestoreEnvironmentVariables
@RestoreSystemProperties
@SetEnvironmentVariable(key = "ALPINE_DATABASE_USERNAME", value = "envUsername")
@SetSystemProperty(key = "alpine.database.password", value = "propertyPassword")
void testGetValue() throws Exception {
final URL propertiesUrl = ConfigTest.class.getResource("/Config_testGetValue.properties");
assertThat(propertiesUrl).isNotNull();

final Path tmpPropertiesFile = Files.createTempFile(null, ".properties");
Files.copy(propertiesUrl.openStream(), tmpPropertiesFile, StandardCopyOption.REPLACE_EXISTING);

System.setProperty("alpine.application.properties", tmpPropertiesFile.toUri().toString());

Config.reload();

ConfigValue configValue = Config.getInstance().getDelegate().getConfigValue(Config.AlpineKey.DATABASE_URL.getPropertyName());
assertThat(configValue.getValue()).isEqualTo("jdbc:h2:mem:alpine");
assertThat(configValue.getSourceName()).matches(
"PropertiesConfigSource\\[source=file:.+\\.properties]");

configValue = Config.getInstance().getDelegate().getConfigValue(Config.AlpineKey.DATABASE_USERNAME.getPropertyName());
assertThat(configValue.getValue()).isEqualTo("envUsername");
assertThat(configValue.getSourceName()).isEqualTo("EnvConfigSource");

configValue = Config.getInstance().getDelegate().getConfigValue(Config.AlpineKey.DATABASE_PASSWORD.getPropertyName());
assertThat(configValue.getValue()).isEqualTo("propertyPassword");
assertThat(configValue.getSourceName()).isEqualTo("SysPropConfigSource");
}

@Test
@RestoreEnvironmentVariables
@SetEnvironmentVariable(key = "ALPINE_DATABASE_USERNAME", value = "dbUsername")
@SetEnvironmentVariable(key = "ALPINE_DATABASE_PASSWORD", value = "${alpine.database.username}-123")
void testExpression() {
Config.reload();

assertThat(Config.getInstance().getProperty(Config.AlpineKey.DATABASE_USERNAME)).isEqualTo("dbUsername");
assertThat(Config.getInstance().getProperty(Config.AlpineKey.DATABASE_PASSWORD)).isEqualTo("dbUsername-123");
}

}
32 changes: 30 additions & 2 deletions alpine-common/src/test/java/alpine/common/util/ThreadUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,52 @@
*/
package alpine.common.util;

import alpine.Config;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junitpioneer.jupiter.RestoreEnvironmentVariables;
import org.junitpioneer.jupiter.SetEnvironmentVariable;

import java.lang.reflect.Method;

class ThreadUtilTest {

private static Method configReloadMethod;

@BeforeAll
public static void setUp() throws Exception {
configReloadMethod = Config.class.getDeclaredMethod("reload");
configReloadMethod.setAccessible(true);
}

@AfterEach
public void tearDown() throws Exception {
configReloadMethod.invoke(Config.getInstance());
}

@AfterAll
public static void tearDownClass() throws Exception {
configReloadMethod.invoke(Config.getInstance()); // Ensure we're not affecting other tests.
}

@Test
@RestoreEnvironmentVariables
@SetEnvironmentVariable(key = "ALPINE_WORKER_THREADS", value = "10")
void determineNumberOfWorkerThreadsStaticTest() {
void determineNumberOfWorkerThreadsStaticTest() throws Exception {
configReloadMethod.invoke(Config.getInstance());

Assertions.assertEquals(10, ThreadUtil.determineNumberOfWorkerThreads());
}

@Test
@RestoreEnvironmentVariables
@SetEnvironmentVariable(key = "ALPINE_WORKER_THREADS", value = "0")
void determineNumberOfWorkerThreadsDynamicTest() {
void determineNumberOfWorkerThreadsDynamicTest() throws Exception {
configReloadMethod.invoke(Config.getInstance());

Assertions.assertTrue(ThreadUtil.determineNumberOfWorkerThreads() > 0);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ alpine.data.nucleus.foo=fromProps5
datanucleus.foo=fromProps6
alpine.datanucleus.from.props=fromProps7
ALPINE.DATANUCLEUS.FROM.PROPS.UPPERCASE=fromProps8
Alpine.DataNucleus.From.Props.MixedCase=fromProps9
Alpine.DataNucleus.From.Props.MixedCase=fromProps9
alpine.datanucleus.expression.from.props=${alpine.datanucleus.foo}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alpine.database.url=jdbc:h2:mem:alpine
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alpine.ConfigTest$ConfigBuilderCustomizer
55 changes: 55 additions & 0 deletions alpine-test/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>us.springett</groupId>
<artifactId>alpine-parent</artifactId>
<version>3.1.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>alpine-test</artifactId>
<packaging>jar</packaging>
<version>3.1.3-SNAPSHOT</version>

<name>alpine-test</name>
<description>
An opinionated scaffolding library that jumpstarts Java projects with an API-first design,
secure defaults, and minimal dependencies.
</description>
<url>https://github.com/stevespringett/Alpine</url>
<inceptionYear>2016</inceptionYear>

<properties>
<lib.junit4.version>4.13.2</lib.junit4.version>
</properties>

<dependencies>
<dependency>
<groupId>us.springett</groupId>
<artifactId>alpine-common</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${lib.junit4.version}</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${lib.junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Loading

0 comments on commit 2cb2585

Please sign in to comment.