This is an automated email from the ASF dual-hosted git repository. gfournier pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 53a83d9aa477978606243cc7e00979b60ebbe96f Author: Gaelle Fournier <gaelle.fournier.w...@gmail.com> AuthorDate: Wed Oct 2 14:24:12 2024 +0200 CAMEL-21295: refactor knative kubernetes export test --- .../kubernetes/KubernetesExportBaseTest.java | 120 +++++++ .../kubernetes/KubernetesExportKnativeTest.java | 293 ++++++++++++++++++ .../commands/kubernetes/KubernetesExportTest.java | 344 +-------------------- 3 files changed, 414 insertions(+), 343 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportBaseTest.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportBaseTest.java new file mode 100644 index 00000000000..712272adbd5 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportBaseTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.dsl.jbang.core.commands.kubernetes; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.Properties; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Service; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.common.RuntimeType; +import org.apache.camel.util.IOHelper; +import org.junit.jupiter.api.BeforeEach; +import picocli.CommandLine; + +public class KubernetesExportBaseTest extends KubernetesBaseTest { + + protected File workingDir; + protected String[] defaultArgs; + + @BeforeEach + public void setup() { + super.setup(); + + try { + Path base = Paths.get("target"); + workingDir = Files.createTempDirectory(base, "camel-k8s-export").toFile(); + workingDir.deleteOnExit(); + } catch (IOException e) { + throw new RuntimeCamelException(e); + } + + defaultArgs = new String[] { "--dir=" + workingDir, "--quiet" }; + } + + protected KubernetesExport createCommand(String[] files, String... args) { + var argsArr = Optional.ofNullable(args).orElse(new String[0]); + var argsLst = new ArrayList<>(Arrays.asList(argsArr)); + argsLst.addAll(Arrays.asList(defaultArgs)); + KubernetesExport command = new KubernetesExport(new CamelJBangMain(), files); + CommandLine.populateCommand(command, argsLst.toArray(new String[0])); + return command; + } + + protected boolean hasService(RuntimeType rt) throws IOException { + return getResource(rt, Service.class).isPresent(); + } + + protected boolean hasKnativeService(RuntimeType rt) throws IOException { + return getResource(rt, io.fabric8.knative.serving.v1.Service.class).isPresent(); + } + + protected <T extends HasMetadata> Optional<T> getResource(RuntimeType rt, Class<T> type) throws IOException { + if (rt == RuntimeType.quarkus) { + try (FileInputStream fis + = new FileInputStream( + KubernetesHelper.getKubernetesManifest(ClusterType.KUBERNETES.name(), + new File(workingDir, "/src/main/kubernetes")))) { + List<HasMetadata> resources = kubernetesClient.load(fis).items(); + return resources.stream() + .filter(it -> type.isAssignableFrom(it.getClass())) + .map(type::cast) + .findFirst(); + } + } + if (rt == RuntimeType.springBoot || rt == RuntimeType.main) { + var kind = type.getSimpleName().toLowerCase(); + File file = new File(workingDir, "src/main/jkube/%s.yml".formatted(kind)); + if (file.isFile()) { + try (FileInputStream fis = new FileInputStream(file)) { + List<HasMetadata> resources = kubernetesClient.load(fis).items(); + return resources.stream() + .filter(it -> type.isAssignableFrom(it.getClass())) + .map(type::cast) + .findFirst(); + } + } + } + return Optional.empty(); + } + + protected String readResource(File workingDir, String path) throws IOException { + try (FileInputStream fis = new FileInputStream(workingDir.toPath().resolve(path).toFile())) { + return IOHelper.loadText(fis); + } + } + + protected Properties getApplicationProperties(File workingDir) throws IOException { + String content = readResource(workingDir, "src/main/resources/application.properties"); + Properties applicationProperties = new Properties(); + applicationProperties.load(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); + return applicationProperties; + } +} diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportKnativeTest.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportKnativeTest.java new file mode 100644 index 00000000000..e06ac35976a --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportKnativeTest.java @@ -0,0 +1,293 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.dsl.jbang.core.commands.kubernetes; + +import java.io.File; +import java.io.IOException; +import java.util.Properties; +import java.util.stream.Stream; + +import io.fabric8.knative.eventing.v1.Trigger; +import io.fabric8.knative.messaging.v1.Subscription; +import io.fabric8.knative.sources.v1.SinkBinding; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.dsl.jbang.core.commands.kubernetes.traits.BaseTrait; +import org.apache.camel.dsl.jbang.core.common.RuntimeType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class KubernetesExportKnativeTest extends KubernetesExportBaseTest { + + private static Stream<Arguments> runtimeProvider() { + return Stream.of( + Arguments.of(RuntimeType.main), + Arguments.of(RuntimeType.springBoot), + Arguments.of(RuntimeType.quarkus)); + } + + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldAddKnativeServiceSpec(RuntimeType rt) throws Exception { + KubernetesExport command = createCommand(new String[] { "classpath:route-service.yaml" }, + "--image-group=camel-test", "--runtime=" + rt.runtime()); + + command.traits = new String[] { + "knative-service.enabled=true", + "knative-service.class=hpa.autoscaling.knative.dev", + "knative-service.autoscaling-metric=cpu", + "knative-service.autoscaling-target=80", + "knative-service.min-scale=1", + "knative-service.max-scale=10", + "knative-service.rollout-duration=60", + "knative-service.visibility=cluster-local" }; + command.doCall(); + + Assertions.assertFalse(hasService(rt)); + Assertions.assertTrue(hasKnativeService(rt)); + + io.fabric8.knative.serving.v1.Service service = getResource(rt, io.fabric8.knative.serving.v1.Service.class) + .orElseThrow(() -> new RuntimeCamelException("Missing Knative service in Kubernetes manifest")); + + Assertions.assertEquals("route-service", service.getMetadata().getName()); + Assertions.assertEquals(3, service.getMetadata().getLabels().size()); + Assertions.assertEquals("route-service", service.getMetadata().getLabels().get(BaseTrait.INTEGRATION_LABEL)); + Assertions.assertEquals("true", service.getMetadata().getLabels().get("bindings.knative.dev/include")); + Assertions.assertEquals("cluster-local", service.getMetadata().getLabels().get("networking.knative.dev/visibility")); + Assertions.assertEquals(1, service.getMetadata().getAnnotations().size()); + Assertions.assertEquals("60", service.getMetadata().getAnnotations().get("serving.knative.dev/rolloutDuration")); + Assertions.assertEquals(1, service.getSpec().getTemplate().getMetadata().getLabels().size()); + Assertions.assertEquals("route-service", + service.getSpec().getTemplate().getMetadata().getLabels().get(BaseTrait.INTEGRATION_LABEL)); + Assertions.assertEquals(5, service.getSpec().getTemplate().getMetadata().getAnnotations().size()); + Assertions.assertEquals("cpu", + service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/metric")); + Assertions.assertEquals("hpa.autoscaling.knative.dev", + service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/class")); + Assertions.assertEquals("80", + service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/target")); + Assertions.assertEquals("1", + service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/minScale")); + Assertions.assertEquals("10", + service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/maxScale")); + } + + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldAddKnativeTrigger(RuntimeType rt) throws Exception { + KubernetesExport command = createCommand(new String[] { "classpath:knative-event-source.yaml" }, + "--image-group=camel-test", "--runtime=" + rt.runtime()); + command.doCall(); + + Assertions.assertTrue(hasService(rt)); + Assertions.assertFalse(hasKnativeService(rt)); + + Trigger trigger = getResource(rt, Trigger.class) + .orElseThrow(() -> new RuntimeCamelException("Missing Knative trigger in Kubernetes manifest")); + + Assertions.assertEquals("my-broker-knative-event-source-camel-event", trigger.getMetadata().getName()); + Assertions.assertEquals("my-broker", trigger.getSpec().getBroker()); + Assertions.assertEquals(1, trigger.getSpec().getFilter().getAttributes().size()); + Assertions.assertEquals("camel-event", trigger.getSpec().getFilter().getAttributes().get("type")); + Assertions.assertEquals("knative-event-source", trigger.getSpec().getSubscriber().getRef().getName()); + Assertions.assertEquals("Service", trigger.getSpec().getSubscriber().getRef().getKind()); + Assertions.assertEquals("v1", trigger.getSpec().getSubscriber().getRef().getApiVersion()); + Assertions.assertEquals("/events/camel-event", trigger.getSpec().getSubscriber().getUri()); + + Properties applicationProperties = getApplicationProperties(workingDir); + Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); + + Assertions.assertEquals(""" + { + "resources" : [ { + "name" : "camel-event", + "type" : "event", + "endpointKind" : "source", + "path" : "/events/camel-event", + "objectApiVersion" : "eventing.knative.dev/v1", + "objectKind" : "Broker", + "objectName" : "my-broker", + "reply" : false + } ] + } + """, getKnativeResourceConfiguration(workingDir)); + } + + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldAddKnativeSubscription(RuntimeType rt) throws Exception { + KubernetesExport command = createCommand(new String[] { "classpath:knative-channel-source.yaml" }, + "--image-group=camel-test", "--runtime=" + rt.runtime()); + command.doCall(); + + Assertions.assertTrue(hasService(rt)); + Assertions.assertFalse(hasKnativeService(rt)); + + Subscription subscription = getResource(rt, Subscription.class) + .orElseThrow(() -> new RuntimeCamelException("Missing Knative subscription in Kubernetes manifest")); + + Assertions.assertEquals("my-channel-knative-channel-source", subscription.getMetadata().getName()); + Assertions.assertEquals("my-channel", subscription.getSpec().getChannel().getName()); + Assertions.assertEquals("knative-channel-source", subscription.getSpec().getSubscriber().getRef().getName()); + Assertions.assertEquals("Service", subscription.getSpec().getSubscriber().getRef().getKind()); + Assertions.assertEquals("v1", subscription.getSpec().getSubscriber().getRef().getApiVersion()); + Assertions.assertEquals("/channels/my-channel", subscription.getSpec().getSubscriber().getUri()); + + Properties applicationProperties = getApplicationProperties(workingDir); + Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); + + Assertions.assertEquals(""" + { + "resources" : [ { + "name" : "my-channel", + "type" : "channel", + "endpointKind" : "source", + "path" : "/channels/my-channel", + "objectApiVersion" : "messaging.knative.dev/v1", + "objectKind" : "Channel", + "objectName" : "my-channel", + "reply" : false + } ] + } + """, getKnativeResourceConfiguration(workingDir)); + } + + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldAddKnativeBrokerSinkBinding(RuntimeType rt) throws Exception { + KubernetesExport command = createCommand(new String[] { "classpath:knative-event-sink.yaml" }, + "--image-group=camel-test", "--runtime=" + rt.runtime()); + command.doCall(); + + Assertions.assertTrue(hasService(rt)); + Assertions.assertFalse(hasKnativeService(rt)); + + SinkBinding sinkBinding = getResource(rt, SinkBinding.class) + .orElseThrow(() -> new RuntimeCamelException("Missing Knative sinkBinding in Kubernetes manifest")); + + Assertions.assertEquals("knative-event-sink", sinkBinding.getMetadata().getName()); + Assertions.assertEquals("my-broker", sinkBinding.getSpec().getSink().getRef().getName()); + Assertions.assertEquals("Broker", sinkBinding.getSpec().getSink().getRef().getKind()); + Assertions.assertEquals("eventing.knative.dev/v1", sinkBinding.getSpec().getSink().getRef().getApiVersion()); + Assertions.assertEquals("knative-event-sink", sinkBinding.getSpec().getSubject().getName()); + Assertions.assertEquals("Deployment", sinkBinding.getSpec().getSubject().getKind()); + Assertions.assertEquals("apps/v1", sinkBinding.getSpec().getSubject().getApiVersion()); + + Properties applicationProperties = getApplicationProperties(workingDir); + Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); + + Assertions.assertEquals(""" + { + "resources" : [ { + "name" : "my-broker", + "type" : "event", + "endpointKind" : "sink", + "url" : "{{k.sink:http://localhost:8080}}", + "objectApiVersion" : "eventing.knative.dev/v1", + "objectKind" : "Broker", + "objectName" : "my-broker", + "reply" : false + } ] + } + """, getKnativeResourceConfiguration(workingDir)); + } + + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldAddKnativeChannelSinkBinding(RuntimeType rt) throws Exception { + KubernetesExport command = createCommand(new String[] { "classpath:knative-channel-sink.yaml" }, + "--image-group=camel-test", "--runtime=" + rt.runtime()); + command.doCall(); + + Assertions.assertTrue(hasService(rt)); + Assertions.assertFalse(hasKnativeService(rt)); + + SinkBinding sinkBinding = getResource(rt, SinkBinding.class) + .orElseThrow(() -> new RuntimeCamelException("Missing Knative sinkBinding in Kubernetes manifest")); + + Assertions.assertEquals("knative-channel-sink", sinkBinding.getMetadata().getName()); + Assertions.assertEquals("my-channel", sinkBinding.getSpec().getSink().getRef().getName()); + Assertions.assertEquals("Channel", sinkBinding.getSpec().getSink().getRef().getKind()); + Assertions.assertEquals("messaging.knative.dev/v1", sinkBinding.getSpec().getSink().getRef().getApiVersion()); + Assertions.assertEquals("knative-channel-sink", sinkBinding.getSpec().getSubject().getName()); + Assertions.assertEquals("Deployment", sinkBinding.getSpec().getSubject().getKind()); + Assertions.assertEquals("apps/v1", sinkBinding.getSpec().getSubject().getApiVersion()); + + Properties applicationProperties = getApplicationProperties(workingDir); + Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); + + Assertions.assertEquals(""" + { + "resources" : [ { + "name" : "my-channel", + "type" : "channel", + "endpointKind" : "sink", + "url" : "{{k.sink:http://localhost:8080}}", + "objectApiVersion" : "messaging.knative.dev/v1", + "objectKind" : "Channel", + "objectName" : "my-channel", + "reply" : false + } ] + } + """, getKnativeResourceConfiguration(workingDir)); + } + + @ParameterizedTest + @MethodSource("runtimeProvider") + public void shouldAddKnativeEndpointSinkBinding(RuntimeType rt) throws Exception { + KubernetesExport command = createCommand(new String[] { "classpath:knative-endpoint-sink.yaml" }, + "--image-group=camel-test", "--runtime=" + rt.runtime()); + command.doCall(); + + Assertions.assertTrue(hasService(rt)); + Assertions.assertFalse(hasKnativeService(rt)); + + SinkBinding sinkBinding = getResource(rt, SinkBinding.class) + .orElseThrow(() -> new RuntimeCamelException("Missing Knative sinkBinding in Kubernetes manifest")); + + Assertions.assertEquals("knative-endpoint-sink", sinkBinding.getMetadata().getName()); + Assertions.assertEquals("my-endpoint", sinkBinding.getSpec().getSink().getRef().getName()); + Assertions.assertEquals("Service", sinkBinding.getSpec().getSink().getRef().getKind()); + Assertions.assertEquals("serving.knative.dev/v1", sinkBinding.getSpec().getSink().getRef().getApiVersion()); + Assertions.assertEquals("knative-endpoint-sink", sinkBinding.getSpec().getSubject().getName()); + Assertions.assertEquals("Deployment", sinkBinding.getSpec().getSubject().getKind()); + Assertions.assertEquals("apps/v1", sinkBinding.getSpec().getSubject().getApiVersion()); + + Properties applicationProperties = getApplicationProperties(workingDir); + Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); + + Assertions.assertEquals(""" + { + "resources" : [ { + "name" : "my-endpoint", + "type" : "endpoint", + "endpointKind" : "sink", + "url" : "{{k.sink:http://localhost:8080}}", + "objectApiVersion" : "serving.knative.dev/v1", + "objectKind" : "Service", + "objectName" : "my-endpoint", + "reply" : false + } ] + } + """, getKnativeResourceConfiguration(workingDir)); + } + + private String getKnativeResourceConfiguration(File workingDir) throws IOException { + return readResource(workingDir, "src/main/resources/knative.json"); + } +} diff --git a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java index 12818e034b1..89665bce127 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java +++ b/dsl/camel-jbang/camel-jbang-plugin-kubernetes/src/test/java/org/apache/camel/dsl/jbang/core/commands/kubernetes/KubernetesExportTest.java @@ -17,66 +17,33 @@ package org.apache.camel.dsl.jbang.core.commands.kubernetes; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Properties; import java.util.stream.Stream; -import io.fabric8.knative.eventing.v1.Trigger; -import io.fabric8.knative.messaging.v1.Subscription; -import io.fabric8.knative.sources.v1.SinkBinding; import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServicePort; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.networking.v1.Ingress; import io.fabric8.openshift.api.model.Route; import org.apache.camel.RuntimeCamelException; -import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; import org.apache.camel.dsl.jbang.core.commands.kubernetes.traits.BaseTrait; import org.apache.camel.dsl.jbang.core.common.RuntimeType; import org.apache.camel.util.IOHelper; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import picocli.CommandLine; -class KubernetesExportTest extends KubernetesBaseTest { - - private File workingDir; - private String[] defaultArgs; - - @BeforeEach - public void setup() { - super.setup(); - - try { - Path base = Paths.get("target"); - workingDir = Files.createTempDirectory(base, "camel-k8s-export").toFile(); - workingDir.deleteOnExit(); - } catch (IOException e) { - throw new RuntimeCamelException(e); - } - - defaultArgs = new String[] { "--dir=" + workingDir, "--quiet" }; - } +class KubernetesExportTest extends KubernetesExportBaseTest { private static Stream<Arguments> runtimeProvider() { return Stream.of( @@ -344,252 +311,6 @@ class KubernetesExportTest extends KubernetesBaseTest { Assertions.assertEquals("custom", service.getSpec().getPorts().get(0).getTargetPort().getStrVal()); } - @ParameterizedTest - @MethodSource("runtimeProvider") - public void shouldAddKnativeServiceSpec(RuntimeType rt) throws Exception { - KubernetesExport command = createCommand(new String[] { "classpath:route-service.yaml" }, - "--image-group=camel-test", "--runtime=" + rt.runtime()); - - command.traits = new String[] { - "knative-service.enabled=true", - "knative-service.class=hpa.autoscaling.knative.dev", - "knative-service.autoscaling-metric=cpu", - "knative-service.autoscaling-target=80", - "knative-service.min-scale=1", - "knative-service.max-scale=10", - "knative-service.rollout-duration=60", - "knative-service.visibility=cluster-local" }; - command.doCall(); - - Assertions.assertFalse(hasService(rt)); - Assertions.assertTrue(hasKnativeService(rt)); - - io.fabric8.knative.serving.v1.Service service = getResource(rt, io.fabric8.knative.serving.v1.Service.class) - .orElseThrow(() -> new RuntimeCamelException("Missing Knative service in Kubernetes manifest")); - - Assertions.assertEquals("route-service", service.getMetadata().getName()); - Assertions.assertEquals(3, service.getMetadata().getLabels().size()); - Assertions.assertEquals("route-service", service.getMetadata().getLabels().get(BaseTrait.INTEGRATION_LABEL)); - Assertions.assertEquals("true", service.getMetadata().getLabels().get("bindings.knative.dev/include")); - Assertions.assertEquals("cluster-local", service.getMetadata().getLabels().get("networking.knative.dev/visibility")); - Assertions.assertEquals(1, service.getMetadata().getAnnotations().size()); - Assertions.assertEquals("60", service.getMetadata().getAnnotations().get("serving.knative.dev/rolloutDuration")); - Assertions.assertEquals(1, service.getSpec().getTemplate().getMetadata().getLabels().size()); - Assertions.assertEquals("route-service", - service.getSpec().getTemplate().getMetadata().getLabels().get(BaseTrait.INTEGRATION_LABEL)); - Assertions.assertEquals(5, service.getSpec().getTemplate().getMetadata().getAnnotations().size()); - Assertions.assertEquals("cpu", - service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/metric")); - Assertions.assertEquals("hpa.autoscaling.knative.dev", - service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/class")); - Assertions.assertEquals("80", - service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/target")); - Assertions.assertEquals("1", - service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/minScale")); - Assertions.assertEquals("10", - service.getSpec().getTemplate().getMetadata().getAnnotations().get("autoscaling.knative.dev/maxScale")); - } - - @ParameterizedTest - @MethodSource("runtimeProvider") - public void shouldAddKnativeTrigger(RuntimeType rt) throws Exception { - KubernetesExport command = createCommand(new String[] { "classpath:knative-event-source.yaml" }, - "--image-group=camel-test", "--runtime=" + rt.runtime()); - command.doCall(); - - Assertions.assertTrue(hasService(rt)); - Assertions.assertFalse(hasKnativeService(rt)); - - Trigger trigger = getResource(rt, Trigger.class) - .orElseThrow(() -> new RuntimeCamelException("Missing Knative trigger in Kubernetes manifest")); - - Assertions.assertEquals("my-broker-knative-event-source-camel-event", trigger.getMetadata().getName()); - Assertions.assertEquals("my-broker", trigger.getSpec().getBroker()); - Assertions.assertEquals(1, trigger.getSpec().getFilter().getAttributes().size()); - Assertions.assertEquals("camel-event", trigger.getSpec().getFilter().getAttributes().get("type")); - Assertions.assertEquals("knative-event-source", trigger.getSpec().getSubscriber().getRef().getName()); - Assertions.assertEquals("Service", trigger.getSpec().getSubscriber().getRef().getKind()); - Assertions.assertEquals("v1", trigger.getSpec().getSubscriber().getRef().getApiVersion()); - Assertions.assertEquals("/events/camel-event", trigger.getSpec().getSubscriber().getUri()); - - Properties applicationProperties = getApplicationProperties(workingDir); - Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); - - Assertions.assertEquals(""" - { - "resources" : [ { - "name" : "camel-event", - "type" : "event", - "endpointKind" : "source", - "path" : "/events/camel-event", - "objectApiVersion" : "eventing.knative.dev/v1", - "objectKind" : "Broker", - "objectName" : "my-broker", - "reply" : false - } ] - } - """, getKnativeResourceConfiguration(workingDir)); - } - - @ParameterizedTest - @MethodSource("runtimeProvider") - public void shouldAddKnativeSubscription(RuntimeType rt) throws Exception { - KubernetesExport command = createCommand(new String[] { "classpath:knative-channel-source.yaml" }, - "--image-group=camel-test", "--runtime=" + rt.runtime()); - command.doCall(); - - Assertions.assertTrue(hasService(rt)); - Assertions.assertFalse(hasKnativeService(rt)); - - Subscription subscription = getResource(rt, Subscription.class) - .orElseThrow(() -> new RuntimeCamelException("Missing Knative subscription in Kubernetes manifest")); - - Assertions.assertEquals("my-channel-knative-channel-source", subscription.getMetadata().getName()); - Assertions.assertEquals("my-channel", subscription.getSpec().getChannel().getName()); - Assertions.assertEquals("knative-channel-source", subscription.getSpec().getSubscriber().getRef().getName()); - Assertions.assertEquals("Service", subscription.getSpec().getSubscriber().getRef().getKind()); - Assertions.assertEquals("v1", subscription.getSpec().getSubscriber().getRef().getApiVersion()); - Assertions.assertEquals("/channels/my-channel", subscription.getSpec().getSubscriber().getUri()); - - Properties applicationProperties = getApplicationProperties(workingDir); - Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); - - Assertions.assertEquals(""" - { - "resources" : [ { - "name" : "my-channel", - "type" : "channel", - "endpointKind" : "source", - "path" : "/channels/my-channel", - "objectApiVersion" : "messaging.knative.dev/v1", - "objectKind" : "Channel", - "objectName" : "my-channel", - "reply" : false - } ] - } - """, getKnativeResourceConfiguration(workingDir)); - } - - @ParameterizedTest - @MethodSource("runtimeProvider") - public void shouldAddKnativeBrokerSinkBinding(RuntimeType rt) throws Exception { - KubernetesExport command = createCommand(new String[] { "classpath:knative-event-sink.yaml" }, - "--image-group=camel-test", "--runtime=" + rt.runtime()); - command.doCall(); - - Assertions.assertTrue(hasService(rt)); - Assertions.assertFalse(hasKnativeService(rt)); - - SinkBinding sinkBinding = getResource(rt, SinkBinding.class) - .orElseThrow(() -> new RuntimeCamelException("Missing Knative sinkBinding in Kubernetes manifest")); - - Assertions.assertEquals("knative-event-sink", sinkBinding.getMetadata().getName()); - Assertions.assertEquals("my-broker", sinkBinding.getSpec().getSink().getRef().getName()); - Assertions.assertEquals("Broker", sinkBinding.getSpec().getSink().getRef().getKind()); - Assertions.assertEquals("eventing.knative.dev/v1", sinkBinding.getSpec().getSink().getRef().getApiVersion()); - Assertions.assertEquals("knative-event-sink", sinkBinding.getSpec().getSubject().getName()); - Assertions.assertEquals("Deployment", sinkBinding.getSpec().getSubject().getKind()); - Assertions.assertEquals("apps/v1", sinkBinding.getSpec().getSubject().getApiVersion()); - - Properties applicationProperties = getApplicationProperties(workingDir); - Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); - - Assertions.assertEquals(""" - { - "resources" : [ { - "name" : "my-broker", - "type" : "event", - "endpointKind" : "sink", - "url" : "{{k.sink:http://localhost:8080}}", - "objectApiVersion" : "eventing.knative.dev/v1", - "objectKind" : "Broker", - "objectName" : "my-broker", - "reply" : false - } ] - } - """, getKnativeResourceConfiguration(workingDir)); - } - - @ParameterizedTest - @MethodSource("runtimeProvider") - public void shouldAddKnativeChannelSinkBinding(RuntimeType rt) throws Exception { - KubernetesExport command = createCommand(new String[] { "classpath:knative-channel-sink.yaml" }, - "--image-group=camel-test", "--runtime=" + rt.runtime()); - command.doCall(); - - Assertions.assertTrue(hasService(rt)); - Assertions.assertFalse(hasKnativeService(rt)); - - SinkBinding sinkBinding = getResource(rt, SinkBinding.class) - .orElseThrow(() -> new RuntimeCamelException("Missing Knative sinkBinding in Kubernetes manifest")); - - Assertions.assertEquals("knative-channel-sink", sinkBinding.getMetadata().getName()); - Assertions.assertEquals("my-channel", sinkBinding.getSpec().getSink().getRef().getName()); - Assertions.assertEquals("Channel", sinkBinding.getSpec().getSink().getRef().getKind()); - Assertions.assertEquals("messaging.knative.dev/v1", sinkBinding.getSpec().getSink().getRef().getApiVersion()); - Assertions.assertEquals("knative-channel-sink", sinkBinding.getSpec().getSubject().getName()); - Assertions.assertEquals("Deployment", sinkBinding.getSpec().getSubject().getKind()); - Assertions.assertEquals("apps/v1", sinkBinding.getSpec().getSubject().getApiVersion()); - - Properties applicationProperties = getApplicationProperties(workingDir); - Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); - - Assertions.assertEquals(""" - { - "resources" : [ { - "name" : "my-channel", - "type" : "channel", - "endpointKind" : "sink", - "url" : "{{k.sink:http://localhost:8080}}", - "objectApiVersion" : "messaging.knative.dev/v1", - "objectKind" : "Channel", - "objectName" : "my-channel", - "reply" : false - } ] - } - """, getKnativeResourceConfiguration(workingDir)); - } - - @ParameterizedTest - @MethodSource("runtimeProvider") - public void shouldAddKnativeEndpointSinkBinding(RuntimeType rt) throws Exception { - KubernetesExport command = createCommand(new String[] { "classpath:knative-endpoint-sink.yaml" }, - "--image-group=camel-test", "--runtime=" + rt.runtime()); - command.doCall(); - - Assertions.assertTrue(hasService(rt)); - Assertions.assertFalse(hasKnativeService(rt)); - - SinkBinding sinkBinding = getResource(rt, SinkBinding.class) - .orElseThrow(() -> new RuntimeCamelException("Missing Knative sinkBinding in Kubernetes manifest")); - - Assertions.assertEquals("knative-endpoint-sink", sinkBinding.getMetadata().getName()); - Assertions.assertEquals("my-endpoint", sinkBinding.getSpec().getSink().getRef().getName()); - Assertions.assertEquals("Service", sinkBinding.getSpec().getSink().getRef().getKind()); - Assertions.assertEquals("serving.knative.dev/v1", sinkBinding.getSpec().getSink().getRef().getApiVersion()); - Assertions.assertEquals("knative-endpoint-sink", sinkBinding.getSpec().getSubject().getName()); - Assertions.assertEquals("Deployment", sinkBinding.getSpec().getSubject().getKind()); - Assertions.assertEquals("apps/v1", sinkBinding.getSpec().getSubject().getApiVersion()); - - Properties applicationProperties = getApplicationProperties(workingDir); - Assertions.assertEquals("classpath:knative.json", applicationProperties.get("camel.component.knative.environmentPath")); - - Assertions.assertEquals(""" - { - "resources" : [ { - "name" : "my-endpoint", - "type" : "endpoint", - "endpointKind" : "sink", - "url" : "{{k.sink:http://localhost:8080}}", - "objectApiVersion" : "serving.knative.dev/v1", - "objectKind" : "Service", - "objectName" : "my-endpoint", - "reply" : false - } ] - } - """, getKnativeResourceConfiguration(workingDir)); - } - @ParameterizedTest @MethodSource("runtimeProvider") public void shouldAddVolumes(RuntimeType rt) throws Exception { @@ -750,15 +471,6 @@ class KubernetesExportTest extends KubernetesBaseTest { deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); } - private KubernetesExport createCommand(String[] files, String... args) { - var argsArr = Optional.ofNullable(args).orElse(new String[0]); - var argsLst = new ArrayList<>(Arrays.asList(argsArr)); - argsLst.addAll(Arrays.asList(defaultArgs)); - KubernetesExport command = new KubernetesExport(new CamelJBangMain(), files); - CommandLine.populateCommand(command, argsLst.toArray(new String[0])); - return command; - } - private Deployment getDeployment(RuntimeType rt) throws IOException { return getResource(rt, Deployment.class) .orElseThrow(() -> new RuntimeCamelException("Cannot find deployment for: %s".formatted(rt.runtime()))); @@ -787,60 +499,6 @@ class KubernetesExportTest extends KubernetesBaseTest { return getResource(rt, Route.class).isPresent(); } - private boolean hasService(RuntimeType rt) throws IOException { - return getResource(rt, Service.class).isPresent(); - } - - private boolean hasKnativeService(RuntimeType rt) throws IOException { - return getResource(rt, io.fabric8.knative.serving.v1.Service.class).isPresent(); - } - - private <T extends HasMetadata> Optional<T> getResource(RuntimeType rt, Class<T> type) throws IOException { - if (rt == RuntimeType.quarkus) { - try (FileInputStream fis - = new FileInputStream( - KubernetesHelper.getKubernetesManifest(ClusterType.KUBERNETES.name(), - new File(workingDir, "/src/main/kubernetes")))) { - List<HasMetadata> resources = kubernetesClient.load(fis).items(); - return resources.stream() - .filter(it -> type.isAssignableFrom(it.getClass())) - .map(type::cast) - .findFirst(); - } - } - if (rt == RuntimeType.springBoot || rt == RuntimeType.main) { - var kind = type.getSimpleName().toLowerCase(); - File file = new File(workingDir, "src/main/jkube/%s.yml".formatted(kind)); - if (file.isFile()) { - try (FileInputStream fis = new FileInputStream(file)) { - List<HasMetadata> resources = kubernetesClient.load(fis).items(); - return resources.stream() - .filter(it -> type.isAssignableFrom(it.getClass())) - .map(type::cast) - .findFirst(); - } - } - } - return Optional.empty(); - } - - private String readResource(File workingDir, String path) throws IOException { - try (FileInputStream fis = new FileInputStream(workingDir.toPath().resolve(path).toFile())) { - return IOHelper.loadText(fis); - } - } - - private Properties getApplicationProperties(File workingDir) throws IOException { - String content = readResource(workingDir, "src/main/resources/application.properties"); - Properties applicationProperties = new Properties(); - applicationProperties.load(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); - return applicationProperties; - } - - private String getKnativeResourceConfiguration(File workingDir) throws IOException { - return readResource(workingDir, "src/main/resources/knative.json"); - } - private Model readMavenModel() throws Exception { File f = workingDir.toPath().resolve("pom.xml").toFile(); Assertions.assertTrue(f.isFile(), "Not a pom.xml file: " + f);