From c29ce11170d3cac2f8770056db97f7049b560630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 14 Jul 2022 10:30:30 +0200 Subject: [PATCH] feat: conversion hooks integration tests (#25) --- core/pom.xml | 1 - .../conversion/AsyncConversionController.java | 2 + .../conversion/ConversionController.java | 2 + .../webhook/conversion/Utils.java | 27 ++++++++ .../webhook/conversion/UtilsTest.java | 19 +++++ .../conversion/crd/CustomResourceV1.java | 2 +- .../conversion/crd/CustomResourceV2.java | 2 +- .../conversion/crd/CustomResourceV3.java | 2 +- pom.xml | 3 - samples/commons/pom.xml | 46 +++++++++++++ .../MultiVersionCustomResource.java | 16 +++++ .../MultiVersionCustomResourceSpec.java | 15 ++++ .../MultiVersionCustomResourceSpecV2.java | 25 +++++++ .../MultiVersionCustomResourceStatus.java | 16 +++++ .../MultiVersionCustomResourceStatusV2.java | 27 ++++++++ .../MultiVersionCustomResourceV2.java | 15 ++++ .../sample/commons/mapper/AsyncV1Mapper.java | 27 ++++++++ .../sample/commons/mapper/AsyncV2Mapper.java | 27 ++++++++ .../sample/commons/mapper/V1Mapper.java | 48 +++++++++++++ .../sample/commons/mapper/V2Mapper.java | 21 ++++++ samples/pom.xml | 1 + samples/quarkus/pom.xml | 5 ++ .../AdmissionControllerConfig.java | 2 +- .../{ => admission}/AdmissionEndpoint.java | 2 +- .../ConversionControllerConfig.java | 33 +++++++++ .../conversion/ConversionEndpoint.java | 47 +++++++++++++ .../AdmissionEndpointTest.java | 2 +- .../NativeAdmissionEndpointIT.java | 2 +- .../conversion/ConversionEndpointTest.java | 52 ++++++++++++++ .../NativeConversionEndpointTest.java | 7 ++ .../test/resources/conversion-request.json | 47 +++++++++++++ samples/spring-boot/pom.xml | 10 +++ .../AdmissionConfig.java} | 4 +- .../{ => admission}/AdmissionEndpoint.java | 4 +- .../conversion/ConversionConfig.java | 32 +++++++++ .../conversion/ConversionEndpoint.java | 41 +++++++++++ .../AdmissionEndpointTest.java | 6 +- .../conversion/ConversionEndpointTest.java | 69 +++++++++++++++++++ .../test/resources/conversion-request.json | 47 +++++++++++++ 39 files changed, 738 insertions(+), 18 deletions(-) create mode 100644 samples/commons/pom.xml create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResource.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpec.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpecV2.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceStatus.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceStatusV2.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceV2.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/AsyncV1Mapper.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/AsyncV2Mapper.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V1Mapper.java create mode 100644 samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V2Mapper.java rename samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/{ => admission}/AdmissionControllerConfig.java (98%) rename samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/{ => admission}/AdmissionEndpoint.java (98%) create mode 100644 samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionControllerConfig.java create mode 100644 samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpoint.java rename samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/{ => admission}/AdmissionEndpointTest.java (97%) rename samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/{ => admission}/NativeAdmissionEndpointIT.java (72%) create mode 100644 samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpointTest.java create mode 100644 samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/NativeConversionEndpointTest.java create mode 100644 samples/quarkus/src/test/resources/conversion-request.json rename samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/{Config.java => admission/AdmissionConfig.java} (97%) rename samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/{ => admission}/AdmissionEndpoint.java (98%) create mode 100644 samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionConfig.java create mode 100644 samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionEndpoint.java rename samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/{ => admission}/AdmissionEndpointTest.java (93%) create mode 100644 samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionEndpointTest.java create mode 100644 samples/spring-boot/src/test/resources/conversion-request.json diff --git a/core/pom.xml b/core/pom.xml index 689c3ef6..b8c3950b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -50,7 +50,6 @@ - io.fabric8 kubernetes-client diff --git a/core/src/main/java/io/javaoperatorsdk/webhook/conversion/AsyncConversionController.java b/core/src/main/java/io/javaoperatorsdk/webhook/conversion/AsyncConversionController.java index 077507ab..7b6f9e6f 100644 --- a/core/src/main/java/io/javaoperatorsdk/webhook/conversion/AsyncConversionController.java +++ b/core/src/main/java/io/javaoperatorsdk/webhook/conversion/AsyncConversionController.java @@ -28,6 +28,8 @@ public void registerMapper(AsyncMapper mapper) { throw new IllegalStateException(MAPPER_ALREADY_REGISTERED_FOR_VERSION_MESSAGE + version); } mappers.put(version, mapper); + Utils.registerCustomKind( + Utils.getFirstTypeArgumentFromInterface(mapper.getClass(), AsyncMapper.class)); } @Override diff --git a/core/src/main/java/io/javaoperatorsdk/webhook/conversion/ConversionController.java b/core/src/main/java/io/javaoperatorsdk/webhook/conversion/ConversionController.java index 4c98f83c..00ba1f36 100644 --- a/core/src/main/java/io/javaoperatorsdk/webhook/conversion/ConversionController.java +++ b/core/src/main/java/io/javaoperatorsdk/webhook/conversion/ConversionController.java @@ -27,6 +27,8 @@ public void registerMapper(Mapper mapper) { throw new IllegalStateException(MAPPER_ALREADY_REGISTERED_FOR_VERSION_MESSAGE + version); } mappers.put(version, mapper); + Utils.registerCustomKind( + Utils.getFirstTypeArgumentFromInterface(mapper.getClass(), Mapper.class)); } @Override diff --git a/core/src/main/java/io/javaoperatorsdk/webhook/conversion/Utils.java b/core/src/main/java/io/javaoperatorsdk/webhook/conversion/Utils.java index 7f16d81e..a423ddea 100644 --- a/core/src/main/java/io/javaoperatorsdk/webhook/conversion/Utils.java +++ b/core/src/main/java/io/javaoperatorsdk/webhook/conversion/Utils.java @@ -1,5 +1,11 @@ package io.javaoperatorsdk.webhook.conversion; +import java.lang.reflect.ParameterizedType; +import java.util.Arrays; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.internal.KubernetesDeserializer; + public class Utils { private Utils() {} @@ -12,4 +18,25 @@ public static String versionOfApiVersion(String apiVersion) { var lastDelimiter = apiVersion.lastIndexOf("/"); return apiVersion.substring(lastDelimiter + 1); } + + public static void registerCustomKind(Class clazz) { + KubernetesDeserializer.registerCustomKind(HasMetadata.getApiVersion(clazz), + HasMetadata.getKind(clazz), clazz); + } + + @SuppressWarnings("unchecked") + public static Class getFirstTypeArgumentFromInterface(Class clazz, + Class expectedImplementedInterface) { + return (Class) Arrays.stream(clazz.getGenericInterfaces()) + .filter(type -> type.getTypeName().startsWith(expectedImplementedInterface.getName()) + && type instanceof ParameterizedType) + .map(ParameterizedType.class::cast) + .findFirst() + .map(t -> (Class) t.getActualTypeArguments()[0]) + .orElseThrow(() -> new RuntimeException( + "Couldn't retrieve generic parameter type from " + clazz.getSimpleName() + + " because it doesn't implement " + + expectedImplementedInterface.getSimpleName() + + " directly")); + } } diff --git a/core/src/test/java/io/javaoperatorsdk/webhook/conversion/UtilsTest.java b/core/src/test/java/io/javaoperatorsdk/webhook/conversion/UtilsTest.java index 6229d126..bed5264a 100644 --- a/core/src/test/java/io/javaoperatorsdk/webhook/conversion/UtilsTest.java +++ b/core/src/test/java/io/javaoperatorsdk/webhook/conversion/UtilsTest.java @@ -2,6 +2,13 @@ import org.junit.jupiter.api.Test; +import io.javaoperatorsdk.webhook.conversion.crd.CustomResourceV1; +import io.javaoperatorsdk.webhook.conversion.crd.CustomResourceV2; +import io.javaoperatorsdk.webhook.conversion.mapper.AsyncV1Mapper; +import io.javaoperatorsdk.webhook.conversion.mapper.AsyncV2Mapper; +import io.javaoperatorsdk.webhook.conversion.mapper.CustomResourceV1Mapper; +import io.javaoperatorsdk.webhook.conversion.mapper.CustomResourceV2Mapper; + import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; @@ -13,4 +20,16 @@ void getsVersionFromApiVersion() { assertThat(Utils.versionOfApiVersion("extensions/v1beta1")).isEqualTo("v1beta1"); } + @Test + void getMapperResourceType() { + assertThat(Utils.getFirstTypeArgumentFromInterface(CustomResourceV1Mapper.class, Mapper.class)) + .isEqualTo(CustomResourceV1.class); + assertThat(Utils.getFirstTypeArgumentFromInterface(CustomResourceV2Mapper.class, Mapper.class)) + .isEqualTo(CustomResourceV2.class); + assertThat(Utils.getFirstTypeArgumentFromInterface(AsyncV1Mapper.class, AsyncMapper.class)) + .isEqualTo(CustomResourceV1.class); + assertThat(Utils.getFirstTypeArgumentFromInterface(AsyncV2Mapper.class, AsyncMapper.class)) + .isEqualTo(CustomResourceV2.class); + } + } diff --git a/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV1.java b/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV1.java index ea003ef6..7c277104 100644 --- a/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV1.java +++ b/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV1.java @@ -9,7 +9,7 @@ @Group("sample.javaoperatorsdk") @Version("v1") -@Kind("MultiVersionCustomResource") +@Kind("MultiVersionTestCustomResource") @ShortNames("mv1") public class CustomResourceV1 extends diff --git a/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV2.java b/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV2.java index 0f357f92..75f25ead 100644 --- a/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV2.java +++ b/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV2.java @@ -9,7 +9,7 @@ @Group("sample.javaoperatorsdk") @Version(value = "v2", storage = false) -@Kind("MultiVersionCustomResource") +@Kind("MultiVersionTestCustomResource") @ShortNames("mv2") public class CustomResourceV2 extends diff --git a/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV3.java b/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV3.java index 2916fb8f..76d7be68 100644 --- a/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV3.java +++ b/core/src/test/java/io/javaoperatorsdk/webhook/conversion/crd/CustomResourceV3.java @@ -9,7 +9,7 @@ @Group("sample.javaoperatorsdk") @Version(value = "v3", storage = false) -@Kind("MultiVersionCustomResource") +@Kind("MultiVersionTestCustomResource") @ShortNames("mv3") public class CustomResourceV3 extends diff --git a/pom.xml b/pom.xml index d9eba037..d0f394d4 100644 --- a/pom.xml +++ b/pom.xml @@ -158,9 +158,6 @@ org.apache.maven.plugins maven-surefire-plugin ${maven-surefire-plugin.version} - - 3 - org.apache.maven.plugins diff --git a/samples/commons/pom.xml b/samples/commons/pom.xml new file mode 100644 index 00000000..3d70ff7b --- /dev/null +++ b/samples/commons/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + io.javaoperatorsdk + admission-controller-framework-samples + 0.2.1-SNAPSHOT + + + io.javaoperatorsdk.admissioncontroller.sample + sample-commons + Admission Controller Framework - Samples - Commons + + + 11 + 2.6.6 + + + + + io.fabric8 + kubernetes-client + + + io.javaoperatorsdk + admission-controller-framework-core + ${project.version} + + + io.fabric8 + crd-generator-apt + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot-dependencies.version} + + + + + diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResource.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResource.java new file mode 100644 index 00000000..cd6bea05 --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResource.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.webhook.sample.commons.customresource; + +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Kind; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version(value = "v1", storage = false) +@Kind("MultiVersionCustomResource") +@ShortNames("tcr") +public class MultiVersionCustomResource + extends CustomResource { + +} diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpec.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpec.java new file mode 100644 index 00000000..8a43e055 --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpec.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.webhook.sample.commons.customresource; + +public class MultiVersionCustomResourceSpec { + + private int value; + + public int getValue() { + return value; + } + + public MultiVersionCustomResourceSpec setValue(int value) { + this.value = value; + return this; + } +} diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpecV2.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpecV2.java new file mode 100644 index 00000000..13ac0848 --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceSpecV2.java @@ -0,0 +1,25 @@ +package io.javaoperatorsdk.webhook.sample.commons.customresource; + +public class MultiVersionCustomResourceSpecV2 { + + private String value; + + private String additionalValue; + + public String getValue() { + return value; + } + + public MultiVersionCustomResourceSpecV2 setValue(String value) { + this.value = value; + return this; + } + + public String getAdditionalValue() { + return additionalValue; + } + + public void setAdditionalValue(String additionalValue) { + this.additionalValue = additionalValue; + } +} diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceStatus.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceStatus.java new file mode 100644 index 00000000..3735d14b --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceStatus.java @@ -0,0 +1,16 @@ +package io.javaoperatorsdk.webhook.sample.commons.customresource; + +public class MultiVersionCustomResourceStatus { + + private Boolean ready; + + public Boolean getReady() { + return ready; + } + + public MultiVersionCustomResourceStatus setReady(Boolean ready) { + this.ready = ready; + return this; + } +} + diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceStatusV2.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceStatusV2.java new file mode 100644 index 00000000..528882ce --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceStatusV2.java @@ -0,0 +1,27 @@ +package io.javaoperatorsdk.webhook.sample.commons.customresource; + + +public class MultiVersionCustomResourceStatusV2 { + + private Boolean ready; + + private String message; + + public Boolean getReady() { + return ready; + } + + public MultiVersionCustomResourceStatusV2 setReady(Boolean ready) { + this.ready = ready; + return this; + } + + public String getMessage() { + return message; + } + + public MultiVersionCustomResourceStatusV2 setMessage(String message) { + this.message = message; + return this; + } +} diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceV2.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceV2.java new file mode 100644 index 00000000..1ae12dae --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/customresource/MultiVersionCustomResourceV2.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.webhook.sample.commons.customresource; + +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Kind; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version(value = "v2") +@Kind("MultiVersionCustomResource") +@ShortNames("tcr") +public class MultiVersionCustomResourceV2 + extends CustomResource { +} diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/AsyncV1Mapper.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/AsyncV1Mapper.java new file mode 100644 index 00000000..9e37f727 --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/AsyncV1Mapper.java @@ -0,0 +1,27 @@ +package io.javaoperatorsdk.webhook.sample.commons.mapper; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import io.javaoperatorsdk.webhook.conversion.AsyncMapper; +import io.javaoperatorsdk.webhook.conversion.TargetVersion; +import io.javaoperatorsdk.webhook.sample.commons.customresource.MultiVersionCustomResource; +import io.javaoperatorsdk.webhook.sample.commons.customresource.MultiVersionCustomResourceV2; + +@TargetVersion("v1") +public class AsyncV1Mapper + implements AsyncMapper { + + private V1Mapper mapper = new V1Mapper(); + + @Override + public CompletionStage toHub(MultiVersionCustomResource resource) { + return CompletableFuture.completedStage(mapper.toHub(resource)); + } + + @Override + public CompletionStage fromHub( + MultiVersionCustomResourceV2 testCustomResourceV2) { + return CompletableFuture.completedStage(mapper.fromHub(testCustomResourceV2)); + } +} diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/AsyncV2Mapper.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/AsyncV2Mapper.java new file mode 100644 index 00000000..b941ff23 --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/AsyncV2Mapper.java @@ -0,0 +1,27 @@ +package io.javaoperatorsdk.webhook.sample.commons.mapper; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; + +import io.javaoperatorsdk.webhook.conversion.AsyncMapper; +import io.javaoperatorsdk.webhook.conversion.TargetVersion; +import io.javaoperatorsdk.webhook.sample.commons.customresource.MultiVersionCustomResourceV2; + +@TargetVersion("v2") +public class AsyncV2Mapper + implements AsyncMapper { + + private V2Mapper mapper = new V2Mapper(); + + @Override + public CompletionStage toHub( + MultiVersionCustomResourceV2 resource) { + return CompletableFuture.completedStage(mapper.toHub(resource)); + } + + @Override + public CompletionStage fromHub( + MultiVersionCustomResourceV2 multiVersionCustomResourceV2) { + return CompletableFuture.completedStage(mapper.fromHub(multiVersionCustomResourceV2)); + } +} diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V1Mapper.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V1Mapper.java new file mode 100644 index 00000000..7d5d305f --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V1Mapper.java @@ -0,0 +1,48 @@ +package io.javaoperatorsdk.webhook.sample.commons.mapper; + +import io.javaoperatorsdk.webhook.conversion.Mapper; +import io.javaoperatorsdk.webhook.conversion.TargetVersion; +import io.javaoperatorsdk.webhook.sample.commons.customresource.*; + +@TargetVersion("v1") +public class V1Mapper implements Mapper { + + + public static final String DEFAULT_ADDITIONAL_VALUE = "default_additional_value"; + + @Override + public MultiVersionCustomResourceV2 toHub(MultiVersionCustomResource resource) { + var hub = new MultiVersionCustomResourceV2(); + hub.setMetadata(resource.getMetadata()); + + var spec = new MultiVersionCustomResourceSpecV2(); + spec.setValue(String.valueOf(resource.getSpec().getValue())); + spec.setAdditionalValue(DEFAULT_ADDITIONAL_VALUE); + hub.setSpec(spec); + + + if (resource.getStatus() != null) { + var status = new MultiVersionCustomResourceStatusV2(); + status.setReady(resource.getStatus().getReady()); + hub.setStatus(status); + } + return hub; + } + + @Override + public MultiVersionCustomResource fromHub(MultiVersionCustomResourceV2 hub) { + var res = new MultiVersionCustomResource(); + res.setMetadata(hub.getMetadata()); + + var spec = new MultiVersionCustomResourceSpec(); + spec.setValue(Integer.parseInt(hub.getSpec().getValue())); + res.setSpec(spec); + + if (hub.getStatus() != null) { + var status = new MultiVersionCustomResourceStatus(); + status.setReady(hub.getStatus().getReady()); + res.setStatus(status); + } + return res; + } +} diff --git a/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V2Mapper.java b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V2Mapper.java new file mode 100644 index 00000000..9342160d --- /dev/null +++ b/samples/commons/src/main/java/io/javaoperatorsdk/webhook/sample/commons/mapper/V2Mapper.java @@ -0,0 +1,21 @@ +package io.javaoperatorsdk.webhook.sample.commons.mapper; + +import io.javaoperatorsdk.webhook.conversion.Mapper; +import io.javaoperatorsdk.webhook.conversion.TargetVersion; +import io.javaoperatorsdk.webhook.sample.commons.customresource.MultiVersionCustomResourceV2; + +@TargetVersion("v2") +public class V2Mapper + implements Mapper { + + @Override + public MultiVersionCustomResourceV2 toHub(MultiVersionCustomResourceV2 resource) { + return resource; + } + + @Override + public MultiVersionCustomResourceV2 fromHub( + MultiVersionCustomResourceV2 multiVersionCustomResourceV2) { + return multiVersionCustomResourceV2; + } +} diff --git a/samples/pom.xml b/samples/pom.xml index 352a8d9f..d3ce7434 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -11,6 +11,7 @@ pom Admission Controller Framework - Samples + commons spring-boot quarkus diff --git a/samples/quarkus/pom.xml b/samples/quarkus/pom.xml index a6952857..f7464803 100644 --- a/samples/quarkus/pom.xml +++ b/samples/quarkus/pom.xml @@ -59,6 +59,11 @@ org.jboss.resteasy resteasy-jackson2-provider + + io.javaoperatorsdk.admissioncontroller.sample + sample-commons + ${project.version} + diff --git a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionControllerConfig.java b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerConfig.java similarity index 98% rename from samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionControllerConfig.java rename to samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerConfig.java index 344149c3..b60990fe 100644 --- a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionControllerConfig.java +++ b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionControllerConfig.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.webhook.admission.sample.quarkus; +package io.javaoperatorsdk.webhook.admission.sample.quarkus.admission; import java.util.HashMap; import java.util.concurrent.CompletableFuture; diff --git a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionEndpoint.java b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpoint.java similarity index 98% rename from samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionEndpoint.java rename to samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpoint.java index d544cb00..501a51a4 100644 --- a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionEndpoint.java +++ b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpoint.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.webhook.admission.sample.quarkus; +package io.javaoperatorsdk.webhook.admission.sample.quarkus.admission; import javax.inject.Inject; import javax.inject.Named; diff --git a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionControllerConfig.java b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionControllerConfig.java new file mode 100644 index 00000000..19a3ab9b --- /dev/null +++ b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionControllerConfig.java @@ -0,0 +1,33 @@ +package io.javaoperatorsdk.webhook.admission.sample.quarkus.conversion; + +import javax.enterprise.context.Dependent; +import javax.inject.Singleton; + +import io.javaoperatorsdk.webhook.conversion.AsyncConversionController; +import io.javaoperatorsdk.webhook.conversion.ConversionController; +import io.javaoperatorsdk.webhook.sample.commons.mapper.AsyncV1Mapper; +import io.javaoperatorsdk.webhook.sample.commons.mapper.AsyncV2Mapper; +import io.javaoperatorsdk.webhook.sample.commons.mapper.V1Mapper; +import io.javaoperatorsdk.webhook.sample.commons.mapper.V2Mapper; + +@Dependent +public class ConversionControllerConfig { + + + @Singleton + public ConversionController conversionController() { + var controller = new ConversionController(); + controller.registerMapper(new V1Mapper()); + controller.registerMapper(new V2Mapper()); + return controller; + } + + @Singleton + public AsyncConversionController asyncConversionController() { + var controller = new AsyncConversionController(); + controller.registerMapper(new AsyncV1Mapper()); + controller.registerMapper(new AsyncV2Mapper()); + return controller; + } + +} diff --git a/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpoint.java b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpoint.java new file mode 100644 index 00000000..cd54662d --- /dev/null +++ b/samples/quarkus/src/main/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpoint.java @@ -0,0 +1,47 @@ +package io.javaoperatorsdk.webhook.admission.sample.quarkus.conversion; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import io.fabric8.kubernetes.api.model.apiextensions.v1.ConversionReview; +import io.javaoperatorsdk.webhook.conversion.AsyncConversionController; +import io.javaoperatorsdk.webhook.conversion.ConversionController; +import io.smallrye.mutiny.Uni; + +@Path("/") +public class ConversionEndpoint { + + public static final String CONVERSION_PATH = "convert"; + public static final String ASYNC_CONVERSION_PATH = "async-convert"; + + private final ConversionController conversionController; + private final AsyncConversionController asyncConversionController; + + public ConversionEndpoint(ConversionController conversionController, + AsyncConversionController asyncConversionController) { + this.conversionController = conversionController; + this.asyncConversionController = asyncConversionController; + } + + + @POST + @Path(CONVERSION_PATH) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public ConversionReview convert(ConversionReview conversionReview) { + return conversionController.handle(conversionReview); + } + + @POST + @Path(ASYNC_CONVERSION_PATH) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Uni convertAsync(ConversionReview conversionReview) { + return Uni.createFrom() + .completionStage(() -> asyncConversionController.handle(conversionReview)); + } + +} diff --git a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionEndpointTest.java b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpointTest.java similarity index 97% rename from samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionEndpointTest.java rename to samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpointTest.java index 9d32bd13..97af8bc0 100644 --- a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/AdmissionEndpointTest.java +++ b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/AdmissionEndpointTest.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.webhook.admission.sample.quarkus; +package io.javaoperatorsdk.webhook.admission.sample.quarkus.admission; import java.io.IOException; import java.io.InputStream; diff --git a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/NativeAdmissionEndpointIT.java b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/NativeAdmissionEndpointIT.java similarity index 72% rename from samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/NativeAdmissionEndpointIT.java rename to samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/NativeAdmissionEndpointIT.java index 80970f09..f42d13e2 100644 --- a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/NativeAdmissionEndpointIT.java +++ b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/admission/NativeAdmissionEndpointIT.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.webhook.admission.sample.quarkus; +package io.javaoperatorsdk.webhook.admission.sample.quarkus.admission; import io.quarkus.test.junit.NativeImageTest; diff --git a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpointTest.java b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpointTest.java new file mode 100644 index 00000000..878b49b1 --- /dev/null +++ b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/ConversionEndpointTest.java @@ -0,0 +1,52 @@ +package io.javaoperatorsdk.webhook.admission.sample.quarkus.conversion; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.http.ContentType; + +import static io.javaoperatorsdk.webhook.admission.sample.quarkus.conversion.ConversionEndpoint.ASYNC_CONVERSION_PATH; +import static io.javaoperatorsdk.webhook.admission.sample.quarkus.conversion.ConversionEndpoint.CONVERSION_PATH; +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; + +@QuarkusTest +class ConversionEndpointTest { + + final static String expectedResult = + "{\"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\",\"additionalValue\":\"default_additional_value\"},\"status\":{\"ready\":true,\"message\":null}},{\"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\",\"additionalValue\":\"default_additional_value\"},\"status\":{\"ready\":false,\"message\":null}}],\"result\":{\"apiVersion\":\"v1\",\"kind\":\"Status\",\"status\":\"Success\"},\"uid\":\"705ab4f5-6393-11e8-b7cc-42010a800002\"}}"; + + @Disabled + @Test + void conversion() { + testConversion(CONVERSION_PATH); + } + + @Disabled + @Test + void asyncConversion() { + testConversion(ASYNC_CONVERSION_PATH); + } + + public void testConversion(String path) { + given().contentType(ContentType.JSON) + .body(jsonRequest()) + .when().post("/" + path) + .then() + .statusCode(200) + .body(is(expectedResult)); + } + + private String jsonRequest() { + try (InputStream is = this.getClass().getResourceAsStream("/conversion-request.json")) { + return new String(is.readAllBytes(), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/NativeConversionEndpointTest.java b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/NativeConversionEndpointTest.java new file mode 100644 index 00000000..bb07997e --- /dev/null +++ b/samples/quarkus/src/test/java/io/javaoperatorsdk/webhook/admission/sample/quarkus/conversion/NativeConversionEndpointTest.java @@ -0,0 +1,7 @@ +package io.javaoperatorsdk.webhook.admission.sample.quarkus.conversion; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +public class NativeConversionEndpointTest extends ConversionEndpointTest { +} diff --git a/samples/quarkus/src/test/resources/conversion-request.json b/samples/quarkus/src/test/resources/conversion-request.json new file mode 100644 index 00000000..bb07e07f --- /dev/null +++ b/samples/quarkus/src/test/resources/conversion-request.json @@ -0,0 +1,47 @@ +{ + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "ConversionReview", + "request": { + + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", + + "desiredAPIVersion": "sample.javaoperatorsdk/v2", + + "objects": [ + { + "kind": "MultiVersionCustomResource", + "apiVersion": "sample.javaoperatorsdk/v1", + "metadata": { + "creationTimestamp": "2021-09-04T14:03:02Z", + "name": "resource1", + "namespace": "default", + "resourceVersion": "143", + "uid": "3415a7fc-162b-4300-b5da-fd6083580d66" + }, + "spec": { + "value": 1 + }, + "status":{ + "ready": true + } + }, + { + "kind": "MultiVersionCustomResource", + "apiVersion": "sample.javaoperatorsdk/v1", + "metadata": { + "creationTimestamp": "2021-09-04T14:03:02Z", + "name": "resource2", + "namespace": "default", + "resourceVersion": "14344", + "uid": "1115a7fc-162b-4300-b5da-fd6083580d55" + }, + "spec": { + "value": 2 + }, + "status":{ + "ready": false + } + } + ] +} +} \ No newline at end of file diff --git a/samples/spring-boot/pom.xml b/samples/spring-boot/pom.xml index ea65aefe..3bec0ace 100644 --- a/samples/spring-boot/pom.xml +++ b/samples/spring-boot/pom.xml @@ -70,6 +70,16 @@ admission-controller-framework-core ${project.version} + + io.javaoperatorsdk.admissioncontroller.sample + sample-commons + ${project.version} + + + org.assertj + assertj-core + test + diff --git a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/Config.java b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionConfig.java similarity index 97% rename from samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/Config.java rename to samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionConfig.java index 1e83946a..fe024e23 100644 --- a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/Config.java +++ b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionConfig.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.webhook.sample.springboot; +package io.javaoperatorsdk.webhook.sample.springboot.admission; import java.util.HashMap; import java.util.concurrent.CompletableFuture; @@ -15,7 +15,7 @@ import io.javaoperatorsdk.webhook.admission.validation.Validator; @Configuration -public class Config { +public class AdmissionConfig { public static final String APP_NAME_LABEL_KEY = "app.kubernetes.io/name"; public static final String ERROR_MESSAGE = "Some error happened"; diff --git a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/AdmissionEndpoint.java b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpoint.java similarity index 98% rename from samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/AdmissionEndpoint.java rename to samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpoint.java index a3c7d24d..585b8bc3 100644 --- a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/AdmissionEndpoint.java +++ b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpoint.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.webhook.sample.springboot; +package io.javaoperatorsdk.webhook.sample.springboot.admission; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -14,7 +14,7 @@ import reactor.core.publisher.Mono; -@RestController("/") +@RestController public class AdmissionEndpoint { public static final String MUTATE_PATH = "mutate"; diff --git a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionConfig.java b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionConfig.java new file mode 100644 index 00000000..406899b0 --- /dev/null +++ b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionConfig.java @@ -0,0 +1,32 @@ +package io.javaoperatorsdk.webhook.sample.springboot.conversion; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.javaoperatorsdk.webhook.conversion.AsyncConversionController; +import io.javaoperatorsdk.webhook.conversion.ConversionController; +import io.javaoperatorsdk.webhook.sample.commons.mapper.AsyncV1Mapper; +import io.javaoperatorsdk.webhook.sample.commons.mapper.AsyncV2Mapper; +import io.javaoperatorsdk.webhook.sample.commons.mapper.V1Mapper; +import io.javaoperatorsdk.webhook.sample.commons.mapper.V2Mapper; + +@Configuration +public class ConversionConfig { + + @Bean + public ConversionController conversionController() { + var controller = new ConversionController(); + controller.registerMapper(new V1Mapper()); + controller.registerMapper(new V2Mapper()); + return controller; + } + + @Bean + public AsyncConversionController asyncConversionController() { + var controller = new AsyncConversionController(); + controller.registerMapper(new AsyncV1Mapper()); + controller.registerMapper(new AsyncV2Mapper()); + return controller; + } + +} diff --git a/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionEndpoint.java b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionEndpoint.java new file mode 100644 index 00000000..0cecae93 --- /dev/null +++ b/samples/spring-boot/src/main/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionEndpoint.java @@ -0,0 +1,41 @@ +package io.javaoperatorsdk.webhook.sample.springboot.conversion; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import io.fabric8.kubernetes.api.model.apiextensions.v1.ConversionReview; +import io.javaoperatorsdk.webhook.conversion.AsyncConversionController; +import io.javaoperatorsdk.webhook.conversion.ConversionController; + +import reactor.core.publisher.Mono; + +@RestController +public class ConversionEndpoint { + + public static final String CONVERSION_PATH = "convert"; + public static final String ASYNC_CONVERSION_PATH = "async-convert"; + + private final ConversionController conversionController; + private final AsyncConversionController asyncConversionController; + + public ConversionEndpoint(ConversionController conversionController, + AsyncConversionController asyncConversionController) { + this.conversionController = conversionController; + this.asyncConversionController = asyncConversionController; + } + + @PostMapping(CONVERSION_PATH) + @ResponseBody + public ConversionReview convert(@RequestBody ConversionReview conversionReview) { + return conversionController.handle(conversionReview); + } + + @PostMapping(ASYNC_CONVERSION_PATH) + @ResponseBody + public Mono convertAsync(@RequestBody ConversionReview conversionReview) { + return Mono.fromCompletionStage(asyncConversionController.handle(conversionReview)); + } + +} diff --git a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/AdmissionEndpointTest.java b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpointTest.java similarity index 93% rename from samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/AdmissionEndpointTest.java rename to samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpointTest.java index 1f7f983b..2036e84e 100644 --- a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/AdmissionEndpointTest.java +++ b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/admission/AdmissionEndpointTest.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.webhook.sample.springboot; +package io.javaoperatorsdk.webhook.sample.springboot.admission; import java.io.IOException; import java.nio.file.Files; @@ -15,9 +15,9 @@ import org.springframework.web.reactive.function.BodyInserter; import org.springframework.web.reactive.function.BodyInserters; -import static io.javaoperatorsdk.webhook.sample.springboot.AdmissionEndpoint.*; +import static io.javaoperatorsdk.webhook.sample.springboot.admission.AdmissionEndpoint.*; -@Import(Config.class) +@Import(AdmissionConfig.class) @WebFluxTest(AdmissionEndpoint.class) class AdmissionEndpointTest { diff --git a/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionEndpointTest.java b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionEndpointTest.java new file mode 100644 index 00000000..45ddbb06 --- /dev/null +++ b/samples/spring-boot/src/test/java/io/javaoperatorsdk/webhook/sample/springboot/conversion/ConversionEndpointTest.java @@ -0,0 +1,69 @@ +package io.javaoperatorsdk.webhook.sample.springboot.conversion; + +import java.io.IOException; +import java.nio.file.Files; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.context.annotation.Import; +import org.springframework.core.io.Resource; +import org.springframework.http.MediaType; +import org.springframework.http.ReactiveHttpOutputMessage; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; + +import io.fabric8.kubernetes.api.model.apiextensions.v1.ConversionReview; +import io.javaoperatorsdk.webhook.sample.commons.customresource.MultiVersionCustomResourceV2; + +import static io.javaoperatorsdk.webhook.sample.commons.mapper.V1Mapper.DEFAULT_ADDITIONAL_VALUE; +import static io.javaoperatorsdk.webhook.sample.springboot.conversion.ConversionEndpoint.ASYNC_CONVERSION_PATH; +import static io.javaoperatorsdk.webhook.sample.springboot.conversion.ConversionEndpoint.CONVERSION_PATH; +import static org.assertj.core.api.Assertions.assertThat; + +@Import(ConversionConfig.class) +@WebFluxTest(ConversionEndpoint.class) +class ConversionEndpointTest { + + @Autowired + private WebTestClient webClient; + + @Value("classpath:conversion-request.json") + private Resource request; + + + @Test + void convert() { + testConversion(CONVERSION_PATH); + } + + @Test + void asyncConvert() { + testConversion(ASYNC_CONVERSION_PATH); + } + + public void testConversion(String path) { + webClient.post().uri("/" + path).contentType(MediaType.APPLICATION_JSON) + .body(request()) + .exchange() + .expectStatus().isOk().expectBody(ConversionReview.class).consumeWith(res -> { + var review = res.getResponseBody(); + var resource1 = + ((MultiVersionCustomResourceV2) review.getResponse().getConvertedObjects().get(0)); + assertThat(review.getResponse().getConvertedObjects()).hasSize(2); + assertThat(resource1.getSpec().getAdditionalValue()).isEqualTo(DEFAULT_ADDITIONAL_VALUE); + assertThat(resource1.getMetadata().getName()).isEqualTo("resource1"); + }); + } + + private BodyInserter request() { + try { + return BodyInserters.fromValue(new String(Files.readAllBytes(request.getFile().toPath()))); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + +} diff --git a/samples/spring-boot/src/test/resources/conversion-request.json b/samples/spring-boot/src/test/resources/conversion-request.json new file mode 100644 index 00000000..bb07e07f --- /dev/null +++ b/samples/spring-boot/src/test/resources/conversion-request.json @@ -0,0 +1,47 @@ +{ + "apiVersion": "apiextensions.k8s.io/v1", + "kind": "ConversionReview", + "request": { + + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", + + "desiredAPIVersion": "sample.javaoperatorsdk/v2", + + "objects": [ + { + "kind": "MultiVersionCustomResource", + "apiVersion": "sample.javaoperatorsdk/v1", + "metadata": { + "creationTimestamp": "2021-09-04T14:03:02Z", + "name": "resource1", + "namespace": "default", + "resourceVersion": "143", + "uid": "3415a7fc-162b-4300-b5da-fd6083580d66" + }, + "spec": { + "value": 1 + }, + "status":{ + "ready": true + } + }, + { + "kind": "MultiVersionCustomResource", + "apiVersion": "sample.javaoperatorsdk/v1", + "metadata": { + "creationTimestamp": "2021-09-04T14:03:02Z", + "name": "resource2", + "namespace": "default", + "resourceVersion": "14344", + "uid": "1115a7fc-162b-4300-b5da-fd6083580d55" + }, + "spec": { + "value": 2 + }, + "status":{ + "ready": false + } + } + ] +} +} \ No newline at end of file