diff --git a/spring-cloud-kubernetes-fabric8-autoconfig/src/main/java/org/springframework/cloud/kubernetes/fabric8/Fabric8Utils.java b/spring-cloud-kubernetes-fabric8-autoconfig/src/main/java/org/springframework/cloud/kubernetes/fabric8/Fabric8Utils.java new file mode 100644 index 00000000..2aa5fa20 --- /dev/null +++ b/spring-cloud-kubernetes-fabric8-autoconfig/src/main/java/org/springframework/cloud/kubernetes/fabric8/Fabric8Utils.java @@ -0,0 +1,88 @@ +/* + * Copyright 2013-2022 the original author or authors. + * + * 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 + * + * https://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.springframework.cloud.kubernetes.fabric8; + +import io.fabric8.kubernetes.client.KubernetesClient; +import org.apache.commons.logging.LogFactory; + +import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; +import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException; +import org.springframework.core.log.LogAccessor; +import org.springframework.util.StringUtils; + +/** + * Utility class related to Fabric8 Client. It resides in this module because it is + * supposed to be re-used in fabric8 specific ones (like config or discovery) + * + * @author wind57 + */ +public final class Fabric8Utils { + + private Fabric8Utils() { + + } + + private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(Fabric8Utils.class)); + + /** + * this method does the namespace resolution for both config map and secrets + * implementations. It tries these places to find the namespace: + * + *
+ * 1. from a normalized source (which can be null) + * 2. from a property 'spring.cloud.kubernetes.client.namespace', if such is present + * 3. from a String residing in a file denoted by `spring.cloud.kubernetes.client.serviceAccountNamespacePath` + * property, if such is present + * 4. from a String residing in `/var/run/secrets/kubernetes.io/serviceaccount/namespace` file, + * if such is present (kubernetes default path) + * 5. from KubernetesClient::getNamespace, which is implementation specific. + *+ * + * If any of the above fail, we throw a {@link NamespaceResolutionFailedException}. + * @param namespace normalized namespace + * @param configurationTarget Config Map/Secret + * @param provider the provider which computes the namespace + * @param client fabric8 Kubernetes client + * @return application namespace + * @throws NamespaceResolutionFailedException when namespace could not be resolved + */ + public static String getApplicationNamespace(KubernetesClient client, String namespace, String configurationTarget, + KubernetesNamespaceProvider provider) { + + if (StringUtils.hasText(namespace)) { + LOG.debug(configurationTarget + " namespace : " + namespace); + return namespace; + } + + if (provider != null) { + String providerNamespace = provider.getNamespace(); + if (StringUtils.hasText(providerNamespace)) { + LOG.debug(() -> configurationTarget + " namespace from provider : " + providerNamespace); + return providerNamespace; + } + } + + String clientNamespace = client.getNamespace(); + LOG.debug(() -> configurationTarget + " namespace from client : " + clientNamespace); + if (clientNamespace == null) { + throw new NamespaceResolutionFailedException("unresolved namespace"); + } + return clientNamespace; + + } + +} diff --git a/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/fabric8/Fabric8UtilsTests.java b/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/fabric8/Fabric8UtilsTests.java new file mode 100644 index 00000000..1cd3cef3 --- /dev/null +++ b/spring-cloud-kubernetes-fabric8-autoconfig/src/test/java/org/springframework/cloud/kubernetes/fabric8/Fabric8UtilsTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013-2022 the original author or authors. + * + * 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 + * + * https://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.springframework.cloud.kubernetes.fabric8; + +import io.fabric8.kubernetes.client.DefaultKubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; +import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * @author wind57 + */ +@EnableKubernetesMockClient(crud = true, https = false) +class Fabric8UtilsTests { + + private KubernetesClient client; + + private final DefaultKubernetesClient mockClient = Mockito.mock(DefaultKubernetesClient.class); + + private final KubernetesNamespaceProvider provider = Mockito.mock(KubernetesNamespaceProvider.class); + + @Test + void testGetApplicationNamespaceNotPresent() { + String result = Fabric8Utils.getApplicationNamespace(client, "", "target", null); + assertThat(result).isEqualTo("test"); + } + + @Test + void testGetApplicationNamespacePresent() { + String result = Fabric8Utils.getApplicationNamespace(client, "namespace", "target", null); + assertThat(result).isEqualTo("namespace"); + } + + @Test + void testNamespaceFromNormalizedSource() { + String result = Fabric8Utils.getApplicationNamespace(client, "abc", "target", null); + assertThat(result).isEqualTo("abc"); + } + + @Test + void testNamespaceFromProvider() { + Mockito.when(provider.getNamespace()).thenReturn("def"); + String result = Fabric8Utils.getApplicationNamespace(client, "", "target", provider); + assertThat(result).isEqualTo("def"); + } + + @Test + void testNamespaceFromClient() { + Mockito.when(mockClient.getNamespace()).thenReturn("qwe"); + String result = Fabric8Utils.getApplicationNamespace(mockClient, "", "target", null); + assertThat(result).isEqualTo("qwe"); + } + + @Test + void testNamespaceResolutionFailed() { + assertThatThrownBy(() -> Fabric8Utils.getApplicationNamespace(mockClient, "", "target", null)) + .isInstanceOf(NamespaceResolutionFailedException.class); + } + +} diff --git a/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigMapPropertySourceLocator.java b/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigMapPropertySourceLocator.java index f76a4c61..b8e9a70d 100644 --- a/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigMapPropertySourceLocator.java +++ b/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigMapPropertySourceLocator.java @@ -27,7 +27,7 @@ import org.springframework.core.annotation.Order; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; -import static org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigUtils.getApplicationNamespace; +import static org.springframework.cloud.kubernetes.fabric8.Fabric8Utils.getApplicationNamespace; /** * A {@link PropertySourceLocator} that uses config maps. diff --git a/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigUtils.java b/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigUtils.java index e09f6c7d..7fcab208 100644 --- a/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigUtils.java +++ b/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigUtils.java @@ -31,11 +31,10 @@ import org.apache.commons.logging.LogFactory; import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider; import org.springframework.cloud.kubernetes.commons.config.ConfigUtils; import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer; -import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException; import org.springframework.cloud.kubernetes.commons.config.StrippedSourceContainer; import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties; +import org.springframework.cloud.kubernetes.fabric8.Fabric8Utils; import org.springframework.core.env.Environment; -import org.springframework.util.StringUtils; /** * Utility class that works with configuration properties. @@ -56,59 +55,12 @@ public final class Fabric8ConfigUtils { ConfigReloadProperties properties, String target) { Set
- * 1. from a normalized source (which can be null) - * 2. from a property 'spring.cloud.kubernetes.client.namespace', if such is present - * 3. from a String residing in a file denoted by `spring.cloud.kubernetes.client.serviceAccountNamespacePath` - * property, if such is present - * 4. from a String residing in `/var/run/secrets/kubernetes.io/serviceaccount/namespace` file, - * if such is present (kubernetes default path) - * 5. from KubernetesClient::getNamespace, which is implementation specific. - *- * - * If any of the above fail, we throw a NamespaceResolutionFailedException. - * @param namespace normalized namespace - * @param configurationTarget Config Map/Secret - * @param provider the provider which computes the namespace - * @param client fabric8 Kubernetes client - * @return application namespace - * @throws NamespaceResolutionFailedException when namespace could not be resolved - */ - static String getApplicationNamespace(KubernetesClient client, String namespace, String configurationTarget, - KubernetesNamespaceProvider provider) { - - if (StringUtils.hasText(namespace)) { - LOG.debug(configurationTarget + " namespace : " + namespace); - return namespace; - } - - if (provider != null) { - String providerNamespace = provider.getNamespace(); - if (StringUtils.hasText(providerNamespace)) { - LOG.debug(configurationTarget + " namespace from provider : " + providerNamespace); - return providerNamespace; - } - } - - String clientNamespace = client.getNamespace(); - LOG.debug(configurationTarget + " namespace from client : " + clientNamespace); - if (clientNamespace == null) { - throw new NamespaceResolutionFailedException("unresolved namespace"); - } - return clientNamespace; - - } - /** *
* 1. read all secrets in the provided namespace
diff --git a/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8SecretsPropertySourceLocator.java b/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8SecretsPropertySourceLocator.java
index 98d816e5..829648fb 100644
--- a/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8SecretsPropertySourceLocator.java
+++ b/spring-cloud-kubernetes-fabric8-config/src/main/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8SecretsPropertySourceLocator.java
@@ -27,7 +27,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
-import static org.springframework.cloud.kubernetes.fabric8.config.Fabric8ConfigUtils.getApplicationNamespace;
+import static org.springframework.cloud.kubernetes.fabric8.Fabric8Utils.getApplicationNamespace;
/**
* Kubernetes {@link PropertySourceLocator} for secrets.
diff --git a/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigUtilsTests.java b/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigUtilsTests.java
index 219d8c7a..d96aaca1 100644
--- a/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigUtilsTests.java
+++ b/spring-cloud-kubernetes-fabric8-config/src/test/java/org/springframework/cloud/kubernetes/fabric8/config/Fabric8ConfigUtilsTests.java
@@ -25,22 +25,16 @@ import java.util.Set;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.api.model.SecretBuilder;
-import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.config.MultipleSourcesContainer;
-import org.springframework.cloud.kubernetes.commons.config.NamespaceResolutionFailedException;
import org.springframework.cloud.kubernetes.commons.config.reload.ConfigReloadProperties;
import org.springframework.mock.env.MockEnvironment;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
/**
* @author wind57
*/
@@ -49,48 +43,6 @@ class Fabric8ConfigUtilsTests {
private KubernetesClient client;
- private final DefaultKubernetesClient mockClient = Mockito.mock(DefaultKubernetesClient.class);
-
- private final KubernetesNamespaceProvider provider = Mockito.mock(KubernetesNamespaceProvider.class);
-
- @Test
- void testGetApplicationNamespaceNotPresent() {
- String result = Fabric8ConfigUtils.getApplicationNamespace(client, "", "target", null);
- assertThat(result).isEqualTo("test");
- }
-
- @Test
- void testGetApplicationNamespacePresent() {
- String result = Fabric8ConfigUtils.getApplicationNamespace(client, "namespace", "target", null);
- assertThat(result).isEqualTo("namespace");
- }
-
- @Test
- void testNamespaceFromNormalizedSource() {
- String result = Fabric8ConfigUtils.getApplicationNamespace(client, "abc", "target", null);
- assertThat(result).isEqualTo("abc");
- }
-
- @Test
- void testNamespaceFromProvider() {
- Mockito.when(provider.getNamespace()).thenReturn("def");
- String result = Fabric8ConfigUtils.getApplicationNamespace(client, "", "target", provider);
- assertThat(result).isEqualTo("def");
- }
-
- @Test
- void testNamespaceFromClient() {
- Mockito.when(mockClient.getNamespace()).thenReturn("qwe");
- String result = Fabric8ConfigUtils.getApplicationNamespace(mockClient, "", "target", null);
- assertThat(result).isEqualTo("qwe");
- }
-
- @Test
- void testNamespaceResolutionFailed() {
- assertThatThrownBy(() -> Fabric8ConfigUtils.getApplicationNamespace(mockClient, "", "target", null))
- .isInstanceOf(NamespaceResolutionFailedException.class);
- }
-
// secret "my-secret" is deployed without any labels; we search for it by labels
// "color=red" and do not find it.
@Test
diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatch.java b/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatch.java
index 55396232..b0c40a46 100644
--- a/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatch.java
+++ b/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatch.java
@@ -27,8 +27,10 @@ import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
+import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
+import org.springframework.cloud.kubernetes.fabric8.Fabric8Utils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.core.log.LogAccessor;
@@ -45,13 +47,17 @@ public class KubernetesCatalogWatch implements ApplicationEventPublisherAware {
private final KubernetesDiscoveryProperties properties;
+ private final KubernetesNamespaceProvider namespaceProvider;
+
private volatile List catalogEndpointsState = null;
private ApplicationEventPublisher publisher;
- public KubernetesCatalogWatch(KubernetesClient kubernetesClient, KubernetesDiscoveryProperties properties) {
+ public KubernetesCatalogWatch(KubernetesClient kubernetesClient, KubernetesDiscoveryProperties properties,
+ KubernetesNamespaceProvider namespaceProvider) {
this.kubernetesClient = kubernetesClient;
this.properties = properties;
+ this.namespaceProvider = namespaceProvider;
}
@Override
@@ -67,13 +73,28 @@ public class KubernetesCatalogWatch implements ApplicationEventPublisherAware {
// endpoints.
List endpoints;
if (properties.allNamespaces()) {
+ LOG.debug(() -> "discovering endpoints in all namespaces");
endpoints = kubernetesClient.endpoints().inAnyNamespace().withLabels(properties.serviceLabels()).list()
.getItems();
}
else {
- endpoints = kubernetesClient.endpoints().withLabels(properties.serviceLabels()).list().getItems();
+ String namespace = Fabric8Utils.getApplicationNamespace(kubernetesClient, null, "catalog-watcher",
+ namespaceProvider);
+ LOG.debug(() -> "fabric8 catalog watcher will use namespace : " + namespace);
+ endpoints = kubernetesClient.endpoints().inNamespace(namespace).withLabels(properties.serviceLabels())
+ .list().getItems();
}
+ /*
+ *
+ * - An "Endpoints" holds a List of EndpointSubset.
+ * - A single EndpointSubset holds a List of EndpointAddress
+ *
+ * - (The union of all EndpointSubsets is the Set of all Endpoints)
+ * - Set of Endpoints is the cartesian product of :
+ * EndpointSubset::getAddresses and EndpointSubset::getPorts (each is a List)
+ *
+ */
List currentState = endpoints.stream().map(Endpoints::getSubsets)
.filter(Objects::nonNull).flatMap(List::stream).map(EndpointSubset::getAddresses)
.filter(Objects::nonNull).flatMap(List::stream).map(EndpointAddress::getTargetRef)
diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatchAutoConfiguration.java b/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatchAutoConfiguration.java
index 83d0e644..c613b39c 100644
--- a/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatchAutoConfiguration.java
+++ b/spring-cloud-kubernetes-fabric8-discovery/src/main/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatchAutoConfiguration.java
@@ -24,10 +24,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.cloud.CloudPlatform;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
+import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.cloud.kubernetes.fabric8.Fabric8AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
/**
* Auto configuration for catalog watcher.
@@ -45,8 +47,8 @@ public class KubernetesCatalogWatchAutoConfiguration {
@ConditionalOnProperty(name = "spring.cloud.kubernetes.discovery.catalog-services-watch.enabled",
matchIfMissing = true)
public KubernetesCatalogWatch kubernetesCatalogWatch(KubernetesClient client,
- KubernetesDiscoveryProperties properties) {
- return new KubernetesCatalogWatch(client, properties);
+ KubernetesDiscoveryProperties properties, Environment environment) {
+ return new KubernetesCatalogWatch(client, properties, new KubernetesNamespaceProvider(environment));
}
}
diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesCatalogWatchTests.java b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesCatalogWatchTests.java
new file mode 100644
index 00000000..8536c0d9
--- /dev/null
+++ b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/Fabric8KubernetesCatalogWatchTests.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2013-2022 the original author or authors.
+ *
+ * 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
+ *
+ * https://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.springframework.cloud.kubernetes.fabric8.discovery;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import io.fabric8.kubernetes.api.model.EndpointAddress;
+import io.fabric8.kubernetes.api.model.EndpointAddressBuilder;
+import io.fabric8.kubernetes.api.model.EndpointSubset;
+import io.fabric8.kubernetes.api.model.EndpointSubsetBuilder;
+import io.fabric8.kubernetes.api.model.Endpoints;
+import io.fabric8.kubernetes.api.model.EndpointsBuilder;
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+import io.fabric8.kubernetes.api.model.ObjectReferenceBuilder;
+import io.fabric8.kubernetes.client.Config;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
+import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
+import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace;
+import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
+import org.springframework.context.ApplicationEventPublisher;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Some tests that use the fabric8 mock client.
+ *
+ * @author wind57
+ */
+@EnableKubernetesMockClient(crud = true, https = false)
+class Fabric8KubernetesCatalogWatchTests {
+
+ private final KubernetesNamespaceProvider namespaceProvider = Mockito.mock(KubernetesNamespaceProvider.class);
+
+ private static final ArgumentCaptor HEARTBEAT_EVENT_ARGUMENT_CAPTOR = ArgumentCaptor
+ .forClass(HeartbeatEvent.class);
+
+ private static final ApplicationEventPublisher APPLICATION_EVENT_PUBLISHER = Mockito
+ .mock(ApplicationEventPublisher.class);
+
+ private static KubernetesClient mockClient;
+
+ @BeforeAll
+ static void setUp() {
+ // Configure the kubernetes master url to point to the mock server
+ System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient.getConfiguration().getMasterUrl());
+ System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
+ System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false");
+ System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false");
+ System.setProperty(Config.KUBERNETES_NAMESPACE_SYSTEM_PROPERTY, "test");
+ System.setProperty(Config.KUBERNETES_HTTP2_DISABLE, "true");
+ }
+
+ @AfterEach
+ void afterEach() {
+ Mockito.reset(APPLICATION_EVENT_PUBLISHER);
+ mockClient.endpoints().inAnyNamespace().delete();
+ }
+
+ /**
+ *
+ *
+ * - we have 5 pods involved in this test
+ * - podA in namespaceA with no labels
+ * - podB in namespaceA with labels {color=blue}
+ * - podC in namespaceA with labels {color=red}
+ * - podD in namespaceB with labels {color=blue}
+ * - podE in namespaceB with no labels
+ *
+ * We set the namespace to be "namespaceA" and search for labels {color=blue}
+ * As a result only one pod is taken: podB
+ *
+ *
+ */
+ @Test
+ void testEndpointsInSpecificNamespaceWithServiceLabels() {
+
+ KubernetesCatalogWatch watch = createWatcherInSpecificNamespaceAndLabels("namespaceA", Map.of("color", "blue"));
+
+ createSingleEndpoints("namespaceA", Map.of(), "podA");
+ createSingleEndpoints("namespaceA", Map.of("color", "blue"), "podB");
+ createSingleEndpoints("namespaceA", Map.of("color", "red"), "podC");
+ createSingleEndpoints("namespaceB", Map.of("color", "blue"), "podD");
+ createSingleEndpoints("namespaceB", Map.of(), "podE");
+
+ watch.catalogServicesWatch();
+
+ verify(APPLICATION_EVENT_PUBLISHER).publishEvent(HEARTBEAT_EVENT_ARGUMENT_CAPTOR.capture());
+
+ HeartbeatEvent event = HEARTBEAT_EVENT_ARGUMENT_CAPTOR.getValue();
+ assertThat(event.getValue()).isInstanceOf(List.class);
+
+ List expectedOutput = List.of(new EndpointNameAndNamespace("podB", "namespaceA"));
+ assertThat(event.getValue()).isEqualTo(expectedOutput);
+ }
+
+ /**
+ *
+ *
+ * - we have 5 pods involved in this test
+ * - podA in namespaceA with no labels
+ * - podB in namespaceA with labels {color=blue}
+ * - podC in namespaceA with labels {color=red}
+ * - podD in namespaceB with labels {color=blue}
+ * - podE in namespaceB with no labels
+ *
+ * We set the namespace to be "namespaceA" and search without labels
+ * As a result we get three pods:
+ * - podA in namespaceA
+ * - podB in namespaceA
+ * - pocC in namespaceA
+ *
+ *
+ */
+ @Test
+ void testEndpointsInSpecificNamespaceWithoutServiceLabels() {
+
+ KubernetesCatalogWatch watch = createWatcherInSpecificNamespaceAndLabels("namespaceA", Map.of());
+
+ createSingleEndpoints("namespaceA", Map.of(), "podA");
+ createSingleEndpoints("namespaceA", Map.of("color", "blue"), "podB");
+ createSingleEndpoints("namespaceA", Map.of("color", "red"), "podC");
+ createSingleEndpoints("namespaceB", Map.of("color", "blue"), "podD");
+ createSingleEndpoints("namespaceB", Map.of(), "podE");
+
+ watch.catalogServicesWatch();
+
+ verify(APPLICATION_EVENT_PUBLISHER).publishEvent(HEARTBEAT_EVENT_ARGUMENT_CAPTOR.capture());
+
+ HeartbeatEvent event = HEARTBEAT_EVENT_ARGUMENT_CAPTOR.getValue();
+ assertThat(event.getValue()).isInstanceOf(List.class);
+
+ List expectedOutput = List.of(new EndpointNameAndNamespace("podA", "namespaceA"),
+ new EndpointNameAndNamespace("podB", "namespaceA"), new EndpointNameAndNamespace("podC", "namespaceA"));
+ assertThat(event.getValue()).isEqualTo(expectedOutput);
+ }
+
+ /**
+ *
+ *
+ * - we have 5 pods involved in this test
+ * - podA in namespaceA with no labels
+ * - podB in namespaceA with labels {color=blue}
+ * - podC in namespaceA with labels {color=red}
+ * - podD in namespaceB with labels {color=blue}
+ * - podE in namespaceB with no labels
+ *
+ * We search in all namespaces with labels {color=blue}
+ * As a result two pods are taken:
+ * - podB in namespaceA
+ * - podD in namespaceB
+ *
+ *
+ */
+ @Test
+ void testEndpointsInAllNamespacesWithServiceLabels() {
+
+ KubernetesCatalogWatch watch = createWatcherInAllNamespacesAndLabels(Map.of("color", "blue"));
+
+ createSingleEndpoints("namespaceA", Map.of(), "podA");
+ createSingleEndpoints("namespaceA", Map.of("color", "blue"), "podB");
+ createSingleEndpoints("namespaceA", Map.of("color", "red"), "podC");
+ createSingleEndpoints("namespaceB", Map.of("color", "blue"), "podD");
+ createSingleEndpoints("namespaceB", Map.of(), "podE");
+
+ watch.catalogServicesWatch();
+
+ verify(APPLICATION_EVENT_PUBLISHER).publishEvent(HEARTBEAT_EVENT_ARGUMENT_CAPTOR.capture());
+
+ HeartbeatEvent event = HEARTBEAT_EVENT_ARGUMENT_CAPTOR.getValue();
+ assertThat(event.getValue()).isInstanceOf(List.class);
+
+ List expectedOutput = List.of(new EndpointNameAndNamespace("podB", "namespaceA"),
+ new EndpointNameAndNamespace("podD", "namespaceB"));
+ assertThat(event.getValue()).isEqualTo(expectedOutput);
+ }
+
+ /**
+ *
+ *
+ * - we have 5 pods involved in this test
+ * - podA in namespaceA with no labels
+ * - podB in namespaceA with labels {color=blue}
+ * - podC in namespaceA with labels {color=red}
+ * - podD in namespaceB with labels {color=blue}
+ * - podE in namespaceB with no labels
+ *
+ * We search in all namespaces without labels
+ * As a result we get all 5 pods
+ *
+ *
+ */
+ @Test
+ void testEndpointsInAllNamespacesWithoutServiceLabels() {
+
+ KubernetesCatalogWatch watch = createWatcherInAllNamespacesAndLabels(Map.of());
+
+ createSingleEndpoints("namespaceA", Map.of(), "podA");
+ createSingleEndpoints("namespaceA", Map.of("color", "blue"), "podB");
+ createSingleEndpoints("namespaceA", Map.of("color", "red"), "podC");
+ createSingleEndpoints("namespaceB", Map.of("color", "blue"), "podD");
+ createSingleEndpoints("namespaceB", Map.of(), "podE");
+
+ watch.catalogServicesWatch();
+
+ verify(APPLICATION_EVENT_PUBLISHER).publishEvent(HEARTBEAT_EVENT_ARGUMENT_CAPTOR.capture());
+
+ HeartbeatEvent event = HEARTBEAT_EVENT_ARGUMENT_CAPTOR.getValue();
+ assertThat(event.getValue()).isInstanceOf(List.class);
+
+ List expectedOutput = List.of(new EndpointNameAndNamespace("podA", "namespaceA"),
+ new EndpointNameAndNamespace("podB", "namespaceA"), new EndpointNameAndNamespace("podC", "namespaceA"),
+ new EndpointNameAndNamespace("podD", "namespaceB"), new EndpointNameAndNamespace("podE", "namespaceB"));
+ assertThat(event.getValue()).isEqualTo(expectedOutput);
+ }
+
+ private KubernetesCatalogWatch createWatcherInSpecificNamespaceAndLabels(String namespace,
+ Map labels) {
+
+ when(namespaceProvider.getNamespace()).thenReturn(namespace);
+
+ // all-namespaces = false
+ KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, false, true, 60, false, "",
+ Set.of(), labels, "", null, 0);
+
+ KubernetesCatalogWatch watch = new KubernetesCatalogWatch(mockClient, properties, namespaceProvider);
+ watch.setApplicationEventPublisher(APPLICATION_EVENT_PUBLISHER);
+ return watch;
+
+ }
+
+ private KubernetesCatalogWatch createWatcherInAllNamespacesAndLabels(Map labels) {
+
+ // all-namespaces = true
+ KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, true, 60, false, "",
+ Set.of(), labels, "", null, 0);
+
+ KubernetesCatalogWatch watch = new KubernetesCatalogWatch(mockClient, properties, namespaceProvider);
+ watch.setApplicationEventPublisher(APPLICATION_EVENT_PUBLISHER);
+ return watch;
+
+ }
+
+ private static void createSingleEndpoints(String namespace, Map labels, String podName) {
+
+ EndpointAddress endpointAddress = new EndpointAddressBuilder()
+ .withTargetRef(new ObjectReferenceBuilder().withName(podName).withNamespace(namespace).build()).build();
+
+ EndpointSubset endpointSubset = new EndpointSubsetBuilder().withAddresses(List.of(endpointAddress)).build();
+
+ Endpoints endpoints = new EndpointsBuilder()
+ .withMetadata(new ObjectMetaBuilder().withLabels(labels).withName("endpoints-" + podName).build())
+ .withSubsets(List.of(endpointSubset)).build();
+ mockClient.endpoints().inNamespace(namespace).create(endpoints);
+ }
+
+}
diff --git a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatchTest.java b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatchTest.java
index 21307938..63c97206 100644
--- a/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatchTest.java
+++ b/spring-cloud-kubernetes-fabric8-discovery/src/test/java/org/springframework/cloud/kubernetes/fabric8/discovery/KubernetesCatalogWatchTest.java
@@ -18,6 +18,8 @@ package org.springframework.cloud.kubernetes.fabric8.discovery;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
import io.fabric8.kubernetes.api.model.EndpointAddress;
@@ -26,22 +28,23 @@ import io.fabric8.kubernetes.api.model.Endpoints;
import io.fabric8.kubernetes.api.model.EndpointsList;
import io.fabric8.kubernetes.api.model.ObjectReference;
import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
+import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
+import org.springframework.cloud.kubernetes.commons.KubernetesNamespaceProvider;
import org.springframework.cloud.kubernetes.commons.discovery.EndpointNameAndNamespace;
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
import org.springframework.context.ApplicationEventPublisher;
import static java.util.Arrays.stream;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -49,13 +52,14 @@ import static org.mockito.Mockito.when;
/**
* @author Oleg Vyukov
*/
-@SuppressWarnings("unchecked")
+@SuppressWarnings({ "unchecked" })
class KubernetesCatalogWatchTest {
private static final KubernetesClient CLIENT = Mockito.mock(KubernetesClient.class);
- private final KubernetesCatalogWatch kubernetesCatalogWatch = new KubernetesCatalogWatch(CLIENT,
- KubernetesDiscoveryProperties.DEFAULT);
+ private final KubernetesNamespaceProvider namespaceProvider = Mockito.mock(KubernetesNamespaceProvider.class);
+
+ private KubernetesCatalogWatch kubernetesCatalogWatch;
private static final ApplicationEventPublisher APPLICATION_EVENT_PUBLISHER = Mockito
.mock(ApplicationEventPublisher.class);
@@ -63,25 +67,29 @@ class KubernetesCatalogWatchTest {
private static final MixedOperation> MIXED_OPERATION = Mockito
.mock(MixedOperation.class);
+ private static final NonNamespaceOperation> NON_NAMESPACE_OPERATION = Mockito
+ .mock(NonNamespaceOperation.class);
+
+ private static final FilterWatchListDeletable FILTER_WATCH_LIST_DELETABLE = Mockito
+ .mock(FilterWatchListDeletable.class);
+
private static final ArgumentCaptor HEARTBEAT_EVENT_ARGUMENT_CAPTOR = ArgumentCaptor
.forClass(HeartbeatEvent.class);
- @BeforeEach
- void setUp() {
- kubernetesCatalogWatch.setApplicationEventPublisher(APPLICATION_EVENT_PUBLISHER);
- }
-
@AfterEach
void afterEach() {
- Mockito.reset(APPLICATION_EVENT_PUBLISHER, CLIENT, MIXED_OPERATION);
+ Mockito.reset(APPLICATION_EVENT_PUBLISHER, CLIENT, MIXED_OPERATION, FILTER_WATCH_LIST_DELETABLE,
+ NON_NAMESPACE_OPERATION);
}
@Test
void testRandomOrderChangePods() {
- when(MIXED_OPERATION.list()).thenReturn(createSingleEndpointEndpointListByPodName("api-pod", "other-pod"))
+
+ createInSpecificNamespaceWatcher();
+
+ when(FILTER_WATCH_LIST_DELETABLE.list())
+ .thenReturn(createSingleEndpointEndpointListByPodName("api-pod", "other-pod"))
.thenReturn(createSingleEndpointEndpointListByPodName("other-pod", "api-pod"));
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -92,11 +100,11 @@ class KubernetesCatalogWatchTest {
@Test
void testRandomOrderChangePodsAllNamespaces() {
+
+ createInAllNamespaceWatcher();
+
when(MIXED_OPERATION.list()).thenReturn(createSingleEndpointEndpointListByPodName("api-pod", "other-pod"))
.thenReturn(createSingleEndpointEndpointListByPodName("other-pod", "api-pod"));
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -107,10 +115,12 @@ class KubernetesCatalogWatchTest {
@Test
void testRandomOrderChangeServices() {
- when(MIXED_OPERATION.list()).thenReturn(createEndpointsListByServiceName("api-service", "other-service"))
+
+ createInSpecificNamespaceWatcher();
+
+ when(FILTER_WATCH_LIST_DELETABLE.list())
+ .thenReturn(createEndpointsListByServiceName("api-service", "other-service"))
.thenReturn(createEndpointsListByServiceName("other-service", "api-service"));
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -121,11 +131,11 @@ class KubernetesCatalogWatchTest {
@Test
void testRandomOrderChangeServicesAllNamespaces() {
+
+ createInAllNamespaceWatcher();
+
when(MIXED_OPERATION.list()).thenReturn(createEndpointsListByServiceName("api-service", "other-service"))
.thenReturn(createEndpointsListByServiceName("other-service", "api-service"));
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -136,10 +146,11 @@ class KubernetesCatalogWatchTest {
@Test
void testEventBody() {
- when(MIXED_OPERATION.list())
+
+ createInSpecificNamespaceWatcher();
+
+ when(FILTER_WATCH_LIST_DELETABLE.list())
.thenReturn(createSingleEndpointListWithNamespace("default", "api-pod", "other-pod"));
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
@@ -155,11 +166,11 @@ class KubernetesCatalogWatchTest {
@Test
void testEventBodyAllNamespaces() {
+
+ createInAllNamespaceWatcher();
+
when(MIXED_OPERATION.list())
.thenReturn(createSingleEndpointListWithNamespace("default", "api-pod", "other-pod"));
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
@@ -176,11 +187,11 @@ class KubernetesCatalogWatchTest {
@Test
void testEndpointsWithoutSubsets() {
+ createInSpecificNamespaceWatcher();
+
EndpointsList endpoints = createSingleEndpointEndpointListWithoutSubsets();
- when(MIXED_OPERATION.list()).thenReturn(endpoints);
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
+ when(FILTER_WATCH_LIST_DELETABLE.list()).thenReturn(endpoints);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -192,12 +203,11 @@ class KubernetesCatalogWatchTest {
@Test
void testEndpointsWithoutSubsetsAllNamespaces() {
+ createInAllNamespaceWatcher();
+
EndpointsList endpoints = createSingleEndpointEndpointListWithoutSubsets();
when(MIXED_OPERATION.list()).thenReturn(endpoints);
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -209,12 +219,12 @@ class KubernetesCatalogWatchTest {
@Test
void testEndpointsWithoutAddresses() {
+ createInSpecificNamespaceWatcher();
+
EndpointsList endpoints = createSingleEndpointEndpointListByPodName("api-pod");
endpoints.getItems().get(0).getSubsets().get(0).setAddresses(null);
- when(MIXED_OPERATION.list()).thenReturn(endpoints);
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
+ when(FILTER_WATCH_LIST_DELETABLE.list()).thenReturn(endpoints);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -226,13 +236,12 @@ class KubernetesCatalogWatchTest {
@Test
void testEndpointsWithoutAddressesAllNamespaces() {
+ createInAllNamespaceWatcher();
+
EndpointsList endpoints = createSingleEndpointEndpointListByPodName("api-pod");
endpoints.getItems().get(0).getSubsets().get(0).setAddresses(null);
when(MIXED_OPERATION.list()).thenReturn(endpoints);
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -244,12 +253,12 @@ class KubernetesCatalogWatchTest {
@Test
void testEndpointsWithoutTargetRefs() {
+ createInSpecificNamespaceWatcher();
+
EndpointsList endpoints = createSingleEndpointEndpointListByPodName("api-pod");
endpoints.getItems().get(0).getSubsets().get(0).getAddresses().get(0).setTargetRef(null);
- when(MIXED_OPERATION.list()).thenReturn(endpoints);
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
+ when(FILTER_WATCH_LIST_DELETABLE.list()).thenReturn(endpoints);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -261,13 +270,12 @@ class KubernetesCatalogWatchTest {
@Test
void testEndpointsWithoutTargetRefsAllNamespaces() {
+ createInAllNamespaceWatcher();
+
EndpointsList endpoints = createSingleEndpointEndpointListByPodName("api-pod");
endpoints.getItems().get(0).getSubsets().get(0).getAddresses().get(0).setTargetRef(null);
when(MIXED_OPERATION.list()).thenReturn(endpoints);
- when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace()).thenReturn(MIXED_OPERATION);
- when(CLIENT.endpoints().inAnyNamespace().withLabels(anyMap())).thenReturn(MIXED_OPERATION);
kubernetesCatalogWatch.catalogServicesWatch();
// second execution on shuffleServices
@@ -336,7 +344,7 @@ class KubernetesCatalogWatchTest {
EndpointAddress endpointAddress = new EndpointAddress();
endpointAddress.setTargetRef(podRef);
return endpointAddress;
- }).collect(Collectors.toList());
+ }).toList();
}
private List createEndpointAddressWithNamespace(String[] names, String namespace) {
@@ -347,7 +355,36 @@ class KubernetesCatalogWatchTest {
EndpointAddress endpointAddress = new EndpointAddress();
endpointAddress.setTargetRef(podRef);
return endpointAddress;
- }).collect(Collectors.toList());
+ }).toList();
+ }
+
+ private void createInAllNamespaceWatcher() {
+
+ when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
+ when(MIXED_OPERATION.inAnyNamespace()).thenReturn(MIXED_OPERATION);
+ when(MIXED_OPERATION.withLabels(Map.of())).thenReturn(MIXED_OPERATION);
+
+ // all-namespaces = true
+ KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, true, true, 60, false, "",
+ Set.of(), Map.of(), "", null, 0);
+
+ kubernetesCatalogWatch = new KubernetesCatalogWatch(CLIENT, properties, namespaceProvider);
+ kubernetesCatalogWatch.setApplicationEventPublisher(APPLICATION_EVENT_PUBLISHER);
+ }
+
+ private void createInSpecificNamespaceWatcher() {
+
+ // all-namespaces = false
+ KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(true, false, true, 60, false, "",
+ Set.of(), Map.of(), "", null, 0);
+
+ kubernetesCatalogWatch = new KubernetesCatalogWatch(CLIENT, properties, namespaceProvider);
+ kubernetesCatalogWatch.setApplicationEventPublisher(APPLICATION_EVENT_PUBLISHER);
+
+ when(namespaceProvider.getNamespace()).thenReturn("catalog-watcher-namespace");
+ when(CLIENT.endpoints()).thenReturn(MIXED_OPERATION);
+ when(MIXED_OPERATION.inNamespace("catalog-watcher-namespace")).thenReturn(NON_NAMESPACE_OPERATION);
+ when(NON_NAMESPACE_OPERATION.withLabels(Map.of())).thenReturn(FILTER_WATCH_LIST_DELETABLE);
}
}