This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 0231dba4c3d CAMEL-21250: camel-report-maven-plugin - Can we cover 
anonymous routes if loaded from xml files (#16687)
0231dba4c3d is described below

commit 0231dba4c3d238191f1614289617f86b25cadca6
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Thu Jan 2 14:26:41 2025 +0100

    CAMEL-21250: camel-report-maven-plugin - Can we cover anonymous routes if 
loaded from xml files (#16687)
---
 .../org/apache/camel/maven/RouteCoverageMojo.java  | 80 ++++++++++++++++++----
 .../camel/parser/helper/RouteCoverageHelper.java   | 49 +++++++++++++
 .../apache/camel/parser/model/CoverageData.java    | 11 ++-
 .../management/mbean/RouteCoverageXmlParser.java   |  4 ++
 4 files changed, 129 insertions(+), 15 deletions(-)

diff --git 
a/catalog/camel-report-maven-plugin/src/main/java/org/apache/camel/maven/RouteCoverageMojo.java
 
b/catalog/camel-report-maven-plugin/src/main/java/org/apache/camel/maven/RouteCoverageMojo.java
index c0681586dd3..c803450584c 100644
--- 
a/catalog/camel-report-maven-plugin/src/main/java/org/apache/camel/maven/RouteCoverageMojo.java
+++ 
b/catalog/camel-report-maven-plugin/src/main/java/org/apache/camel/maven/RouteCoverageMojo.java
@@ -182,7 +182,8 @@ public class RouteCoverageMojo extends AbstractMojo {
         int totalNumberOfNodes = 0;
 
         List<CamelNodeDetails> routeIdTrees = routeTrees.stream().filter(t -> 
t.getRouteId() != null).toList();
-        List<CamelNodeDetails> anonymousRouteTrees = 
routeTrees.stream().filter(t -> t.getRouteId() == null).toList();
+        List<CamelNodeDetails> anonymousRouteTrees
+                = new ArrayList<>(routeTrees.stream().filter(t -> 
t.getRouteId() == null).toList());
         Document document = null;
         File file = null;
         Element report = null;
@@ -220,18 +221,48 @@ public class RouteCoverageMojo extends AbstractMojo {
 
             // grab dump data for the route
             totalNumberOfNodes
-                    = grabDumpData(t, routeId, totalNumberOfNodes, fileName, 
notCovered, coveredNodes, report, document,
+                    += grabDumpData(t, routeId, totalNumberOfNodes, fileName, 
notCovered, coveredNodes, report, document,
                             sourceFileName, pack);
         }
+        List<CamelNodeDetails> anonymousHandled = new ArrayList<>();
+        for (CamelNodeDetails t : anonymousRouteTrees) {
+            String fileName = stripRootPath(asRelativeFile(t.getFileName(), 
project), project);
+            String sourceFileName = new File(fileName).getName();
+            String packageName = new File(fileName).getParent();
+            String loc = sourceFileName + ":" + t.getLineNumber();
+            Element pack = null;
 
-        if (report != null) {
-            doGenerateJacocoReport(file, document);
+            if (report != null) {
+                // package tag
+                pack = document.createElement("package");
+                createAttrString(document, pack, "name", packageName);
+                report.appendChild(pack);
+            }
+
+            // grab dump data for the route
+            int extra = grabDumpDataBySourceLocation(t, loc, 
totalNumberOfNodes, fileName, notCovered, coveredNodes, report,
+                    document,
+                    sourceFileName, pack);
+            if (extra > 0) {
+                anonymousHandled.add(t);
+            }
+            totalNumberOfNodes += extra;
         }
+        anonymousRouteTrees.removeAll(anonymousHandled);
 
-        if (anonymousRoutes && !anonymousRouteTrees.isEmpty()) {
-            totalNumberOfNodes = handleAnonymousRoutes(anonymousRouteTrees, 
totalNumberOfNodes, notCovered, coveredNodes);
+        if (!anonymousRouteTrees.isEmpty()) {
+            if (anonymousRoutes) {
+                totalNumberOfNodes = 
handleAnonymousRoutes(anonymousRouteTrees, totalNumberOfNodes, notCovered, 
coveredNodes);
+            } else {
+                getLog().warn(
+                        "Discovered " + anonymousRouteTrees.size()
+                              + " anonymous routes. Add route ids to these 
routes for route coverage support.");
+            }
         }
 
+        if (report != null) {
+            doGenerateJacocoReport(file, document);
+        }
         if (generateHtmlReport) {
             doGenerateHtmlReport();
         }
@@ -279,14 +310,6 @@ public class RouteCoverageMojo extends AbstractMojo {
 
         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 (!anonymousRoutes && anonymous > 0) {
-            getLog().warn(
-                    "Discovered " + anonymous + " anonymous routes. Add route 
ids to these routes for route coverage support.");
-        }
-
         return routeTrees;
     }
 
@@ -318,6 +341,35 @@ public class RouteCoverageMojo extends AbstractMojo {
         return totalNumberOfNodes;
     }
 
+    private int grabDumpDataBySourceLocation(
+            CamelNodeDetails t, String sourceLocation, int totalNumberOfNodes, 
String fileName, AtomicInteger notCovered,
+            AtomicInteger coveredNodes, Element report, Document document, 
String sourceFileName, Element pack)
+            throws MojoExecutionException {
+        try {
+            List<CoverageData> coverageData = RouteCoverageHelper
+                    .parseDumpRouteCoverageByLineNumber(project.getBasedir() + 
DESTINATION_DIR, sourceLocation);
+            if (coverageData.isEmpty()) {
+                getLog().warn("No route coverage data found for route: " + 
sourceLocation
+                              + ". Make sure to enable route coverage in your 
unit tests and assign unique route ids to your routes. Also remember to run 
unit tests first.");
+            } else {
+                List<RouteCoverageNode> coverage = 
gatherRouteCoverageSummary(List.of(t), coverageData);
+                totalNumberOfNodes += coverage.size();
+                String routeId = coverageData.get(0).getRouteId();
+                String out = templateCoverageData(fileName, routeId, coverage, 
notCovered, coveredNodes);
+                getLog().info("Route coverage summary:\n\n" + out);
+                getLog().info("");
+
+                if (report != null) {
+                    appendSourcefileNode(document, sourceFileName, pack, 
coverage);
+                }
+            }
+
+        } catch (Exception e) {
+            throw new MojoExecutionException("Error during gathering route 
coverage data for route: " + sourceFileName, e);
+        }
+        return totalNumberOfNodes;
+    }
+
     private void doGenerateJacocoReport(File file, Document document) {
         try {
             getLog().info("Generating Jacoco XML report: " + file + "\n\n");
diff --git 
a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/RouteCoverageHelper.java
 
b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/RouteCoverageHelper.java
index ceb3d5bc265..1a696231414 100644
--- 
a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/RouteCoverageHelper.java
+++ 
b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/helper/RouteCoverageHelper.java
@@ -81,6 +81,55 @@ public final class RouteCoverageHelper {
         return answer;
     }
 
+    /**
+     * Parses the dumped route coverage data and creates a line by line 
coverage data
+     *
+     * @param  directory      the directory with the dumped route coverage data
+     * @param  sourceLocation the location of the route (filename:line)
+     * @return                line by line coverage data
+     */
+    public static List<CoverageData> parseDumpRouteCoverageByLineNumber(String 
directory, String sourceLocation)
+            throws Exception {
+        List<CoverageData> answer = new ArrayList<>();
+
+        if (sourceLocation == null) {
+            return answer;
+        }
+
+        File[] files = new File(directory).listFiles(f -> 
f.getName().endsWith(".xml"));
+        if (files == null) {
+            return answer;
+        }
+
+        CamelCatalog catalog = new DefaultCamelCatalog(true);
+
+        for (File file : files) {
+            try (FileInputStream fis = new FileInputStream(file)) {
+                Document dom = XmlLineNumberParser.parseXml(fis);
+                NodeList routes = dom.getElementsByTagName("route");
+                for (int i = 0; i < routes.getLength(); i++) {
+                    Node route = routes.item(i);
+                    Node n = route.getAttributes().getNamedItem("id");
+                    String id = n != null ? n.getNodeValue() : null;
+                    n = route.getAttributes().getNamedItem("sourceLocation");
+                    String loc = n != null ? n.getNodeValue() : null;
+                    if (sourceLocation.equals(loc)) {
+                        // parse each route and build a List<CoverageData> for 
line by line coverage data
+                        AtomicInteger counter = new AtomicInteger();
+                        List<CoverageData> list = new ArrayList<>();
+                        parseRouteData(catalog, route, list, counter);
+                        if (id != null && !list.isEmpty()) {
+                            list.get(0).setRouteId(id);
+                        }
+                        answer.addAll(list);
+                    }
+                }
+            }
+        }
+
+        return answer;
+    }
+
     public static Map<String, List<CoverageData>> 
parseDumpRouteCoverageByClassAndTestMethod(String directory)
             throws Exception {
         Map<String, List<CoverageData>> answer = new LinkedHashMap<>();
diff --git 
a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/model/CoverageData.java
 
b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/model/CoverageData.java
index 403d682859c..13bfeb4f80d 100644
--- 
a/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/model/CoverageData.java
+++ 
b/catalog/camel-route-parser/src/main/java/org/apache/camel/parser/model/CoverageData.java
@@ -23,10 +23,11 @@ public class CoverageData {
 
     private final String node;
     private final int count;
+    private String routeId;
 
     public CoverageData(String node, int count) {
-        this.count = count;
         this.node = node;
+        this.count = count;
     }
 
     public String getNode() {
@@ -36,4 +37,12 @@ public class CoverageData {
     public int getCount() {
         return count;
     }
+
+    public void setRouteId(String routeId) {
+        this.routeId = routeId;
+    }
+
+    public String getRouteId() {
+        return routeId;
+    }
 }
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/RouteCoverageXmlParser.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/RouteCoverageXmlParser.java
index 4b3a3c2dbc8..50df46a5730 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/RouteCoverageXmlParser.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/RouteCoverageXmlParser.java
@@ -115,6 +115,10 @@ public final class RouteCoverageXmlParser {
                         ManagedRouteMBean route = 
camelContext.getCamelContextExtension()
                                 
.getContextPlugin(ManagedCamelContext.class).getManagedRoute(id);
                         if (route != null) {
+                            String loc = route.getSourceLocationShort();
+                            if (loc != null) {
+                                el.setAttribute("sourceLocation", loc);
+                            }
                             long total = route.getExchangesTotal();
                             el.setAttribute("exchangesTotal", 
Long.toString(total));
                             long totalTime = route.getTotalProcessingTime();

Reply via email to