From fe4a2466811735cdef911532fbafda751c5e5ee8 Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Sun, 14 Jul 2024 19:36:09 +0530 Subject: [PATCH] chore : add code for blogpost https://rohankanojia.github.io/articles/2024/06/29/effective-kubernetes-testing-kube-api-test/ Signed-off-by: Rohan Kumar --- ...inUsingUsernameAndPasswordAndListPods.java | 26 +++ writing-tests-with-fabric8/pom.xml | 5 + .../kubeapitest/PodGroupServiceTest.java | 154 ++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 src/main/java/io/fabric8/openshift/LoginUsingUsernameAndPasswordAndListPods.java create mode 100644 writing-tests-with-fabric8/src/test/java/io/fabric8/demos/tests/kubeapitest/PodGroupServiceTest.java diff --git a/src/main/java/io/fabric8/openshift/LoginUsingUsernameAndPasswordAndListPods.java b/src/main/java/io/fabric8/openshift/LoginUsingUsernameAndPasswordAndListPods.java new file mode 100644 index 0000000..fd4aa30 --- /dev/null +++ b/src/main/java/io/fabric8/openshift/LoginUsingUsernameAndPasswordAndListPods.java @@ -0,0 +1,26 @@ +package io.fabric8.openshift; + +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; +import io.fabric8.openshift.client.OpenShiftClient; + +public class LoginUsingUsernameAndPasswordAndListPods { + public static void main(String[] args) { + Config config = new ConfigBuilder(Config.empty()) + .withMasterUrl("https://api.crc.testing:6443") + .withUsername("kubeadmin") + .withPassword("IHiBd-9zJ6H-vICp4-Lpd69") + .withTrustCerts() + .build(); + + try (KubernetesClient kubernetesClient = new KubernetesClientBuilder().withConfig(config).build()) { + OpenShiftClient openShiftClient = kubernetesClient.adapt(OpenShiftClient.class); + + openShiftClient.pods().list().getItems().stream().map(Pod::getMetadata).map(ObjectMeta::getName).forEach(System.out::println); + } + } +} diff --git a/writing-tests-with-fabric8/pom.xml b/writing-tests-with-fabric8/pom.xml index 99d6e7a..748022b 100644 --- a/writing-tests-with-fabric8/pom.xml +++ b/writing-tests-with-fabric8/pom.xml @@ -38,6 +38,11 @@ kubernetes-junit-jupiter test + + io.fabric8 + kube-api-test + test + org.junit.jupiter junit-jupiter-api diff --git a/writing-tests-with-fabric8/src/test/java/io/fabric8/demos/tests/kubeapitest/PodGroupServiceTest.java b/writing-tests-with-fabric8/src/test/java/io/fabric8/demos/tests/kubeapitest/PodGroupServiceTest.java new file mode 100644 index 0000000..0cbf424 --- /dev/null +++ b/writing-tests-with-fabric8/src/test/java/io/fabric8/demos/tests/kubeapitest/PodGroupServiceTest.java @@ -0,0 +1,154 @@ +package io.fabric8.demos.tests.kubeapitest; + +import io.fabric8.demos.tests.mockserver.PodGroupService; +import io.fabric8.kubeapitest.junit.EnableKubeAPIServer; +import io.fabric8.kubeapitest.junit.KubeConfig; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.api.model.PodList; +import io.fabric8.kubernetes.api.model.StatusDetails; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientBuilder; +import io.fabric8.kubernetes.client.Watch; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.WatcherException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@EnableKubeAPIServer( + // Kubernetes Api Server version + kubeAPIVersion = "1.30.0", + // Kubernetes Api Server Flags + apiServerFlags = {"--audit-webhook-truncate-enabled"}, + // Whether modify local kube config + updateKubeConfigFile = false +) +class PodGroupServiceTest { + KubernetesClient kubernetesClient; + + @KubeConfig + static String configYaml; + + @BeforeEach + void setUp() { + kubernetesClient = new KubernetesClientBuilder() + .withConfig(Config.fromKubeconfig(configYaml)) + .build(); + } + + @Test + void list_whenPodsPresent_thenReturnList() { + // Given + Map matchLabel = Collections.singletonMap("app", "list"); + PodGroupService podGroupService = new PodGroupService(kubernetesClient, matchLabel); + // When + PodList podList = podGroupService.list(); + + // Then + assertNotNull(podList); + } + + @Test + void addToGroup_whenPodProvided_thenShouldUpdatePod() { + // Given + Map matchLabel = Collections.singletonMap("app", "add-to-group"); + PodGroupService podGroupService = new PodGroupService(kubernetesClient, matchLabel); + Pod p1 = createNewPod("p1", "add-to-group"); + + // When + podGroupService.addToGroup(p1); + + // Then + PodList podList = podGroupService.list(); + assertTrue(podList.getItems().stream().map(Pod::getMetadata).map(ObjectMeta::getName).anyMatch(n -> n.startsWith("p1"))); + } + + @Test + void size_whenPodsAbsent_thenReturnZero() { + // Given + PodGroupService podGroupService = new PodGroupService(kubernetesClient, Collections.singletonMap("app", "size-zero")); + + // When + int result = podGroupService.size(); + + // Then + assertEquals(0, result); + } + + @Test + void size_whenPodsPresent_thenReturnActualSize() { + // Given + PodGroupService podGroupService = new PodGroupService(kubernetesClient, Collections.singletonMap("app", "size-non-zero")); + podGroupService.addToGroup(createNewPod("p1", "size-non-zero")); + podGroupService.addToGroup(createNewPod("p2", "size-non-zero")); + + // When + int result = podGroupService.size(); + + // Then + assertEquals(2, result); + } + + @Test + void watch_whenInvoked_shouldMonitorUpdates() throws Exception { + // Given + PodGroupService podGroupService = new PodGroupService(kubernetesClient, Collections.singletonMap("app", "watch-test")); + CountDownLatch eventReceivedLatch = new CountDownLatch(1); + + // When + try (Watch ignore = podGroupService.watch(new Watcher<>() { + @Override + public void eventReceived(Action action, Pod pod) { + eventReceivedLatch.countDown(); + } + + @Override + public void onClose(WatcherException e) { } + })) { + podGroupService.addToGroup(createNewPod("p1-watch", "watch-test")); + assertTrue(eventReceivedLatch.await(5, TimeUnit.SECONDS)); + } + // Then + assertEquals(0, eventReceivedLatch.getCount()); + } + + @Test + void delete_whenInvoked_shouldDeleteAllMatchingPods() { + // Given + PodGroupService podGroupService = new PodGroupService(kubernetesClient, Collections.singletonMap("app", "delete-test")); + podGroupService.addToGroup(createNewPod("p1", "delete-test")); + podGroupService.addToGroup(createNewPod("p2", "delete-test")); + + // When + List deleteStatusDetails = podGroupService.delete(); + int sizeAfterDelete = podGroupService.size(); + + // Then + assertEquals(2, deleteStatusDetails.size()); + assertEquals(0, sizeAfterDelete); + } + + private Pod createNewPod(String generateName, String appLabelValue) { + return new PodBuilder() + .withNewMetadata().withGenerateName(generateName).withLabels(Collections.singletonMap("app", appLabelValue)).endMetadata() + .withNewSpec() + .addNewContainer() + .withName("demo-container") + .withImage("alpine:latest") + .endContainer() + .endSpec() + .build(); + } +}