diff --git a/docs/antora.yml b/docs/antora.yml
index 4fe07e8df2c6..1a1c8912a86b 100644
--- a/docs/antora.yml
+++ b/docs/antora.yml
@@ -29,11 +29,11 @@ asciidoc:
min-maven-version: 3.8.2 # replace ${min-maven-version}
target-maven-version: 3.8.4 # replace ${target-maven-version}
- camel-version: 3.17.0 # replace ${camel.version}
- camel-docs-version: 3.17.x # replace ${camel.docs.components.version}
+ camel-version: 3.18.0-SNAPSHOT # replace ${camel.version}
+ camel-docs-version: 3.18.x # replace ${camel.docs.components.version}
quarkus-version: 2.10.0.Final # replace ${quarkus.version}
graalvm-version: 22.1.0 # replace ${graalvm.version}
graalvm-docs-version: 22.1
# attributes used in xrefs to other Antora components
- cq-camel-components: 3.17.x@components # replace ${camel.docs.components.xref}
+ cq-camel-components: 3.18.x@components # replace ${camel.docs.components.xref}
quarkus-examples-version: latest
diff --git a/extensions-core/core/deployment/pom.xml b/extensions-core/core/deployment/pom.xml
index 765250a7dee4..065008c38e8b 100644
--- a/extensions-core/core/deployment/pom.xml
+++ b/extensions-core/core/deployment/pom.xml
@@ -37,6 +37,10 @@
io.quarkus
quarkus-arc-deployment
+
+ io.quarkus.arc
+ arc-processor
+
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelTestProcessor.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelTestProcessor.java
new file mode 100644
index 000000000000..9f0e61a13d3f
--- /dev/null
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelTestProcessor.java
@@ -0,0 +1,62 @@
+/*
+ * 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.quarkus.core.deployment;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.TestAnnotationBuildItem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CamelTestProcessor {
+ private static final Logger LOGGER = LoggerFactory.getLogger(CamelTestProcessor.class);
+ static String TEST_ANNOTATION_CLASS_NAME = "org.apache.camel.quarkus.test.CamelQuarkusTest";
+
+ @BuildStep
+ void produceTestAnnotationBuildItem(BuildProducer testAnnotationBuildItems) {
+ testAnnotationBuildItems.produce(new TestAnnotationBuildItem(TEST_ANNOTATION_CLASS_NAME));
+ }
+
+ // @BuildStep
+ // void annotationTransformerBuildItem(BuildProducer annotationsTransformerBuildItems) {
+ // annotationsTransformerBuildItems.produce(createAnnotationTransformer(null));
+ // }
+ //
+ // private AnnotationsTransformerBuildItem createAnnotationTransformer(DotName className) {
+ // return new AnnotationsTransformerBuildItem(new AnnotationsTransformer() {
+ // public boolean appliesTo(org.jboss.jandex.AnnotationTarget.Kind kind) {
+ // return kind == AnnotationTarget.Kind.CLASS;
+ // }
+ //
+ // public void transform(TransformationContext context) {
+ //
+ // if (context.getAnnotations().contains(
+ // AnnotationInstance.create(
+ // DotName.createSimple(CamelQuarkusTest.class.getName()),
+ // context.getTarget(),
+ // new AnnotationValue[] {}))) {
+ // context.transform().add(AnnotationInstance.create(
+ // DotName.createSimple(TestProfile.class.getName()),
+ // context.getTarget(),
+ // new AnnotationValue[] { AnnotationValue.createClassValue("value",
+ // Type.create(context.getTarget().asClass().name(), Type.Kind.CLASS)) }))
+ // .done();
+ // }
+ // }
+ // });
+ // }
+}
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/InjectionPointsProcessor.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/InjectionPointsProcessor.java
index e8ced1788acf..6e7098919409 100644
--- a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/InjectionPointsProcessor.java
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/InjectionPointsProcessor.java
@@ -70,6 +70,7 @@
public class InjectionPointsProcessor {
private static final Logger LOGGER = Logger.getLogger(InjectionPointsProcessor.class);
+
private static final DotName ANNOTATION_NAME_NAMED = DotName.createSimple(
Named.class.getName());
private static final DotName INTERFACE_NAME_COMPONENT = DotName.createSimple(
@@ -226,12 +227,16 @@ void syntheticBeans(
BuildProducer syntheticBeans,
BuildProducer proxyDefinitions) {
+ Set alreadyCreated = new HashSet<>();
+
for (AnnotationInstance annot : index.getIndex().getAnnotations(ENDPOINT_INJECT_ANNOTATION)) {
final AnnotationTarget target = annot.target();
switch (target.kind()) {
case FIELD: {
final FieldInfo field = target.asField();
- endpointInjectBeans(recorder, syntheticBeans, index.getIndex(), annot, field.type().name());
+ if (!excludeTestSyntheticBeanDuplicities(annot, alreadyCreated, field.declaringClass())) {
+ endpointInjectBeans(recorder, syntheticBeans, index.getIndex(), annot, field.type().name());
+ }
break;
}
case METHOD: {
@@ -251,8 +256,10 @@ void syntheticBeans(
switch (target.kind()) {
case FIELD: {
final FieldInfo field = target.asField();
- produceBeans(recorder, capabilities, syntheticBeans, proxyDefinitions, beanCapabilityAvailable,
- index.getIndex(), annot, field.type().name(), field.name(), field.declaringClass().name());
+ if (!excludeTestSyntheticBeanDuplicities(annot, alreadyCreated, field.declaringClass())) {
+ produceBeans(recorder, capabilities, syntheticBeans, proxyDefinitions, beanCapabilityAvailable,
+ index.getIndex(), annot, field.type().name(), field.name(), field.declaringClass().name());
+ }
break;
}
case METHOD: {
@@ -266,6 +273,33 @@ void syntheticBeans(
}
}
+ private boolean excludeTestSyntheticBeanDuplicities(AnnotationInstance annot, Set alreadyCreated,
+ ClassInfo declaringClass) {
+ String identifier = annot.toString(false) + ":" + getTargetClass(annot).toString();
+
+ if (declaringClass.annotations().containsKey(DotName.createSimple(CamelTestProcessor.TEST_ANNOTATION_CLASS_NAME))) {
+ if (alreadyCreated.contains(identifier)) {
+ // System.out.println(">>>>>>>>>> already exists: " + identifier);
+ return true;
+ } else {
+ // System.out.println(">>>>>>>>>> creating: " + identifier);
+ alreadyCreated.add(identifier);
+ }
+ }
+ return false;
+ }
+
+ private DotName getTargetClass(AnnotationInstance annot) {
+ switch (annot.target().kind()) {
+ case FIELD:
+ return annot.target().asField().type().name();
+ case METHOD:
+ return annot.target().asMethod().returnType().name();
+ default:
+ return null;
+ }
+ }
+
void produceBeans(CamelRecorder recorder, List capabilities,
BuildProducer syntheticBeans,
BuildProducer proxyDefinitions,
diff --git a/pom.xml b/pom.xml
index ecd259d87236..66a027ea000d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -222,6 +222,7 @@
integration-test-groups
docs
integration-tests-jvm
+ test-framework
@@ -586,6 +587,10 @@
integration-tests-support
camel-quarkus-integration-test-support-
+
+ test-framework
+ camel-quarkus-test-framework
+
diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml
index 679a37770633..931d11337cc3 100644
--- a/poms/bom/pom.xml
+++ b/poms/bom/pom.xml
@@ -5299,6 +5299,11 @@
+
+ org.apache.camel
+ camel-test-junit5
+ ${camel.version}
+
org.apache.camel
camel-threadpoolfactory-vertx
@@ -7602,6 +7607,11 @@
camel-quarkus-jta-deployment
${camel-quarkus.version}
+
+ org.apache.camel.quarkus
+ camel-quarkus-junit5
+ ${camel-quarkus.version}
+
org.apache.camel.quarkus
camel-quarkus-kafka
@@ -10199,92 +10209,92 @@
-
- org.l2x6.cq
- cq-maven-plugin
-
-
- flatten-bom
-
- flatten-bom
-
- process-resources
-
-
-
-
-
- io.quarkus:quarkus-bom
-
-
-
-
-
- org.apache.camel.quarkus:*
- ca.uhn.hapi:*
- net.openhft:affinity
-
-
-
- org.amqphub.quarkus:quarkus-qpid-jms
- org.apache.geronimo.specs:geronimo-jms_2.0_spec
-
-
- com.datastax.oss:java-driver-core
- com.google.code.findbugs:jsr305
-
-
- com.datastax.oss:java-driver-query-builder
- com.google.code.findbugs:jsr305
-
-
- io.quarkiverse.minio:quarkus-minio
- com.google.code.findbugs:jsr305
-
-
- software.amazon.awssdk:apache-client
- commons-logging:commons-logging
-
-
- io.debezium:debezium-embedded:1.6.1.Final:jar
- javax.activation:activation,javax.servlet:javax.servlet-api,log4j:log4j,org.apache.kafka:kafka-log4j-appender,org.apache.kafka:connect-runtime,org.apache.kafka:connect-file
-
-
- org.glassfish.jaxb:jaxb-runtime
- jakarta.xml.bind:jakarta.xml.bind-api
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
- com.google.http-client:google-http-client
- com.google.code.findbugs:jsr305
-
-
- io.debezium:debezium-embedded
- javax.ws.rs:javax.ws.rs-api
-
-
- io.grpc:grpc-netty
- com.google.code.findbugs:jsr305
-
-
- org.apache.httpcomponents:*
- commons-logging:commons-logging
-
-
- org.apache.kafka:connect-runtime
- javax.activation:activation,javax.servlet:javax.servlet-api,log4j:log4j
-
-
- com.fasterxml.jackson.module:jackson-module-jaxb-annotations
- jakarta.activation:jakarta.activation-api,jakarta.xml.bind:jakarta.xml.bind-api
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
diff --git a/test-framework/junit5/pom.xml b/test-framework/junit5/pom.xml
new file mode 100644
index 000000000000..a1611417190f
--- /dev/null
+++ b/test-framework/junit5/pom.xml
@@ -0,0 +1,67 @@
+
+
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-test-framework
+ 2.10.0-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ camel-quarkus-junit5
+ Camel Quarkus :: Test Framework :: Junit5
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+ io.quarkus
+ quarkus-junit5
+
+
+ org.assertj
+ assertj-core
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-integration-test-support
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-core
+
+
+ org.apache.camel
+ camel-test-junit5
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-bean
+ test
+
+
+
diff --git a/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/AfterAllCallback.java b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/AfterAllCallback.java
new file mode 100644
index 000000000000..764c9b769899
--- /dev/null
+++ b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/AfterAllCallback.java
@@ -0,0 +1,32 @@
+/*
+ * 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.quarkus.test;
+
+import io.quarkus.test.junit.callback.QuarkusTestAfterAllCallback;
+import io.quarkus.test.junit.callback.QuarkusTestContext;
+
+public class AfterAllCallback implements QuarkusTestAfterAllCallback {
+
+ @Override
+ public void afterAll(QuarkusTestContext context) {
+ CamelQuarkusTestSupport testInstance = (CamelQuarkusTestSupport) context.getTestInstance();
+
+ if (CallbackUtil.isPerClass(testInstance)) {
+ CallbackUtil.resetContext(testInstance);
+ }
+ }
+}
diff --git a/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/AfterEachCallback.java b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/AfterEachCallback.java
new file mode 100644
index 000000000000..22e8e3af3599
--- /dev/null
+++ b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/AfterEachCallback.java
@@ -0,0 +1,32 @@
+/*
+ * 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.quarkus.test;
+
+import io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback;
+import io.quarkus.test.junit.callback.QuarkusTestMethodContext;
+
+public class AfterEachCallback implements QuarkusTestAfterEachCallback {
+
+ @Override
+ public void afterEach(QuarkusTestMethodContext context) {
+ CamelQuarkusTestSupport testInstance = (CamelQuarkusTestSupport) context.getTestInstance();
+
+ if (!CallbackUtil.isPerClass(testInstance)) {
+ CallbackUtil.resetContext(testInstance);
+ }
+ }
+}
diff --git a/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/BeforeEachCallback.java b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/BeforeEachCallback.java
new file mode 100644
index 000000000000..fbded7f4c217
--- /dev/null
+++ b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/BeforeEachCallback.java
@@ -0,0 +1,52 @@
+/*
+ * 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.quarkus.test;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback;
+import io.quarkus.test.junit.callback.QuarkusTestMethodContext;
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+public class BeforeEachCallback implements QuarkusTestBeforeEachCallback {
+
+ @Override
+ public void beforeEach(QuarkusTestMethodContext context) {
+ CamelQuarkusTestSupport testInstance = (CamelQuarkusTestSupport) context.getTestInstance();
+ ExtensionContext mockContext = new CallbackUtil.MockExtensionContext(CallbackUtil.getLifecycle(testInstance),
+ getDisplayName(context.getTestMethod()));
+
+ try {
+ testInstance.mockBeforeEach(mockContext);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ testInstance.mockBeforeAll(mockContext);
+ }
+
+ private String getDisplayName(Method method) {
+ StringBuilder sb = new StringBuilder(method.getName());
+ sb.append("(");
+ sb.append(Arrays.stream(method.getParameterTypes()).map(c -> c.getSimpleName()).collect(Collectors.joining(", ")));
+ sb.append(")");
+
+ return sb.toString();
+ }
+
+}
diff --git a/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CallbackUtil.java b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CallbackUtil.java
new file mode 100644
index 000000000000..11fe14ece11f
--- /dev/null
+++ b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CallbackUtil.java
@@ -0,0 +1,146 @@
+package org.apache.camel.quarkus.test;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.TestInstances;
+import org.junit.jupiter.api.parallel.ExecutionMode;
+import org.junit.jupiter.engine.execution.ExtensionValuesStore;
+import org.junit.jupiter.engine.execution.NamespaceAwareStore;
+
+public class CallbackUtil {
+
+ static boolean isPerClass(CamelQuarkusTestSupport testSupport) {
+ return getLifecycle(testSupport).filter(lc -> lc.equals(TestInstance.Lifecycle.PER_CLASS)).isPresent();
+ }
+
+ static Optional getLifecycle(CamelQuarkusTestSupport testSupport) {
+ if (testSupport.getClass().getAnnotation(TestInstance.class) != null) {
+ return Optional.of(testSupport.getClass().getAnnotation(TestInstance.class).value());
+ }
+
+ return Optional.empty();
+ }
+
+ static void resetContext(CamelQuarkusTestSupport testInstance) {
+
+ try {
+ testInstance.context.getRouteController().stopAllRoutes();
+ testInstance.context.getRouteController().removeAllRoutes();
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ testInstance.context.getComponentNames().forEach(cn -> testInstance.context.removeComponent(cn));
+ MockEndpoint.resetMocks(testInstance.context);
+ }
+
+ static class MockExtensionContext implements ExtensionContext {
+
+ private final Optional lifecycle;
+ private final String currentTestName;
+ private final ExtensionContext.Store globalStore;
+
+ public MockExtensionContext(Optional lifecycle, String currentTestName) {
+ this.lifecycle = lifecycle;
+ this.currentTestName = currentTestName;
+ this.globalStore = new NamespaceAwareStore(new ExtensionValuesStore(null), ExtensionContext.Namespace.GLOBAL);
+ }
+
+ @Override
+ public Optional getParent() {
+ return Optional.empty();
+ }
+
+ @Override
+ public ExtensionContext getRoot() {
+ return null;
+ }
+
+ @Override
+ public String getUniqueId() {
+ return null;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return currentTestName;
+ }
+
+ @Override
+ public Set getTags() {
+ return null;
+ }
+
+ @Override
+ public Optional getElement() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional> getTestClass() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional getTestInstanceLifecycle() {
+ return lifecycle;
+ }
+
+ @Override
+ public Optional