This is an automated email from the ASF dual-hosted git repository. aldettinger pushed a commit to branch CAMEL-13342-JUNIT5-EXPLORATORY in repository https://gitbox.apache.org/repos/asf/camel.git
commit 3aa278dcee915dead978df4cba56487ecd58dda8 Author: aldettinger <aldettin...@gmail.com> AuthorDate: Thu Jun 6 15:27:20 2019 +0200 CAMEL-13342: Added a JUnit 5 version of JUnit 4 test patterns --- .../test/junit5/CamelTestParameterResolver.java | 16 + .../apache/camel/test/junit5/CamelTestSupport.java | 1214 ++++++++++++++++++++ .../org/apache/camel/test/junit5/TestSupport.java | 553 +++++++++ .../junit5/patterns/AdviceWithNotStartedTest.java | 74 ++ .../test/junit5/patterns/AsyncSendMockTest.java | 47 + .../test/junit5/patterns/DebugJUnit5Test.java | 86 ++ .../patterns/DebugNoLazyTypeConverterTest.java | 91 ++ .../camel/test/junit5/patterns/DebugTest.java | 86 ++ .../FilterCreateCamelContextPerClassTest.java | 65 ++ .../junit5/patterns/FilterFluentTemplateTest.java | 75 ++ .../test/junit5/patterns/FilterJUnit5Test.java | 69 ++ .../camel/test/junit5/patterns/FilterTest.java | 75 ++ .../patterns/IsMockEndpointsAndSkipJUnit5Test.java | 65 ++ .../junit5/patterns/IsMockEndpointsFileTest.java | 68 ++ .../junit5/patterns/IsMockEndpointsJUnit5Test.java | 72 ++ .../test/junit5/patterns/IsMockEndpointsTest.java | 65 ++ .../patterns/MockEndpointFailNoHeaderTest.java | 63 + .../camel/test/junit5/patterns/MyProduceBean.java | 32 + .../camel/test/junit5/patterns/MySender.java | 25 + .../ProduceBeanTest.java} | 34 +- .../RouteBuilderConfigureExceptionTest.java | 54 + .../RouteProcessorDumpRouteCoverageTest.java} | 44 +- .../SimpleMockEndpointsTest.java} | 35 +- .../test/junit5/{ => patterns}/SimpleMockTest.java | 27 +- .../SimpleMockUsingExtensionTest.java} | 13 +- .../SimpleNotifyBuilderTest.java} | 46 +- .../SimpleWeaveAddMockLastTest.java} | 44 +- ...rridePropertiesWithPropertiesComponentTest.java | 78 ++ 28 files changed, 3094 insertions(+), 122 deletions(-) diff --git a/components/camel-test/src/main/java/org/apache/camel/test/junit5/CamelTestParameterResolver.java b/components/camel-test/src/main/java/org/apache/camel/test/junit5/CamelTestParameterResolver.java index ce58940..21a8d7b 100644 --- a/components/camel-test/src/main/java/org/apache/camel/test/junit5/CamelTestParameterResolver.java +++ b/components/camel-test/src/main/java/org/apache/camel/test/junit5/CamelTestParameterResolver.java @@ -1,3 +1,19 @@ +/* + * 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.test.junit5; import org.apache.camel.ConsumerTemplate; diff --git a/components/camel-test/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java b/components/camel-test/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java new file mode 100644 index 0000000..0ff4509 --- /dev/null +++ b/components/camel-test/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java @@ -0,0 +1,1214 @@ +/* + * 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.test.junit5; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.naming.Context; +import javax.naming.InitialContext; + +import org.apache.camel.CamelContext; +import org.apache.camel.ConsumerTemplate; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Expression; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.FluentProducerTemplate; +import org.apache.camel.Message; +import org.apache.camel.NamedNode; +import org.apache.camel.NoSuchEndpointException; +import org.apache.camel.Predicate; +import org.apache.camel.Processor; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.Route; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.Service; +import org.apache.camel.ServiceStatus; +import org.apache.camel.api.management.JmxSystemPropertyKeys; +import org.apache.camel.api.management.ManagedCamelContext; +import org.apache.camel.api.management.mbean.ManagedCamelContextMBean; +import org.apache.camel.api.management.mbean.ManagedProcessorMBean; +import org.apache.camel.api.management.mbean.ManagedRouteMBean; +import org.apache.camel.builder.AdviceWithRouteBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.component.properties.PropertiesComponent; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.impl.engine.DefaultCamelBeanPostProcessor; +import org.apache.camel.impl.engine.InterceptSendToMockEndpointStrategy; +import org.apache.camel.model.Model; +import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.model.ProcessorDefinition; +import org.apache.camel.processor.interceptor.BreakpointSupport; +import org.apache.camel.processor.interceptor.DefaultDebugger; +import org.apache.camel.reifier.RouteReifier; +import org.apache.camel.spi.Language; +import org.apache.camel.spi.Registry; +import org.apache.camel.support.EndpointHelper; +import org.apache.camel.util.IOHelper; +import org.apache.camel.util.StopWatch; +import org.apache.camel.util.StringHelper; +import org.apache.camel.util.TimeUtils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * A useful base class which creates a {@link org.apache.camel.CamelContext} + * with some routes along with a {@link org.apache.camel.ProducerTemplate} for + * use in the test case Do <tt>not</tt> use this class for Spring Boot testing, + * instead use <code>@RunWith(CamelSpringBootRunner.class)</code>. + */ +public class CamelTestSupport extends TestSupport implements BeforeEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback { + + /** + * JVM system property which can be set to true to turn on dumping route + * coverage statistics. + */ + public static final String ROUTE_COVERAGE_ENABLED = "CamelTestRouteCoverage"; + + private static final Logger LOG = LoggerFactory.getLogger(CamelTestSupport.class); + private static ThreadLocal<ModelCamelContext> threadCamelContext = new ThreadLocal<>(); + private static ThreadLocal<ProducerTemplate> threadTemplate = new ThreadLocal<>(); + private static ThreadLocal<FluentProducerTemplate> threadFluentTemplate = new ThreadLocal<>(); + private static ThreadLocal<ConsumerTemplate> threadConsumer = new ThreadLocal<>(); + private static ThreadLocal<Service> threadService = new ThreadLocal<>(); + protected volatile ModelCamelContext context; + protected volatile ProducerTemplate template; + protected volatile FluentProducerTemplate fluentTemplate; + protected volatile ConsumerTemplate consumer; + protected volatile Service camelContextService; + protected boolean dumpRouteStats; + @RegisterExtension + protected CamelTestSupport camelTestSupportExtension = this; + private boolean useRouteBuilder = true; + private final DebugBreakpoint breakpoint = new DebugBreakpoint(); + private final StopWatch watch = new StopWatch(); + private final Map<String, String> fromEndpoints = new HashMap<>(); + private final AtomicInteger tests = new AtomicInteger(0); + private String currentTestName; + + @Override + public void afterTestExecution(ExtensionContext context) throws Exception { + watch.taken(); + } + + @Override + public void beforeTestExecution(ExtensionContext context) throws Exception { + watch.restart(); + } + + public long timeTaken() { + return watch.taken(); + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + currentTestName = context.getDisplayName(); + } + + /** + * Use the RouteBuilder or not + * + * @return <tt>true</tt> then {@link CamelContext} will be auto started, + * <tt>false</tt> then {@link CamelContext} will <b>not</b> be auto + * started (you will have to start it manually) + */ + public boolean isUseRouteBuilder() { + return useRouteBuilder; + } + + public void setUseRouteBuilder(boolean useRouteBuilder) { + this.useRouteBuilder = useRouteBuilder; + } + + /** + * Whether to dump route coverage stats at the end of the test. + * <p/> + * This allows tooling or manual inspection of the stats, so you can + * generate a route trace diagram of which EIPs have been in use and which + * have not. Similar concepts as a code coverage report. + * <p/> + * You can also turn on route coverage globally via setting JVM system + * property <tt>CamelTestRouteCoverage=true</tt>. + * + * @return <tt>true</tt> to write route coverage status in an xml file in + * the <tt>target/camel-route-coverage</tt> directory after the test + * has finished. + */ + public boolean isDumpRouteCoverage() { + return false; + } + + /** + * Override when using + * <a href="http://camel.apache.org/advicewith.html">advice with</a> and + * return <tt>true</tt>. This helps knowing advice with is to be used, and + * {@link CamelContext} will not be started before the advice with takes + * place. This helps by ensuring the advice with has been property setup + * before the {@link CamelContext} is started + * <p/> + * <b>Important:</b> Its important to start {@link CamelContext} manually + * from the unit test after you are done doing all the advice with. + * + * @return <tt>true</tt> if you use advice with in your unit tests. + */ + public boolean isUseAdviceWith() { + return false; + } + + /** + * Override to control whether {@link CamelContext} should be setup per test + * or per class. + * <p/> + * By default it will be setup/teardown per test (per test method). If you + * want to re-use {@link CamelContext} between test methods you can override + * this method and return <tt>true</tt> + * <p/> + * <b>Important:</b> Use this with care as the {@link CamelContext} will + * carry over state from previous tests, such as endpoints, components etc. + * So you cannot use this in all your tests. + * <p/> + * Setting up {@link CamelContext} uses the {@link #doPreSetup()}, + * {@link #doSetUp()}, and {@link #doPostSetup()} methods in that given + * order. + * + * @return <tt>true</tt> per class, <tt>false</tt> per test. + */ + public boolean isCreateCamelContextPerClass() { + return false; + } + + /** + * Override to enable auto mocking endpoints based on the pattern. + * <p/> + * Return <tt>*</tt> to mock all endpoints. + * + * @see EndpointHelper#matchEndpoint(CamelContext, String, String) + */ + public String isMockEndpoints() { + return null; + } + + /** + * Override to enable auto mocking endpoints based on the pattern, and + * <b>skip</b> sending to original endpoint. + * <p/> + * Return <tt>*</tt> to mock all endpoints. + * + * @see EndpointHelper#matchEndpoint(CamelContext, String, String) + */ + public String isMockEndpointsAndSkip() { + return null; + } + + public void replaceRouteFromWith(String routeId, String fromEndpoint) { + fromEndpoints.put(routeId, fromEndpoint); + } + + /** + * Used for filtering routes routes matching the given pattern, which + * follows the following rules: - Match by route id - Match by route input + * endpoint uri The matching is using exact match, by wildcard and regular + * expression. For example to only include routes which starts with foo in + * their route id's, use: include=foo* And to exclude routes which + * starts from JMS endpoints, use: exclude=jms:* Multiple patterns can + * be separated by comma, for example to exclude both foo and bar routes, + * use: exclude=foo*,bar* Exclude takes precedence over include. + */ + public String getRouteFilterIncludePattern() { + return null; + } + + /** + * Used for filtering routes routes matching the given pattern, which + * follows the following rules: - Match by route id - Match by route input + * endpoint uri The matching is using exact match, by wildcard and regular + * expression. For example to only include routes which starts with foo in + * their route id's, use: include=foo* And to exclude routes which + * starts from JMS endpoints, use: exclude=jms:* Multiple patterns can + * be separated by comma, for example to exclude both foo and bar routes, + * use: exclude=foo*,bar* Exclude takes precedence over include. + */ + public String getRouteFilterExcludePattern() { + return null; + } + + /** + * Override to enable debugger + * <p/> + * Is default <tt>false</tt> + */ + public boolean isUseDebugger() { + return false; + } + + public Service getCamelContextService() { + return camelContextService; + } + + public Service camelContextService() { + return camelContextService; + } + + public CamelContext context() { + return context; + } + + public ProducerTemplate template() { + return template; + } + + public FluentProducerTemplate fluentTemplate() { + return fluentTemplate; + } + + public ConsumerTemplate consumer() { + return consumer; + } + + /** + * Allows a service to be registered a separate lifecycle service to start + * and stop the context; such as for Spring when the ApplicationContext is + * started and stopped, rather than directly stopping the CamelContext + */ + public void setCamelContextService(Service service) { + camelContextService = service; + threadService.set(camelContextService); + } + + @BeforeEach + public void setUp() throws Exception { + log.info("********************************************************************************"); + log.info("Testing: " + currentTestName + "(" + getClass().getName() + ")"); + log.info("********************************************************************************"); + + if (isCreateCamelContextPerClass()) { + while (true) { + int v = tests.get(); + if (tests.compareAndSet(v, v + 1)) { + if (v == 0) { + // test is per class, so only setup once (the first + // time) + doSpringBootCheck(); + setupResources(); + doPreSetup(); + doSetUp(); + doPostSetup(); + } else { + // and in between tests we must do IoC and reset mocks + postProcessTest(); + resetMocks(); + } + + break; + } + } + } else { + // test is per test so always setup + doSpringBootCheck(); + setupResources(); + doPreSetup(); + doSetUp(); + doPostSetup(); + } + + // only start timing after all the setup + watch.restart(); + } + + /** + * Strategy to perform any pre setup, before {@link CamelContext} is created + */ + protected void doPreSetup() throws Exception { + // noop + } + + /** + * Strategy to perform any post setup after {@link CamelContext} is created + */ + protected void doPostSetup() throws Exception { + // noop + } + + /** + * Detects if this is a Spring-Boot test and throws an exception, as these + * base classes is not intended for testing Camel on Spring Boot. + */ + protected void doSpringBootCheck() { + boolean springBoot = hasClassAnnotation("org.springframework.boot.test.context.SpringBootTest"); + if (springBoot) { + throw new RuntimeException("Spring Boot detected: The CamelTestSupport/CamelSpringTestSupport class is not intended for Camel testing with Spring Boot." + + " Prefer to not extend this class, but use @RunWith(CamelSpringBootRunner.class) instead."); + } + } + + private void doSetUp() throws Exception { + log.debug("setUp test"); + // jmx is enabled if we have configured to use it, or if dump route + // coverage is enabled (it requires JMX) + boolean jmx = useJmx() || isRouteCoverageEnabled(); + if (jmx) { + enableJMX(); + } else { + disableJMX(); + } + + context = (ModelCamelContext)createCamelContext(); + threadCamelContext.set(context); + + assertNotNull(context, "No context found!"); + + // add custom beans + bindToRegistry(context.getRegistry()); + + // reduce default shutdown timeout to avoid waiting for 300 seconds + context.getShutdownStrategy().setTimeout(getShutdownTimeout()); + + // set debugger if enabled + if (isUseDebugger()) { + if (context.getStatus().equals(ServiceStatus.Started)) { + log.info("Cannot setting the Debugger to the starting CamelContext, stop the CamelContext now."); + // we need to stop the context first to setup the debugger + context.stop(); + } + context.setDebugger(new DefaultDebugger()); + context.getDebugger().addBreakpoint(breakpoint); + // note: when stopping CamelContext it will automatic remove the + // breakpoint + } + + template = context.createProducerTemplate(); + template.start(); + fluentTemplate = context.createFluentProducerTemplate(); + fluentTemplate.start(); + consumer = context.createConsumerTemplate(); + consumer.start(); + + threadTemplate.set(template); + threadFluentTemplate.set(fluentTemplate); + threadConsumer.set(consumer); + + // enable auto mocking if enabled + String pattern = isMockEndpoints(); + if (pattern != null) { + context.adapt(ExtendedCamelContext.class).registerEndpointCallback(new InterceptSendToMockEndpointStrategy(pattern)); + } + pattern = isMockEndpointsAndSkip(); + if (pattern != null) { + context.adapt(ExtendedCamelContext.class).registerEndpointCallback(new InterceptSendToMockEndpointStrategy(pattern, true)); + } + + // configure properties component (mandatory for testing) + PropertiesComponent pc = context.getComponent("properties", PropertiesComponent.class); + Properties extra = useOverridePropertiesWithPropertiesComponent(); + if (extra != null && !extra.isEmpty()) { + pc.setOverrideProperties(extra); + } + Boolean ignore = ignoreMissingLocationWithPropertiesComponent(); + if (ignore != null) { + pc.setIgnoreMissingLocation(ignore); + } + + String include = getRouteFilterIncludePattern(); + String exclude = getRouteFilterExcludePattern(); + if (include != null || exclude != null) { + log.info("Route filtering pattern: include={}, exclude={}", include, exclude); + context.getExtension(Model.class).setRouteFilterPattern(include, exclude); + } + + // prepare for in-between tests + postProcessTest(); + + if (isUseRouteBuilder()) { + RoutesBuilder[] builders = createRouteBuilders(); + for (RoutesBuilder builder : builders) { + log.debug("Using created route builder: " + builder); + context.addRoutes(builder); + } + replaceFromEndpoints(); + boolean skip = "true".equalsIgnoreCase(System.getProperty("skipStartingCamelContext")); + if (skip) { + log.info("Skipping starting CamelContext as system property skipStartingCamelContext is set to be true."); + } else if (isUseAdviceWith()) { + log.info("Skipping starting CamelContext as isUseAdviceWith is set to true."); + } else { + startCamelContext(); + } + } else { + replaceFromEndpoints(); + log.debug("Using route builder from the created context: " + context); + } + log.debug("Routing Rules are: " + context.getRoutes()); + + assertValidContext(context); + } + + private void replaceFromEndpoints() throws Exception { + for (final Map.Entry<String, String> entry : fromEndpoints.entrySet()) { + RouteReifier.adviceWith(context.getRouteDefinition(entry.getKey()), context, new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + replaceFromWith(entry.getValue()); + } + }); + } + } + + private boolean isRouteCoverageEnabled() { + return System.getProperty(ROUTE_COVERAGE_ENABLED, "false").equalsIgnoreCase("true") || isDumpRouteCoverage(); + } + + @AfterEach + public void tearDown() throws Exception { + long time = watch.taken(); + + log.info("********************************************************************************"); + log.info("Testing done: " + currentTestName + "(" + getClass().getName() + ")"); + log.info("Took: " + TimeUtils.printDuration(time) + " (" + time + " millis)"); + + // if we should dump route stats, then write that to a file + if (isRouteCoverageEnabled()) { + String className = this.getClass().getSimpleName(); + String dir = "target/camel-route-coverage"; + String name = className + "-" + StringHelper.before(currentTestName, "(") + ".xml"; + + ManagedCamelContext mc = context != null ? context.getExtension(ManagedCamelContext.class) : null; + ManagedCamelContextMBean managedCamelContext = mc != null ? mc.getManagedCamelContext() : null; + if (managedCamelContext == null) { + log.warn("Cannot dump route coverage to file as JMX is not enabled. " + + "Add camel-management-impl JAR as dependency and/or override useJmx() method to enable JMX in the unit test classes."); + } else { + logCoverageSummary(managedCamelContext); + + String xml = managedCamelContext.dumpRoutesCoverageAsXml(); + String combined = "<camelRouteCoverage>\n" + gatherTestDetailsAsXml() + xml + "\n</camelRouteCoverage>"; + + File file = new File(dir); + // ensure dir exists + file.mkdirs(); + file = new File(dir, name); + + log.info("Dumping route coverage to file: {}", file); + InputStream is = new ByteArrayInputStream(combined.getBytes()); + OutputStream os = new FileOutputStream(file, false); + IOHelper.copyAndCloseInput(is, os); + IOHelper.close(os); + } + } + log.info("********************************************************************************"); + + if (isCreateCamelContextPerClass()) { + while (true) { + int v = tests.get(); + if (v <= 0) { + LOG.warn("Test already teared down"); + break; + } + + if (tests.compareAndSet(v, v - 1)) { + if (v == 1) { + LOG.debug("tearDown test"); + doStopTemplates(threadConsumer.get(), threadTemplate.get(), threadFluentTemplate.get()); + doStopCamelContext(threadCamelContext.get(), threadService.get()); + doPostTearDown(); + cleanupResources(); + } + + break; + } + } + } else { + LOG.debug("tearDown test"); + doStopTemplates(consumer, template, fluentTemplate); + doStopCamelContext(context, camelContextService); + doPostTearDown(); + cleanupResources(); + } + } + + /** + * Strategy to perform any post action, after {@link CamelContext} is + * stopped + */ + protected void doPostTearDown() throws Exception { + // noop + } + + /** + * Strategy to perform resources setup, before {@link CamelContext} is + * created + */ + protected void setupResources() throws Exception { + // noop + } + + /** + * Strategy to perform resources cleanup, after {@link CamelContext} is + * stopped + */ + protected void cleanupResources() throws Exception { + // noop + } + + /** + * Logs route coverage summary: - which routes are uncovered - what is the + * coverage of each processor in each route + */ + private void logCoverageSummary(ManagedCamelContextMBean managedCamelContext) throws Exception { + StringBuilder builder = new StringBuilder("\nCoverage summary\n"); + + int routes = managedCamelContext.getTotalRoutes(); + + long contextExchangesTotal = managedCamelContext.getExchangesTotal(); + + List<String> uncoveredRoutes = new ArrayList<>(); + + StringBuilder routesSummary = new StringBuilder(); + routesSummary.append("\tProcessor coverage\n"); + + MBeanServer server = context.getManagementStrategy().getManagementAgent().getMBeanServer(); + + Map<String, List<ManagedProcessorMBean>> processorsForRoute = findProcessorsForEachRoute(server); + + // log processor coverage for each route + for (Route route : context.getRoutes()) { + ManagedRouteMBean managedRoute = context.getExtension(ManagedCamelContext.class).getManagedRoute(route.getId()); + if (managedRoute.getExchangesTotal() == 0) { + uncoveredRoutes.add(route.getId()); + } + + long routeCoveragePercentage = Math.round((double)managedRoute.getExchangesTotal() / contextExchangesTotal * 100); + routesSummary.append("\t\tRoute ").append(route.getId()).append(" total: ").append(managedRoute.getExchangesTotal()).append(" (").append(routeCoveragePercentage) + .append("%)\n"); + + if (server != null) { + List<ManagedProcessorMBean> processors = processorsForRoute.get(route.getId()); + if (processors != null) { + for (ManagedProcessorMBean managedProcessor : processors) { + String processorId = managedProcessor.getProcessorId(); + long processorExchangesTotal = managedProcessor.getExchangesTotal(); + long processorCoveragePercentage = Math.round((double)processorExchangesTotal / contextExchangesTotal * 100); + routesSummary.append("\t\t\tProcessor ").append(processorId).append(" total: ").append(processorExchangesTotal).append(" (") + .append(processorCoveragePercentage).append("%)\n"); + } + } + } + } + + int used = routes - uncoveredRoutes.size(); + + long contextPercentage = Math.round((double)used / routes * 100); + builder.append("\tRoute coverage: ").append(used).append(" out of ").append(routes).append(" routes used (").append(contextPercentage).append("%)\n"); + builder.append("\t\tCamelContext (").append(managedCamelContext.getCamelId()).append(") total: ").append(contextExchangesTotal).append("\n"); + + if (uncoveredRoutes.size() > 0) { + builder.append("\t\tUncovered routes: ").append(uncoveredRoutes.stream().collect(Collectors.joining(", "))).append("\n"); + } + + builder.append(routesSummary); + log.info(builder.toString()); + } + + /** + * Groups all processors from Camel context by route id + */ + private Map<String, List<ManagedProcessorMBean>> findProcessorsForEachRoute(MBeanServer server) + throws MalformedObjectNameException, MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException { + String domain = context.getManagementStrategy().getManagementAgent().getMBeanServerDefaultDomain(); + + Map<String, List<ManagedProcessorMBean>> processorsForRoute = new HashMap<>(); + + ObjectName processorsObjectName = new ObjectName(domain + ":context=" + context.getManagementName() + ",type=processors,name=*"); + Set<ObjectName> objectNames = server.queryNames(processorsObjectName, null); + + for (ObjectName objectName : objectNames) { + String routeId = server.getAttribute(objectName, "RouteId").toString(); + String name = objectName.getKeyProperty("name"); + name = ObjectName.unquote(name); + + ManagedProcessorMBean managedProcessor = context.getExtension(ManagedCamelContext.class).getManagedProcessor(name); + + if (managedProcessor != null) { + if (processorsForRoute.get(routeId) == null) { + List<ManagedProcessorMBean> processorsList = new ArrayList<>(); + processorsList.add(managedProcessor); + + processorsForRoute.put(routeId, processorsList); + } else { + processorsForRoute.get(routeId).add(managedProcessor); + } + } + } + + // sort processors by position in route definition + for (Map.Entry<String, List<ManagedProcessorMBean>> entry : processorsForRoute.entrySet()) { + Collections.sort(entry.getValue(), Comparator.comparing(ManagedProcessorMBean::getIndex)); + } + + return processorsForRoute; + } + + /** + * Gathers test details as xml + */ + private String gatherTestDetailsAsXml() { + StringBuilder sb = new StringBuilder(); + sb.append("<test>\n"); + sb.append(" <class>").append(getClass().getName()).append("</class>\n"); + sb.append(" <method>").append(currentTestName).append("</method>\n"); + sb.append(" <time>").append(timeTaken()).append("</time>\n"); + sb.append("</test>\n"); + return sb.toString(); + } + + /** + * Returns the timeout to use when shutting down (unit in seconds). + * <p/> + * Will default use 10 seconds. + * + * @return the timeout to use + */ + protected int getShutdownTimeout() { + return 10; + } + + /** + * Whether or not JMX should be used during testing. + * + * @return <tt>false</tt> by default. + */ + protected boolean useJmx() { + return false; + } + + /** + * Whether or not type converters should be lazy loaded (notice core + * converters is always loaded) + * + * @return <tt>false</tt> by default. + */ + @Deprecated + protected boolean isLazyLoadingTypeConverter() { + return false; + } + + /** + * Override this method to include and override properties with the Camel + * {@link PropertiesComponent}. + * + * @return additional properties to add/override. + */ + protected Properties useOverridePropertiesWithPropertiesComponent() { + return null; + } + + /** + * Whether to ignore missing locations with the {@link PropertiesComponent}. + * For example when unit testing you may want to ignore locations that are + * not available in the environment you use for testing. + * + * @return <tt>true</tt> to ignore, <tt>false</tt> to not ignore, and + * <tt>null</tt> to leave as configured on the + * {@link PropertiesComponent} + */ + protected Boolean ignoreMissingLocationWithPropertiesComponent() { + return null; + } + + protected void postProcessTest() throws Exception { + context = threadCamelContext.get(); + template = threadTemplate.get(); + fluentTemplate = threadFluentTemplate.get(); + consumer = threadConsumer.get(); + camelContextService = threadService.get(); + applyCamelPostProcessor(); + } + + /** + * Applies the {@link DefaultCamelBeanPostProcessor} to this instance. + * Derived classes using IoC / DI frameworks may wish to turn this into a + * NoOp such as for CDI we would just use CDI to inject this + */ + protected void applyCamelPostProcessor() throws Exception { + // use the default bean post processor from camel-core if the test class + // is not dependency injected already by Spring + boolean spring = hasClassAnnotation("org.springframework.boot.test.context.SpringBootTest", "org.springframework.context.annotation.ComponentScan"); + if (!spring) { + DefaultCamelBeanPostProcessor processor = new DefaultCamelBeanPostProcessor(context); + processor.postProcessBeforeInitialization(this, getClass().getName()); + processor.postProcessAfterInitialization(this, getClass().getName()); + } + } + + /** + * Does this test class have any of the following annotations on the + * class-level. + */ + protected boolean hasClassAnnotation(String... names) { + for (String name : names) { + for (Annotation ann : getClass().getAnnotations()) { + String annName = ann.annotationType().getName(); + if (annName.equals(name)) { + return true; + } + } + } + return false; + } + + protected void stopCamelContext() throws Exception { + doStopCamelContext(context, camelContextService); + } + + private static void doStopCamelContext(CamelContext context, Service camelContextService) throws Exception { + if (camelContextService != null) { + if (camelContextService == threadService.get()) { + threadService.remove(); + } + camelContextService.stop(); + } else { + if (context != null) { + if (context == threadCamelContext.get()) { + threadCamelContext.remove(); + } + context.stop(); + } + } + } + + private static void doStopTemplates(ConsumerTemplate consumer, ProducerTemplate template, FluentProducerTemplate fluentTemplate) throws Exception { + if (consumer != null) { + if (consumer == threadConsumer.get()) { + threadConsumer.remove(); + } + consumer.stop(); + } + if (template != null) { + if (template == threadTemplate.get()) { + threadTemplate.remove(); + } + template.stop(); + } + if (fluentTemplate != null) { + if (fluentTemplate == threadFluentTemplate.get()) { + threadFluentTemplate.remove(); + } + fluentTemplate.stop(); + } + } + + protected void startCamelContext() throws Exception { + if (camelContextService != null) { + camelContextService.start(); + } else { + if (context instanceof DefaultCamelContext) { + DefaultCamelContext defaultCamelContext = (DefaultCamelContext)context; + if (!defaultCamelContext.isStarted()) { + defaultCamelContext.start(); + } + } else { + context.start(); + } + } + } + + protected CamelContext createCamelContext() throws Exception { + // for backwards compatibility + Registry registry = createRegistry(); + if (registry instanceof FakeJndiRegistry) { + boolean inUse = ((FakeJndiRegistry)registry).isInUse(); + if (!inUse) { + registry = null; + } + } + if (registry != null) { + String msg = "createRegistry() from camel-test is deprecated. Use createCamelRegistry if you want to control which registry to use, however" + + " if you need to bind beans to the registry then this is possible already with the bind method on registry," + + " and there is no need to override this method."; + LOG.warn(msg); + } else { + registry = createCamelRegistry(); + } + + CamelContext context; + if (registry != null) { + context = new DefaultCamelContext(registry); + } else { + context = new DefaultCamelContext(); + } + return context; + } + + /** + * Allows to bind custom beans to the Camel {@link Registry}. + */ + protected void bindToRegistry(Registry registry) throws Exception { + // noop + } + + /** + * Override to use a custom {@link Registry}. However if you need to bind + * beans to the registry then this is possible already with the bind method + * on registry," and there is no need to override this method. + */ + protected Registry createCamelRegistry() throws Exception { + return null; + } + + /** + * @deprecated use createCamelRegistry if you want to control which registry + * to use, however if you need to bind beans to the registry + * then this is possible already with the bind method on + * registry, and there is no need to override this method. + */ + @Deprecated + protected JndiRegistry createRegistry() throws Exception { + return new FakeJndiRegistry(createJndiContext()); + } + + /** + * @deprecated use createCamelRegistry if you want to control which registry + * to use, however if you need to bind beans to the registry + * then this is possible already with the bind method on + * registry, and there is no need to use JndiRegistry and + * override this method. + */ + @Deprecated + protected Context createJndiContext() throws Exception { + LOG.warn("The method createJndiContext() in camel-test is deprecated. You can bind beans directly from Camel Registry instead"); + Properties properties = new Properties(); + + // jndi.properties is optional + InputStream in = getClass().getClassLoader().getResourceAsStream("jndi.properties"); + if (in != null) { + log.debug("Using jndi.properties from classpath root"); + properties.load(in); + } else { + properties.put("java.naming.factory.initial", "org.apache.camel.support.jndi.CamelInitialContextFactory"); + } + return new InitialContext(new Hashtable<>(properties)); + } + + private class FakeJndiRegistry extends JndiRegistry { + + private boolean inUse; + + public FakeJndiRegistry(Context context) { + super(context); + } + + @Override + public void bind(String name, Object object) { + super.bind(name, object); + inUse = true; + } + + public boolean isInUse() { + // only if the end user bind beans then its in use + return inUse; + } + } + + /** + * Factory method which derived classes can use to create a + * {@link RouteBuilder} to define the routes for testing + */ + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() { + // no routes added by default + } + }; + } + + /** + * 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 + * + * @see #createRouteBuilder() + */ + protected RoutesBuilder[] createRouteBuilders() throws Exception { + return new RoutesBuilder[] {createRouteBuilder()}; + } + + /** + * Resolves a mandatory endpoint for the given URI or an exception is thrown + * + * @param uri the Camel <a href="">URI</a> to use to create or resolve an + * endpoint + * @return the endpoint + */ + protected Endpoint resolveMandatoryEndpoint(String uri) { + return resolveMandatoryEndpoint(context, uri); + } + + /** + * Resolves a mandatory endpoint for the given URI and expected type or an + * exception is thrown + * + * @param uri the Camel <a href="">URI</a> to use to create or resolve an + * endpoint + * @return the endpoint + */ + protected <T extends Endpoint> T resolveMandatoryEndpoint(String uri, Class<T> endpointType) { + return resolveMandatoryEndpoint(context, uri, endpointType); + } + + /** + * 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 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. + * + * @param uri the URI which typically starts with "mock:" and has some name + * @param create whether or not 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 exists + */ + protected MockEndpoint getMockEndpoint(String uri, boolean create) throws NoSuchEndpointException { + if (create) { + return resolveMandatoryEndpoint(uri, MockEndpoint.class); + } else { + Endpoint endpoint = context.hasEndpoint(uri); + if (endpoint instanceof MockEndpoint) { + return (MockEndpoint)endpoint; + } + throw new NoSuchEndpointException(String.format("MockEndpoint %s does not exist.", uri)); + } + } + + /** + * Sends a message to the given endpoint URI with the body value + * + * @param endpointUri the URI of the endpoint to send to + * @param body the body for the message + */ + protected void sendBody(String endpointUri, final Object body) { + template.send(endpointUri, new Processor() { + public void process(Exchange exchange) { + Message in = exchange.getIn(); + in.setBody(body); + } + }); + } + + /** + * Sends a message to the given endpoint URI with the body value and + * specified headers + * + * @param endpointUri the URI of the endpoint to send to + * @param body the body for the message + * @param headers any headers to set on the message + */ + protected void sendBody(String endpointUri, final Object body, final Map<String, Object> headers) { + template.send(endpointUri, new Processor() { + public void process(Exchange exchange) { + Message in = exchange.getIn(); + in.setBody(body); + for (Map.Entry<String, Object> entry : headers.entrySet()) { + in.setHeader(entry.getKey(), entry.getValue()); + } + } + }); + } + + /** + * Sends messages to the given endpoint for each of the specified bodies + * + * @param endpointUri the endpoint URI to send to + * @param bodies the bodies to send, one per message + */ + protected void sendBodies(String endpointUri, Object... bodies) { + for (Object body : bodies) { + sendBody(endpointUri, body); + } + } + + /** + * Creates an exchange with the given body + */ + protected Exchange createExchangeWithBody(Object body) { + return createExchangeWithBody(context, body); + } + + /** + * Asserts that the given language name and expression evaluates to the + * given value on a specific exchange + */ + protected void assertExpression(Exchange exchange, String languageName, String expressionText, Object expectedValue) { + Language language = assertResolveLanguage(languageName); + + Expression expression = language.createExpression(expressionText); + assertNotNull(expression, "No Expression could be created for text: " + expressionText + " language: " + language); + + assertExpression(expression, exchange, expectedValue); + } + + /** + * Asserts that the given language name and predicate expression evaluates + * to the expected value on the message exchange + */ + protected void assertPredicate(String languageName, String expressionText, Exchange exchange, boolean expected) { + Language language = assertResolveLanguage(languageName); + + Predicate predicate = language.createPredicate(expressionText); + assertNotNull(predicate, "No Predicate could be created for text: " + expressionText + " language: " + language); + + assertPredicate(predicate, exchange, expected); + } + + /** + * Asserts that the language name can be resolved + */ + protected Language assertResolveLanguage(String languageName) { + Language language = context.resolveLanguage(languageName); + assertNotNull(language, "No language found for name: " + languageName); + return language; + } + + /** + * Asserts that all the expectations of the Mock endpoints are valid + */ + protected void assertMockEndpointsSatisfied() throws InterruptedException { + MockEndpoint.assertIsSatisfied(context); + } + + /** + * Asserts that all the expectations of the Mock endpoints are valid + */ + protected void assertMockEndpointsSatisfied(long timeout, TimeUnit unit) throws InterruptedException { + MockEndpoint.assertIsSatisfied(context, timeout, unit); + } + + /** + * Reset all Mock endpoints. + */ + protected void resetMocks() { + MockEndpoint.resetMocks(context); + } + + protected void assertValidContext(CamelContext context) { + assertNotNull(context, "No context found!"); + } + + protected <T extends Endpoint> T getMandatoryEndpoint(String uri, Class<T> type) { + T endpoint = context.getEndpoint(uri, type); + assertNotNull(endpoint, "No endpoint found for uri: " + uri); + return endpoint; + } + + protected Endpoint getMandatoryEndpoint(String uri) { + Endpoint endpoint = context.getEndpoint(uri); + assertNotNull(endpoint, "No endpoint found for uri: " + uri); + return endpoint; + } + + /** + * Disables the JMX agent. Must be called before the {@link #setUp()} + * method. + */ + protected void disableJMX() { + System.setProperty(JmxSystemPropertyKeys.DISABLED, "true"); + } + + /** + * Enables the JMX agent. Must be called before the {@link #setUp()} method. + */ + protected void enableJMX() { + System.setProperty(JmxSystemPropertyKeys.DISABLED, "false"); + } + + /** + * Single step debugs and Camel invokes this method before entering the + * given processor + */ + 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 + */ + protected void debugAfter(Exchange exchange, Processor processor, ProcessorDefinition<?> definition, String id, String label, long timeTaken) { + } + + /** + * To easily debug by overriding the <tt>debugBefore</tt> and + * <tt>debugAfter</tt> methods. + */ + private class DebugBreakpoint extends BreakpointSupport { + + @Override + public void beforeProcess(Exchange exchange, Processor processor, NamedNode definition) { + CamelTestSupport.this.debugBefore(exchange, processor, (ProcessorDefinition)definition, definition.getId(), definition.getLabel()); + } + + @Override + public void afterProcess(Exchange exchange, Processor processor, NamedNode definition, long timeTaken) { + CamelTestSupport.this.debugAfter(exchange, processor, (ProcessorDefinition)definition, definition.getId(), definition.getLabel(), timeTaken); + } + } + +} diff --git a/components/camel-test/src/main/java/org/apache/camel/test/junit5/TestSupport.java b/components/camel-test/src/main/java/org/apache/camel/test/junit5/TestSupport.java new file mode 100644 index 0000000..a24ca42 --- /dev/null +++ b/components/camel-test/src/main/java/org/apache/camel/test/junit5/TestSupport.java @@ -0,0 +1,553 @@ +/* + * 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.test.junit5; + +import java.io.File; +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; +import org.apache.camel.Expression; +import org.apache.camel.InvalidPayloadException; +import org.apache.camel.Message; +import org.apache.camel.Predicate; +import org.apache.camel.Route; +import org.apache.camel.builder.Builder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.builder.ValueBuilder; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.support.DefaultExchange; +import org.apache.camel.support.PredicateAssertHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * A bunch of useful testing methods + */ +public abstract class TestSupport { + + protected static final String LS = System.lineSeparator(); + private static final Logger LOG = LoggerFactory.getLogger(TestSupport.class); + protected Logger log = LoggerFactory.getLogger(getClass()); + + // Builder methods for expressions used when testing + // ------------------------------------------------------------------------- + + /** + * Returns a value builder for the given header + */ + public static ValueBuilder header(String name) { + return Builder.header(name); + } + + /** + * Returns a value builder for the given property + * + * @deprecated use {@link #exchangeProperty(String)} + */ + @Deprecated + public static ValueBuilder property(String name) { + return Builder.exchangeProperty(name); + } + + /** + * Returns a value builder for the given exchange property + */ + public static ValueBuilder exchangeProperty(String name) { + return Builder.exchangeProperty(name); + } + + /** + * Returns a predicate and value builder for the inbound body on an exchange + */ + public static ValueBuilder body() { + return Builder.body(); + } + + /** + * Returns a predicate and value builder for the inbound message body as a + * specific type + */ + public static <T> ValueBuilder bodyAs(Class<T> type) { + return Builder.bodyAs(type); + } + + /** + * Returns a value builder for the given system property + */ + public static ValueBuilder systemProperty(String name) { + return Builder.systemProperty(name); + } + + /** + * Returns a value builder for the given system property + */ + public static ValueBuilder systemProperty(String name, String defaultValue) { + return Builder.systemProperty(name, defaultValue); + } + + // Assertions + // ----------------------------------------------------------------------- + + public static <T> T assertIsInstanceOf(Class<T> expectedType, Object value) { + assertNotNull(value, "Expected an instance of type: " + expectedType.getName() + " but was null"); + assertTrue(expectedType.isInstance(value), "Object should be of type " + expectedType.getName() + " but was: " + value + " with the type: " + value.getClass().getName()); + return expectedType.cast(value); + } + + public static void assertEndpointUri(Endpoint endpoint, String uri) { + assertNotNull(endpoint, "Endpoint is null when expecting endpoint for: " + uri); + assertEquals(uri, endpoint.getEndpointUri(), "Endpoint uri for: " + endpoint); + } + + /** + * Asserts the In message on the exchange contains the expected value + */ + public static Object assertInMessageHeader(Exchange exchange, String name, Object expected) { + return assertMessageHeader(exchange.getIn(), name, expected); + } + + /** + * Asserts the Out message on the exchange contains the expected value + */ + public static Object assertOutMessageHeader(Exchange exchange, String name, Object expected) { + return assertMessageHeader(exchange.getOut(), name, expected); + } + + /** + * Asserts that the given exchange has an OUT message of the given body + * value + * + * @param exchange the exchange which should have an OUT message + * @param expected the expected value of the OUT message + * @throws InvalidPayloadException is thrown if the payload is not the + * expected class type + */ + public static void assertInMessageBodyEquals(Exchange exchange, Object expected) throws InvalidPayloadException { + assertNotNull(exchange, "Should have a response exchange!"); + + Object actual; + if (expected == null) { + actual = exchange.getIn().getMandatoryBody(); + assertEquals(expected, actual, "in body of: " + exchange); + } else { + actual = exchange.getIn().getMandatoryBody(expected.getClass()); + } + assertEquals(expected, actual, "in body of: " + exchange); + + LOG.debug("Received response: " + exchange + " with in: " + exchange.getIn()); + } + + /** + * Asserts that the given exchange has an OUT message of the given body + * value + * + * @param exchange the exchange which should have an OUT message + * @param expected the expected value of the OUT message + * @throws InvalidPayloadException is thrown if the payload is not the + * expected class type + */ + public static void assertOutMessageBodyEquals(Exchange exchange, Object expected) throws InvalidPayloadException { + assertNotNull(exchange, "Should have a response exchange!"); + + Object actual; + if (expected == null) { + actual = exchange.getOut().getMandatoryBody(); + assertEquals(expected, actual, "output body of: " + exchange); + } else { + actual = exchange.getOut().getMandatoryBody(expected.getClass()); + } + assertEquals(expected, actual, "output body of: " + exchange); + + LOG.debug("Received response: " + exchange + " with out: " + exchange.getOut()); + } + + public static Object assertMessageHeader(Message message, String name, Object expected) { + Object value = message.getHeader(name); + assertEquals(expected, value, "Header: " + name + " on Message: " + message); + return value; + } + + /** + * Asserts that the given expression when evaluated returns the given answer + */ + public static Object assertExpression(Expression expression, Exchange exchange, Object expected) { + Object value; + if (expected != null) { + value = expression.evaluate(exchange, expected.getClass()); + } else { + value = expression.evaluate(exchange, Object.class); + } + + LOG.debug("Evaluated expression: " + expression + " on exchange: " + exchange + " result: " + value); + + assertEquals(expected, value, "Expression: " + expression + " on Exchange: " + exchange); + return value; + } + + /** + * Asserts that the predicate returns the expected value on the exchange + */ + public static void assertPredicateMatches(Predicate predicate, Exchange exchange) { + assertPredicate(predicate, exchange, true); + } + + /** + * Asserts that the predicate returns the expected value on the exchange + */ + public static void assertPredicateDoesNotMatch(Predicate predicate, Exchange exchange) { + try { + PredicateAssertHelper.assertMatches(predicate, "Predicate should match: ", exchange); + } catch (AssertionError e) { + LOG.debug("Caught expected assertion error: " + e); + } + assertPredicate(predicate, exchange, false); + } + + /** + * Asserts that the predicate returns the expected value on the exchange + */ + public static boolean assertPredicate(final Predicate predicate, Exchange exchange, boolean expected) { + if (expected) { + PredicateAssertHelper.assertMatches(predicate, "Predicate failed: ", exchange); + } + boolean value = predicate.matches(exchange); + + LOG.debug("Evaluated predicate: " + predicate + " on exchange: " + exchange + " result: " + value); + + assertEquals(expected, value, "Predicate: " + predicate + " on Exchange: " + exchange); + return value; + } + + /** + * Resolves an endpoint and asserts that it is found + */ + public static Endpoint resolveMandatoryEndpoint(CamelContext context, String uri) { + Endpoint endpoint = context.getEndpoint(uri); + + assertNotNull(endpoint, "No endpoint found for URI: " + uri); + + return endpoint; + } + + /** + * Resolves an endpoint and asserts that it is found + */ + public static <T extends Endpoint> T resolveMandatoryEndpoint(CamelContext context, String uri, Class<T> endpointType) { + T endpoint = context.getEndpoint(uri, endpointType); + + assertNotNull(endpoint, "No endpoint found for URI: " + uri); + + return endpoint; + } + + /** + * Creates an exchange with the given body + */ + protected Exchange createExchangeWithBody(CamelContext camelContext, Object body) { + Exchange exchange = new DefaultExchange(camelContext); + Message message = exchange.getIn(); + message.setHeader("testClass", getClass().getName()); + message.setBody(body); + return exchange; + } + + public static <T> T assertOneElement(List<T> list) { + assertEquals(1, list.size(), "Size of list should be 1: " + list); + return list.get(0); + } + + /** + * Asserts that a list is of the given size + */ + public static <T> List<T> assertListSize(List<T> list, int size) { + return assertListSize("List", list, size); + } + + /** + * Asserts that a list is of the given size + */ + public static <T> List<T> assertListSize(String message, List<T> list, int size) { + assertEquals(size, list.size(), message + " should be of size: " + size + " but is: " + list); + return list; + } + + /** + * Asserts that a list is of the given size + */ + public static <T> Collection<T> assertCollectionSize(Collection<T> list, int size) { + return assertCollectionSize("List", list, size); + } + + /** + * Asserts that a list is of the given size + */ + public static <T> Collection<T> assertCollectionSize(String message, Collection<T> list, int size) { + assertEquals(size, list.size(), message + " should be of size: " + size + " but is: " + list); + return list; + } + + /** + * A helper method to create a list of Route objects for a given route + * builder + */ + public static List<Route> getRouteList(RouteBuilder builder) throws Exception { + CamelContext context = new DefaultCamelContext(); + context.addRoutes(builder); + context.start(); + List<Route> answer = context.getRoutes(); + context.stop(); + return answer; + } + + /** + * Asserts that the text contains the given string + * + * @param text the text to compare + * @param containedText the text which must be contained inside the other + * text parameter + */ + public static void assertStringContains(String text, String containedText) { + assertNotNull("Text should not be null!", text); + assertTrue(text.contains(containedText), "Text: " + text + " does not contain: " + containedText); + } + + /** + * Recursively delete a directory, useful to zapping test data + * + * @param file the directory to be deleted + * @return <tt>false</tt> if error deleting directory + */ + public static boolean deleteDirectory(String file) { + return deleteDirectory(new File(file)); + } + + /** + * Recursively delete a directory, useful to zapping test data + * + * @param file the directory to be deleted + * @return <tt>false</tt> if error deleting directory + */ + public static boolean deleteDirectory(File file) { + int tries = 0; + int maxTries = 5; + boolean exists = true; + while (exists && (tries < maxTries)) { + recursivelyDeleteDirectory(file); + tries++; + exists = file.exists(); + if (exists) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } + } + } + return !exists; + } + + private static void recursivelyDeleteDirectory(File file) { + if (!file.exists()) { + return; + } + + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (File child : files) { + recursivelyDeleteDirectory(child); + } + } + boolean success = file.delete(); + if (!success) { + LOG.warn("Deletion of file: " + file.getAbsolutePath() + " failed"); + } + } + + /** + * create the directory + * + * @param file the directory to be created + */ + public static void createDirectory(String file) { + File dir = new File(file); + dir.mkdirs(); + } + + /** + * To be used for folder/directory comparison that works across different + * platforms such as Window, Mac and Linux. + */ + public static void assertDirectoryEquals(String expected, String actual) { + assertDirectoryEquals(null, expected, actual); + } + + /** + * To be used for folder/directory comparison that works across different + * platforms such as Window, Mac and Linux. + */ + public static void assertDirectoryEquals(String message, String expected, String actual) { + // must use single / as path separators + String expectedPath = expected.replace('\\', '/'); + String actualPath = actual.replace('\\', '/'); + + if (message != null) { + assertEquals(message, expectedPath, actualPath); + } else { + assertEquals(expectedPath, actualPath); + } + } + + /** + * To be used to check is a directory is found in the file system + */ + public static void assertDirectoryExists(String filename) { + File file = new File(filename); + assertTrue(file.exists(), "Directory " + filename + " should exist"); + assertTrue(file.isDirectory(), "Directory " + filename + " should be a directory"); + } + + /** + * To be used to check is a file is found in the file system + */ + public static void assertFileExists(String filename) { + File file = new File(filename); + assertTrue(file.exists(), "File " + filename + " should exist"); + assertTrue(file.isFile(), "File " + filename + " should be a file"); + } + + /** + * To be used to check is a file is <b>not</b> found in the file system + */ + public static void assertFileNotExists(String filename) { + File file = new File(filename); + assertFalse(file.exists(), "File " + filename + " should not exist"); + } + + /** + * Is this OS the given platform. + * <p/> + * Uses <tt>os.name</tt> from the system properties to determine the OS. + * + * @param platform such as Windows + * @return <tt>true</tt> if its that platform. + */ + public static boolean isPlatform(String platform) { + String osName = System.getProperty("os.name").toLowerCase(Locale.US); + return osName.contains(platform.toLowerCase(Locale.US)); + } + + /** + * Is this Java by the given vendor. + * <p/> + * Uses <tt>java.vendor</tt> from the system properties to determine the + * vendor. + * + * @param vendor such as IBM + * @return <tt>true</tt> if its that vendor. + */ + public static boolean isJavaVendor(String vendor) { + String javaVendor = System.getProperty("java.vendor").toLowerCase(Locale.US); + return javaVendor.contains(vendor.toLowerCase(Locale.US)); + } + + /** + * Is this Java 1.5 + * + * @return <tt>true</tt> if its Java 1.5, <tt>false</tt> if its not (for + * example Java 1.6 or better) + * @deprecated will be removed in the future as Camel requires JDK1.8+ + */ + @Deprecated + public static boolean isJava15() { + return getJavaMajorVersion() == 5; + } + + /** + * Is this Java 1.6 + * + * @return <tt>true</tt> if its Java 1.6, <tt>false</tt> if its not (for + * example Java 1.7 or better) + * @deprecated will be removed in the future as Camel requires JDK1.8+ + */ + @Deprecated + public static boolean isJava16() { + return getJavaMajorVersion() == 6; + + } + + /** + * Is this Java 1.7 + * + * @return <tt>true</tt> if its Java 1.7, <tt>false</tt> if its not (for + * example Java 1.6 or older) + * @deprecated will be removed in the future as Camel requires JDK1.8+ + */ + @Deprecated + public static boolean isJava17() { + return getJavaMajorVersion() == 7; + + } + + /** + * Is this Java 1.8 + * + * @return <tt>true</tt> if its Java 1.8, <tt>false</tt> if its not (for + * example Java 1.7 or older) + */ + public static boolean isJava18() { + return getJavaMajorVersion() == 8; + + } + + /** + * Is this Java 1.9 + * + * @return <tt>true</tt> if its Java 1.9, <tt>false</tt> if its not (for + * example Java 1.8 or older) + */ + public static boolean isJava19() { + return getJavaMajorVersion() == 9; + + } + + /** + * Returns the current major Java version e.g 8. + * <p/> + * Uses <tt>java.specification.version</tt> from the system properties to + * determine the major version. + * + * @return the current major Java version. + */ + public static int getJavaMajorVersion() { + String javaSpecVersion = System.getProperty("java.specification.version"); + if (javaSpecVersion.contains(".")) { // before jdk 9 + return Integer.parseInt(javaSpecVersion.split("\\.")[1]); + } else { + return Integer.parseInt(javaSpecVersion); + } + } + +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/AdviceWithNotStartedTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/AdviceWithNotStartedTest.java new file mode 100644 index 0000000..55e0a54 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/AdviceWithNotStartedTest.java @@ -0,0 +1,74 @@ +/* + * 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.test.junit5.patterns; + +import java.util.concurrent.RejectedExecutionException; + +import org.apache.camel.CamelExecutionException; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.AdviceWithRouteBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.reifier.RouteReifier; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.fail; + +public class AdviceWithNotStartedTest extends CamelTestSupport { + + @Override + public boolean isUseAdviceWith() { + return true; + } + + @Test + public void testNotStarted() throws Exception { + RouteReifier.adviceWith(context.getRouteDefinition("foo"), context, new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + weaveAddLast().to("mock:result"); + } + }); + + getMockEndpoint("mock:result").expectedMessageCount(1); + + try { + template.sendBody("direct:start", "Hello World"); + fail("Should throw exception"); + } catch (CamelExecutionException e) { + assertIsInstanceOf(RejectedExecutionException.class, e.getCause()); + } + + // start Camel + context.start(); + + template.sendBody("direct:start", "Bye World"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").routeId("foo") + .to("log:foo"); + } + }; + } +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/AsyncSendMockTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/AsyncSendMockTest.java new file mode 100644 index 0000000..f1f8ca9 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/AsyncSendMockTest.java @@ -0,0 +1,47 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.support.DefaultExchange; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class AsyncSendMockTest extends CamelTestSupport { + @Override + public String isMockEndpoints() { + return "seda*"; + } + + @Test + public void testmakeAsyncApiCall() { + try { + getMockEndpoint("mock:seda:start").expectedHeaderReceived("username", "admin123"); + getMockEndpoint("mock:seda:start").expectedBodiesReceived("Hello"); + DefaultExchange dfex = new DefaultExchange(context); + dfex.getIn().setHeader("username", "admin123"); + dfex.getIn().setHeader("password", "admin"); + dfex.getIn().setBody("Hello"); + template.asyncSend("seda:start", dfex); + assertMockEndpointsSatisfied(); + } catch (Exception e) { + e.printStackTrace(); + assertTrue(false, "Failed to make async call to api"); + } + } +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugJUnit5Test.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugJUnit5Test.java new file mode 100644 index 0000000..0d6c600 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugJUnit5Test.java @@ -0,0 +1,86 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.ProcessorDefinition; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +public class DebugJUnit5Test extends CamelTestSupport { + + // START SNIPPET: e1 + @Override + public boolean isUseDebugger() { + // must enable debugger + return true; + } + + @Override + protected void debugBefore(Exchange exchange, Processor processor, + ProcessorDefinition<?> definition, String id, String shortName) { + // this method is invoked before we are about to enter the given processor + // from your Java editor you can just add a breakpoint in the code line below + log.info("Before " + definition + " with body " + exchange.getIn().getBody()); + } + // END SNIPPET: e1 + + @Test + public void testDebugger() throws Exception { + // set mock expectations + getMockEndpoint("mock:a").expectedMessageCount(1); + getMockEndpoint("mock:b").expectedMessageCount(1); + + // send a message + template.sendBody("direct:start", "World"); + + // assert mocks + assertMockEndpointsSatisfied(); + } + + @Test + public void testTwo() throws Exception { + // set mock expectations + getMockEndpoint("mock:a").expectedMessageCount(2); + getMockEndpoint("mock:b").expectedMessageCount(2); + + // send a message + template.sendBody("direct:start", "World"); + template.sendBody("direct:start", "Camel"); + + // assert mocks + assertMockEndpointsSatisfied(); + } + + // START SNIPPET: e2 + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + // this is the route we want to debug + from("direct:start") + .to("mock:a") + .transform(body().prepend("Hello ")) + .to("mock:b"); + } + }; + } + // END SNIPPET: e2 +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugNoLazyTypeConverterTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugNoLazyTypeConverterTest.java new file mode 100644 index 0000000..0aac087 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugNoLazyTypeConverterTest.java @@ -0,0 +1,91 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.ProcessorDefinition; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +public class DebugNoLazyTypeConverterTest extends CamelTestSupport { + + @Override + protected boolean isLazyLoadingTypeConverter() { + return false; + } + + // START SNIPPET: e1 + @Override + public boolean isUseDebugger() { + // must enable debugger + return true; + } + + @Override + protected void debugBefore(Exchange exchange, Processor processor, + ProcessorDefinition<?> definition, String id, String shortName) { + // this method is invoked before we are about to enter the given processor + // from your Java editor you can just add a breakpoint in the code line below + log.info("Before " + definition + " with body " + exchange.getIn().getBody()); + } + // END SNIPPET: e1 + + @Test + public void testDebugger() throws Exception { + // set mock expectations + getMockEndpoint("mock:a").expectedMessageCount(1); + getMockEndpoint("mock:b").expectedMessageCount(1); + + // send a message + template.sendBody("direct:start", "World"); + + // assert mocks + assertMockEndpointsSatisfied(); + } + + @Test + public void testTwo() throws Exception { + // set mock expectations + getMockEndpoint("mock:a").expectedMessageCount(2); + getMockEndpoint("mock:b").expectedMessageCount(2); + + // send a message + template.sendBody("direct:start", "World"); + template.sendBody("direct:start", "Camel"); + + // assert mocks + assertMockEndpointsSatisfied(); + } + + // START SNIPPET: e2 + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + // this is the route we want to debug + from("direct:start") + .to("mock:a") + .transform(body().prepend("Hello ")) + .to("mock:b"); + } + }; + } + // END SNIPPET: e2 +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugTest.java new file mode 100644 index 0000000..401bdac --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/DebugTest.java @@ -0,0 +1,86 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.ProcessorDefinition; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +public class DebugTest extends CamelTestSupport { + + // START SNIPPET: e1 + @Override + public boolean isUseDebugger() { + // must enable debugger + return true; + } + + @Override + protected void debugBefore(Exchange exchange, Processor processor, + ProcessorDefinition<?> definition, String id, String shortName) { + // this method is invoked before we are about to enter the given processor + // from your Java editor you can just add a breakpoint in the code line below + log.info("Before " + definition + " with body " + exchange.getIn().getBody()); + } + // END SNIPPET: e1 + + @Test + public void testDebugger() throws Exception { + // set mock expectations + getMockEndpoint("mock:a").expectedMessageCount(1); + getMockEndpoint("mock:b").expectedMessageCount(1); + + // send a message + template.sendBody("direct:start", "World"); + + // assert mocks + assertMockEndpointsSatisfied(); + } + + @Test + public void testTwo() throws Exception { + // set mock expectations + getMockEndpoint("mock:a").expectedMessageCount(2); + getMockEndpoint("mock:b").expectedMessageCount(2); + + // send a message + template.sendBody("direct:start", "World"); + template.sendBody("direct:start", "Camel"); + + // assert mocks + assertMockEndpointsSatisfied(); + } + + // START SNIPPET: e2 + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + // this is the route we want to debug + from("direct:start") + .to("mock:a") + .transform(body().prepend("Hello ")) + .to("mock:b"); + } + }; + } + // END SNIPPET: e2 +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterCreateCamelContextPerClassTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterCreateCamelContextPerClassTest.java new file mode 100644 index 0000000..37144bc --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterCreateCamelContextPerClassTest.java @@ -0,0 +1,65 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +/** + * Tests filtering using Camel Test + */ +// START SNIPPET: example +public class FilterCreateCamelContextPerClassTest extends CamelTestSupport { + + @Override + public boolean isCreateCamelContextPerClass() { + // we override this method and return true, to tell Camel test-kit that + // it should only create CamelContext once (per class), so we will + // re-use the CamelContext between each test method in this class + return true; + } + + @Test + public void testSendMatchingMessage() throws Exception { + String expectedBody = "<matched/>"; + + getMockEndpoint("mock:result").expectedBodiesReceived(expectedBody); + + template.sendBodyAndHeader("direct:start", expectedBody, "foo", "bar"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testSendNotMatchingMessage() throws Exception { + getMockEndpoint("mock:result").expectedMessageCount(0); + + template.sendBodyAndHeader("direct:start", "<notMatched/>", "foo", "notMatchedHeaderValue"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result"); + } + }; + } +} \ No newline at end of file diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterFluentTemplateTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterFluentTemplateTest.java new file mode 100644 index 0000000..e4cef04 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterFluentTemplateTest.java @@ -0,0 +1,75 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.EndpointInject; +import org.apache.camel.FluentProducerTemplate; +import org.apache.camel.Produce; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +/** + * Tests filtering using Camel Test + */ +// START SNIPPET: example +// tag::example[] +public class FilterFluentTemplateTest extends CamelTestSupport { + + @EndpointInject("mock:result") + protected MockEndpoint resultEndpoint; + + @Produce("direct:start") + protected FluentProducerTemplate fluentTemplate; + + @Override + public boolean isDumpRouteCoverage() { + return true; + } + + @Test + public void testSendMatchingMessage() throws Exception { + String expectedBody = "<matched/>"; + + resultEndpoint.expectedBodiesReceived(expectedBody); + + fluentTemplate.withBody(expectedBody).withHeader("foo", "bar").send(); + + resultEndpoint.assertIsSatisfied(); + } + + @Test + public void testSendNotMatchingMessage() throws Exception { + resultEndpoint.expectedMessageCount(0); + + fluentTemplate.withBody("<notMatched/>").withHeader("foo", "notMatchedHeaderValue").send(); + + resultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result"); + } + }; + } +} +// end::example[] +// END SNIPPET: example diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterJUnit5Test.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterJUnit5Test.java new file mode 100644 index 0000000..e946d6b --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterJUnit5Test.java @@ -0,0 +1,69 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +/** + * Tests filtering using Camel Test + */ +// START SNIPPET: example +public class FilterJUnit5Test extends CamelTestSupport { + + @EndpointInject("mock:result") + protected MockEndpoint resultEndpoint; + + @Produce("direct:start") + protected ProducerTemplate template; + + @Test + public void testSendMatchingMessage() throws Exception { + String expectedBody = "<matched/>"; + + resultEndpoint.expectedBodiesReceived(expectedBody); + + template.sendBodyAndHeader(expectedBody, "foo", "bar"); + + resultEndpoint.assertIsSatisfied(); + } + + @Test + public void testSendNotMatchingMessage() throws Exception { + resultEndpoint.expectedMessageCount(0); + + template.sendBodyAndHeader("<notMatched/>", "foo", "notMatchedHeaderValue"); + + resultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result"); + } + }; + } + +} +// END SNIPPET: example diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterTest.java new file mode 100644 index 0000000..a2455ce --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/FilterTest.java @@ -0,0 +1,75 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +/** + * Tests filtering using Camel Test + */ +// START SNIPPET: example +// tag::example[] +public class FilterTest extends CamelTestSupport { + + @EndpointInject("mock:result") + protected MockEndpoint resultEndpoint; + + @Produce("direct:start") + protected ProducerTemplate template; + + @Override + public boolean isDumpRouteCoverage() { + return true; + } + + @Test + public void testSendMatchingMessage() throws Exception { + String expectedBody = "<matched/>"; + + resultEndpoint.expectedBodiesReceived(expectedBody); + + template.sendBodyAndHeader(expectedBody, "foo", "bar"); + + resultEndpoint.assertIsSatisfied(); + } + + @Test + public void testSendNotMatchingMessage() throws Exception { + resultEndpoint.expectedMessageCount(0); + + template.sendBodyAndHeader("<notMatched/>", "foo", "notMatchedHeaderValue"); + + resultEndpoint.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result"); + } + }; + } +} +// end::example[] +// END SNIPPET: example diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsAndSkipJUnit5Test.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsAndSkipJUnit5Test.java new file mode 100644 index 0000000..11c4bea --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsAndSkipJUnit5Test.java @@ -0,0 +1,65 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.seda.SedaEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +// START SNIPPET: e1 +// tag::e1[] +public class IsMockEndpointsAndSkipJUnit5Test extends CamelTestSupport { + + @Override + public String isMockEndpointsAndSkip() { + // override this method and return the pattern for which endpoints to mock, + // and skip sending to the original endpoint. + return "direct:foo"; + } + + @Test + public void testMockEndpointAndSkip() throws Exception { + // notice we have automatic mocked the direct:foo endpoints and the name of the endpoints is "mock:uri" + getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); + getMockEndpoint("mock:direct:foo").expectedMessageCount(1); + + template.sendBody("direct:start", "Hello World"); + + assertMockEndpointsSatisfied(); + + // the message was not send to the direct:foo route and thus not sent to the seda endpoint + SedaEndpoint seda = context.getEndpoint("seda:foo", SedaEndpoint.class); + assertEquals(0, seda.getCurrentQueueSize()); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").to("direct:foo").to("mock:result"); + + from("direct:foo").transform(constant("Bye World")).to("seda:foo"); + } + }; + } +} +// end::e1[] +// END SNIPPET: e1 diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsFileTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsFileTest.java new file mode 100644 index 0000000..6bedaa2 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsFileTest.java @@ -0,0 +1,68 @@ +/* + * 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.test.junit5.patterns; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class IsMockEndpointsFileTest extends CamelTestSupport { + + @Override + @BeforeEach + public void setUp() throws Exception { + deleteDirectory("target/input"); + deleteDirectory("target/messages"); + super.setUp(); + } + + @Override + public String isMockEndpoints() { + // override this method and return the pattern for which endpoints to mock. + return "file:target*"; + } + + @Test + public void testMockFileEndpoints() throws Exception { + // notice we have automatic mocked all endpoints and the name of the endpoints is "mock:uri" + MockEndpoint camel = getMockEndpoint("mock:file:target/messages/camel"); + camel.expectedMessageCount(1); + + MockEndpoint other = getMockEndpoint("mock:file:target/messages/others"); + other.expectedMessageCount(1); + + template.sendBodyAndHeader("file:target/input", "Hello Camel", Exchange.FILE_NAME, "camel.txt"); + template.sendBodyAndHeader("file:target/input", "Hello World", Exchange.FILE_NAME, "world.txt"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("file:target/input") + .choice() + .when(bodyAs(String.class).contains("Camel")).to("file:target/messages/camel") + .otherwise().to("file:target/messages/others"); + } + }; + } +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsJUnit5Test.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsJUnit5Test.java new file mode 100644 index 0000000..e8a9e27 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsJUnit5Test.java @@ -0,0 +1,72 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +// START SNIPPET: e1 +// tag::e1[] +public class IsMockEndpointsJUnit5Test extends CamelTestSupport { + + @Override + public String isMockEndpoints() { + // override this method and return the pattern for which endpoints to mock. + // use * to indicate all + return "*"; + } + + @Test + public void testMockAllEndpoints() throws Exception { + // notice we have automatic mocked all endpoints and the name of the endpoints is "mock:uri" + getMockEndpoint("mock:direct:start").expectedBodiesReceived("Hello World"); + getMockEndpoint("mock:direct:foo").expectedBodiesReceived("Hello World"); + getMockEndpoint("mock:log:foo").expectedBodiesReceived("Bye World"); + getMockEndpoint("mock:result").expectedBodiesReceived("Bye World"); + + template.sendBody("direct:start", "Hello World"); + + assertMockEndpointsSatisfied(); + + // additional test to ensure correct endpoints in registry + assertNotNull(context.hasEndpoint("direct:start")); + assertNotNull(context.hasEndpoint("direct:foo")); + assertNotNull(context.hasEndpoint("log:foo")); + assertNotNull(context.hasEndpoint("mock:result")); + // all the endpoints was mocked + assertNotNull(context.hasEndpoint("mock:direct:start")); + assertNotNull(context.hasEndpoint("mock:direct:foo")); + assertNotNull(context.hasEndpoint("mock:log:foo")); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").to("direct:foo").to("log:foo").to("mock:result"); + + from("direct:foo").transform(constant("Bye World")); + } + }; + } +} +// end::e1[] +// END SNIPPET: e1 diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsTest.java new file mode 100644 index 0000000..9bc4707 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/IsMockEndpointsTest.java @@ -0,0 +1,65 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class IsMockEndpointsTest extends CamelTestSupport { + + @Override + public String isMockEndpoints() { + return "*"; + } + + @Test + public void testMockAllEndpoints() throws Exception { + getMockEndpoint("mock:direct:start").expectedBodiesReceived("Hello World"); + getMockEndpoint("mock:direct:foo").expectedBodiesReceived("Hello World"); + getMockEndpoint("mock:log:foo").expectedBodiesReceived("Bye World"); + getMockEndpoint("mock:result").expectedBodiesReceived("Bye World"); + + template.sendBody("direct:start", "Hello World"); + + assertMockEndpointsSatisfied(); + + // additional test to ensure correct endpoints in registry + assertNotNull(context.hasEndpoint("direct:start")); + assertNotNull(context.hasEndpoint("direct:foo")); + assertNotNull(context.hasEndpoint("log:foo")); + assertNotNull(context.hasEndpoint("mock:result")); + // all the endpoints was mocked + assertNotNull(context.hasEndpoint("mock:direct:start")); + assertNotNull(context.hasEndpoint("mock:direct:foo")); + assertNotNull(context.hasEndpoint("mock:log:foo")); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start").to("direct:foo").to("log:foo").to("mock:result"); + + from("direct:foo").transform(constant("Bye World")); + } + }; + } +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MockEndpointFailNoHeaderTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MockEndpointFailNoHeaderTest.java new file mode 100644 index 0000000..8746df2 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MockEndpointFailNoHeaderTest.java @@ -0,0 +1,63 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; + +public class MockEndpointFailNoHeaderTest extends CamelTestSupport { + + @EndpointInject("mock:result") + protected MockEndpoint resultEndpoint; + + @Produce("direct:start") + protected ProducerTemplate template; + + @Override + public boolean isDumpRouteCoverage() { + return true; + } + + @Test + public void withHeaderTestCase() throws InterruptedException { + String expectedBody = "<matched/>"; + resultEndpoint.expectedHeaderReceived("foo", "bar"); + template.sendBodyAndHeader(expectedBody, "foo", "bar"); + resultEndpoint.assertIsSatisfied(); + } + + @Test + public void noHeaderTestCase() throws InterruptedException { + resultEndpoint.expectedHeaderReceived("foo", "bar"); + resultEndpoint.setResultWaitTime(1); // speedup test + resultEndpoint.assertIsNotSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result"); + } + }; + } +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MyProduceBean.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MyProduceBean.java new file mode 100644 index 0000000..95d7263 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MyProduceBean.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.test.junit5.patterns; + +import org.apache.camel.Produce; + +/** + * + */ +public class MyProduceBean { + + @Produce("mock:result") + MySender sender; + + public void doSomething(String body) { + sender.send(body); + } +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MySender.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MySender.java new file mode 100644 index 0000000..0188296 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/MySender.java @@ -0,0 +1,25 @@ +/* + * 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.test.junit5.patterns; + +/** + * + */ +public interface MySender { + + void send(String body); +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/ProduceBeanTest.java similarity index 55% copy from components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java copy to components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/ProduceBeanTest.java index 33987ac..0b7969b 100644 --- a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/ProduceBeanTest.java @@ -14,39 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.test.junit5; +package org.apache.camel.test.junit5.patterns; -import org.apache.camel.ProducerTemplate; -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.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; -@CamelTest -public class SimpleMockTest { +/** + * + */ +public class ProduceBeanTest extends CamelTestSupport { @Test - public void testMock(ProducerTemplate template, ModelCamelContext ctx) throws Exception { - MockEndpoint mockResult = ctx.getEndpoint("mock:result", MockEndpoint.class); - mockResult.expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - MockEndpoint.assertIsSatisfied(ctx); - } + public void testProduceBean() throws Exception { + getMockEndpoint("mock:result").expectedMessageCount(1); - /* Same test is shorter with junit4 - @Test - public void testMock() throws Exception { - getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); template.sendBody("direct:start", "Hello World"); + assertMockEndpointsSatisfied(); - }*/ + } - protected RoutesBuilder createRouteBuilder() throws Exception { + @Override + protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").to("mock:result"); + from("direct:start") + .bean(MyProduceBean.class, "doSomething"); } }; } diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/RouteBuilderConfigureExceptionTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/RouteBuilderConfigureExceptionTest.java new file mode 100644 index 0000000..46954b6 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/RouteBuilderConfigureExceptionTest.java @@ -0,0 +1,54 @@ +/* + * 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.test.junit5.patterns; + +import org.apache.camel.Predicate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.fail; + +public class RouteBuilderConfigureExceptionTest extends CamelTestSupport { + + private Predicate iAmNull; + + @Override + @BeforeEach + public void setUp() throws Exception { + try { + super.setUp(); + fail("Should have thrown exception"); + } catch (Exception e) { + // expected + } + } + + @Test + public void testFoo() throws Exception { + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:start").choice().when(iAmNull).to("mock:dead"); + } + }; + } +} diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/RouteProcessorDumpRouteCoverageTest.java similarity index 54% copy from components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java copy to components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/RouteProcessorDumpRouteCoverageTest.java index 33987ac..53150c0 100644 --- a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/RouteProcessorDumpRouteCoverageTest.java @@ -14,40 +14,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.test.junit5; +package org.apache.camel.test.junit5.patterns; -import org.apache.camel.ProducerTemplate; 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.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -@CamelTest -public class SimpleMockTest { +import static org.junit.jupiter.api.Assertions.assertEquals; - @Test - public void testMock(ProducerTemplate template, ModelCamelContext ctx) throws Exception { - MockEndpoint mockResult = ctx.getEndpoint("mock:result", MockEndpoint.class); - mockResult.expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - MockEndpoint.assertIsSatisfied(ctx); +public class RouteProcessorDumpRouteCoverageTest extends CamelTestSupport { + + @Override + public boolean isDumpRouteCoverage() { + return true; } - /* Same test is shorter with junit4 @Test - public void testMock() throws Exception { - getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - assertMockEndpointsSatisfied(); - }*/ + public void testProcessorJunit5() throws Exception { + String out = template.requestBody("direct:start", "Hello World", String.class); + assertEquals("Bye World", out); + } + @Override + @AfterEach + public void tearDown() throws Exception { + super.tearDown(); + // should create that file when test is done + assertFileExists("target/camel-route-coverage/RouteProcessorDumpRouteCoverageTest-testProcessorJunit5.xml"); + } + + @Override protected RoutesBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").to("mock:result"); + from("direct:start") + .process(exchange -> exchange.getOut().setBody("Bye World")); } }; } + } diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockEndpointsTest.java similarity index 58% copy from components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java copy to components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockEndpointsTest.java index 33987ac..6f32ff8 100644 --- a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockEndpointsTest.java @@ -14,40 +14,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.test.junit5; +package org.apache.camel.test.junit5.patterns; -import org.apache.camel.ProducerTemplate; 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.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; -@CamelTest -public class SimpleMockTest { +public class SimpleMockEndpointsTest extends CamelTestSupport { - @Test - public void testMock(ProducerTemplate template, ModelCamelContext ctx) throws Exception { - MockEndpoint mockResult = ctx.getEndpoint("mock:result", MockEndpoint.class); - mockResult.expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - MockEndpoint.assertIsSatisfied(ctx); + @Override + public String isMockEndpointsAndSkip() { + return "seda:queue"; } - /* Same test is shorter with junit4 @Test - public void testMock() throws Exception { - getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); + public void testMockAndSkip() throws Exception { + getMockEndpoint("mock:seda:queue").expectedBodiesReceived("Bye Camel"); + + template.sendBody("seda:start", "Camel"); + assertMockEndpointsSatisfied(); - }*/ + } + @Override protected RoutesBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").to("mock:result"); + from("seda:start") + .transform(simple("Bye ${body}")) + .to("seda:queue"); } }; } + } diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockTest.java similarity index 67% copy from components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java copy to components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockTest.java index 33987ac..beaa4c9 100644 --- a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockTest.java @@ -14,40 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.test.junit5; +package org.apache.camel.test.junit5.patterns; -import org.apache.camel.ProducerTemplate; 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.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; -@CamelTest -public class SimpleMockTest { +public class SimpleMockTest extends CamelTestSupport { @Test - public void testMock(ProducerTemplate template, ModelCamelContext ctx) throws Exception { - MockEndpoint mockResult = ctx.getEndpoint("mock:result", MockEndpoint.class); - mockResult.expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - MockEndpoint.assertIsSatisfied(ctx); - } - - /* Same test is shorter with junit4 - @Test public void testMock() throws Exception { getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); + template.sendBody("direct:start", "Hello World"); + assertMockEndpointsSatisfied(); - }*/ + } + @Override protected RoutesBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").to("mock:result"); + from("direct:start") + .to("mock:result"); } }; } + } diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockUsingExtensionTest.java similarity index 83% copy from components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java copy to components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockUsingExtensionTest.java index 33987ac..9b8d2d2 100644 --- a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleMockUsingExtensionTest.java @@ -14,17 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.test.junit5; +package org.apache.camel.test.junit5.patterns; import org.apache.camel.ProducerTemplate; 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.test.junit5.CamelTest; import org.junit.jupiter.api.Test; @CamelTest -public class SimpleMockTest { +public class SimpleMockUsingExtensionTest { @Test public void testMock(ProducerTemplate template, ModelCamelContext ctx) throws Exception { @@ -34,14 +35,6 @@ public class SimpleMockTest { MockEndpoint.assertIsSatisfied(ctx); } - /* Same test is shorter with junit4 - @Test - public void testMock() throws Exception { - getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - assertMockEndpointsSatisfied(); - }*/ - protected RoutesBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleNotifyBuilderTest.java similarity index 56% copy from components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java copy to components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleNotifyBuilderTest.java index 33987ac..ba91a1a 100644 --- a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleNotifyBuilderTest.java @@ -14,40 +14,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.test.junit5; +package org.apache.camel.test.junit5.patterns; + +import java.util.concurrent.TimeUnit; -import org.apache.camel.ProducerTemplate; import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.NotifyBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; -@CamelTest -public class SimpleMockTest { +import static org.junit.jupiter.api.Assertions.assertTrue; - @Test - public void testMock(ProducerTemplate template, ModelCamelContext ctx) throws Exception { - MockEndpoint mockResult = ctx.getEndpoint("mock:result", MockEndpoint.class); - mockResult.expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - MockEndpoint.assertIsSatisfied(ctx); - } +public class SimpleNotifyBuilderTest extends CamelTestSupport { - /* Same test is shorter with junit4 @Test - public void testMock() throws Exception { - getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - assertMockEndpointsSatisfied(); - }*/ + public void testNotifyBuilder() throws Exception { + NotifyBuilder notify = new NotifyBuilder(context) + .from("seda:start") + .wereSentTo("seda:queue") + .whenDone(10) + .create(); + + for (int i = 0; i < 10; i++) { + template.sendBody("seda:start", "Camel" + i); + } + boolean matches = notify.matches(10, TimeUnit.SECONDS); + assertTrue(matches); + } + + @Override protected RoutesBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").to("mock:result"); + from("seda:start") + .transform(simple("Bye ${body}")) + .to("seda:queue"); } }; } + } diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleWeaveAddMockLastTest.java similarity index 55% rename from components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java rename to components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleWeaveAddMockLastTest.java index 33987ac..aaf8800 100644 --- a/components/camel-test/src/test/java/org/apache/camel/test/junit5/SimpleMockTest.java +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/SimpleWeaveAddMockLastTest.java @@ -14,40 +14,48 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.test.junit5; +package org.apache.camel.test.junit5.patterns; -import org.apache.camel.ProducerTemplate; import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.AdviceWithRouteBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.reifier.RouteReifier; +import org.apache.camel.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; -@CamelTest -public class SimpleMockTest { +public class SimpleWeaveAddMockLastTest extends CamelTestSupport { - @Test - public void testMock(ProducerTemplate template, ModelCamelContext ctx) throws Exception { - MockEndpoint mockResult = ctx.getEndpoint("mock:result", MockEndpoint.class); - mockResult.expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); - MockEndpoint.assertIsSatisfied(ctx); + public boolean isUseAdviceWith() { + return true; } - /* Same test is shorter with junit4 @Test - public void testMock() throws Exception { - getMockEndpoint("mock:result").expectedBodiesReceived("Hello World"); - template.sendBody("direct:start", "Hello World"); + public void testWeaveAddMockLast() throws Exception { + RouteReifier.adviceWith(context.getRouteDefinitions().get(0), context, new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + weaveAddLast().to("mock:result"); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedBodiesReceived("Bye Camel"); + + template.sendBody("seda:start", "Camel"); + assertMockEndpointsSatisfied(); - }*/ + } + @Override protected RoutesBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:start").to("mock:result"); + from("seda:start") + .transform(simple("Bye ${body}")) + .to("seda:queue"); } }; } + } diff --git a/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/UseOverridePropertiesWithPropertiesComponentTest.java b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/UseOverridePropertiesWithPropertiesComponentTest.java new file mode 100644 index 0000000..d4a4719 --- /dev/null +++ b/components/camel-test/src/test/java/org/apache/camel/test/junit5/patterns/UseOverridePropertiesWithPropertiesComponentTest.java @@ -0,0 +1,78 @@ +/* + * 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.test.junit5.patterns; + +import java.util.Properties; + +import org.apache.camel.builder.AdviceWithRouteBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.reifier.RouteReifier; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class UseOverridePropertiesWithPropertiesComponentTest extends CamelTestSupport { + + @Override + public boolean isUseAdviceWith() { + return true; + } + + @BeforeEach + public void doSomethingBefore() throws Exception { + AdviceWithRouteBuilder mocker = new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + replaceFromWith("direct:sftp"); + + interceptSendToEndpoint("file:*") + .skipSendToOriginalEndpoint() + .to("mock:file"); + } + }; + RouteReifier.adviceWith(context.getRouteDefinition("myRoute"), context, mocker); + } + + @Override + protected Properties useOverridePropertiesWithPropertiesComponent() { + Properties pc = new Properties(); + pc.put("ftp.username", "scott"); + pc.put("ftp.password", "tiger"); + return pc; + } + + @Test + public void testOverride() throws Exception { + context.start(); + + getMockEndpoint("mock:file").expectedMessageCount(1); + + template.sendBody("direct:sftp", "Hello World"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("ftp:somepath?username={{ftp.username}}&password={{ftp.password}}").routeId("myRoute") + .to("file:target/out"); + } + }; + } +}