diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/CustomResourceSelectorTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/CustomResourceSelectorTest.java deleted file mode 100644 index 3aea530d18..0000000000 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/CustomResourceSelectorTest.java +++ /dev/null @@ -1,169 +0,0 @@ -package io.javaoperatorsdk.operator.processing.event.source; - -import java.util.Date; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -import org.awaitility.core.ConditionTimeoutException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; -import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; -import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; -import io.javaoperatorsdk.operator.Operator; -import io.javaoperatorsdk.operator.api.config.ConfigurationService; -import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider; -import io.javaoperatorsdk.operator.api.config.DefaultControllerConfiguration; -import io.javaoperatorsdk.operator.api.config.Version; -import io.javaoperatorsdk.operator.api.reconciler.Constants; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.await; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -@Disabled("issue with fabric8 v6") -@EnableKubernetesMockClient(crud = true, https = false) -class CustomResourceSelectorTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(CustomResourceSelectorTest.class); - public static final String NAMESPACE = "test"; - - KubernetesMockServer server; - KubernetesClient client; - ConfigurationService configurationService; - - @BeforeEach - void setUpResources() { - // need to reset the provider if we plan on changing the configuration service since it likely - // has already been set in previous tests - ConfigurationServiceProvider.reset(); - - configurationService = spy(ConfigurationService.class); - when(configurationService.checkCRDAndValidateLocalModel()).thenReturn(false); - when(configurationService.getVersion()).thenReturn(new Version("1", "1", new Date())); - // make sure not the same config instance is used for the controller, so rate limiter is not - // shared - when(configurationService.getConfigurationFor(any(MyController.class))) - .thenReturn(new MyConfiguration()) - .thenReturn(new MyConfiguration()); - } - - @Test - void resourceWatchedByLabel() { - assertThat(server).isNotNull(); - assertThat(client).isNotNull(); - - Operator o1 = new Operator(client, configurationService); - Operator o2 = new Operator(client, configurationService); - try { - AtomicInteger c1 = new AtomicInteger(); - AtomicInteger c1err = new AtomicInteger(); - AtomicInteger c2 = new AtomicInteger(); - AtomicInteger c2err = new AtomicInteger(); - - o1.register( - new MyController( - resource -> { - if ("foo".equals(resource.getMetadata().getName())) { - c1.incrementAndGet(); - } - if ("bar".equals(resource.getMetadata().getName())) { - c1err.incrementAndGet(); - } - }), - (overrider) -> overrider.settingNamespace(NAMESPACE).withLabelSelector("app=foo")); - o1.start(); - o2.register( - new MyController( - resource -> { - if ("bar".equals(resource.getMetadata().getName())) { - c2.incrementAndGet(); - } - if ("foo".equals(resource.getMetadata().getName())) { - c2err.incrementAndGet(); - } - }), - (overrider) -> overrider.settingNamespace(NAMESPACE).withLabelSelector("app=bar")); - o2.start(); - - client.resources(TestCustomResource.class).inNamespace(NAMESPACE).create(newMyResource("foo", - NAMESPACE)); - client.resources(TestCustomResource.class).inNamespace(NAMESPACE).create(newMyResource("bar", - NAMESPACE)); - - await() - .atMost(5, TimeUnit.SECONDS) - .pollInterval(100, TimeUnit.MILLISECONDS) - .until(() -> c1.get() == 1 && c1err.get() == 0); - await() - .atMost(5, TimeUnit.SECONDS) - .pollInterval(100, TimeUnit.MILLISECONDS) - .until(() -> c2.get() == 1 && c2err.get() == 0); - - assertThrows( - ConditionTimeoutException.class, - () -> await().atMost(2, TimeUnit.SECONDS).untilAtomic(c1err, is(greaterThan(0)))); - assertThrows( - ConditionTimeoutException.class, - () -> await().atMost(2, TimeUnit.SECONDS).untilAtomic(c2err, is(greaterThan(0)))); - } finally { - o1.stop(); - o2.stop(); - } - - } - - public TestCustomResource newMyResource(String app, String namespace) { - TestCustomResource resource = new TestCustomResource(); - resource.setMetadata(new ObjectMetaBuilder().withName(app).addToLabels("app", app).build()); - resource.getMetadata().setNamespace(namespace); - return resource; - } - - public static class MyConfiguration extends DefaultControllerConfiguration { - - public MyConfiguration() { - super(MyController.class.getCanonicalName(), "mycontroller", null, Constants.NO_VALUE_SET, - false, null, - null, null, null, TestCustomResource.class, null, null, null, null, - null, null); - } - } - - @ControllerConfiguration(namespaces = NAMESPACE) - public static class MyController implements Reconciler { - - private final Consumer consumer; - - public MyController(Consumer consumer) { - this.consumer = consumer; - } - - @Override - public UpdateControl reconcile( - TestCustomResource resource, Context context) { - - LOGGER.info("Received event on: {}", resource); - - consumer.accept(resource); - // patch status now increases generation, this seems to be an issue with the mock server - return UpdateControl.updateStatus(resource); - } - } -} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/LabelSelectorIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/LabelSelectorIT.java new file mode 100644 index 0000000000..8324a8c1d2 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/LabelSelectorIT.java @@ -0,0 +1,50 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; +import java.util.Collections; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension; +import io.javaoperatorsdk.operator.sample.labelselector.LabelSelectorTestCustomResource; +import io.javaoperatorsdk.operator.sample.labelselector.LabelSelectorTestReconciler; + +import static io.javaoperatorsdk.operator.sample.labelselector.LabelSelectorTestReconciler.LABEL_KEY; +import static io.javaoperatorsdk.operator.sample.labelselector.LabelSelectorTestReconciler.LABEL_VALUE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +class LabelSelectorIT { + + @RegisterExtension + LocallyRunOperatorExtension operator = + LocallyRunOperatorExtension.builder().withReconciler(new LabelSelectorTestReconciler()) + .build(); + + + @Test + void filtersCustomResourceByLabel() { + operator.create(resource("r1", true)); + operator.create(resource("r2", false)); + + await().pollDelay(Duration.ofMillis(150)).untilAsserted(() -> { + assertThat( + operator.getReconcilerOfType(LabelSelectorTestReconciler.class).getNumberOfExecutions()) + .isEqualTo(1); + }); + } + + LabelSelectorTestCustomResource resource(String name, boolean addLabel) { + var res = new LabelSelectorTestCustomResource(); + res.setMetadata(new ObjectMetaBuilder() + .withName(name) + .withLabels(addLabel ? Map.of(LABEL_KEY, LABEL_VALUE) + : Collections.emptyMap()) + .build()); + return res; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/labelselector/LabelSelectorTestCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/labelselector/LabelSelectorTestCustomResource.java new file mode 100644 index 0000000000..0b304aa9e7 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/labelselector/LabelSelectorTestCustomResource.java @@ -0,0 +1,15 @@ +package io.javaoperatorsdk.operator.sample.labelselector; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@ShortNames("lst") +public class LabelSelectorTestCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/labelselector/LabelSelectorTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/labelselector/LabelSelectorTestReconciler.java new file mode 100644 index 0000000000..3fc0a78630 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/labelselector/LabelSelectorTestReconciler.java @@ -0,0 +1,31 @@ +package io.javaoperatorsdk.operator.sample.labelselector; + +import java.util.concurrent.atomic.AtomicInteger; + +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; + +import static io.javaoperatorsdk.operator.sample.labelselector.LabelSelectorTestReconciler.LABEL_KEY; +import static io.javaoperatorsdk.operator.sample.labelselector.LabelSelectorTestReconciler.LABEL_VALUE; + +@ControllerConfiguration(labelSelector = LABEL_KEY + "=" + LABEL_VALUE) +public class LabelSelectorTestReconciler + implements Reconciler, TestExecutionInfoProvider { + + public static final String LABEL_KEY = "app"; + public static final String LABEL_VALUE = "myapp"; + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + + @Override + public UpdateControl reconcile( + LabelSelectorTestCustomResource resource, Context context) { + numberOfExecutions.addAndGet(1); + return UpdateControl.noUpdate(); + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + +}