Fix 1592 empty source on error part 2 (#1800)

This commit is contained in:
erabii
2024-11-25 16:25:36 +02:00
committed by GitHub
parent ac236777c3
commit 8eae516c09
21 changed files with 195 additions and 177 deletions

View File

@@ -39,10 +39,8 @@ import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
import org.springframework.cloud.kubernetes.commons.config.Constants;
import org.springframework.cloud.kubernetes.commons.config.RetryProperties;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockEnvironment;
@@ -100,12 +98,11 @@ class KubernetesClientConfigMapErrorOnReadingSourceTests {
/**
* <pre>
* we try to read all config maps in a namespace and fail,
* thus generate a well defined name for the source.
* we try to read all config maps in a namespace and fail.
* </pre>
*/
@Test
void namedSingleConfigMapFails() {
void namedSingleConfigMapFails(CapturedOutput output) {
String name = "my-config";
String namespace = "spring-k8s";
String path = "/api/v1/namespaces/" + namespace + "/configmaps";
@@ -120,13 +117,10 @@ class KubernetesClientConfigMapErrorOnReadingSourceTests {
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
MapPropertySource mapPropertySource = (MapPropertySource) propertySource.getPropertySources()
.stream()
.findAny()
.orElseThrow();
assertThat(mapPropertySource.getName()).isEqualTo("configmap..spring-k8s");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { config-map name : 'Optional[my-config]'");
}
@@ -168,11 +162,12 @@ class KubernetesClientConfigMapErrorOnReadingSourceTests {
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
// two sources are present, one being empty
assertThat(names).containsExactly("configmap.two.default", "configmap..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
// one property source is present
assertThat(names).containsExactly("configmap.two.default");
assertThat(output.getOut())
.doesNotContain("sourceName : two was requested, but not found in namespace : default");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { config-map name : 'Optional[one]'");
}
@@ -212,20 +207,19 @@ class KubernetesClientConfigMapErrorOnReadingSourceTests {
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
assertThat(names).containsExactly("configmap..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut())
.doesNotContain("sourceName : one was requested, but not found in namespace : default");
assertThat(output.getOut())
.doesNotContain("sourceName : two was requested, but not found in namespace : default");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { config-map name : 'Optional[one]'");
}
/**
* <pre>
* we try to read all config maps in a namespace and fail,
* thus generate a well defined name for the source.
* we try to read all config maps in a namespace and fail.
* </pre>
*/
@Test
@@ -256,12 +250,11 @@ class KubernetesClientConfigMapErrorOnReadingSourceTests {
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> sourceNames = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
assertThat(sourceNames).containsExactly("configmap..spring-k8s");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failure in reading labeled sources");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { config map labels : '{a=b}'");
}
/**
@@ -311,12 +304,11 @@ class KubernetesClientConfigMapErrorOnReadingSourceTests {
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
// two sources are present, one being empty
assertThat(names).containsExactly("configmap.two.default", "configmap..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
// one source is present
assertThat(names).containsExactly("configmap.two.default");
assertThat(output.getOut()).contains("Failure in reading labeled sources");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { config map labels : '{one=1}'");
}
@@ -364,15 +356,12 @@ class KubernetesClientConfigMapErrorOnReadingSourceTests {
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
// all 3 sources ('application' named source, and two labeled sources)
assertThat(names).containsExactly("configmap..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output).contains("Failure in reading labeled sources");
assertThat(output).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { config map labels : '{one=1}'");
assertThat(output.getOut()).contains("Failed to load source: { config map labels : '{two=2}'");
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.kubernetes.client.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -34,12 +35,16 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
import org.springframework.cloud.kubernetes.commons.config.Constants;
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
import org.springframework.cloud.kubernetes.commons.config.RetryProperties;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockEnvironment;
@@ -55,6 +60,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
* @author Ryan Baxter
* @author Isik Erhan
*/
@ExtendWith(OutputCaptureExtension.class)
class KubernetesClientConfigMapPropertySourceLocatorTests {
private static final V1ConfigMapList PROPERTIES_CONFIGMAP_LIST = new V1ConfigMapList()
@@ -185,7 +191,7 @@ class KubernetesClientConfigMapPropertySourceLocatorTests {
}
@Test
public void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() {
public void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled(CapturedOutput output) {
CoreV1Api api = new CoreV1Api();
stubFor(get("/api/v1/namespaces/default/configmaps")
.willReturn(aResponse().withStatus(500).withBody("Internal Server Error")));
@@ -196,7 +202,18 @@ class KubernetesClientConfigMapPropertySourceLocatorTests {
KubernetesClientConfigMapPropertySourceLocator locator = new KubernetesClientConfigMapPropertySourceLocator(api,
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
assertThatNoException().isThrownBy(() -> locator.locate(new MockEnvironment()));
List<PropertySource<?>> result = new ArrayList<>();
assertThatNoException().isThrownBy(() -> {
PropertySource<?> source = locator.locate(new MockEnvironment());
result.add(source);
});
assertThat(result.get(0)).isInstanceOf(CompositePropertySource.class);
CompositePropertySource composite = (CompositePropertySource) result.get(0);
assertThat(composite.getPropertySources()).hasSize(0);
assertThat(output.getOut()).contains("Failed to load source:");
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.kubernetes.client.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -30,11 +31,15 @@ import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
import org.springframework.cloud.kubernetes.commons.config.RetryProperties;
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockEnvironment;
@@ -50,6 +55,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
* @author Ryan Baxter
* @author Isik Erhan
*/
@ExtendWith(OutputCaptureExtension.class)
class KubernetesClientSecretsPropertySourceLocatorTests {
private static final String LIST_API = "/api/v1/namespaces/default/secrets";
@@ -200,7 +206,7 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
}
@Test
void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() {
void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled(CapturedOutput output) {
CoreV1Api api = new CoreV1Api();
stubFor(get(LIST_API).willReturn(aResponse().withStatus(500).withBody("Internal Server Error")));
@@ -210,7 +216,16 @@ class KubernetesClientSecretsPropertySourceLocatorTests {
KubernetesClientSecretsPropertySourceLocator locator = new KubernetesClientSecretsPropertySourceLocator(api,
new KubernetesNamespaceProvider(new MockEnvironment()), secretsConfigProperties);
assertThatNoException().isThrownBy(() -> locator.locate(new MockEnvironment()));
List<PropertySource<?>> result = new ArrayList<>();
assertThatNoException().isThrownBy(() -> {
PropertySource<?> source = locator.locate(new MockEnvironment());
result.add(source);
});
assertThat(result.get(0)).isInstanceOf(CompositePropertySource.class);
CompositePropertySource composite = (CompositePropertySource) result.get(0);
assertThat(composite.getPropertySources()).hasSize(0);
assertThat(output.getOut()).contains("Failed to load source:");
}
}

View File

@@ -154,11 +154,10 @@ class EventReloadConfigMapTest {
// we fail while reading 'configMapOne'
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
boolean one = output.getOut().contains("failure in reading named sources");
boolean two = output.getOut()
.contains("there was an error while reading config maps/secrets, no reload will happen");
boolean one = output.getOut().contains("Failure in reading named sources");
boolean two = output.getOut().contains("Failed to load source");
boolean three = output.getOut()
.contains("reloadable condition was not satisfied, reload will not be triggered");
.contains("Reloadable condition was not satisfied, reload will not be triggered");
boolean updateStrategyNotCalled = !strategyCalled[0];
return one && two && three && updateStrategyNotCalled;
});

View File

@@ -156,11 +156,10 @@ class EventReloadSecretTest {
// we fail while reading 'configMapOne'
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
boolean one = output.getOut().contains("failure in reading named sources");
boolean two = output.getOut()
.contains("there was an error while reading config maps/secrets, no reload will happen");
boolean one = output.getOut().contains("Failure in reading named sources");
boolean two = output.getOut().contains("Failed to load source");
boolean three = output.getOut()
.contains("reloadable condition was not satisfied, reload will not be triggered");
.contains("Reloadable condition was not satisfied, reload will not be triggered");
boolean updateStrategyNotCalled = !strategyCalled[0];
return one && two && three && updateStrategyNotCalled;
});

View File

@@ -136,11 +136,10 @@ class PollingReloadConfigMapTest {
void test(CapturedOutput output) {
// we fail while reading 'configMapOne'
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
boolean one = output.getOut().contains("failure in reading named sources");
boolean two = output.getOut()
.contains("there was an error while reading config maps/secrets, no reload will happen");
boolean one = output.getOut().contains("Failure in reading named sources");
boolean two = output.getOut().contains("Failed to load source");
boolean three = output.getOut()
.contains("reloadable condition was not satisfied, reload will not be triggered");
.contains("Reloadable condition was not satisfied, reload will not be triggered");
boolean updateStrategyNotCalled = !strategyCalled[0];
return one && two && three && updateStrategyNotCalled;
});

View File

@@ -137,11 +137,10 @@ class PollingReloadSecretTest {
void test(CapturedOutput output) {
// we fail while reading 'secretOne'
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
boolean one = output.getOut().contains("failure in reading named sources");
boolean two = output.getOut()
.contains("there was an error while reading config maps/secrets, no reload will happen");
boolean one = output.getOut().contains("Failure in reading named sources");
boolean two = output.getOut().contains("Failed to load source");
boolean three = output.getOut()
.contains("reloadable condition was not satisfied, reload will not be triggered");
.contains("Reloadable condition was not satisfied, reload will not be triggered");
boolean updateStrategyNotCalled = !strategyCalled[0];
return one && two && three && updateStrategyNotCalled;
});

View File

@@ -84,8 +84,13 @@ public abstract class ConfigMapPropertySourceLocator implements PropertySourceLo
LOG.debug("Config Map normalized sources : " + sources);
sources.forEach(s -> {
MapPropertySource propertySource = getMapPropertySource(s, env);
LOG.debug("Adding config map property source " + propertySource.getName());
composite.addFirstPropertySource(propertySource);
if ("true".equals(propertySource.getProperty(Constants.ERROR_PROPERTY))) {
LOG.warn("Failed to load source: " + s);
}
else {
LOG.debug("Adding config map property source " + propertySource.getName());
composite.addFirstPropertySource(propertySource);
}
});
}

View File

@@ -79,7 +79,7 @@ public abstract class LabeledSourceData {
}
}
catch (Exception e) {
LOG.warn("failure in reading labeled sources");
LOG.warn("Failure in reading labeled sources");
onException(failFast, e);
data = new MultipleSourcesContainer(data.names(), Map.of(ERROR_PROPERTY, "true"));
}

View File

@@ -71,7 +71,7 @@ public abstract class NamedSourceData {
}
catch (Exception e) {
LOG.warn("failure in reading named sources");
LOG.warn("Failure in reading named sources");
onException(failFast, e);
data = new MultipleSourcesContainer(data.names(), Map.of(ERROR_PROPERTY, "true"));
}

View File

@@ -90,8 +90,14 @@ public abstract class SecretsPropertySourceLocator implements PropertySourceLoca
if (this.properties.enableApi()) {
uniqueSources.forEach(s -> {
MapPropertySource propertySource = getSecretsPropertySourceForSingleSecret(env, s);
LOG.debug("Adding secret property source " + propertySource.getName());
composite.addFirstPropertySource(propertySource);
if ("true".equals(propertySource.getProperty(Constants.ERROR_PROPERTY))) {
LOG.warn("Failed to load source: " + s);
}
else {
LOG.debug("Adding secret property source " + propertySource.getName());
composite.addFirstPropertySource(propertySource);
}
});
}

View File

@@ -33,8 +33,6 @@ import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.log.LogAccessor;
import static org.springframework.cloud.kubernetes.commons.config.Constants.ERROR_PROPERTY;
/**
* @author wind57
*/
@@ -77,7 +75,7 @@ public final class ConfigReloadUtil {
return true;
}
else {
LOG.debug("reloadable condition was not satisfied, reload will not be triggered");
LOG.debug("Reloadable condition was not satisfied, reload will not be triggered");
}
return false;
@@ -165,11 +163,6 @@ public final class ConfigReloadUtil {
static boolean changed(List<? extends MapPropertySource> k8sSources, List<? extends MapPropertySource> appSources) {
if (k8sSources.stream().anyMatch(source -> "true".equals(source.getProperty(ERROR_PROPERTY)))) {
LOG.info(() -> "there was an error while reading config maps/secrets, no reload will happen");
return false;
}
if (k8sSources.size() != appSources.size()) {
if (LOG.isDebugEnabled()) {
LOG.debug("k8s property sources size: " + k8sSources.size());

View File

@@ -26,7 +26,6 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.bootstrap.config.BootstrapPropertySource;
import org.springframework.cloud.kubernetes.commons.config.Constants;
import org.springframework.cloud.kubernetes.commons.config.MountConfigMapPropertySource;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.EnumerablePropertySource;
@@ -151,16 +150,6 @@ class ConfigReloadUtilTests {
Assertions.assertEquals("from-inner-two-composite", result.get(3).getProperty(""));
}
@Test
void testEmptySourceNameOnError() {
Object value = new Object();
Map<String, Object> rightMap = Map.of("key", value);
MapPropertySource left = new MapPropertySource("on-error", Map.of(Constants.ERROR_PROPERTY, "true"));
MapPropertySource right = new MapPropertySource("right", rightMap);
boolean changed = ConfigReloadUtil.changed(List.of(left), List.of(right));
assertThat(changed).isFalse();
}
private static final class OneComposite extends CompositePropertySource {
private OneComposite() {

View File

@@ -33,10 +33,8 @@ import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
import org.springframework.cloud.kubernetes.commons.config.Constants;
import org.springframework.cloud.kubernetes.commons.config.RetryProperties;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockEnvironment;
@@ -62,11 +60,11 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
/**
* <pre>
* we try to read all config maps in a namespace and fail,
* thus generate a well defined name for the source.
* thus the composite property source is empty.
* </pre>
*/
@Test
void namedSingleConfigMapFails() {
void namedSingleConfigMapFails(CapturedOutput output) {
String name = "my-config";
String namespace = "spring-k8s";
String path = "/api/v1/namespaces/" + namespace + "/configmaps";
@@ -80,13 +78,8 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
MapPropertySource mapPropertySource = (MapPropertySource) propertySource.getPropertySources()
.stream()
.findAny()
.orElseThrow();
assertThat(mapPropertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failed to load source: { config-map name : 'Optional[my-config]'");
}
/**
@@ -96,7 +89,7 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
* </pre>
*/
@Test
void namedTwoConfigMapsOneFails() {
void namedTwoConfigMapsOneFails(CapturedOutput output) {
String configMapNameOne = "one";
String configMapNameTwo = "two";
String namespace = "default";
@@ -123,10 +116,9 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
// two sources are present
assertThat(names).containsExactly("configmap.two.default", "configmap..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
// one source is present
assertThat(names).containsExactly("configmap.two.default");
assertThat(output.getOut()).contains("Failed to load source: { config-map name : 'Optional[one]'");
}
/**
@@ -136,7 +128,7 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
* </pre>
*/
@Test
void namedTwoConfigMapsBothFail() {
void namedTwoConfigMapsBothFail(CapturedOutput output) {
String configMapNameOne = "one";
String configMapNameTwo = "two";
String namespace = "default";
@@ -158,15 +150,14 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
assertThat(names).containsExactly("configmap..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failed to load source: { config-map name : 'Optional[one]'");
assertThat(output.getOut()).contains("Failed to load source: { config-map name : 'Optional[two]'");
}
/**
* <pre>
* we try to read all config maps in a namespace and fail,
* thus generate a well defined name for the source.
* we try to read all config maps in a namespace and fail.
* </pre>
*/
@Test
@@ -190,10 +181,8 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> sourceNames = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
assertThat(sourceNames).containsExactly("configmap..spring-k8s");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failed to load source: { config map labels : '{a=b}'");
}
/**
@@ -236,12 +225,11 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
// two sources are present, one being empty
assertThat(names).containsExactly("configmap.two.default", "configmap..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
// one property source is present
assertThat(names).containsExactly("configmap.two.default");
assertThat(output.getOut()).contains("Failure in reading labeled sources");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { config map labels : '{one=1}'");
}
@@ -274,14 +262,12 @@ class Fabric8ConfigMapErrorOnReadingSourceTests {
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
assertThat(names).containsExactly("configmap..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failure in reading labeled sources");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { config map labels : '{two=2}'");
assertThat(output.getOut()).contains("Failed to load source: { config map labels : '{one=1}'");
}
private ConfigMap configMap(String name, Map<String, String> labels) {

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.kubernetes.fabric8.config;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -24,12 +25,18 @@ import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.ConfigMapConfigProperties;
import org.springframework.cloud.kubernetes.commons.config.RetryProperties;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -37,6 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
* @author Isik Erhan
*/
@EnableKubernetesMockClient
@ExtendWith(OutputCaptureExtension.class)
class Fabric8ConfigMapPropertySourceLocatorTests {
private static KubernetesMockServer mockServer;
@@ -67,7 +75,7 @@ class Fabric8ConfigMapPropertySourceLocatorTests {
}
@Test
void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() {
void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled(CapturedOutput output) {
String name = "my-config";
String namespace = "default";
String path = "/api/v1/namespaces/default/configmaps";
@@ -80,7 +88,16 @@ class Fabric8ConfigMapPropertySourceLocatorTests {
Fabric8ConfigMapPropertySourceLocator locator = new Fabric8ConfigMapPropertySourceLocator(mockClient,
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
assertThatNoException().isThrownBy(() -> locator.locate(new MockEnvironment()));
List<PropertySource<?>> result = new ArrayList<>();
assertThatNoException().isThrownBy(() -> {
PropertySource<?> source = locator.locate(new MockEnvironment());
result.add(source);
});
assertThat(result.get(0)).isInstanceOf(CompositePropertySource.class);
CompositePropertySource composite = (CompositePropertySource) result.get(0);
assertThat(composite.getPropertySources()).hasSize(0);
assertThat(output.getOut()).contains("Failed to load source:");
}
}

View File

@@ -32,11 +32,9 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.Constants;
import org.springframework.cloud.kubernetes.commons.config.RetryProperties;
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockEnvironment;
@@ -61,8 +59,7 @@ class Fabric8SecretErrorOnReadingSourceTests {
/**
* <pre>
* we try to read all secrets in a namespace and fail,
* thus generate a well defined name for the source.
* we try to read all secrets in a namespace and fail.
* </pre>
*/
@Test
@@ -80,14 +77,9 @@ class Fabric8SecretErrorOnReadingSourceTests {
secretsConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
MapPropertySource mapPropertySource = (MapPropertySource) propertySource.getPropertySources()
.stream()
.findAny()
.orElseThrow();
assertThat(mapPropertySource.getName()).isEqualTo("secret..spring-k8s");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(output).contains("failure in reading named sources");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { secret name : 'Optional[my-secret]'");
}
@@ -98,7 +90,7 @@ class Fabric8SecretErrorOnReadingSourceTests {
* </pre>
*/
@Test
void namedTwoSecretsOneFails() {
void namedTwoSecretsOneFails(CapturedOutput output) {
String secretNameOne = "one";
String secretNameTwo = "two";
String namespace = "default";
@@ -121,9 +113,10 @@ class Fabric8SecretErrorOnReadingSourceTests {
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
// two sources are present, one being empty
assertThat(names).containsExactly("secret.two.default", "secret..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
// one property source is present
assertThat(names).containsExactly("secret.two.default");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { secret name : 'Optional[one]'");
}
@@ -134,7 +127,7 @@ class Fabric8SecretErrorOnReadingSourceTests {
* </pre>
*/
@Test
void namedTwoSecretsBothFail() {
void namedTwoSecretsBothFail(CapturedOutput output) {
String secretNameOne = "one";
String secretNameTwo = "two";
String namespace = "default";
@@ -153,10 +146,9 @@ class Fabric8SecretErrorOnReadingSourceTests {
secretsConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
assertThat(names).containsExactly("secret..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failed to load source: { secret name : 'Optional[two]'");
}
@@ -185,12 +177,11 @@ class Fabric8SecretErrorOnReadingSourceTests {
secretsConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> sourceNames = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
assertThat(sourceNames).containsExactly("secret..spring-k8s");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output.getOut()).contains("Failure in reading labeled sources");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { secret labels : '{a=b}'");
}
/**
@@ -233,12 +224,12 @@ class Fabric8SecretErrorOnReadingSourceTests {
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
// two sources are present, one being empty
assertThat(names).containsExactly("secret.two.default", "secret..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
// one property source is present
assertThat(names).containsExactly("secret.two.default");
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
assertThat(output.getOut()).contains("Failure in reading labeled sources");
assertThat(output.getOut()).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { secret labels : '{one=1}'");
}
@@ -271,13 +262,13 @@ class Fabric8SecretErrorOnReadingSourceTests {
secretsConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
CompositePropertySource propertySource = (CompositePropertySource) locator.locate(new MockEnvironment());
List<String> names = propertySource.getPropertySources().stream().map(PropertySource::getName).toList();
assertThat(names).containsExactly("secret..default");
assertThat(propertySource.getProperty(Constants.ERROR_PROPERTY)).isEqualTo("true");
assertThat(propertySource.getPropertySources()).isEmpty();
assertThat(output).contains("failure in reading labeled sources");
assertThat(output).contains("failure in reading named sources");
assertThat(output).contains("Failure in reading labeled sources");
assertThat(output).contains("Failure in reading named sources");
assertThat(output.getOut()).contains("Failed to load source: { secret labels : '{one=1}'");
assertThat(output.getOut()).contains("Failed to load source: { secret labels : '{two=2}'");
}

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.kubernetes.fabric8.config;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -24,12 +25,18 @@ import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.RetryProperties;
import org.springframework.cloud.kubernetes.commons.config.SecretsConfigProperties;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -37,6 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
* @author Isik Erhan
*/
@EnableKubernetesMockClient
@ExtendWith(OutputCaptureExtension.class)
class Fabric8SecretsPropertySourceLocatorTests {
private static KubernetesMockServer mockServer;
@@ -67,7 +75,7 @@ class Fabric8SecretsPropertySourceLocatorTests {
}
@Test
void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled() {
void locateShouldNotThrowExceptionOnFailureWhenFailFastIsDisabled(CapturedOutput output) {
String name = "my-secret";
String namespace = "default";
String path = "/api/v1/namespaces/default/secrets/my-secret";
@@ -80,7 +88,17 @@ class Fabric8SecretsPropertySourceLocatorTests {
Fabric8SecretsPropertySourceLocator locator = new Fabric8SecretsPropertySourceLocator(mockClient,
configMapConfigProperties, new KubernetesNamespaceProvider(new MockEnvironment()));
assertThatNoException().isThrownBy(() -> locator.locate(new MockEnvironment()));
List<PropertySource<?>> result = new ArrayList<>();
assertThatNoException().isThrownBy(() -> {
PropertySource<?> source = locator.locate(new MockEnvironment());
result.add(source);
});
assertThat(result.get(0)).isInstanceOf(CompositePropertySource.class);
CompositePropertySource composite = (CompositePropertySource) result.get(0);
assertThat(composite.getPropertySources()).hasSize(0);
assertThat(output.getOut()).contains("Failed to load source:");
}
}

View File

@@ -114,11 +114,10 @@ public class EventReloadConfigMapTest {
// we fail while reading 'configMapTwo'
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
boolean one = output.getOut().contains("failure in reading named sources");
boolean two = output.getOut()
.contains("there was an error while reading config maps/secrets, no reload will happen");
boolean one = output.getOut().contains("Failure in reading named sources");
boolean two = output.getOut().contains("Failed to load source");
boolean three = output.getOut()
.contains("reloadable condition was not satisfied, reload will not be triggered");
.contains("Reloadable condition was not satisfied, reload will not be triggered");
boolean updateStrategyNotCalled = !strategyCalled[0];
return one && two && three && updateStrategyNotCalled;
});

View File

@@ -116,11 +116,10 @@ class EventReloadSecretTest {
// we fail while reading 'secretTwo'
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
boolean one = output.getOut().contains("failure in reading named sources");
boolean two = output.getOut()
.contains("there was an error while reading config maps/secrets, no reload will happen");
boolean one = output.getOut().contains("Failure in reading named sources");
boolean two = output.getOut().contains("Failed to load source");
boolean three = output.getOut()
.contains("reloadable condition was not satisfied, reload will not be triggered");
.contains("Reloadable condition was not satisfied, reload will not be triggered");
boolean updateStrategyNotCalled = !strategyCalled[0];
return one && two && three && updateStrategyNotCalled;
});

View File

@@ -109,11 +109,10 @@ class PollingReloadConfigMapTest {
void test(CapturedOutput output) {
// we fail while reading 'configMapOne'
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
boolean one = output.getOut().contains("failure in reading named sources");
boolean two = output.getOut()
.contains("there was an error while reading config maps/secrets, no reload will happen");
boolean one = output.getOut().contains("Failure in reading named sources");
boolean two = output.getOut().contains("Failed to load source");
boolean three = output.getOut()
.contains("reloadable condition was not satisfied, reload will not be triggered");
.contains("Reloadable condition was not satisfied, reload will not be triggered");
boolean updateStrategyNotCalled = !strategyCalled[0];
return one && two && three && updateStrategyNotCalled;
});

View File

@@ -112,11 +112,10 @@ public class PollingReloadSecretTest {
void test(CapturedOutput output) {
// we fail while reading 'secretOne'
Awaitility.await().atMost(Duration.ofSeconds(10)).pollInterval(Duration.ofSeconds(1)).until(() -> {
boolean one = output.getOut().contains("failure in reading named sources");
boolean two = output.getOut()
.contains("there was an error while reading config maps/secrets, no reload will happen");
boolean one = output.getOut().contains("Failure in reading named sources");
boolean two = output.getOut().contains("Failed to load source");
boolean three = output.getOut()
.contains("reloadable condition was not satisfied, reload will not be triggered");
.contains("Reloadable condition was not satisfied, reload will not be triggered");
boolean updateStrategyNotCalled = !strategyCalled[0];
return one && two && three && updateStrategyNotCalled;
});