Skip to content

Commit 80525bf

Browse files
authored
feat: conversion hooks e2e tests (#50)
1 parent ace65ab commit 80525bf

File tree

9 files changed

+307
-178
lines changed

9 files changed

+307
-178
lines changed

delme.yaml

Lines changed: 0 additions & 21 deletions
This file was deleted.

samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/Utils.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
import java.io.InputStream;
66
import java.util.Map;
77
import java.util.concurrent.TimeUnit;
8+
import java.util.function.UnaryOperator;
9+
import java.util.stream.Collectors;
810

11+
import io.fabric8.kubernetes.api.model.HasMetadata;
912
import io.fabric8.kubernetes.api.model.networking.v1.*;
1013
import io.fabric8.kubernetes.client.KubernetesClient;
1114

@@ -15,16 +18,30 @@ public class Utils {
1518

1619
public static final int SPIN_UP_GRACE_PERIOD = 120;
1720

21+
1822
public static void applyAndWait(KubernetesClient client, String path) {
23+
applyAndWait(client, path, null);
24+
}
25+
26+
public static void applyAndWait(KubernetesClient client, String path,
27+
UnaryOperator<HasMetadata> transform) {
1928
try (FileInputStream fileInputStream = new FileInputStream(path)) {
20-
applyAndWait(client, fileInputStream);
29+
applyAndWait(client, fileInputStream, transform);
2130
} catch (IOException e) {
2231
throw new IllegalStateException(e);
2332
}
2433
}
2534

2635
public static void applyAndWait(KubernetesClient client, InputStream is) {
36+
applyAndWait(client, is, null);
37+
}
38+
39+
public static void applyAndWait(KubernetesClient client, InputStream is,
40+
UnaryOperator<HasMetadata> transfor) {
2741
var resources = client.load(is).get();
42+
if (transfor != null) {
43+
resources = resources.stream().map(transfor).collect(Collectors.toList());
44+
}
2845
client.resourceList(resources).createOrReplace();
2946
client.resourceList(resources).waitUntilReady(3, TimeUnit.MINUTES);
3047
}

samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpecV2.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22

33
public class MultiVersionCustomResourceSpecV2 {
44

5-
private String value;
5+
private String alteredValue;
66

7-
8-
public String getValue() {
9-
return value;
7+
public String getAlteredValue() {
8+
return alteredValue;
109
}
1110

12-
public MultiVersionCustomResourceSpecV2 setValue(String value) {
13-
this.value = value;
11+
public MultiVersionCustomResourceSpecV2 setAlteredValue(String alteredValue) {
12+
this.alteredValue = alteredValue;
1413
return this;
1514
}
1615

samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V2Mapper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class V2Mapper
1313
public MultiVersionHub toHub(MultiVersionCustomResourceV2 resource) {
1414
var hub = new MultiVersionHub();
1515
hub.setMetadata(resource.getMetadata());
16-
hub.setValue(Integer.parseInt(resource.getSpec().getValue()));
16+
hub.setValue(Integer.parseInt(resource.getSpec().getAlteredValue()));
1717
return hub;
1818
}
1919

@@ -23,7 +23,7 @@ public MultiVersionCustomResourceV2 fromHub(
2323
var res = new MultiVersionCustomResourceV2();
2424
res.setMetadata(hub.getMetadata());
2525
res.setSpec(new MultiVersionCustomResourceSpecV2());
26-
res.getSpec().setValue(Integer.toString(hub.getValue()));
26+
res.getSpec().setAlteredValue(Integer.toString(hub.getValue()));
2727
return res;
2828
}
2929
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package io.javaoperatorsdk.webhook.admission.sample.quarkus;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.net.URL;
6+
import java.time.Duration;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.function.UnaryOperator;
10+
11+
import org.junit.jupiter.api.BeforeAll;
12+
import org.junit.jupiter.api.Test;
13+
14+
import io.fabric8.kubernetes.api.model.HasMetadata;
15+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
16+
import io.fabric8.kubernetes.api.model.apiextensions.v1.*;
17+
import io.fabric8.kubernetes.api.model.networking.v1.*;
18+
import io.fabric8.kubernetes.client.KubernetesClient;
19+
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
20+
import io.fabric8.kubernetes.client.KubernetesClientException;
21+
import io.javaoperatorsdk.webhook.sample.commons.customresource.MultiVersionCustomResource;
22+
import io.javaoperatorsdk.webhook.sample.commons.customresource.MultiVersionCustomResourceSpec;
23+
import io.javaoperatorsdk.webhook.sample.commons.customresource.MultiVersionCustomResourceV2;
24+
25+
import static io.javaoperatorsdk.webhook.admission.sample.quarkus.conversion.ConversionEndpoint.CONVERSION_PATH;
26+
import static io.javaoperatorsdk.webhook.sample.commons.AdmissionControllers.MUTATION_TARGET_LABEL;
27+
import static io.javaoperatorsdk.webhook.sample.commons.Utils.*;
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
import static org.awaitility.Awaitility.await;
30+
import static org.junit.jupiter.api.Assertions.assertThrows;
31+
32+
class WebhooksE2E {
33+
34+
public static final String TEST_CR_NAME = "test-cr";
35+
public static final int CR_SPEC_VALUE = 5;
36+
private KubernetesClient client = new KubernetesClientBuilder().build();
37+
38+
@BeforeAll
39+
static void deployService() throws IOException {
40+
try (KubernetesClient client = new KubernetesClientBuilder().build();
41+
InputStream certManager =
42+
new URL(
43+
"https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml")
44+
.openStream()) {
45+
applyAndWait(client, certManager);
46+
applyAndWait(client, "target/kubernetes/minikube.yml");
47+
applyAndWait(client, "k8s/validating-webhook-configuration.yml");
48+
applyAndWait(client, "k8s/mutating-webhook-configuration.yml");
49+
applyAndWait(client,
50+
"../commons/target/classes/META-INF/fabric8/multiversioncustomresources.sample.javaoperatorsdk-v1.yml",
51+
addConversionHookEndpointToCustomResource());
52+
53+
}
54+
}
55+
56+
@Test
57+
void validationHook() {
58+
var ingressWithLabel = testIngress("normal-add-test");
59+
addRequiredLabels(ingressWithLabel);
60+
await().atMost(Duration.ofSeconds(SPIN_UP_GRACE_PERIOD)).untilAsserted(() -> {
61+
Ingress res = null;
62+
try {
63+
// this can be since coredns in minikube can take some time
64+
res = client.network().v1().ingresses().resource(ingressWithLabel).createOrReplace();
65+
} catch (KubernetesClientException e) {
66+
}
67+
assertThat(res).isNotNull();
68+
});
69+
assertThrows(KubernetesClientException.class,
70+
() -> client.network().v1().ingresses().resource(testIngress("validate-test"))
71+
.createOrReplace());
72+
}
73+
74+
@Test
75+
void mutationHook() {
76+
var ingressWithLabel = testIngress("mutation-test");
77+
addRequiredLabels(ingressWithLabel);
78+
await().atMost(Duration.ofSeconds(SPIN_UP_GRACE_PERIOD)).untilAsserted(() -> {
79+
Ingress res = null;
80+
try {
81+
// this can be since coredns in minikube can take some time
82+
res = client.network().v1().ingresses().resource(ingressWithLabel).createOrReplace();
83+
} catch (KubernetesClientException e) {
84+
}
85+
assertThat(res).isNotNull();
86+
assertThat(res.getMetadata().getLabels()).containsKey(MUTATION_TARGET_LABEL);
87+
});
88+
}
89+
90+
@Test
91+
void conversionHook() {
92+
await().atMost(Duration.ofSeconds(SPIN_UP_GRACE_PERIOD)).untilAsserted(() -> {
93+
try {
94+
// this can be since coredns in minikube can take some time
95+
createV1Resource(TEST_CR_NAME);
96+
} catch (KubernetesClientException e) {
97+
}
98+
});
99+
MultiVersionCustomResourceV2 v2 =
100+
client.resources(MultiVersionCustomResourceV2.class).withName(TEST_CR_NAME).get();
101+
assertThat(v2.getSpec().getAlteredValue()).isEqualTo("" + CR_SPEC_VALUE);
102+
}
103+
104+
private MultiVersionCustomResource createV1Resource(String name) {
105+
var res = new MultiVersionCustomResource();
106+
res.setMetadata(new ObjectMetaBuilder()
107+
.withName(name)
108+
.build());
109+
res.setSpec(new MultiVersionCustomResourceSpec());
110+
res.getSpec().setValue(CR_SPEC_VALUE);
111+
return client.resource(res).createOrReplace();
112+
}
113+
114+
static UnaryOperator<HasMetadata> addConversionHookEndpointToCustomResource() {
115+
return r -> {
116+
if (!(r instanceof CustomResourceDefinition)) {
117+
return r;
118+
}
119+
var crd = (CustomResourceDefinition) r;
120+
var crc = new CustomResourceConversion();
121+
crd.getMetadata()
122+
.setAnnotations(Map.of("cert-manager.io/inject-ca-from", "default/quarkus-sample"));
123+
crd.getSpec().setConversion(crc);
124+
crc.setStrategy("Webhook");
125+
126+
var whc = new WebhookConversionBuilder()
127+
.withConversionReviewVersions(List.of("v1"))
128+
.withClientConfig(new WebhookClientConfigBuilder()
129+
.withService(new ServiceReferenceBuilder()
130+
.withPath("/" + CONVERSION_PATH)
131+
.withName("quarkus-sample")
132+
.withNamespace("default")
133+
.withPort(443)
134+
.build())
135+
.build())
136+
.build();
137+
crc.setWebhook(whc);
138+
return crd;
139+
};
140+
}
141+
142+
}

samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerE2E.java

Lines changed: 0 additions & 73 deletions
This file was deleted.

samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpointTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
class ConversionEndpointTest {
1919

2020
final static String expectedResult =
21-
"{\"apiVersion\":\"apiextensions.k8s.io/v1\",\"kind\":\"ConversionReview\",\"response\":{\"convertedObjects\":[{\"apiVersion\":\"sample.javaoperatorsdk/v2\",\"kind\":\"MultiVersionCustomResource\",\"metadata\":{\"creationTimestamp\":\"2021-09-04T14:03:02Z\",\"name\":\"resource1\",\"namespace\":\"default\",\"resourceVersion\":\"143\",\"uid\":\"3415a7fc-162b-4300-b5da-fd6083580d66\"},\"spec\":{\"value\":\"1\"}},{\"apiVersion\":\"sample.javaoperatorsdk/v2\",\"kind\":\"MultiVersionCustomResource\",\"metadata\":{\"creationTimestamp\":\"2021-09-04T14:03:02Z\",\"name\":\"resource2\",\"namespace\":\"default\",\"resourceVersion\":\"14344\",\"uid\":\"1115a7fc-162b-4300-b5da-fd6083580d55\"},\"spec\":{\"value\":\"2\"}}],\"result\":{\"apiVersion\":\"v1\",\"kind\":\"Status\",\"status\":\"Success\"},\"uid\":\"705ab4f5-6393-11e8-b7cc-42010a800002\"}}";
22-
21+
"{\"apiVersion\":\"apiextensions.k8s.io/v1\",\"kind\":\"ConversionReview\",\"response\":{\"convertedObjects\":[{\"apiVersion\":\"sample.javaoperatorsdk/v2\",\"kind\":\"MultiVersionCustomResource\",\"metadata\":{\"creationTimestamp\":\"2021-09-04T14:03:02Z\",\"name\":\"resource1\",\"namespace\":\"default\",\"resourceVersion\":\"143\",\"uid\":\"3415a7fc-162b-4300-b5da-fd6083580d66\"},\"spec\":{\"alteredValue\":\"1\"}},{\"apiVersion\":\"sample.javaoperatorsdk/v2\",\"kind\":\"MultiVersionCustomResource\",\"metadata\":{\"creationTimestamp\":\"2021-09-04T14:03:02Z\",\"name\":\"resource2\",\"namespace\":\"default\",\"resourceVersion\":\"14344\",\"uid\":\"1115a7fc-162b-4300-b5da-fd6083580d55\"},\"spec\":{\"alteredValue\":\"2\"}}],\"result\":{\"apiVersion\":\"v1\",\"kind\":\"Status\",\"status\":\"Success\"},\"uid\":\"705ab4f5-6393-11e8-b7cc-42010a800002\"}}";
2322

2423
@Test
2524
void conversion() {

0 commit comments

Comments
 (0)