diff --git a/pom.xml b/pom.xml index 58f3a46..617732b 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,12 @@ spring-boot-starter-test test + + com.dajudge.kindcontainer + kindcontainer + 1.2.3 + test + diff --git a/src/test/java/io/spring/FooControllerApplicationTest.java b/src/test/java/io/spring/FooControllerApplicationTest.java new file mode 100644 index 0000000..af525b2 --- /dev/null +++ b/src/test/java/io/spring/FooControllerApplicationTest.java @@ -0,0 +1,61 @@ +package io.spring; + +import com.dajudge.kindcontainer.exception.ExecutionException; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.apis.AppsV1Api; +import io.kubernetes.client.openapi.models.V1Deployment; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.util.generic.GenericKubernetesApi; +import io.spring.models.V1Foo; +import io.spring.models.V1FooList; +import io.spring.models.V1FooSpec; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +import static io.spring.TestApiClientFactory.API_SERVER; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.testcontainers.shaded.org.awaitility.Awaitility.await; + +@SpringBootTest(classes = {TestApiClientFactory.class}) +class FooControllerApplicationTest { + @Autowired + ApiClient client; + @Autowired + GenericKubernetesApi fooClient; + @Autowired + AppsV1Api appsApi; + + String namespace = UUID.randomUUID().toString(); + + @BeforeEach + public void setup() throws IOException, ExecutionException, InterruptedException { + API_SERVER.kubectl().create.namespace.run(namespace); + } + + @Test + public void testReconciler() { + fooClient.create(new V1Foo() + .kind("Foo") + .apiVersion("spring.io/v1") + .metadata(new V1ObjectMeta() + .name("my-foo") + .namespace(namespace)) + .spec(new V1FooSpec() + .name("oh-my"))); + + await("deployment") + .timeout(10, SECONDS) + .until(() -> !getDeployments().isEmpty()); + } + + private List getDeployments() throws ApiException { + return appsApi.listNamespacedDeployment(namespace, null, null, null, null, null, null, null, null, null, null).getItems(); + } +} \ No newline at end of file diff --git a/src/test/java/io/spring/TestApiClientFactory.java b/src/test/java/io/spring/TestApiClientFactory.java new file mode 100644 index 0000000..4f2aa78 --- /dev/null +++ b/src/test/java/io/spring/TestApiClientFactory.java @@ -0,0 +1,42 @@ +package io.spring; + +import com.dajudge.kindcontainer.ApiServerContainer; +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.util.ClientBuilder; +import io.kubernetes.client.util.KubeConfig; +import org.junit.ClassRule; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.testcontainers.utility.MountableFile; + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; + +@TestConfiguration +public class TestApiClientFactory { + // TODO this would be unnecessary if the CRD was on the classpath + private static final File CRD_PATH = getCrdPath(); + + public static final ApiServerContainer API_SERVER = new ApiServerContainer<>() + .withKubectl(kubectl -> { + // TODO this could be prettier if the CRD was on the classpath + kubectl.copyFileToContainer(MountableFile.forHostPath(new File(CRD_PATH, "foo.yaml").getAbsolutePath()), "/tmp/foo.yaml"); + kubectl.apply.from("/tmp/foo.yaml").run(); + kubectl.wait.forCondition("Established").run("crd", "foos.spring.io"); + }); + + @Bean + public ApiClient getTestApiClient() throws IOException { + API_SERVER.start(); + return ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new StringReader(API_SERVER.getKubeconfig()))).build(); + } + + private static File getCrdPath() { + final ClassLoader classLoader = FooControllerApplicationTest.class.getClassLoader(); + final File file = new File(classLoader.getResource("application.properties").getFile()); + final File projectDir = file.getParentFile().getParentFile().getParentFile(); + return new File(projectDir, "k8s/crds"); + } +}