This is an automated email from the ASF dual-hosted git repository. jiriondrusek pushed a commit to branch camel-main in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/camel-main by this push: new ae1be18aea Refactor of CamelQuarkusTestSupport to extends AbstractTestSupport ae1be18aea is described below commit ae1be18aea7ee1ff12981474c4fffa8aac664829 Author: JiriOndrusek <ondrusek.j...@gmail.com> AuthorDate: Fri Jun 7 09:24:53 2024 +0200 Refactor of CamelQuarkusTestSupport to extends AbstractTestSupport --- .../quarkus/test/CamelQuarkusTestSupport.java | 320 +++++++++++++-------- .../test/CustomCamelContextConfiguration.java | 34 +++ .../test/CustomTestExecutionConfiguration.java | 30 ++ 3 files changed, 263 insertions(+), 121 deletions(-) diff --git a/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CamelQuarkusTestSupport.java b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CamelQuarkusTestSupport.java index e91435d977..626391d0ad 100644 --- a/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CamelQuarkusTestSupport.java +++ b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CamelQuarkusTestSupport.java @@ -26,14 +26,29 @@ 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.Exchange; +import org.apache.camel.NoSuchEndpointException; +import org.apache.camel.Processor; import org.apache.camel.Route; +import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.model.ProcessorDefinition; 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.AbstractTestSupport; +import org.apache.camel.test.junit5.CamelContextManager; import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.test.junit5.ContextManagerFactory; +import org.apache.camel.test.junit5.TestSupport; +import org.apache.camel.test.junit5.util.ExtensionHelper; +import org.apache.camel.test.junit5.util.RouteCoverageDumperExtension; +import org.apache.camel.util.StopWatch; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtensionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,11 +87,20 @@ import org.slf4j.LoggerFactory; * them.</li> * </ul> */ -public class CamelQuarkusTestSupport extends CamelTestSupport +public class CamelQuarkusTestSupport extends AbstractTestSupport implements QuarkusTestProfile { private static final Logger LOG = LoggerFactory.getLogger(CamelQuarkusTestSupport.class); +// @RegisterExtension +// protected CamelTestSupport camelTestSupportExtension = this; + + private final StopWatch watch = new StopWatch(); + private String currentTestName; + + private CamelContextManager contextManager; + private final ContextManagerFactory contextManagerFactory; + @Inject protected CamelContext context; @@ -86,12 +110,40 @@ public class CamelQuarkusTestSupport extends CamelTestSupport Set<String> createdRoutes; public CamelQuarkusTestSupport() { - super(new ContextNotStoppingManagerFactory()); + super(new CustomTestExecutionConfiguration(), new CustomCamelContextConfiguration()); + + this.contextManagerFactory = new ContextNotStoppingManagerFactory(); + + testConfigurationBuilder() + .withCustomUseAdviceWith(isUseAdviceWith()) + .withJMX(useJmx()) + .withUseRouteBuilder(isUseRouteBuilder()) + .withDumpRouteCoverage(isDumpRouteCoverage()) + .withAutoStartContext(false); + + contextConfiguration() + .withCustomCamelContextSupplier(this::camelContextSupplier) + .withCustomPostProcessor(this::postProcessTest) + .withCustomRoutesSupplier(this::createRouteBuilders) + .withRegistryBinder(this::bindToRegistry) + .withUseOverridePropertiesWithPropertiesComponent(useOverridePropertiesWithPropertiesComponent()) + .withRouteFilterExcludePattern(getRouteFilterExcludePattern()) + .withRouteFilterIncludePattern(getRouteFilterIncludePattern()) + .withMockEndpoints(isMockEndpoints()) + .withMockEndpointsAndSkip(isMockEndpointsAndSkip()); //CQ starts and stops context with the application start/stop testConfiguration().withAutoStartContext(false); } + CustomCamelContextConfiguration contextConfiguration() { + return (CustomCamelContextConfiguration)camelContextConfiguration; + } + + CustomTestExecutionConfiguration testConfigurationBuilder() { + return (CustomTestExecutionConfiguration)testConfigurationBuilder; + } + //------------------------ quarkus callbacks --------------- /** @@ -130,29 +182,28 @@ public class CamelQuarkusTestSupport extends CamelTestSupport * @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 { + protected CamelContext camelContextSupplier() 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(); + + template = contextManager.template(); + fluentTemplate = contextManager.fluentTemplate(); + consumer = contextManager.consumer(); } /** @@ -160,138 +211,114 @@ public class CamelQuarkusTestSupport extends CamelTestSupport */ @Override public CamelContext context() { - //CamelTestSupport has to use the same context as CamelQuarkusTestSupport - Assertions.assertEquals(context, super.context, "Different context found!"); - return super.context(); + return this.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: - * - * <pre> - * @Override - * protected CamelContext createCamelContext() throws Exception { - * CamelContext ctx = super.createCamelContext(); - * Registry registry = ctx.getRegistry(); - * // do something with the registry... - * return ctx; - * } - * </pre> - * - * @return Never returns any result. UnsupportedOperationException is thrown instead. - */ - @Override - protected final Registry createCamelRegistry() { - throw new UnsupportedOperationException("won't be executed."); + @Deprecated(since = "4.7.0") + public long timeTaken() { + return watch.taken(); } /** - * This method does nothing. All necessary tasks are performed in - * {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} - * Use {@link #doAfterConstruct()} instead of this method. + * Gets the name of the current test being executed. */ - @Override - public final void beforeAll(ExtensionContext context) { - //replaced by quarkus callback (beforeEach) + public final String getCurrentTestName() { + return currentTestName; } /** - * This method does nothing. All tasks are performed in {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} - * Use {@link #doBeforeEach(QuarkusTestMethodContext)} instead of this method. + * Common test setup. For internal use. + * + * @deprecated Use {@link #setupResources()} instead + * @throws Exception if unable to setup the test */ - @Override - public final void beforeEach(ExtensionContext context) throws Exception { - //replaced by quarkus callback (beforeEach) - } + @Deprecated(since = "4.7.0") + public void setUp() throws Exception { + ExtensionHelper.testStartHeader(getClass(), currentTestName); - /** - * 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 - } + setupResources(); + doPreSetup(); - /** - * 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 + contextManager.createCamelContext(this); + context = contextManager.context(); + + doPostSetup(); + + // only start timing after all the setup + watch.restart(); } /** - * This method does nothing All necessary tasks are performed in - * {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)} - * Use {@link #doAfterEach(QuarkusTestMethodContext)} instead of this method. + * Common test tear down. For internal use. + * + * @deprecated Use {@link #cleanupResources()} instead + * @throws Exception if unable to setup the test */ - @Override - public final void afterTestExecution(ExtensionContext context) throws Exception { - //in camel-quarkus, junit5 uses different classloader, necessary code was moved into quarkus's callback + @Deprecated(since = "4.7.0") + @AfterEach + public void tearDown() throws Exception { + long time = watch.taken(); + + if (isRouteCoverageEnabled()) { + ExtensionHelper.testEndFooter(getClass(), currentTestName, time, new RouteCoverageDumperExtension((ModelCamelContext) context)); + } else { + ExtensionHelper.testEndFooter(getClass(), currentTestName, time); + } + + if (testConfigurationBuilder.isCreateCamelContextPerClass()) { + // will tear down test specially in afterAll callback + return; + } + + LOG.debug("tearDown()"); + + contextManager.stop(); + + doPostTearDown(); + cleanupResources(); + } /** - * 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} + * Strategy to perform any post-action, after {@link CamelContext} is stopped. This is meant for internal Camel + * usage and should not be used by user classes. + * + * @deprecated use {@link #cleanupResources()} instead. */ - @Override - public void setUp() throws Exception { - super.setUp(); + @Deprecated(since = "4.7.0") + protected void doPostTearDown() throws Exception { + // noop } + /** - * 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} + * Factory method which derived classes can use to create a {@link RouteBuilder} to define the routes for testing */ - @Override - public void tearDown() throws Exception { - super.tearDown(); + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() { + // no routes added by default + } + }; } /** - * 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) . + * Factory method which derived classes can use to create an array of {@link org.apache.camel.builder.RouteBuilder}s + * to define the routes for testing * - * @throws Exception + * @see #createRouteBuilder() + * @deprecated This method will be made private. Do not use */ - @Override - protected void stopCamelContext() throws Exception { - //context is started and stopped via quarkus lifecycle + @Deprecated(since = "4.7.0") + protected RoutesBuilder[] createRouteBuilders() throws Exception { + return new RoutesBuilder[] { createRouteBuilder() }; } - /** - * Allows running of the CamelTestSupport child in the Quarkus application. - * Method is not intended to be overridden. - */ - @Override - protected final void unsupportedCheck() { - //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 { + if (!testConfiguration().isCreateCamelContextPerClass()) { doPostTearDown(); } cleanupResources(); @@ -302,11 +329,29 @@ public class CamelQuarkusTestSupport extends CamelTestSupport } void internalBeforeAll(ExtensionContext context) { - super.beforeAll(context); + final boolean perClassPresent + = context.getTestInstanceLifecycle().filter(lc -> lc.equals(TestInstance.Lifecycle.PER_CLASS)).isPresent(); + if (perClassPresent) { + LOG.trace("Creating a legacy context manager for {}", context.getDisplayName()); + testConfigurationBuilder().withCustomCreateCamelContextPerClass(perClassPresent); + contextManager = contextManagerFactory.createContextManager(ContextManagerFactory.Type.BEFORE_ALL, + testConfigurationBuilder, camelContextConfiguration); + } + + ExtensionContext.Store globalStore = context.getStore(ExtensionContext.Namespace.GLOBAL); + contextManager.setGlobalStore(globalStore); } void internalBeforeEach(ExtensionContext context) throws Exception { - super.beforeEach(context); + if (contextManager == null) { + LOG.trace("Creating a transient context manager for {}", context.getDisplayName()); + contextManager = contextManagerFactory.createContextManager(ContextManagerFactory.Type.BEFORE_EACH, + testConfigurationBuilder, camelContextConfiguration); + } + + currentTestName = context.getDisplayName(); + ExtensionContext.Store globalStore = context.getStore(ExtensionContext.Namespace.GLOBAL); + contextManager.setGlobalStore(globalStore); } /** @@ -316,7 +361,6 @@ public class CamelQuarkusTestSupport extends CamelTestSupport * If this method is overridden, <i>super.doPreSetup()</i> has to be called. * </p> */ - @Override protected void doPreSetup() throws Exception { if (isUseAdviceWith() || isUseDebugger()) { ((FastCamelContext) context).suspend(); @@ -326,8 +370,6 @@ public class CamelQuarkusTestSupport extends CamelTestSupport //save the routeIds of routes existing before setup createdRoutes = context.getRoutes().stream().map(r -> r.getRouteId()).collect(Collectors.toSet()); } - - super.doPreSetup(); } /** @@ -337,7 +379,6 @@ public class CamelQuarkusTestSupport extends CamelTestSupport * If this method is overridden, <i>super.doPostSetup()</i> has to be called. * </p> */ - @Override protected void doPostSetup() throws Exception { if (isUseAdviceWith() || isUseDebugger()) { ((FastCamelContext) context).resume(); @@ -358,15 +399,6 @@ public class CamelQuarkusTestSupport extends CamelTestSupport } createdRoutes = allRoutes; } - super.doPostSetup(); - } - - /** - * This method does nothing. The context starts together with Quarkus engine. - */ - @Override - protected final void startCamelContext() { - //context has already started } /** @@ -396,4 +428,50 @@ public class CamelQuarkusTestSupport extends CamelTestSupport modelCamelContext.startRouteDefinitions(definitions); } + /** + * Resolves the mandatory Mock endpoint using a URI of the form <code>mock:someName</code> + * + * @param uri the URI which typically starts with "mock:" and has some name + * @return the mandatory mock endpoint or an exception is thrown if it could not be resolved + */ + protected final MockEndpoint getMockEndpoint(String uri) { + return getMockEndpoint(uri, true); + } + + /** + * Resolves the {@link MockEndpoint} using a URI of the form <code>mock:someName</code>, optionally creating it if + * it does not exist. This implementation will lookup existing mock endpoints and match on the mock queue name, eg + * mock:foo and mock:foo?retainFirst=5 would match as the queue name is foo. + * + * @param uri the URI which typically starts with "mock:" and has some name + * @param create whether to allow the endpoint to be created if it doesn't exist + * @return the mock endpoint or an {@link NoSuchEndpointException} is thrown if it could not + * be resolved + * @throws NoSuchEndpointException is the mock endpoint does not exist + */ + @Deprecated(since = "4.7.0") + protected final MockEndpoint getMockEndpoint(String uri, boolean create) throws NoSuchEndpointException { + return TestSupport.getMockEndpoint(context, uri, create); + } + + /** + * Single step debugs and Camel invokes this method before entering the given processor. This method is NOOP. + * + * @deprecated Use {@link #camelContextConfiguration()} to set an instance of {@link DebugBreakpoint} + */ + @Deprecated(since = "4.7.0") + protected void debugBefore( + Exchange exchange, Processor processor, ProcessorDefinition<?> definition, String id, String label) { + } + + /** + * Single step debugs and Camel invokes this method after processing the given processor. This method is NOOP. + * + * @deprecated Use {@link #camelContextConfiguration()} to set an instance of {@link DebugBreakpoint} + */ + @Deprecated(since = "4.7.0") + protected void debugAfter( + Exchange exchange, Processor processor, ProcessorDefinition<?> definition, String id, String label, + long timeTaken) { + } } diff --git a/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CustomCamelContextConfiguration.java b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CustomCamelContextConfiguration.java new file mode 100644 index 0000000000..05b93dcb4f --- /dev/null +++ b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CustomCamelContextConfiguration.java @@ -0,0 +1,34 @@ +/* + * 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 org.apache.camel.test.junit5.CamelContextConfiguration; + +public final class CustomCamelContextConfiguration extends CamelContextConfiguration { + + CustomCamelContextConfiguration withCustomCamelContextSupplier(CamelContextSupplier camelContextSupplier) { + return (CustomCamelContextConfiguration)super.withCamelContextSupplier(camelContextSupplier); + } + + CustomCamelContextConfiguration withCustomPostProcessor(PostProcessor postProcessor) { + return (CustomCamelContextConfiguration)super.withPostProcessor(postProcessor); + } + + CustomCamelContextConfiguration withCustomRoutesSupplier(RoutesSupplier routesSupplier) { + return (CustomCamelContextConfiguration) super.withRoutesSupplier(routesSupplier); + } +} diff --git a/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CustomTestExecutionConfiguration.java b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CustomTestExecutionConfiguration.java new file mode 100644 index 0000000000..b2444e49a1 --- /dev/null +++ b/test-framework/junit5/src/main/java/org/apache/camel/quarkus/test/CustomTestExecutionConfiguration.java @@ -0,0 +1,30 @@ +/* + * 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 org.apache.camel.test.junit5.TestExecutionConfiguration; + +public final class CustomTestExecutionConfiguration extends TestExecutionConfiguration { + + CustomTestExecutionConfiguration withCustomUseAdviceWith(boolean useAdviceWith) { + return (CustomTestExecutionConfiguration) super.withUseAdviceWith(useAdviceWith); + } + + CustomTestExecutionConfiguration withCustomCreateCamelContextPerClass(boolean createCamelContextPerClass) { + return (CustomTestExecutionConfiguration)super.withCreateCamelContextPerClass(createCamelContextPerClass); + } +}