From fafa459587e782dc5aae179fc667b32521f47691 Mon Sep 17 00:00:00 2001 From: Rohan Kumar Date: Thu, 30 May 2024 21:55:27 +0530 Subject: [PATCH] test : Add E2E test for buildpacks build strategy + Added a test BuildPacksBuildStrategyK8sITCase that would be activated in others profile + Add a minimal test project in `projects-to-be-tested/maven/buildpacks/simple` directory for abovementioned integration test Signed-off-by: Rohan Kumar --- .../integrationtests/docker/DockerUtils.java | 19 +++ .../BuildPacksBuildStrategyK8sITCase.java | 154 ++++++++++++++++++ pom.xml | 3 + .../maven/buildpacks/simple/pom.xml | 81 +++++++++ .../buildpacks/simple/App.java | 37 +++++ .../buildpacks/simple/RootHandler.java | 36 ++++ 6 files changed, 330 insertions(+) create mode 100644 it/src/test/java/org/eclipse/jkube/integrationtests/buildpacks/BuildPacksBuildStrategyK8sITCase.java create mode 100644 projects-to-be-tested/maven/buildpacks/simple/pom.xml create mode 100644 projects-to-be-tested/maven/buildpacks/simple/src/main/java/org/eclipse/jkube/integrationtests/buildpacks/simple/App.java create mode 100644 projects-to-be-tested/maven/buildpacks/simple/src/main/java/org/eclipse/jkube/integrationtests/buildpacks/simple/RootHandler.java diff --git a/it/src/main/java/org/eclipse/jkube/integrationtests/docker/DockerUtils.java b/it/src/main/java/org/eclipse/jkube/integrationtests/docker/DockerUtils.java index af9dfe50..2746a2dd 100644 --- a/it/src/main/java/org/eclipse/jkube/integrationtests/docker/DockerUtils.java +++ b/it/src/main/java/org/eclipse/jkube/integrationtests/docker/DockerUtils.java @@ -13,6 +13,7 @@ */ package org.eclipse.jkube.integrationtests.docker; +import com.fasterxml.jackson.databind.ObjectMapper; import org.eclipse.jkube.integrationtests.cli.CliUtils; import org.eclipse.jkube.integrationtests.cli.CliUtils.CliResult; @@ -20,6 +21,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -79,6 +81,23 @@ public static void loadTar(File dockerBuildTar) throws IOException, InterruptedE } } + public static List listDockerVolumeNames() throws IOException, InterruptedException { + final CliResult result = CliUtils.runCommand("docker volume ls --format=\"{{.Name}}\""); + if (result.getExitCode() != 0) { + throw new IOException(String.format("Error in listing docker volumes: %s", result.getOutput())); + } + return Arrays.asList(result.getOutput().replace("\r", "").split("\n")); + } + + public static Map getLabels(String id) throws IOException, InterruptedException { + final CliResult result = CliUtils.runCommand(String.format("docker inspect -f \"{{json .Config.Labels}}\" %s", id)); + if (result.getExitCode() != 0) { + throw new IOException(String.format("Error in getting labels: %s", result.getOutput())); + } + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(result.getOutput(), Map.class); + } + public static final class DockerImage { private final String repository; diff --git a/it/src/test/java/org/eclipse/jkube/integrationtests/buildpacks/BuildPacksBuildStrategyK8sITCase.java b/it/src/test/java/org/eclipse/jkube/integrationtests/buildpacks/BuildPacksBuildStrategyK8sITCase.java new file mode 100644 index 00000000..945f0060 --- /dev/null +++ b/it/src/test/java/org/eclipse/jkube/integrationtests/buildpacks/BuildPacksBuildStrategyK8sITCase.java @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2019 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at: + * + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.jkube.integrationtests.buildpacks; + +import io.fabric8.junit.jupiter.api.KubernetesTest; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.apache.maven.shared.invoker.InvocationResult; +import org.eclipse.jkube.integrationtests.JKubeCase; +import org.eclipse.jkube.integrationtests.maven.MavenCase; +import org.eclipse.jkube.integrationtests.maven.MavenInvocationResult; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.parallel.ResourceLock; + +import java.io.File; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.eclipse.jkube.integrationtests.Locks.CLUSTER_RESOURCE_INTENSIVE; +import static org.eclipse.jkube.integrationtests.Tags.KUBERNETES; +import static org.eclipse.jkube.integrationtests.assertions.InvocationResultAssertion.assertInvocation; +import static org.eclipse.jkube.integrationtests.assertions.JKubeAssertions.assertJKube; +import static org.eclipse.jkube.integrationtests.assertions.KubernetesListAssertion.assertListResource; +import static org.eclipse.jkube.integrationtests.assertions.PodAssertion.awaitPod; +import static org.eclipse.jkube.integrationtests.assertions.ServiceAssertion.awaitService; +import static org.eclipse.jkube.integrationtests.assertions.YamlAssertion.yaml; +import static org.eclipse.jkube.integrationtests.docker.DockerUtils.getLabels; +import static org.eclipse.jkube.integrationtests.docker.DockerUtils.listDockerVolumeNames; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anEmptyMap; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.junit.jupiter.api.parallel.ResourceAccessMode.READ_WRITE; + +@Tag(KUBERNETES) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@KubernetesTest(createEphemeralNamespace = false) +class BuildPacksBuildStrategyK8sITCase implements JKubeCase, MavenCase { + private KubernetesClient kubernetesClient; + private static final String PROJECT_BUILDPACKS_SIMPLE = "projects-to-be-tested/maven/buildpacks/simple"; + + @Override + public KubernetesClient getKubernetesClient() { + return kubernetesClient; + } + + @Override + public String getApplication() { + return "buildpacks-simple"; + } + + @Override + public String getProject() { + return PROJECT_BUILDPACKS_SIMPLE; + } + + @Test + @Order(1) + @DisplayName("k8s:resource, should create manifests") + void k8sResource() throws Exception { + // When + final InvocationResult invocationResult = maven("k8s:resource"); + // Then + assertInvocation(invocationResult); + final File metaInfDirectory = new File( + String.format("../%s/target/classes/META-INF", getProject())); + assertThat(metaInfDirectory.exists(), equalTo(true)); + assertListResource(new File(metaInfDirectory, "jkube/kubernetes.yml")); + assertThat(new File(metaInfDirectory, "jkube/kubernetes/buildpacks-simple-deployment.yml"), yaml(not(anEmptyMap()))); + assertThat(new File(metaInfDirectory, "jkube/kubernetes/buildpacks-simple-service.yml"), yaml(not(anEmptyMap()))); + } + + @Test + @Order(1) + @DisplayName("k8s:build, should create container image using buildpacks") + void k8sBuild() throws Exception { + // When + final MavenInvocationResult invocationResult = maven("k8s:build"); + // Then + assertInvocation(invocationResult); + assertThat(invocationResult.getStdOut(), stringContainsInOrder( + "Delegating container image building process to BuildPacks", + "Using pack", + "base: Pulling from paketobuildpacks/builder", + "===> ANALYZING", + "===> DETECTING", + "===> EXPORTING", + "Successfully built image 'integration-tests/buildpacks-simple:latest'", + "[INFO] BUILD SUCCESS" + )); + Map imageLabels = getLabels("integration-tests/buildpacks-simple:latest"); + assertThat(imageLabels, hasEntry("io.buildpacks.stack.id", "io.buildpacks.stacks.bionic")); + assertThat(imageLabels, hasEntry("io.buildpacks.project.metadata", "{}")); + assertThat(imageLabels, hasKey("io.buildpacks.build.metadata")); + assertThat(imageLabels, hasKey("io.buildpacks.lifecycle.metadata")); + assertThat(imageLabels, hasKey("io.buildpacks.stack.description")); + assertThat(listDockerVolumeNames().stream() + .filter(v -> v.endsWith(".build") || v.endsWith(".launch")) + .filter(v -> v.contains("integration-tests_buildpacks-simple")) + .collect(Collectors.toList()), hasSize(2)); + } + + @Test + @Order(2) + @ResourceLock(value = CLUSTER_RESOURCE_INTENSIVE, mode = READ_WRITE) + @DisplayName("k8s:apply, should deploy pod and service") + void k8sApply() throws Exception { + // Given + // When + final InvocationResult invocationResult = maven("k8s:apply"); + // Then + assertInvocation(invocationResult); + final Pod pod = awaitPod(this).getKubernetesResource(); + awaitService(this, pod.getMetadata().getNamespace()) + .assertIsNodePort() + .assertPorts(hasSize(1)) + .assertPort("http", 8080, true) + .assertNodePortResponse("http", containsString("Simple Application containerized using buildpacks with JKube!"), ""); + } + + @Test + @Order(3) + @DisplayName("k8s:undeploy, should delete all applied resources") + void k8sUndeploy() throws Exception { + // When + final InvocationResult invocationResult = maven("k8s:undeploy"); + // Then + assertInvocation(invocationResult); + assertJKube(this) + .assertThatShouldDeleteAllAppliedResources() + .assertDeploymentDeleted(); + } +} diff --git a/pom.xml b/pom.xml index 7e45e0da..377b0b40 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,7 @@ 3.1.1 4.0.1 2.3.3 + 1.17-SNAPSHOT 5.10.0 4.4.4 @@ -290,6 +291,7 @@ projects-to-be-tested/maven/vertx/simplest projects-to-be-tested/maven/wildfly-jar/microprofile projects-to-be-tested/maven/karaf/camel-log + projects-to-be-tested/maven/buildpacks/simple @@ -311,6 +313,7 @@ **/integrationtests/wildfly/jar/**/*ITCase.java **/integrationtests/karaf/**/*ITCase.java **/integrationtests/dsl/**/*ITCase.java + **/integrationtests/buildpacks/**/*ITCase.java diff --git a/projects-to-be-tested/maven/buildpacks/simple/pom.xml b/projects-to-be-tested/maven/buildpacks/simple/pom.xml new file mode 100644 index 00000000..0e9f0e41 --- /dev/null +++ b/projects-to-be-tested/maven/buildpacks/simple/pom.xml @@ -0,0 +1,81 @@ + + + + 4.0.0 + + + org.eclipse.jkube.integration-tests + buildpacks-simple + 0.0.0-SNAPSHOT + JKube :: Integration Tests :: BuildPacks :: Simple + jar + + + + 1.17-SNAPSHOT + buildpacks + NodePort + UTF-8 + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + org.codehaus.mojo + exec-maven-plugin + 1.5.0 + + org.eclipse.jkube.sample.helloworld.App + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + org.eclipse.jkube.integrationtests.buildpacks.simple.App + + + + + + + org.eclipse.jkube + kubernetes-maven-plugin + ${jkube.version} + + + + diff --git a/projects-to-be-tested/maven/buildpacks/simple/src/main/java/org/eclipse/jkube/integrationtests/buildpacks/simple/App.java b/projects-to-be-tested/maven/buildpacks/simple/src/main/java/org/eclipse/jkube/integrationtests/buildpacks/simple/App.java new file mode 100644 index 00000000..e3da4357 --- /dev/null +++ b/projects-to-be-tested/maven/buildpacks/simple/src/main/java/org/eclipse/jkube/integrationtests/buildpacks/simple/App.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at: + * + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.jkube.integrationtests.buildpacks.simple; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.logging.Logger; +import java.util.logging.Level; + +import com.sun.net.httpserver.HttpServer; + +public class App { + private static final int PORT = 8080; + + public static void main(String[] args) { + + try { + HttpServer server = HttpServer.create(new InetSocketAddress(PORT), 0); + server.createContext("/", new RootHandler()); + server.setExecutor(null); + server.start(); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage()); + } + } +} diff --git a/projects-to-be-tested/maven/buildpacks/simple/src/main/java/org/eclipse/jkube/integrationtests/buildpacks/simple/RootHandler.java b/projects-to-be-tested/maven/buildpacks/simple/src/main/java/org/eclipse/jkube/integrationtests/buildpacks/simple/RootHandler.java new file mode 100644 index 00000000..8c74cff8 --- /dev/null +++ b/projects-to-be-tested/maven/buildpacks/simple/src/main/java/org/eclipse/jkube/integrationtests/buildpacks/simple/RootHandler.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at: + * + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.jkube.integrationtests.buildpacks.simple; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.logging.Logger; +import java.util.logging.Level; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + +public class RootHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) { + try (OutputStream outputStream = exchange.getResponseBody()) { + String response = "Simple Application containerized using buildpacks with JKube!"; + exchange.sendResponseHeaders(200, response.length()); + exchange.getResponseHeaders().set("Content-Type", "text/plain"); + outputStream.write(response.getBytes()); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage()); + } + } +}