All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.quarkus.test.CamelQuarkusTestSupport Maven / Gradle / Ivy

/*
 * 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.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.callback.QuarkusTestContext;
import io.quarkus.test.junit.callback.QuarkusTestMethodContext;
import jakarta.inject.Inject;
import org.apache.camel.CamelContext;
import org.apache.camel.Route;
import org.apache.camel.Service;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.ModelCamelContext;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.quarkus.core.FastCamelContext;
import org.apache.camel.spi.Registry;
import org.apache.camel.test.junit5.CamelTestSupport;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The {@link CamelTestSupport} class does not work on Quarkus. This class provides a replacement, which can be used in
 * JVM mode. There are several differences between {@link CamelTestSupport} and this class.
 * 
    *
  • Starting and stopping {@link CamelContext} in Camel Quarkus is generally bound to starting and stopping the * application * and this holds also when testing.
  • *
  • Starting and stopping the application under test (and thus also {@link CamelContext} is under full control of * Quarkus * JUnit Extension. It prefers keeping the application up and running unless it is told to do otherwise.
  • *
  • Hence normally the application under test is started only once for all test classes of the given Maven/Gradle * module.
  • *
  • To force Quarkus JUnit Extension to restart the application (and thus also `CamelContext`) for a given test * class, you need to assign a unique {@code @io.quarkus.test.junit.TestProfile} to that class. Check the * Quarkus documentation for * how you can do * that. (Note that * QuarkusTestResource * has a similar effect.)
  • *
  • Camel Quarkus executes the production of beans during the build phase. Because all the tests are * build together, exclusion behavior is implemented into {@link CamelQuarkusTestSupport}. If a producer of the specific * type * and name is used in one tests, the instance will be the same for the rest of the tests.
  • *
  • JUnit Jupiter callbacks {@code BeforeEachCallback}, {@code AfterEachCallback}, {@code AfterAllCallback}, * {@code BeforeAllCallback}, * {@code BeforeTestExecutionCallback} and {@code AfterTestExecutionCallback}) might not work correctly. See the * documentation. * Methods {@code afterAll}, {@code afterEach}, {@code afterTestExecution}, {@code beforeAll} and {@code beforeEach} are * not executed anymore. * You should use {@code doAfterAll}, {@code doAfterConstruct}, {@code doAfterEach}, {@code doBeforeEach} and * {@code doBeforeAll} instead of * them.
  • *
*/ public class CamelQuarkusTestSupport extends CamelTestSupport implements QuarkusTestProfile { private static final Logger LOG = LoggerFactory.getLogger(CamelQuarkusTestSupport.class); @Inject protected CamelContext context; /* * Set of routes, which were created by routeBuilder. This set is used by some callbacks. */ Set createdRoutes; //------------------------ quarkus callbacks --------------- /** * Replacement of {@link #afterAll(ExtensionContext)} called from {@link AfterAllCallback#afterAll(QuarkusTestContext)} */ protected void doAfterAll(QuarkusTestContext context) throws Exception { } /** * Replacement of {@link #afterEach(ExtensionContext)} called from * {@link AfterEachCallback#afterEach(QuarkusTestMethodContext)} */ protected void doAfterEach(QuarkusTestMethodContext context) throws Exception { } /** * Replacement of {@link #beforeAll(ExtensionContext)} called from {@link AfterConstructCallback#afterConstruct(Object)} * Execution differs in case of @TestInstance(TestInstance.Lifecycle.PER_METHOD) in which case callback is called * before each test (instead of {@link #beforeAll(ExtensionContext)}). */ protected void doAfterConstruct() throws Exception { } /** * Replacement of {@link #beforeEach(ExtensionContext)} called from * {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} */ protected void doBeforeEach(QuarkusTestMethodContext context) throws Exception { } /** * Feel free to override this method for the sake of customizing the instance returned by this implementation. * Do not create your own CamelContext instance, because there needs to exist just a single instance owned by * Quarkus CDI container. There are checks in place that will make your tests fail if you do otherwise. * * @return The context from Quarkus CDI container * @throws Exception Overridden method has to throw the same Exception as superclass. */ @Override protected CamelContext createCamelContext() throws Exception { return this.context; } /** * The same functionality as {@link CamelTestSupport#bindToRegistry(Registry)}. */ @Override protected void bindToRegistry(Registry registry) throws Exception { //CamelTestSupport has to use the same context as CamelQuarkusTestSupport Assertions.assertEquals(context, super.context, "Different context found!"); super.bindToRegistry(registry); } /** * The same functionality as {@link CamelTestSupport#postProcessTest()} . */ @Override protected void postProcessTest() throws Exception { //CamelTestSupport has to use the same context as CamelQuarkusTestSupport Assertions.assertEquals(context, super.context, "Different context found!"); super.postProcessTest(); } /** * The same functionality as {@link CamelTestSupport#context()} . */ @Override public CamelContext context() { //CamelTestSupport has to use the same context as CamelQuarkusTestSupport Assertions.assertEquals(context, super.context, "Different context found!"); return super.context(); } /** * This method is not called on Camel Quarkus because the `CamelRegistry` is created and owned by Quarkus CDI container. * If you need to customize the registry upon creation, you may want to override {@link #createCamelContext()} * in the following way: * *
     * @Override
     * protected CamelContext createCamelContext() throws Exception {
     *     CamelContext ctx = super.createCamelContext();
     *     Registry registry = ctx.getRegistry();
     *     // do something with the registry...
     *     return ctx;
     * }
     * 
* * @return Never returns any result. UnsupportedOperationException is thrown instead. */ @Override protected final Registry createCamelRegistry() { throw new UnsupportedOperationException("won't be executed."); } /** * This method does nothing. All necessary tasks are performed in * {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} * Use {@link #doAfterConstruct()} instead of this method. */ @Override public final void beforeAll(ExtensionContext context) { //replaced by quarkus callback (beforeEach) } /** * This method does nothing. All tasks are performed in {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} * Use {@link #doBeforeEach(QuarkusTestMethodContext)} instead of this method. */ @Override public final void beforeEach(ExtensionContext context) throws Exception { //replaced by quarkus callback (beforeEach) } /** * This method does nothing. All necessary tasks are performed in * {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} * Use {@link #doAfterAll(QuarkusTestContext)} instead of this method. */ @Override public final void afterAll(ExtensionContext context) { //in camel-quarkus, junit5 uses different classloader, necessary code was moved into quarkus's callback } /** * This method does nothing. All necessary tasks are performed in * {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} * Use {@link #doAfterEach(QuarkusTestMethodContext)} instead of this method. */ @Override public final void afterEach(ExtensionContext context) throws Exception { //in camel-quarkus, junit5 uses different classloader, necessary code was moved into quarkus's callback } /** * This method does nothing All necessary tasks are performed in * {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} * Use {@link #doAfterEach(QuarkusTestMethodContext)} instead of this method. */ @Override public final void afterTestExecution(ExtensionContext context) throws Exception { //in camel-quarkus, junit5 uses different classloader, necessary code was moved into quarkus's callback } /** * Method {@link CamelTestSupport#setUp()} is triggered via annotation {@link org.junit.jupiter.api.BeforeEach}. * Its execution is disabled (by using overriding method without any annotation) and is executed from * {@link BeforeEachCallback} */ @Override public void setUp() throws Exception { super.setUp(); } /** * Method {@link CamelTestSupport#tearDown()} is triggered via annotation * {@link org.junit.jupiter.api.AfterEach}. * Its execution is disabled (by using overriding method without any annotation) and is executed from * {@link AfterEachCallback} */ @Override public void tearDown() throws Exception { super.tearDown(); } /** * This method stops the Camel context. Be aware that on of the limitation that Quarkus brings is that context * can not be started (lifecycle f the context is bound to the application) . * * @throws Exception */ @Override protected void stopCamelContext() throws Exception { //context is started and stopped via quarkus lifecycle } /** * Allows running of the CamelTestSupport child in the Quarkus application. * Method is not intended to be overridden. */ @Override protected final void doQuarkusCheck() { //can run on Quarkus //log warning in case that at least one RouteBuilder in the registry, it might mean, that unintentionally // RouteBuilders are shared across or that RouteBuilder is created with @Produces if (isUseRouteBuilder() && !context.getRegistry().findByType(RouteBuilder.class).isEmpty()) { LOG.warn( "Test with `true` in `isUserRouteBuilder' and `RouteBuilder` detected in the context registry. " + "All tests will share this routeBuilder from the registry. This is usually not intended. " + "If `@Produces` is used to create such a RouteBuilder, please refactor the code " + "by overriding the method `createRouteBuilder()` instead."); } } void internalAfterAll(QuarkusTestContext context, ExtensionContext extensionContext) { try { if (isCreateCamelContextPerClass()) { super.afterAll(extensionContext); } else { doPostTearDown(); } cleanupResources(); } catch (Exception e) { // ignore } } void internalBeforeAll(ExtensionContext context) { super.beforeAll(context); } void internalBeforeEach(ExtensionContext context) throws Exception { super.beforeEach(context); } /** * Strategy to perform any pre setup, before {@link CamelContext} is created *

* Be aware that difference in lifecycle with Quarkus may require a special behavior. * If this method is overridden, super.doPreSetup() has to be called. *

*/ @Override protected void doPreSetup() throws Exception { if (isUseAdviceWith() || isUseDebugger()) { ((FastCamelContext) context).suspend(); } if (isUseRouteBuilder()) { //save the routeIds of routes existing before setup createdRoutes = context.getRoutes().stream().map(r -> r.getRouteId()).collect(Collectors.toSet()); } super.doPreSetup(); } /** * Strategy to perform any post setup after {@link CamelContext} is created *

* Be aware that difference in lifecycle with Quarkus may require a special behavior. * If this method is overridden, super.doPostSetup() has to be called. *

*/ @Override protected void doPostSetup() throws Exception { if (isUseAdviceWith() || isUseDebugger()) { ((FastCamelContext) context).resume(); if (isUseDebugger()) { ModelCamelContext mcc = (ModelCamelContext) context; List rdfs = mcc.getRouteDefinitions(); //if context was suspended routes was not added, because it would trigger start of the context // routes have to be added now mcc.addRouteDefinitions(rdfs); } } if (isUseRouteBuilder()) { //remove from the routes all routes which existed before setup var allRoutes = context.getRoutes().stream().map(r -> r.getRouteId()).collect(Collectors.toSet()); if (createdRoutes != null) { allRoutes.removeAll(createdRoutes); } createdRoutes = allRoutes; } super.doPostSetup(); } /** * Internal disablement of the context stop functionality. */ @Override protected final void doStopCamelContext(CamelContext context, Service camelContextService) { //don't stop } /** * This method does nothing. The context starts together with Quarkus engine. */ @Override protected final void startCamelContext() { //context has already started } /** * Override when using advice with and return true. * This helps knowing advice with is to be used. *

* Important: Its important to execute method {@link #startRouteDefinitions()}} manually from the unit test * after you are done doing all the advice with. * * @return true if you use advice with in your unit tests. */ @Override public boolean isUseAdviceWith() { return false; } /** * Helper method to start routeDefinitions (to be used with `adviceWith`). */ protected void startRouteDefinitions() throws Exception { ModelCamelContext modelCamelContext = (ModelCamelContext) context; List definitions = new ArrayList<>(modelCamelContext.getRouteDefinitions()); for (Route r : context.getRoutes()) { //existing route does not need to be started definitions.remove(r.getRoute()); } modelCamelContext.startRouteDefinitions(definitions); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy