You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2017/10/08 12:02:51 UTC
[08/13] camel git commit: Add RouteCoverage annotation to
camel-test-spring to make it easy to turn on
Add RouteCoverage annotation to camel-test-spring to make it easy to turn on
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/702f4a98
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/702f4a98
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/702f4a98
Branch: refs/heads/parser2
Commit: 702f4a98a608f63ac15f4d49c0542a7daa190556
Parents: b05a46d
Author: Claus Ibsen <da...@apache.org>
Authored: Sat Oct 7 20:48:24 2017 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Sat Oct 7 20:48:24 2017 +0200
----------------------------------------------------------------------
.../test/spring/CamelAnnotationsHandler.java | 15 +
.../CamelSpringBootExecutionListener.java | 1 +
.../CamelSpringDelegatingTestContextLoader.java | 1 +
.../spring/CamelSpringTestContextLoader.java | 42 ++-
...gTestContextLoaderTestExecutionListener.java | 3 +-
.../test/spring/CamelSpringTestHelper.java | 14 +-
.../apache/camel/test/spring/RouteCoverage.java | 39 +++
.../test/spring/RouteCoverageEventNotifier.java | 96 ++++++
...ringRouteProcessorDumpRouteCoverageTest.java | 55 ++++
.../test/spring/CamelSpringRunnerPlainTest.java | 5 +
.../camel/test/junit4/CamelTestSupport.java | 4 +-
.../java/sample/camel/SampleCamelRouter.java | 2 +-
.../apache/camel/parser/graph/RenderRoute.java | 4 +
.../java/RoasterJavaDslTwoRoutesTest.java | 2 +-
.../org/apache/camel/maven/CoverageMojo.java | 323 +++++++++++++++++++
15 files changed, 594 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelAnnotationsHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelAnnotationsHandler.java b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelAnnotationsHandler.java
index 8902f4f..c27f7783 100644
--- a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelAnnotationsHandler.java
+++ b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelAnnotationsHandler.java
@@ -69,6 +69,21 @@ public final class CamelAnnotationsHandler {
}
}
+ /**
+ * Handles disabling of JMX on Camel contexts based on {@link DisableJmx}.
+ *
+ * @param context the initialized Spring context
+ * @param testClass the test class being executed
+ */
+ public static void handleRouteCoverage(ConfigurableApplicationContext context, Class<?> testClass) {
+ if (testClass.isAnnotationPresent(RouteCoverage.class)) {
+ LOGGER.info("Enabling RouteCoverage");
+ // JMX must be enabled to turn on route coverage
+ System.clearProperty(JmxSystemPropertyKeys.DISABLED);
+ System.setProperty("CamelTestRouteCoverage", "true");
+ }
+ }
+
public static void handleProvidesBreakpoint(ConfigurableApplicationContext context, Class<?> testClass) throws Exception {
Collection<Method> methods = getAllMethods(testClass);
final List<Breakpoint> breakpoints = new LinkedList<Breakpoint>();
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringBootExecutionListener.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringBootExecutionListener.java b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringBootExecutionListener.java
index 546462d..f693011 100644
--- a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringBootExecutionListener.java
+++ b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringBootExecutionListener.java
@@ -42,6 +42,7 @@ public class CamelSpringBootExecutionListener extends AbstractTestExecutionListe
ConfigurableApplicationContext context = (ConfigurableApplicationContext) testContext.getApplicationContext();
// Post CamelContext(s) instantiation but pre CamelContext(s) start setup
+ CamelAnnotationsHandler.handleRouteCoverage(context, testClass);
CamelAnnotationsHandler.handleProvidesBreakpoint(context, testClass);
CamelAnnotationsHandler.handleShutdownTimeout(context, testClass);
CamelAnnotationsHandler.handleMockEndpoints(context, testClass);
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringDelegatingTestContextLoader.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringDelegatingTestContextLoader.java b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringDelegatingTestContextLoader.java
index 380fac0..9595d8a 100644
--- a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringDelegatingTestContextLoader.java
+++ b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringDelegatingTestContextLoader.java
@@ -77,6 +77,7 @@ public class CamelSpringDelegatingTestContextLoader extends DelegatingSmartConte
AnnotationConfigUtils.registerAnnotationConfigProcessors((BeanDefinitionRegistry) context);
// Post CamelContext(s) instantiation but pre CamelContext(s) start setup
+ CamelAnnotationsHandler.handleRouteCoverage(context, testClass);
CamelAnnotationsHandler.handleProvidesBreakpoint(context, testClass);
CamelAnnotationsHandler.handleShutdownTimeout(context, testClass);
CamelAnnotationsHandler.handleMockEndpoints(context, testClass);
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoader.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoader.java b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoader.java
index b595ce3..939a57c 100644
--- a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoader.java
+++ b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoader.java
@@ -107,7 +107,7 @@ public class CamelSpringTestContextLoader extends AbstractContextLoader {
public ApplicationContext loadContext(String... locations) throws Exception {
Class<?> testClass = getTestClass();
-
+
if (LOG.isDebugEnabled()) {
LOG.debug("Loading ApplicationContext for locations [" + StringUtils.arrayToCommaDelimitedString(locations) + "].");
}
@@ -153,6 +153,7 @@ public class CamelSpringTestContextLoader extends AbstractContextLoader {
SpringCamelContext.setNoStart(false);
// Post CamelContext(s) instantiation but pre CamelContext(s) start setup
+ handleRouteCoverage(context, testClass);
handleProvidesBreakpoint(context, testClass);
handleShutdownTimeout(context, testClass);
handleMockEndpoints(context, testClass);
@@ -204,7 +205,6 @@ public class CamelSpringTestContextLoader extends AbstractContextLoader {
if (mergedConfig != null) {
parentContext = mergedConfig.getParentApplicationContext();
-
}
if (testClass.isAnnotationPresent(ExcludeRoutes.class)) {
@@ -258,7 +258,7 @@ public class CamelSpringTestContextLoader extends AbstractContextLoader {
*/
protected void handleDisableJmx(GenericApplicationContext context, Class<?> testClass) {
CamelSpringTestHelper.setOriginalJmxDisabledValue(System.getProperty(JmxSystemPropertyKeys.DISABLED));
-
+
if (testClass.isAnnotationPresent(DisableJmx.class)) {
if (testClass.getAnnotation(DisableJmx.class).value()) {
LOG.info("Disabling Camel JMX globally as DisableJmx annotation was found and disableJmx is set to true.");
@@ -267,12 +267,34 @@ public class CamelSpringTestContextLoader extends AbstractContextLoader {
LOG.info("Enabling Camel JMX as DisableJmx annotation was found and disableJmx is set to false.");
System.clearProperty(JmxSystemPropertyKeys.DISABLED);
}
- } else {
+ } else if (!testClass.isAnnotationPresent(RouteCoverage.class)) {
+ // route coverage need JMX so do not disable it by default
LOG.info("Disabling Camel JMX globally for tests by default. Use the DisableJMX annotation to override the default setting.");
System.setProperty(JmxSystemPropertyKeys.DISABLED, "true");
}
}
-
+
+ /**
+ * Handles disabling of JMX on Camel contexts based on {@link DisableJmx}.
+ *
+ * @param context the initialized Spring context
+ * @param testClass the test class being executed
+ */
+ private void handleRouteCoverage(GenericApplicationContext context, Class<?> testClass) throws Exception {
+ if (testClass.isAnnotationPresent(RouteCoverage.class)) {
+ System.setProperty("CamelTestRouteCoverage", "true");
+
+ CamelSpringTestHelper.doToSpringCamelContexts(context, new DoToSpringCamelContextsStrategy() {
+
+ @Override
+ public void execute(String contextName, SpringCamelContext camelContext) throws Exception {
+ LOG.info("Enabling RouteCoverage");
+ camelContext.getManagementStrategy().addEventNotifier(new RouteCoverageEventNotifier(testClass.getName(), (String) -> getTestMethod().getName()));
+ }
+ });
+ }
+ }
+
/**
* Handles the processing of the {@link ProvidesBreakpoint} annotation on a test class. Exists here
* as it is needed in
@@ -504,4 +526,14 @@ public class CamelSpringTestContextLoader extends AbstractContextLoader {
protected Class<?> getTestClass() {
return CamelSpringTestHelper.getTestClass();
}
+
+ /**
+ * Returns the test method under test.
+ *
+ * @return the method that is being executed
+ * @see CamelSpringTestHelper
+ */
+ protected Method getTestMethod() {
+ return CamelSpringTestHelper.getTestMethod();
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoaderTestExecutionListener.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoaderTestExecutionListener.java b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoaderTestExecutionListener.java
index d8533d1..100b998 100644
--- a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoaderTestExecutionListener.java
+++ b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestContextLoaderTestExecutionListener.java
@@ -45,5 +45,6 @@ public class CamelSpringTestContextLoaderTestExecutionListener extends AbstractT
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
CamelSpringTestHelper.setTestClass(testContext.getTestClass());
- }
+ CamelSpringTestHelper.setTestContext(testContext);
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestHelper.java b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestHelper.java
index aa75c0e..1c426b4 100644
--- a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestHelper.java
+++ b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/CamelSpringTestHelper.java
@@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.TestContext;
/**
* Helper that provides state information across the levels of Spring Test that do not expose the
@@ -41,7 +42,8 @@ public final class CamelSpringTestHelper {
private static ThreadLocal<String> originalJmxDisabledValue = new ThreadLocal<String>();
private static ThreadLocal<Class<?>> testClazz = new ThreadLocal<Class<?>>();
-
+ private static ThreadLocal<TestContext> testContext = new ThreadLocal<TestContext>();
+
private CamelSpringTestHelper() {
}
@@ -60,7 +62,15 @@ public final class CamelSpringTestHelper {
public static void setTestClass(Class<?> testClass) {
testClazz.set(testClass);
}
-
+
+ public static Method getTestMethod() {
+ return testContext.get().getTestMethod();
+ }
+
+ public static void setTestContext(TestContext context) {
+ testContext.set(context);
+ }
+
/**
* Returns all methods defined in {@code clazz} and its superclasses/interfaces.
*/
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/RouteCoverage.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/RouteCoverage.java b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/RouteCoverage.java
new file mode 100644
index 0000000..df92663
--- /dev/null
+++ b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/RouteCoverage.java
@@ -0,0 +1,39 @@
+/**
+ * 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.spring;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Enables dumping route coverage statistic.
+ * The route coverage status is written as xml files in the <tt>target/camel-route-coverage</tt> directory after the test has finished.
+ * <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.
+ */
+@Documented
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface RouteCoverage {
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/RouteCoverageEventNotifier.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/RouteCoverageEventNotifier.java b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/RouteCoverageEventNotifier.java
new file mode 100644
index 0000000..7be9370
--- /dev/null
+++ b/components/camel-test-spring/src/main/java/org/apache/camel/test/spring/RouteCoverageEventNotifier.java
@@ -0,0 +1,96 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.spring;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.EventObject;
+import java.util.function.Function;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.api.management.mbean.ManagedCamelContextMBean;
+import org.apache.camel.management.event.CamelContextStoppingEvent;
+import org.apache.camel.support.EventNotifierSupport;
+import org.apache.camel.util.IOHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RouteCoverageEventNotifier extends EventNotifierSupport {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RouteCoverageEventNotifier.class);
+
+ private final String testClassName;
+ private final Function testMethodName;
+
+ public RouteCoverageEventNotifier(String testClassName, Function testMethodName) {
+ this.testClassName = testClassName;
+ this.testMethodName = testMethodName;
+ }
+
+ @Override
+ public boolean isEnabled(EventObject event) {
+ return event instanceof CamelContextStoppingEvent;
+ }
+
+ @Override
+ public void notify(EventObject event) throws Exception {
+ CamelContext context = ((CamelContextStoppingEvent) event).getContext();
+ try {
+ String className = this.getClass().getSimpleName();
+ String dir = "target/camel-route-coverage";
+ String testName = (String) testMethodName.apply(this);
+ String name = className + "-" + testName + ".xml";
+
+ ManagedCamelContextMBean managedCamelContext = context.getManagedCamelContext();
+ if (managedCamelContext == null) {
+ LOG.warn("Cannot dump route coverage to file as JMX is not enabled. Override useJmx() method to enable JMX in the unit test classes.");
+ } else {
+ String xml = managedCamelContext.dumpRoutesCoverageAsXml();
+ String combined = "<camelRouteCoverage>\n" + gatherTestDetailsAsXml(testName) + 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);
+ }
+ } catch (Exception e) {
+ LOG.warn("Error during dumping route coverage statistic. This exception is ignored.", e);
+ }
+ }
+
+ /**
+ * Gathers test details as xml
+ */
+ private String gatherTestDetailsAsXml(String testName) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<test>\n");
+ sb.append(" <class>").append(testClassName).append("</class>\n");
+ sb.append(" <method>").append(testName).append("</method>\n");
+ sb.append("</test>\n");
+ return sb.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRouteProcessorDumpRouteCoverageTest.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRouteProcessorDumpRouteCoverageTest.java b/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRouteProcessorDumpRouteCoverageTest.java
new file mode 100644
index 0000000..b910e7b
--- /dev/null
+++ b/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRouteProcessorDumpRouteCoverageTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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.spring;
+
+import java.io.File;
+
+import org.apache.camel.management.ManagedManagementStrategy;
+import org.apache.camel.test.junit4.TestSupport;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+@RouteCoverage
+public class CamelSpringRouteProcessorDumpRouteCoverageTest extends CamelSpringRunnerPlainTest {
+
+ @BeforeClass
+ public static void prepareFiles() throws Exception {
+ TestSupport.deleteDirectory("target/camel-route-coverage");
+ }
+
+ @Test
+ public void testJmx() throws Exception {
+ // JMX is enabled with route coverage
+ assertEquals(ManagedManagementStrategy.class, camelContext.getManagementStrategy().getClass());
+ }
+
+ @Override
+ public void testRouteCoverage() throws Exception{
+ camelContext.stop();
+ camelContext2.stop();
+
+ // there should be files
+ String[] names = new File("target/camel-route-coverage").list();
+ assertNotNull(names);
+ assertTrue(names.length > 0);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRunnerPlainTest.java
----------------------------------------------------------------------
diff --git a/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRunnerPlainTest.java b/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRunnerPlainTest.java
index 17fa2d6..39b2d88 100644
--- a/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRunnerPlainTest.java
+++ b/components/camel-test-spring/src/test/java/org/apache/camel/test/spring/CamelSpringRunnerPlainTest.java
@@ -118,6 +118,11 @@ public class CamelSpringRunnerPlainTest {
assertNull(camelContext2.getDebugger());
}
+ @Test
+ public void testRouteCoverage() throws Exception {
+ // noop
+ }
+
}
// end::example[]
// END SNIPPET: e1
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
----------------------------------------------------------------------
diff --git a/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java b/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
index 632b8b0..2206822 100644
--- a/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
+++ b/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
@@ -391,7 +391,8 @@ public abstract class CamelTestSupport extends TestSupport {
log.info("Took: " + TimeUtils.printDuration(time) + " (" + time + " millis)");
// if we should dump route stats, then write that to a file
- if (isDumpRouteCoverage()) {
+ boolean coverage = System.getProperty("CamelTestRouteCoverage", "false").equalsIgnoreCase("true") || isDumpRouteCoverage();
+ if (coverage) {
String className = this.getClass().getSimpleName();
String dir = "target/camel-route-coverage";
String name = className + "-" + getTestMethodName() + ".xml";
@@ -485,7 +486,6 @@ public abstract class CamelTestSupport extends TestSupport {
builder.append(routesSummary);
log.info(builder.toString());
-
}
/**
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/examples/camel-example-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java b/examples/camel-example-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
index 4e0422e..20cf957 100644
--- a/examples/camel-example-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
+++ b/examples/camel-example-spring-boot/src/main/java/sample/camel/SampleCamelRouter.java
@@ -29,7 +29,7 @@ public class SampleCamelRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
- from("timer:hello?period={{timer.period}}")
+ from("timer:hello?period={{timer.period}}").routeId("hello")
.transform(method("myBean", "saySomething"))
.to("stream:out");
}
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java
----------------------------------------------------------------------
diff --git a/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java
index 2b1cd1c..a1f4807 100644
--- a/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java
+++ b/tooling/camel-route-parser/src/main/java/org/apache/camel/parser/graph/RenderRoute.java
@@ -24,6 +24,10 @@ import javax.imageio.ImageIO;
import org.apache.camel.parser.model.CamelNodeDetails;
+/**
+ * @deprecated experiment to render a route via Java image
+ */
+@Deprecated
public class RenderRoute {
public static void main(String[] args) {
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTwoRoutesTest.java
----------------------------------------------------------------------
diff --git a/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTwoRoutesTest.java b/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTwoRoutesTest.java
index 4e555a9..23ccef6 100644
--- a/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTwoRoutesTest.java
+++ b/tooling/camel-route-parser/src/test/java/org/apache/camel/parser/java/RoasterJavaDslTwoRoutesTest.java
@@ -51,7 +51,7 @@ public class RoasterJavaDslTwoRoutesTest extends CamelTestSupport {
assertEquals("src/test/java/org/apache/camel/parser/java/TwoRoutesRouteBuilder.java", details2.getFileName());
assertEquals("foo", details.getRouteId());
- assertEquals("bar", details.getRouteId());
+ assertEquals("bar", details2.getRouteId());
String tree = details.dump(0);
LOG.info("\n" + tree);
http://git-wip-us.apache.org/repos/asf/camel/blob/702f4a98/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/CoverageMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/CoverageMojo.java b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/CoverageMojo.java
new file mode 100644
index 0000000..e529587
--- /dev/null
+++ b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/CoverageMojo.java
@@ -0,0 +1,323 @@
+/**
+ * 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.maven;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.camel.maven.helper.EndpointHelper;
+import org.apache.camel.parser.RouteBuilderParser;
+import org.apache.camel.parser.model.CamelEndpointDetails;
+import org.apache.camel.parser.model.CamelNodeDetails;
+import org.apache.camel.parser.model.CamelRouteDetails;
+import org.apache.camel.parser.model.CamelSimpleExpressionDetails;
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.mojo.exec.AbstractExecMojo;
+import org.jboss.forge.roaster.Roaster;
+import org.jboss.forge.roaster.model.JavaType;
+import org.jboss.forge.roaster.model.source.JavaClassSource;
+
+/**
+ * Performs route coverage reports after running Camel unit tests with camel-test modules
+ *
+ * @goal coverage
+ * @threadSafe
+ */
+public class CoverageMojo extends AbstractExecMojo {
+
+ /**
+ * The maven project.
+ *
+ * @parameter property="project"
+ * @required
+ * @readonly
+ */
+ protected MavenProject project;
+
+ /**
+ * Whether to fail if a route was not fully covered
+ *
+ * @parameter property="camel.failOnError"
+ * default-value="false"
+ */
+ private boolean failOnError;
+
+ /**
+ * Whether to include test source code
+ *
+ * @parameter property="camel.includeTest"
+ * default-value="false"
+ */
+ private boolean includeTest;
+
+ /**
+ * To filter the names of java and xml files to only include files matching any of the given list of patterns (wildcard and regular expression).
+ * Multiple values can be separated by comma.
+ *
+ * @parameter property="camel.includes"
+ */
+ private String includes;
+
+ /**
+ * To filter the names of java and xml files to exclude files matching any of the given list of patterns (wildcard and regular expression).
+ * Multiple values can be separated by comma.
+ *
+ * @parameter property="camel.excludes"
+ */
+ private String excludes;
+
+ // CHECKSTYLE:OFF
+ @Override
+ public void execute() throws MojoExecutionException, MojoFailureException {
+
+ List<CamelEndpointDetails> endpoints = new ArrayList<>();
+ List<CamelSimpleExpressionDetails> simpleExpressions = new ArrayList<>();
+ List<CamelRouteDetails> routeIds = new ArrayList<>();
+ Set<File> javaFiles = new LinkedHashSet<File>();
+ Set<File> xmlFiles = new LinkedHashSet<File>();
+
+ // find all java route builder classes
+ List list = project.getCompileSourceRoots();
+ for (Object obj : list) {
+ String dir = (String) obj;
+ findJavaFiles(new File(dir), javaFiles);
+ }
+ // find all xml routes
+ list = project.getResources();
+ for (Object obj : list) {
+ Resource dir = (Resource) obj;
+ findXmlFiles(new File(dir.getDirectory()), xmlFiles);
+ }
+
+ if (includeTest) {
+ list = project.getTestCompileSourceRoots();
+ for (Object obj : list) {
+ String dir = (String) obj;
+ findJavaFiles(new File(dir), javaFiles);
+ }
+ list = project.getTestResources();
+ for (Object obj : list) {
+ Resource dir = (Resource) obj;
+ findXmlFiles(new File(dir.getDirectory()), xmlFiles);
+ }
+ }
+
+ List<CamelNodeDetails> routeTrees = new ArrayList<>();
+
+ for (File file : javaFiles) {
+ if (matchFile(file)) {
+ try {
+
+ // parse the java source code and find Camel RouteBuilder classes
+ String fqn = file.getPath();
+ String baseDir = ".";
+ JavaType out = Roaster.parse(file);
+ // we should only parse java classes (not interfaces and enums etc)
+ if (out != null && out instanceof JavaClassSource) {
+ JavaClassSource clazz = (JavaClassSource) out;
+ List<CamelNodeDetails> result = RouteBuilderParser.parseRouteBuilderTree(clazz, baseDir, fqn, true);
+ routeTrees.addAll(result);
+ }
+ } catch (Exception e) {
+ getLog().warn("Error parsing java file " + file + " code due " + e.getMessage(), e);
+ }
+ }
+ }
+ for (File file : xmlFiles) {
+ if (matchFile(file)) {
+ try {
+ // TODO: implement me
+ } catch (Exception e) {
+ getLog().warn("Error parsing xml file " + file + " code due " + e.getMessage(), e);
+ }
+ }
+ }
+
+ getLog().info("Discovered " + routeTrees.size() + " routes");
+
+ // skip any routes which has no route id assigned
+
+ long anonymous = routeTrees.stream().filter(t -> t.getRouteId() == null).count();
+ if (anonymous > 0) {
+ getLog().warn("Discovered " + anonymous + " anonymous routes. Add route ids to these routes for route coverage support");
+ }
+
+ routeTrees = routeTrees.stream().filter(t -> t.getRouteId() != null).collect(Collectors.toList());
+
+ routeTrees.forEach(t -> {
+ String routeId = t.getRouteId();
+ String fileName = asRelativeFile(t.getFileName());
+ String tree = t.dump(4);
+
+ getLog().info("Route " + routeId + " discovered in file " + fileName);
+ getLog().info("\n" + tree + "\n");
+ });
+
+ int notCovered = 0;
+
+ if (failOnError && (notCovered > 0)) {
+ throw new MojoExecutionException("Some routes are not fully covered");
+ }
+ }
+ // CHECKSTYLE:ON
+
+ private static int countRouteId(List<CamelRouteDetails> details, String routeId) {
+ int answer = 0;
+ for (CamelRouteDetails detail : details) {
+ if (routeId.equals(detail.getRouteId())) {
+ answer++;
+ }
+ }
+ return answer;
+ }
+
+ private void findJavaFiles(File dir, Set<File> javaFiles) {
+ File[] files = dir.isDirectory() ? dir.listFiles() : null;
+ if (files != null) {
+ for (File file : files) {
+ if (file.getName().endsWith(".java")) {
+ javaFiles.add(file);
+ } else if (file.isDirectory()) {
+ findJavaFiles(file, javaFiles);
+ }
+ }
+ }
+ }
+
+ private void findXmlFiles(File dir, Set<File> xmlFiles) {
+ File[] files = dir.isDirectory() ? dir.listFiles() : null;
+ if (files != null) {
+ for (File file : files) {
+ if (file.getName().endsWith(".xml")) {
+ xmlFiles.add(file);
+ } else if (file.isDirectory()) {
+ findXmlFiles(file, xmlFiles);
+ }
+ }
+ }
+ }
+
+ private boolean matchFile(File file) {
+ if (excludes == null && includes == null) {
+ return true;
+ }
+
+ // exclude take precedence
+ if (excludes != null) {
+ for (String exclude : excludes.split(",")) {
+ exclude = exclude.trim();
+ // try both with and without directory in the name
+ String fqn = stripRootPath(asRelativeFile(file.getAbsolutePath()));
+ boolean match = EndpointHelper.matchPattern(fqn, exclude) || EndpointHelper.matchPattern(file.getName(), exclude);
+ if (match) {
+ return false;
+ }
+ }
+ }
+
+ // include
+ if (includes != null) {
+ for (String include : includes.split(",")) {
+ include = include.trim();
+ // try both with and without directory in the name
+ String fqn = stripRootPath(asRelativeFile(file.getAbsolutePath()));
+ boolean match = EndpointHelper.matchPattern(fqn, include) || EndpointHelper.matchPattern(file.getName(), include);
+ if (match) {
+ return true;
+ }
+ }
+ // did not match any includes
+ return false;
+ }
+
+ // was not excluded nor failed include so its accepted
+ return true;
+ }
+
+ private String asRelativeFile(String name) {
+ String answer = name;
+
+ String base = project.getBasedir().getAbsolutePath();
+ if (name.startsWith(base)) {
+ answer = name.substring(base.length());
+ // skip leading slash for relative path
+ if (answer.startsWith(File.separator)) {
+ answer = answer.substring(1);
+ }
+ }
+ return answer;
+ }
+
+ private String stripRootPath(String name) {
+ // strip out any leading source / resource directory
+
+ List list = project.getCompileSourceRoots();
+ for (Object obj : list) {
+ String dir = (String) obj;
+ dir = asRelativeFile(dir);
+ if (name.startsWith(dir)) {
+ return name.substring(dir.length() + 1);
+ }
+ }
+ list = project.getTestCompileSourceRoots();
+ for (Object obj : list) {
+ String dir = (String) obj;
+ dir = asRelativeFile(dir);
+ if (name.startsWith(dir)) {
+ return name.substring(dir.length() + 1);
+ }
+ }
+ List resources = project.getResources();
+ for (Object obj : resources) {
+ Resource resource = (Resource) obj;
+ String dir = asRelativeFile(resource.getDirectory());
+ if (name.startsWith(dir)) {
+ return name.substring(dir.length() + 1);
+ }
+ }
+ resources = project.getTestResources();
+ for (Object obj : resources) {
+ Resource resource = (Resource) obj;
+ String dir = asRelativeFile(resource.getDirectory());
+ if (name.startsWith(dir)) {
+ return name.substring(dir.length() + 1);
+ }
+ }
+
+ return name;
+ }
+
+ private static String asPackageName(String name) {
+ return name.replace(File.separator, ".");
+ }
+
+ private static String asSimpleClassName(String className) {
+ int dot = className.lastIndexOf('.');
+ if (dot > 0) {
+ return className.substring(dot + 1);
+ } else {
+ return className;
+ }
+ }
+}