Skip to content

Commit 5c0be41

Browse files
committed
dirty
Signed-off-by: wind57 <[email protected]>
1 parent d1e555f commit 5c0be41

File tree

4 files changed

+183
-119
lines changed

4 files changed

+183
-119
lines changed

spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchIT.java

Lines changed: 0 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,6 @@ void beforeEach() {
101101
@Test
102102
@Order(2)
103103
void testCatalogWatchWithEndpointSlices() {
104-
KubernetesClientCatalogWatchUtils.patchForEndpointSlices(APP_NAME, NAMESPACE, DOCKER_IMAGE);
105-
waitForLogStatement("stateGenerator is of type: KubernetesEndpointSlicesCatalogWatch", K3S, APP_NAME);
106-
test();
107104

108105
testCatalogWatchWithEndpointsNamespaces();
109106
}
@@ -124,85 +121,6 @@ void testCatalogWatchWithEndpointsNamespaces() {
124121
KubernetesClientCatalogWatchNamespacesDelegate.testCatalogWatchWithEndpointSlicesNamespaces(APP_NAME);
125122
}
126123

127-
/**
128-
* the test is the same for both endpoints and endpoint slices, the set-up for them is
129-
* different.
130-
*/
131-
private void test() {
132-
133-
WebClient client = builder().baseUrl("http://localhost/result").build();
134-
EndpointNameAndNamespace[] holder = new EndpointNameAndNamespace[2];
135-
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(List.class, EndpointNameAndNamespace.class);
136-
137-
await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> {
138-
List<EndpointNameAndNamespace> result = (List<EndpointNameAndNamespace>) client.method(HttpMethod.GET)
139-
.retrieve()
140-
.bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType()))
141-
.retryWhen(retrySpec())
142-
.block();
143-
144-
// we get 3 pods as input, but because they are sorted by name in the catalog
145-
// watcher implementation
146-
// we will get the first busybox instances here.
147-
148-
if (result != null) {
149-
if (result.size() != 3) {
150-
return false;
151-
}
152-
holder[0] = result.get(0);
153-
holder[1] = result.get(1);
154-
return true;
155-
}
156-
157-
return false;
158-
});
159-
160-
EndpointNameAndNamespace resultOne = holder[0];
161-
EndpointNameAndNamespace resultTwo = holder[1];
162-
163-
Assertions.assertNotNull(resultOne);
164-
Assertions.assertNotNull(resultTwo);
165-
166-
Assertions.assertTrue(resultOne.endpointName().contains("busybox"));
167-
Assertions.assertTrue(resultTwo.endpointName().contains("busybox"));
168-
Assertions.assertEquals("default", resultOne.namespace());
169-
Assertions.assertEquals("default", resultTwo.namespace());
170-
171-
util.busybox(NAMESPACE, Phase.DELETE);
172-
173-
// what we get after delete
174-
EndpointNameAndNamespace[] afterDelete = new EndpointNameAndNamespace[1];
175-
176-
await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(240)).until(() -> {
177-
List<EndpointNameAndNamespace> result = (List<EndpointNameAndNamespace>) client.method(HttpMethod.GET)
178-
.retrieve()
179-
.bodyToMono(ParameterizedTypeReference.forType(resolvableType.getType()))
180-
.retryWhen(retrySpec())
181-
.block();
182-
183-
// we need to get the event from KubernetesCatalogWatch, but that happens
184-
// on periodic bases. So in order to be sure we got the event we care about
185-
// we wait until the result has a single entry, which means busybox was
186-
// deleted
187-
// + KubernetesCatalogWatch received the new update.
188-
if (result != null && result.size() != 1) {
189-
return false;
190-
}
191-
192-
// we will only receive one pod here, our own
193-
if (result != null) {
194-
afterDelete[0] = result.get(0);
195-
return true;
196-
}
197-
198-
return false;
199-
});
200-
201-
Assertions.assertTrue(afterDelete[0].endpointName().contains(APP_NAME));
202-
Assertions.assertEquals("default", afterDelete[0].namespace());
203-
204-
}
205-
206124
private static void app(Phase phase) {
207125
V1Deployment deployment = (V1Deployment) util.yaml("app/watcher-deployment.yaml");
208126
V1Service service = (V1Service) util.yaml("app/watcher-service.yaml");
@@ -216,12 +134,4 @@ else if (phase.equals(Phase.DELETE)) {
216134
}
217135
}
218136

219-
private WebClient.Builder builder() {
220-
return WebClient.builder().clientConnector(new ReactorClientHttpConnector(HttpClient.create()));
221-
}
222-
223-
private RetryBackoffSpec retrySpec() {
224-
return Retry.fixedDelay(15, Duration.ofSeconds(1)).filter(Objects::nonNull);
225-
}
226-
227137
}

spring-cloud-kubernetes-integration-tests/spring-cloud-kubernetes-k8s-client-catalog-watcher/src/test/java/org/springframework/cloud/kubernetes/k8s/client/catalog/watcher/KubernetesClientCatalogWatchUtils.java

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,6 @@ private KubernetesClientCatalogWatchUtils() {
3232

3333
}
3434

35-
private static final String BODY_ONE = """
36-
{
37-
"spec": {
38-
"template": {
39-
"spec": {
40-
"containers": [{
41-
"name": "spring-cloud-kubernetes-k8s-client-catalog-watcher",
42-
"image": "image_name_here",
43-
"env": [
44-
{
45-
"name": "SPRING_CLOUD_KUBERNETES_DISCOVERY_USE_ENDPOINT_SLICES",
46-
"value": "TRUE"
47-
},
48-
{
49-
"name": "LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_DISCOVERY_CATALOG",
50-
"value": "DEBUG"
51-
}
52-
]
53-
}]
54-
}
55-
}
56-
}
57-
}
58-
""";
59-
6035
private static final String BODY_TWO = """
6136
{
6237
"spec": {
@@ -123,10 +98,6 @@ private KubernetesClientCatalogWatchUtils() {
12398
}
12499
""";
125100

126-
static void patchForEndpointSlices(String deploymentName, String namespace, String imageName) {
127-
patchWithReplace(imageName, deploymentName, namespace, BODY_ONE, POD_LABELS);
128-
}
129-
130101
static void patchForEndpointsNamespaces(String deploymentName, String namespace, String imageName) {
131102
patchWithReplace(imageName, deploymentName, namespace, BODY_TWO, POD_LABELS);
132103
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2013-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it;
18+
19+
import java.util.Set;
20+
21+
import io.kubernetes.client.openapi.ApiClient;
22+
import org.junit.jupiter.api.AfterEach;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.Test;
25+
26+
import org.springframework.boot.test.context.SpringBootTest;
27+
import org.springframework.boot.test.context.TestConfiguration;
28+
import org.springframework.boot.test.system.CapturedOutput;
29+
import org.springframework.boot.test.web.server.LocalServerPort;
30+
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
31+
import org.springframework.cloud.kubernetes.integration.tests.commons.Images;
32+
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
33+
import org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.Application;
34+
import org.springframework.context.annotation.Bean;
35+
import org.springframework.context.annotation.Primary;
36+
37+
import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.assertLogStatement;
38+
import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.invokeAndAssert;
39+
40+
@SpringBootTest(classes = { KubernetesClientCatalogWatchEndpointSlicesIT.TestConfig.class, Application.class },
41+
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
42+
class KubernetesClientCatalogWatchEndpointSlicesIT extends KubernetesClientCatalogWatchBase {
43+
44+
@LocalServerPort
45+
private int port;
46+
47+
@BeforeEach
48+
void beforeEach() {
49+
50+
util.createNamespace(NAMESPACE_A);
51+
util.createNamespace(NAMESPACE_B);
52+
53+
Images.loadBusybox(K3S);
54+
55+
util.busybox(NAMESPACE_A, Phase.CREATE);
56+
util.busybox(NAMESPACE_B, Phase.CREATE);
57+
58+
}
59+
60+
@AfterEach
61+
void afterEach() {
62+
// busybox is deleted as part of the assertions, thus not seen here
63+
util.deleteNamespace(NAMESPACE_A);
64+
util.deleteNamespace(NAMESPACE_B);
65+
}
66+
67+
/**
68+
* <pre>
69+
* - we deploy a busybox service with 2 replica pods in two namespaces : a, b
70+
* - we use endpoints
71+
* - we enable namespace filtering for 'default' and 'a'
72+
* - we receive an event from KubernetesCatalogWatcher, assert what is inside it
73+
* - delete the busybox service in 'a' and 'b'
74+
* - assert that we receive an empty response
75+
* </pre>
76+
*/
77+
@Test
78+
void testCatalogWatchWithEndpoints(CapturedOutput output) {
79+
assertLogStatement(output, "stateGenerator is of type: KubernetesEndpointSlicesCatalogWatch");
80+
invokeAndAssert(util, Set.of(NAMESPACE_A, NAMESPACE_B), port, NAMESPACE_A);
81+
}
82+
83+
@TestConfiguration
84+
static class TestConfig {
85+
86+
@Bean
87+
@Primary
88+
ApiClient client() {
89+
return apiClient();
90+
}
91+
92+
@Bean
93+
@Primary
94+
KubernetesDiscoveryProperties kubernetesDiscoveryProperties() {
95+
return discoveryProperties(true);
96+
}
97+
98+
}
99+
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it;
2+
3+
import io.kubernetes.client.openapi.ApiClient;
4+
import org.junit.jupiter.api.AfterEach;
5+
import org.junit.jupiter.api.BeforeEach;
6+
import org.junit.jupiter.api.Test;
7+
import org.springframework.boot.test.context.SpringBootTest;
8+
import org.springframework.boot.test.context.TestConfiguration;
9+
import org.springframework.boot.test.system.CapturedOutput;
10+
import org.springframework.boot.test.web.server.LocalServerPort;
11+
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
12+
import org.springframework.cloud.kubernetes.integration.tests.commons.Images;
13+
import org.springframework.cloud.kubernetes.integration.tests.commons.Phase;
14+
import org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.Application;
15+
import org.springframework.context.annotation.Bean;
16+
import org.springframework.context.annotation.Primary;
17+
18+
import java.util.Set;
19+
20+
import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.assertLogStatement;
21+
import static org.springframework.cloud.kubernetes.k8s.client.catalog.watcher.it.TestAssertions.invokeAndAssert;
22+
23+
@SpringBootTest(classes = { KubernetesClientCatalogWatchEndpointsNamespaceFilterIT.TestConfig.class, Application.class },
24+
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
25+
class KubernetesClientCatalogWatchEndpointsNamespaceFilterIT extends KubernetesClientCatalogWatchBase {
26+
27+
@LocalServerPort
28+
private int port;
29+
30+
@BeforeEach
31+
void beforeEach() {
32+
33+
util.createNamespace(NAMESPACE_A);
34+
util.createNamespace(NAMESPACE_B);
35+
36+
Images.loadBusybox(K3S);
37+
38+
util.busybox(NAMESPACE_A, Phase.CREATE);
39+
util.busybox(NAMESPACE_B, Phase.CREATE);
40+
41+
}
42+
43+
@AfterEach
44+
void afterEach() {
45+
// busybox is deleted as part of the assertions, thus not seen here
46+
util.deleteNamespace(NAMESPACE_A);
47+
util.deleteNamespace(NAMESPACE_B);
48+
}
49+
50+
/**
51+
* <pre>
52+
* - we deploy a busybox service with 2 replica pods in two namespaces : a, b
53+
* - we use endpoints
54+
* - we enable namespace filtering for 'default' and 'a'
55+
* - we receive an event from KubernetesCatalogWatcher, assert what is inside it
56+
* - delete the busybox service in 'a' and 'b'
57+
* - assert that we receive an empty response
58+
* </pre>
59+
*/
60+
@Test
61+
void testCatalogWatchWithEndpoints(CapturedOutput output) {
62+
assertLogStatement(output, "stateGenerator is of type: KubernetesEndpointsCatalogWatch");
63+
invokeAndAssert(util, Set.of(NAMESPACE_A, NAMESPACE_B), port, NAMESPACE_A);
64+
}
65+
66+
@TestConfiguration
67+
static class TestConfig {
68+
69+
@Bean
70+
@Primary
71+
ApiClient client() {
72+
return apiClient();
73+
}
74+
75+
@Bean
76+
@Primary
77+
KubernetesDiscoveryProperties kubernetesDiscoveryProperties() {
78+
return discoveryProperties(false);
79+
}
80+
81+
}
82+
83+
}

0 commit comments

Comments
 (0)