diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java index a2c92bf48b..241c59371d 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java @@ -10,12 +10,14 @@ import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; +import io.fabric8.kubernetes.client.dsl.NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable; import org.junit.jupiter.api.extension.ExtensionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,6 +42,7 @@ public class LocallyRunOperatorExtension extends AbstractOperatorExtension { private static final Logger LOGGER = LoggerFactory.getLogger(LocallyRunOperatorExtension.class); + private static final int CRD_DELETE_TIMEOUT = 1000; private final Operator operator; private final List reconcilers; @@ -48,6 +51,7 @@ public class LocallyRunOperatorExtension extends AbstractOperatorExtension { private final List> additionalCustomResourceDefinitions; private final Map registeredControllers; private final Map crdMappings; + private static final LinkedList appliedCRDs = new LinkedList<>(); private LocallyRunOperatorExtension( List reconcilers, @@ -144,6 +148,7 @@ private static void applyCrd(String crdString, String path, KubernetesClient cli LOGGER.debug("Applying CRD: {}", crdString); final var crd = client.load(new ByteArrayInputStream(crdString.getBytes())); crd.serverSideApply(); + appliedCRDs.add(new AppliedCRD(crdString, path)); Thread.sleep(CRD_READY_WAIT); // readiness is not applicable for CRD, just wait a little LOGGER.debug("Applied CRD with path: {}", path); } catch (InterruptedException ex) { @@ -290,6 +295,14 @@ protected void before(ExtensionContext context) { protected void after(ExtensionContext context) { super.after(context); + var kubernetesClient = getKubernetesClient(); + + while (!appliedCRDs.isEmpty()) { + deleteCrd(appliedCRDs.poll(), kubernetesClient); + } + + kubernetesClient.close(); + try { this.operator.stop(); } catch (Exception e) { @@ -306,6 +319,19 @@ protected void after(ExtensionContext context) { localPortForwards.clear(); } + private void deleteCrd(AppliedCRD appliedCRD, KubernetesClient client) { + try { + LOGGER.debug("Deleting CRD: {}", appliedCRD.crdString); + final var crd = client.load(new ByteArrayInputStream(appliedCRD.crdString.getBytes())); + crd.withTimeoutInMillis(CRD_DELETE_TIMEOUT).delete(); + LOGGER.debug("Deleted CRD with path: {}", appliedCRD.path); + } catch (Exception ex) { + throw new IllegalStateException("Cannot delete CRD yaml: " + appliedCRD.path, ex); + } + } + + private record AppliedCRD(String crdString, String path) {} + @SuppressWarnings("rawtypes") public static class Builder extends AbstractBuilder { private final List reconcilers; diff --git a/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java b/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java index 929af47e5d..3095e7db8c 100644 --- a/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java +++ b/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java @@ -117,6 +117,11 @@ void test() { throw new AssertionError(ex); } }); + + log.info("Deleting test Tomcat object: {}", tomcat); + tomcatClient.inNamespace(operator.getNamespace()).resource(tomcat).delete(); + log.info("Deleting test Webapp object: {}", webapp1); + webappClient.inNamespace(operator.getNamespace()).resource(webapp1).delete(); } }