From 0ac7a492ef5606266b81e91828f5061d5a41a9b7 Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Fri, 30 Oct 2026 14:32:52 -0400 Subject: [PATCH] Treat the always-applied default profile in AWS repositories as intended The AWS Secrets Manager and Parameter Store repositories apply the default profile even when another profile is active, so that application-default is shared by every profile. This is documented, so keep the behavior instead of changing it. Add a DEFAULT_PROFILE_ALWAYS_ACTIVE capability to the compliance tests. Repositories that declare it skip the scenario expecting Spring Boot's behavior and run a scenario that pins the documented behavior instead. Signed-off-by: Ryan Baxter --- ...eEnvironmentRepositoryComplianceTests.java | 11 +-------- ...3EnvironmentRepositoryComplianceTests.java | 2 +- ...rEnvironmentRepositoryComplianceTests.java | 11 +-------- .../environment/compliance/Capability.java | 8 +++++++ .../EnvironmentRepositoryComplianceTests.java | 23 +++++++++++++++++++ ...ileSystemEnvironmentRepositoryFixture.java | 2 +- ...tEnvironmentRepositoryComplianceTests.java | 2 +- ...tEnvironmentRepositoryComplianceTests.java | 2 +- 8 files changed, 37 insertions(+), 24 deletions(-) diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsParameterStoreEnvironmentRepositoryComplianceTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsParameterStoreEnvironmentRepositoryComplianceTests.java index 45672bf48..fc41b0059 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsParameterStoreEnvironmentRepositoryComplianceTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsParameterStoreEnvironmentRepositoryComplianceTests.java @@ -20,9 +20,7 @@ import java.util.Set; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; import org.testcontainers.containers.localstack.LocalStackContainer.Service; import software.amazon.awssdk.services.ssm.SsmClient; import software.amazon.awssdk.services.ssm.model.ParameterMetadata; @@ -56,13 +54,6 @@ protected EnvironmentRepositoryFixture fixture() { return this.fixture; } - @Override - @Test - @Disabled("TODO-issue: The default profile is always included, even when another profile is active") - public void activeProfileExcludesDefaultProfileFiles() throws Exception { - super.activeProfileExcludesDefaultProfileFiles(); - } - static class Fixture implements EnvironmentRepositoryFixture { private final AwsParameterStoreEnvironmentProperties properties = new AwsParameterStoreEnvironmentProperties(); @@ -92,7 +83,7 @@ public EnvironmentRepository repository() { @Override public Set capabilities() { - return EnumSet.of(Capability.DISTINCT_DEFAULT_PROFILE); + return EnumSet.of(Capability.DISTINCT_DEFAULT_PROFILE, Capability.DEFAULT_PROFILE_ALWAYS_ACTIVE); } } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsS3EnvironmentRepositoryComplianceTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsS3EnvironmentRepositoryComplianceTests.java index f914ef8c5..5fe5d8b37 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsS3EnvironmentRepositoryComplianceTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsS3EnvironmentRepositoryComplianceTests.java @@ -93,7 +93,7 @@ public EnvironmentRepository repository() { @Override public Set capabilities() { - return EnumSet.allOf(Capability.class); + return EnumSet.complementOf(EnumSet.of(Capability.DEFAULT_PROFILE_ALWAYS_ACTIVE)); } } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsSecretsManagerEnvironmentRepositoryComplianceTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsSecretsManagerEnvironmentRepositoryComplianceTests.java index 6df523ba6..1864171a2 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsSecretsManagerEnvironmentRepositoryComplianceTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/AwsSecretsManagerEnvironmentRepositoryComplianceTests.java @@ -20,9 +20,7 @@ import java.util.Set; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; import org.testcontainers.containers.localstack.LocalStackContainer.Service; import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; import software.amazon.awssdk.services.secretsmanager.model.CreateSecretResponse; @@ -58,13 +56,6 @@ protected EnvironmentRepositoryFixture fixture() { return this.fixture; } - @Override - @Test - @Disabled("TODO-issue: The default profile is always included, even when another profile is active") - public void activeProfileExcludesDefaultProfileFiles() throws Exception { - super.activeProfileExcludesDefaultProfileFiles(); - } - static class Fixture implements EnvironmentRepositoryFixture { private final AwsSecretsManagerEnvironmentProperties properties = new AwsSecretsManagerEnvironmentProperties(); @@ -113,7 +104,7 @@ public EnvironmentRepository repository() { @Override public Set capabilities() { return EnumSet.of(Capability.LABELS, Capability.MULTIPLE_LABELS, Capability.MULTIPLE_APPLICATIONS, - Capability.DISTINCT_DEFAULT_PROFILE); + Capability.DISTINCT_DEFAULT_PROFILE, Capability.DEFAULT_PROFILE_ALWAYS_ACTIVE); } } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/Capability.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/Capability.java index 19a054886..3cb035050 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/Capability.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/Capability.java @@ -63,6 +63,14 @@ public enum Capability { */ DISTINCT_DEFAULT_PROFILE, + /** + * Configuration for the {@code default} profile is applied even when another profile + * is active, as a layer shared by all profiles. Spring Boot only applies it when no + * other profile is active, so this is a deliberate, documented difference. Only + * meaningful together with {@link #DISTINCT_DEFAULT_PROFILE}. + */ + DEFAULT_PROFILE_ALWAYS_ACTIVE, + /** * A {@code .properties} and a {@code .yml} file with the same name can exist at the * same location. diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/EnvironmentRepositoryComplianceTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/EnvironmentRepositoryComplianceTests.java index c0a824fc5..f72bc6e9e 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/EnvironmentRepositoryComplianceTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/EnvironmentRepositoryComplianceTests.java @@ -31,6 +31,7 @@ import org.springframework.cloud.config.server.environment.compliance.ConfigFile.Format; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeFalse; import static org.junit.jupiter.api.Assumptions.assumeTrue; /** @@ -100,6 +101,7 @@ public void defaultProfileResolvesDefaultProfileFilesFirst() throws Exception { @Test public void activeProfileExcludesDefaultProfileFiles() throws Exception { assumeCapabilities(Capability.DISTINCT_DEFAULT_PROFILE); + assumeNoCapability(Capability.DEFAULT_PROFILE_ALWAYS_ACTIVE); store("orders", null); store("application", null); store("orders", "default"); @@ -108,6 +110,19 @@ public void activeProfileExcludesDefaultProfileFiles() throws Exception { assertPrecedence(findOne("orders", "dev", null), "orders-dev", "orders", "application"); } + @Test + public void defaultProfileFilesAreAppliedWhenAnotherProfileIsActive() throws Exception { + assumeCapabilities(Capability.DISTINCT_DEFAULT_PROFILE, Capability.DEFAULT_PROFILE_ALWAYS_ACTIVE); + store("orders", null); + store("application", null); + store("orders", "default"); + store("application", "default"); + store("orders", "dev"); + + assertPrecedence(findOne("orders", "dev", null), "orders-dev", "orders-default", "application-default", + "orders", "application"); + } + @Test public void profileSpecificFilesTakePrecedenceOverFilesWithoutProfile() throws Exception { store("orders", null); @@ -314,6 +329,14 @@ protected Environment findOne(String application, String profile, String label) return fixture().repository().findOne(application, profile, label); } + /** + * Skip the current scenario if the fixture supports the capability. + * @param capability the capability that makes the scenario not applicable + */ + protected void assumeNoCapability(Capability capability) { + assumeFalse(fixture().capabilities().contains(capability), () -> "Fixture has capability " + capability); + } + /** * Skip the current scenario unless the fixture supports all the capabilities. * @param capabilities the required capabilities diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/FileSystemEnvironmentRepositoryFixture.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/FileSystemEnvironmentRepositoryFixture.java index 5c1ad9acf..0af688fbd 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/FileSystemEnvironmentRepositoryFixture.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/FileSystemEnvironmentRepositoryFixture.java @@ -57,7 +57,7 @@ public void store(ConfigFile file) throws IOException { @Override public Set capabilities() { - return EnumSet.allOf(Capability.class); + return EnumSet.complementOf(EnumSet.of(Capability.DEFAULT_PROFILE_ALWAYS_ACTIVE)); } } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/JGitEnvironmentRepositoryComplianceTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/JGitEnvironmentRepositoryComplianceTests.java index e8594146a..7db29f99d 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/JGitEnvironmentRepositoryComplianceTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/JGitEnvironmentRepositoryComplianceTests.java @@ -128,7 +128,7 @@ private Path realDir() throws IOException { @Override public Set capabilities() { - return EnumSet.allOf(Capability.class); + return EnumSet.complementOf(EnumSet.of(Capability.DEFAULT_PROFILE_ALWAYS_ACTIVE)); } } diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/SvnKitEnvironmentRepositoryComplianceTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/SvnKitEnvironmentRepositoryComplianceTests.java index 9695c95ba..083654e9e 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/SvnKitEnvironmentRepositoryComplianceTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/compliance/SvnKitEnvironmentRepositoryComplianceTests.java @@ -119,7 +119,7 @@ private Path realDir() throws IOException { @Override public Set capabilities() { - return EnumSet.allOf(Capability.class); + return EnumSet.complementOf(EnumSet.of(Capability.DEFAULT_PROFILE_ALWAYS_ACTIVE)); } }