diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java index 71f006026..609eef9cd 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java @@ -80,6 +80,8 @@ public class BootstrapAppModelFactory { private LocalProject appClassesWorkspace; + private List forcedDependencies = Collections.emptyList(); + private BootstrapAppModelFactory() { } @@ -143,6 +145,11 @@ public class BootstrapAppModelFactory { return this; } + public BootstrapAppModelFactory setForcedDependencies(List forcedDependencies) { + this.forcedDependencies = forcedDependencies; + return this; + } + public AppModelResolver getAppModelResolver() { if (bootstrapAppModelResolver != null) { @@ -273,7 +280,7 @@ public class BootstrapAppModelFactory { } AppModelResolver appModelResolver = getAppModelResolver(); CurationResult curationResult = new CurationResult(appModelResolver - .resolveManagedModel(appArtifact, Collections.emptyList(), managingProject)); + .resolveManagedModel(appArtifact, forcedDependencies, managingProject)); if (cachedCpPath != null) { Files.createDirectories(cachedCpPath.getParent()); try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(cachedCpPath))) { diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/QuarkusBootstrap.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/QuarkusBootstrap.java index 980ceaa29..ede1400a6 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/QuarkusBootstrap.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/QuarkusBootstrap.java @@ -3,6 +3,7 @@ package io.quarkus.bootstrap.app; import io.quarkus.bootstrap.BootstrapAppModelFactory; import io.quarkus.bootstrap.BootstrapException; import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.bootstrap.model.AppDependency; import io.quarkus.bootstrap.resolver.AppModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.resolver.update.DependenciesOrigin; @@ -72,6 +73,7 @@ public class QuarkusBootstrap implements Serializable { private final boolean isolateDeployment; private final MavenArtifactResolver mavenArtifactResolver; private final AppArtifact managingProject; + private final List forcedDependencies; private QuarkusBootstrap(Builder builder) { this.applicationRoot = builder.applicationRoot; @@ -95,6 +97,7 @@ public class QuarkusBootstrap implements Serializable { this.additionalDeploymentArchives = builder.additionalDeploymentArchives; this.mavenArtifactResolver = builder.mavenArtifactResolver; this.managingProject = builder.managingProject; + this.forcedDependencies = new ArrayList<>(builder.forcedDependencies); } public CuratedApplication bootstrap() throws BootstrapException { @@ -119,6 +122,7 @@ public class QuarkusBootstrap implements Serializable { .setLocalProjectsDiscovery(localProjectDiscovery) .setAppArtifact(appArtifact) .setManagingProject(managingProject) + .setForcedDependencies(forcedDependencies) .setAppClasses(getProjectRoot() != null ? getProjectRoot() : getApplicationRoot()); if (mode == Mode.TEST || test) { @@ -213,6 +217,7 @@ public class QuarkusBootstrap implements Serializable { boolean isolateDeployment; MavenArtifactResolver mavenArtifactResolver; AppArtifact managingProject; + List forcedDependencies = new ArrayList<>(); public Builder(Path applicationRoot) { this.applicationRoot = applicationRoot; @@ -329,6 +334,15 @@ public class QuarkusBootstrap implements Serializable { return this; } + /** + * If set, each of these dependencies will either be added to the application dependencies if the GA doesn't match any + * application dependencies, or override the existing version if the GA does match + */ + public Builder setForcedDependencies(List forcedDependencies) { + this.forcedDependencies = forcedDependencies; + return this; + } + public QuarkusBootstrap build() { return new QuarkusBootstrap(this); } diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/pom.xml b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/pom.xml deleted file mode 100644 index 2fea06915..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/pom.xml +++ /dev/null @@ -1,121 +0,0 @@ - - - 4.0.0 - org.acme - kubernetes-with-client - 0.1-SNAPSHOT - - UTF-8 - 2.22.0 - 1.8 - UTF-8 - 1.8 - - - - - io.quarkus - quarkus-bom - @project.version@ - pom - import - - - - - - io.quarkus - quarkus-resteasy - - - io.quarkus - quarkus-kubernetes - - - io.quarkus - quarkus-kubernetes-client - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - - - - io.quarkus - quarkus-maven-plugin - @project.version@ - - - - build - - - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - - - - - - - - native - - - native - - - - - - io.quarkus - quarkus-maven-plugin - @project.version@ - - - - native-image - - - true - - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - ${project.build.directory}/${project.build.finalName}-runner - - - - - - - - - - diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/java/org/acme/Hello.java b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/java/org/acme/Hello.java deleted file mode 100644 index ad80766a1..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/java/org/acme/Hello.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.acme; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -@Path("/hello") -public class Hello { - - @GET - @Produces(MediaType.TEXT_PLAIN) - public String hello() { - return "hello"; - } -} \ No newline at end of file diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/resources/META-INF/resources/index.html b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/resources/META-INF/resources/index.html deleted file mode 100644 index 47619beb5..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/resources/META-INF/resources/index.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - kubernetes - 0.1-SNAPSHOT - - - - - - -
-
-

Congratulations, you have created a new Quarkus application.

- -

Why do you see this?

- -

This page is served by Quarkus. The source is in - src/main/resources/META-INF/resources/index.html.

- -

What can I do from here?

- -

If not already done, run the application in dev mode using: mvn compile quarkus:dev. -

-
    -
  • Add REST resources, Servlets, functions and other services in src/main/java.
  • -
  • Your static assets are located in src/main/resources/META-INF/resources.
  • -
  • Configure your application in src/main/resources/application.properties. -
  • -
- -

How do I get rid of this page?

-

Just delete the src/main/resources/META-INF/resources/index.html file.

-
-
-
-

Application

-
    -
  • GroupId: org.acme
  • -
  • ArtifactId: kubernetes
  • -
  • Version: 0.1-SNAPSHOT
  • -
  • Quarkus Version: 999-SNAPSHOT
  • -
-
- -
-
- - - - \ No newline at end of file diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/resources/application.properties b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/resources/application.properties deleted file mode 100644 index 3c1ac56a1..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -# Configuration file -# key = value \ No newline at end of file diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/verify.groovy b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/verify.groovy deleted file mode 100644 index 4752b9843..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-client/verify.groovy +++ /dev/null @@ -1,28 +0,0 @@ -import io.dekorate.utils.Serialization -import io.dekorate.deps.kubernetes.api.model.KubernetesList -import io.dekorate.deps.kubernetes.api.model.ServiceAccount -import io.dekorate.deps.kubernetes.api.model.apps.Deployment; -import io.dekorate.deps.kubernetes.api.model.rbac.RoleBinding; - -//Check that file exits -String base = basedir -File kubernetesYml = new File(base, "target/kubernetes/kubernetes.yml") -assert kubernetesYml.exists() -kubernetesYml.withInputStream { stream -> - //Check that its parse-able - KubernetesList list = Serialization.unmarshalAsList(stream) - assert list != null - Deployment deployment = list.items.find{r -> r.kind == "Deployment"} - - //Check that ti contains a Deployment named after the project - assert deployment != null - assert deployment.metadata.name == "kubernetes-with-client" - - ServiceAccount serviceAccount = list.items.find{r -> r.kind == "ServiceAccount"} - assert serviceAccount != null - assert serviceAccount.metadata.name == "kubernetes-with-client" - - RoleBinding rolebinding = list.items.find{r -> r.kind == "RoleBinding"} - assert rolebinding != null - assert rolebinding.metadata.name == "kubernetes-with-client:view" -} diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/pom.xml b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/pom.xml deleted file mode 100644 index 74dab0266..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/pom.xml +++ /dev/null @@ -1,121 +0,0 @@ - - - 4.0.0 - org.acme - kubernetes-with-http-root-and-health - 0.1-SNAPSHOT - - UTF-8 - 2.22.0 - 1.8 - UTF-8 - 1.8 - - - - - io.quarkus - quarkus-bom - @project.version@ - pom - import - - - - - - io.quarkus - quarkus-resteasy - - - io.quarkus - quarkus-kubernetes - - - io.quarkus - quarkus-smallrye-health - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - - - - io.quarkus - quarkus-maven-plugin - @project.version@ - - - - build - - - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - - - - - - - - native - - - native - - - - - - io.quarkus - quarkus-maven-plugin - @project.version@ - - - - native-image - - - true - - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - ${project.build.directory}/${project.build.finalName}-runner - - - - - - - - - - diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/src/main/java/org/acme/Hello.java b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/src/main/java/org/acme/Hello.java deleted file mode 100644 index ad80766a1..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/src/main/java/org/acme/Hello.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.acme; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -@Path("/hello") -public class Hello { - - @GET - @Produces(MediaType.TEXT_PLAIN) - public String hello() { - return "hello"; - } -} \ No newline at end of file diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/verify.groovy b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/verify.groovy deleted file mode 100644 index 94e9b5d0d..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/verify.groovy +++ /dev/null @@ -1,28 +0,0 @@ -import io.dekorate.utils.Serialization -import io.dekorate.deps.kubernetes.api.model.* -import io.dekorate.deps.kubernetes.api.model.apps.Deployment; - -//Check that file exits -String base = basedir -File kubernetesYml = new File(base, "target/kubernetes/kubernetes.yml") -assert kubernetesYml.exists() - -kubernetesYml.withInputStream { stream -> - //Check that its parse-able - KubernetesList list = Serialization.unmarshalAsList(stream) - assert list != null - Deployment deployment = list.items.find{r -> r.kind == "Deployment"} - - assert deployment != null - assert deployment.metadata.name == "kubernetes-with-http-root-and-health" - - //Check that container has probes pointing to smallrye-health endpoint - Container container = deployment.spec.template.spec.containers.get(0) - assert container != null - Probe readiness = container.readinessProbe - assert readiness != null - assert readiness.httpGet.path == "/api/health/ready" - Probe liveness = container.livenessProbe - assert liveness != null - assert liveness.httpGet.path == "/api/health/liveness" -} diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/pom.xml b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/pom.xml deleted file mode 100644 index 77d69d767..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/pom.xml +++ /dev/null @@ -1,121 +0,0 @@ - - - 4.0.0 - org.acme - kubernetes-with-smallrye-health - 0.1-SNAPSHOT - - UTF-8 - 2.22.0 - 1.8 - UTF-8 - 1.8 - - - - - io.quarkus - quarkus-bom - @project.version@ - pom - import - - - - - - io.quarkus - quarkus-resteasy - - - io.quarkus - quarkus-kubernetes - - - io.quarkus - quarkus-smallrye-health - - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - - - - - - io.quarkus - quarkus-maven-plugin - @project.version@ - - - - build - - - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - - - - - - - - native - - - native - - - - - - io.quarkus - quarkus-maven-plugin - @project.version@ - - - - native-image - - - true - - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - ${project.build.directory}/${project.build.finalName}-runner - - - - - - - - - - diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/java/org/acme/Hello.java b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/java/org/acme/Hello.java deleted file mode 100644 index ad80766a1..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/java/org/acme/Hello.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.acme; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -@Path("/hello") -public class Hello { - - @GET - @Produces(MediaType.TEXT_PLAIN) - public String hello() { - return "hello"; - } -} \ No newline at end of file diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/resources/META-INF/resources/index.html b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/resources/META-INF/resources/index.html deleted file mode 100644 index 47619beb5..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/resources/META-INF/resources/index.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - kubernetes - 0.1-SNAPSHOT - - - - - - -
-
-

Congratulations, you have created a new Quarkus application.

- -

Why do you see this?

- -

This page is served by Quarkus. The source is in - src/main/resources/META-INF/resources/index.html.

- -

What can I do from here?

- -

If not already done, run the application in dev mode using: mvn compile quarkus:dev. -

-
    -
  • Add REST resources, Servlets, functions and other services in src/main/java.
  • -
  • Your static assets are located in src/main/resources/META-INF/resources.
  • -
  • Configure your application in src/main/resources/application.properties. -
  • -
- -

How do I get rid of this page?

-

Just delete the src/main/resources/META-INF/resources/index.html file.

-
-
-
-

Application

-
    -
  • GroupId: org.acme
  • -
  • ArtifactId: kubernetes
  • -
  • Version: 0.1-SNAPSHOT
  • -
  • Quarkus Version: 999-SNAPSHOT
  • -
-
- -
-
- - - - \ No newline at end of file diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/resources/application.properties b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/resources/application.properties deleted file mode 100644 index 3c1ac56a1..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -# Configuration file -# key = value \ No newline at end of file diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/verify.groovy b/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/verify.groovy deleted file mode 100644 index 6ef651c9f..000000000 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-smallrye-health/verify.groovy +++ /dev/null @@ -1,28 +0,0 @@ -import io.dekorate.utils.Serialization -import io.dekorate.deps.kubernetes.api.model.* -import io.dekorate.deps.kubernetes.api.model.apps.Deployment; - -//Check that file exits -String base = basedir -File kubernetesYml = new File(base, "target/kubernetes/kubernetes.yml") -assert kubernetesYml.exists() - -kubernetesYml.withInputStream { stream -> - //Check that its parse-able - KubernetesList list = Serialization.unmarshalAsList(stream) - assert list != null - Deployment deployment = list.items.find{r -> r.kind == "Deployment"} - - assert deployment != null - assert deployment.metadata.name == "kubernetes-with-smallrye-health" - - //Check that container has probes pointing to smallrye-health endpoint - Container container = deployment.spec.template.spec.containers.get(0) - assert container != null - Probe readiness = container.readinessProbe - assert readiness != null - assert readiness.httpGet.path == "/health/ready" - Probe liveness = container.livenessProbe - assert liveness != null - assert liveness.httpGet.path == "/health/live" -} diff --git a/integration-tests/kubernetes/standard/pom.xml b/integration-tests/kubernetes/standard/pom.xml index d47875ccd..a2e8b0e58 100644 --- a/integration-tests/kubernetes/standard/pom.xml +++ b/integration-tests/kubernetes/standard/pom.xml @@ -80,5 +80,24 @@ test + + + + + src/test/resources + + **/*.txt + + true + + + src/test/resources + + **/*.txt + + false + + + \ No newline at end of file diff --git a/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/KubernetesWithHealthTest.java b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/KubernetesWithHealthTest.java new file mode 100644 index 000000000..fc761ec67 --- /dev/null +++ b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/KubernetesWithHealthTest.java @@ -0,0 +1,94 @@ +package io.quarkus.it.kubernetes; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Probe; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.test.LogFile; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class KubernetesWithHealthTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class)) + .setApplicationName("health") + .setApplicationVersion("0.1-SNAPSHOT") + .setRun(true) + .setLogFileName("k8s.log") + .setForcedDependencies( + Collections.singletonList( + new AppArtifact("io.quarkus", "quarkus-smallrye-health", TestUtil.getProjectVersion()))); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @LogFile + private Path logfile; + + @Test + public void asertApplicationRuns() throws IOException { + assertThat(logfile).isRegularFile().hasFileName("k8s.log"); + String entireLogContent = String.join("\n", Files.readAllLines(logfile)); + assertThat(entireLogContent).contains("kubernetes").contains("health"); + + given() + .when().get("/greeting") + .then() + .statusCode(200) + .body(is("hello")); + } + + @Test + public void assertGeneratedResources() throws IOException { + final Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { + assertThat(d.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("health"); + }); + + assertThat(d.getSpec()).satisfies(deploymentSpec -> { + assertThat(deploymentSpec.getTemplate()).satisfies(t -> { + assertThat(t.getSpec()).satisfies(podSpec -> { + assertThat(podSpec.getContainers()).hasOnlyOneElementSatisfying(container -> { + assertThat(container.getReadinessProbe()).satisfies(p -> { + assertProbePath(p, "/health/ready"); + }); + assertThat(container.getLivenessProbe()).satisfies(p -> { + assertProbePath(p, "/health/live"); + }); + }); + }); + }); + }); + }); + } + + private void assertProbePath(Probe p, String expectedPath) { + assertThat(p.getHttpGet()).satisfies(h -> { + assertThat(h.getPath()).isEqualTo(expectedPath); + }); + } +} diff --git a/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/KubernetesWithRootAndHealthTest.java b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/KubernetesWithRootAndHealthTest.java new file mode 100644 index 000000000..6e6c9b245 --- /dev/null +++ b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/KubernetesWithRootAndHealthTest.java @@ -0,0 +1,73 @@ +package io.quarkus.it.kubernetes; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Probe; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class KubernetesWithRootAndHealthTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class)) + .setApplicationName("root-and-health") + .setApplicationVersion("0.1-SNAPSHOT") + .withConfigurationResource("kubernetes-with-root-and-health.properties") + .setForcedDependencies( + Collections.singletonList( + new AppArtifact("io.quarkus", "quarkus-smallrye-health", TestUtil.getProjectVersion()))); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @Test + public void assertGeneratedResources() throws IOException { + final Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> { + assertThat(d.getMetadata()).satisfies(m -> { + assertThat(m.getName()).isEqualTo("root-and-health"); + }); + + assertThat(d.getSpec()).satisfies(deploymentSpec -> { + assertThat(deploymentSpec.getTemplate()).satisfies(t -> { + assertThat(t.getSpec()).satisfies(podSpec -> { + assertThat(podSpec.getContainers()).hasOnlyOneElementSatisfying(container -> { + assertThat(container.getReadinessProbe()).satisfies(p -> { + assertProbePath(p, "/api/health/ready"); + }); + assertThat(container.getLivenessProbe()).satisfies(p -> { + assertProbePath(p, "/api/health/liveness"); + }); + }); + }); + }); + }); + }); + } + + private void assertProbePath(Probe p, String expectedPath) { + assertThat(p.getHttpGet()).satisfies(h -> { + assertThat(h.getPath()).isEqualTo(expectedPath); + }); + } +} diff --git a/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithOverridenNameTest.java b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithOverridenNameTest.java deleted file mode 100644 index 0424ba4f8..000000000 --- a/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/OpenshiftWithOverridenNameTest.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.quarkus.it.kubernetes; - -public class OpenshiftWithOverridenNameTest { -} diff --git a/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/TestUtil.java b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/TestUtil.java new file mode 100644 index 000000000..6b533ce60 --- /dev/null +++ b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/TestUtil.java @@ -0,0 +1,25 @@ +package io.quarkus.it.kubernetes; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; + +final class TestUtil { + + private TestUtil() { + } + + /** + * Gets the project version from a version.txt (that has been properly setup in maven to contain the version) + * This is needed in order to avoid hard-coding Quarkus dependency versions that could break the release process + */ + public static String getProjectVersion() { + try (BufferedReader bufferedReader = new BufferedReader( + new InputStreamReader(TestUtil.class.getResourceAsStream("/version.txt")))) { + return bufferedReader.readLine(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/WithKubernetesClientTest.java b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/WithKubernetesClientTest.java new file mode 100644 index 000000000..86dfcc866 --- /dev/null +++ b/integration-tests/kubernetes/standard/src/test/java/io/quarkus/it/kubernetes/WithKubernetesClientTest.java @@ -0,0 +1,74 @@ +package io.quarkus.it.kubernetes; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.test.LogFile; +import io.quarkus.test.ProdBuildResults; +import io.quarkus.test.ProdModeTestResults; +import io.quarkus.test.QuarkusProdModeTest; + +public class WithKubernetesClientTest { + + @RegisterExtension + static final QuarkusProdModeTest config = new QuarkusProdModeTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class)) + .setApplicationName("kubernetes-with-client") + .setApplicationVersion("0.1-SNAPSHOT") + .setRun(true) + .setLogFileName("k8s.log") + .setForcedDependencies( + Collections.singletonList( + new AppArtifact("io.quarkus", "quarkus-kubernetes-client", TestUtil.getProjectVersion()))); + + @ProdBuildResults + private ProdModeTestResults prodModeTestResults; + + @LogFile + private Path logfile; + + @Test + public void asertApplicationRuns() throws IOException { + assertThat(logfile).isRegularFile().hasFileName("k8s.log"); + String entireLogContent = String.join("\n", Files.readAllLines(logfile)); + assertThat(entireLogContent).contains("kubernetes").contains("kubernetes-client"); + + given() + .when().get("/greeting") + .then() + .statusCode(200) + .body(is("hello")); + } + + @Test + public void assertGeneratedResources() throws IOException { + final Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes"); + assertThat(kubernetesDir) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json")) + .isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml")); + List kubernetesList = DeserializationUtil + .deserializeAsList(kubernetesDir.resolve("kubernetes.yml")); + + assertThat(kubernetesList).filteredOn(h -> "ServiceAccount".equals(h.getKind())).hasOnlyOneElementSatisfying(h -> { + assertThat(h.getMetadata().getName()).isEqualTo("kubernetes-with-client"); + }); + + assertThat(kubernetesList).filteredOn(h -> "RoleBinding".equals(h.getKind())).hasOnlyOneElementSatisfying(h -> { + assertThat(h.getMetadata().getName()).isEqualTo("kubernetes-with-client:view"); + }); + } +} diff --git a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/src/main/resources/application.properties b/integration-tests/kubernetes/standard/src/test/resources/kubernetes-with-root-and-health.properties similarity index 68% rename from integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/src/main/resources/application.properties rename to integration-tests/kubernetes/standard/src/test/resources/kubernetes-with-root-and-health.properties index 1b8755910..7f6a6a754 100644 --- a/integration-tests/kubernetes/invoker/src/it/kubernetes-with-http-root-and-health/src/main/resources/application.properties +++ b/integration-tests/kubernetes/standard/src/test/resources/kubernetes-with-root-and-health.properties @@ -1,4 +1,2 @@ -# Configuration file -# key = value quarkus.http.root-path=/api quarkus.smallrye-health.liveness-path=/liveness \ No newline at end of file diff --git a/integration-tests/kubernetes/standard/src/test/resources/version.txt b/integration-tests/kubernetes/standard/src/test/resources/version.txt new file mode 100644 index 000000000..f2ab45c3b --- /dev/null +++ b/integration-tests/kubernetes/standard/src/test/resources/version.txt @@ -0,0 +1 @@ +${project.version} \ No newline at end of file diff --git a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusProdModeTest.java b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusProdModeTest.java index 0472a874f..4821f67e0 100644 --- a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusProdModeTest.java +++ b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusProdModeTest.java @@ -15,6 +15,7 @@ import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -42,6 +43,8 @@ import io.quarkus.bootstrap.app.AugmentAction; import io.quarkus.bootstrap.app.AugmentResult; import io.quarkus.bootstrap.app.CuratedApplication; import io.quarkus.bootstrap.app.QuarkusBootstrap; +import io.quarkus.bootstrap.model.AppArtifact; +import io.quarkus.bootstrap.model.AppDependency; import io.quarkus.test.common.PathTestHelper; import io.quarkus.test.common.RestAssuredURLManager; import io.quarkus.utilities.JavaBinFinder; @@ -84,6 +87,7 @@ public class QuarkusProdModeTest private Optional prodModeTestResultsField = Optional.empty(); private Path logfilePath; private Optional logfileField = Optional.empty(); + private List forcedDependencies = Collections.emptyList(); public Supplier getArchiveProducer() { return archiveProducer; @@ -148,6 +152,15 @@ public class QuarkusProdModeTest return this; } + /** + * Provides a convenient way to either add additional dependencies to the application (if it doesn't already contain a + * dependency), or override a version (if the dependency already exists) + */ + public QuarkusProdModeTest setForcedDependencies(List forcedDependencies) { + this.forcedDependencies = forcedDependencies; + return this; + } + private void exportArchive(Path deploymentDir, Class testClass) { try { JavaArchive archive = getArchiveProducerOrDefault(); @@ -229,7 +242,9 @@ public class QuarkusProdModeTest .setLocalProjectDiscovery(true) .addExcludedPath(testLocation) .setProjectRoot(testLocation) - .setTargetDirectory(buildDir); + .setTargetDirectory(buildDir) + .setForcedDependencies(forcedDependencies.stream().map(d -> new AppDependency(d, "compile")) + .collect(Collectors.toList())); if (applicationName != null) { builder.setBaseName(applicationName); }