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

org.apache.camel.test.CamelRouteCoverageDumper Maven / Gradle / Ivy

There is a newer version: 4.9.0
Show newest version
/*
 * 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;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

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 org.apache.camel.Route;
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.model.ModelCamelContext;
import org.apache.camel.util.IOHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A CamelRouteCoverageDumper instance dumps the route coverage of a given camel test.
 */
public class CamelRouteCoverageDumper {

    private static final Logger LOG = LoggerFactory.getLogger(CamelRouteCoverageDumper.class);

    public void dump(
            ManagedCamelContextMBean managedCamelContext, ModelCamelContext context, String dumpDir, String dumpFilename,
            String testClass, String testName,
            long testTimeTaken)
            throws Exception {
        logCoverageSummary(managedCamelContext, context);

        String routeCoverageAsXml = managedCamelContext.dumpRoutesCoverageAsXml();
        String combined = "\n" + gatherTestDetailsAsXml(testClass, testName, testTimeTaken)
                          + routeCoverageAsXml + "\n";

        File dumpFile = new File(dumpDir);
        // ensure dir exists
        dumpFile.mkdirs();
        dumpFile = new File(dumpDir, dumpFilename);

        LOG.info("Dumping route coverage to file: {}", dumpFile);
        InputStream is = new ByteArrayInputStream(combined.getBytes());
        OutputStream os = new FileOutputStream(dumpFile, false);
        IOHelper.copyAndCloseInput(is, os);
        IOHelper.close(os);
    }

    /**
     * Groups all processors from Camel context by route id.
     */
    private Map> findProcessorsForEachRoute(MBeanServer server, ModelCamelContext context)
            throws MalformedObjectNameException, MBeanException, AttributeNotFoundException, InstanceNotFoundException,
            ReflectionException {
        String domain = context.getManagementStrategy().getManagementAgent().getMBeanServerDefaultDomain();

        Map> processorsForRoute = new HashMap<>();

        ObjectName processorsObjectName
                = new ObjectName(domain + ":context=" + context.getManagementName() + ",type=processors,name=*");
        Set 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.getCamelContextExtension().getContextPlugin(ManagedCamelContext.class).getManagedProcessor(name);

            if (managedProcessor != null) {
                if (processorsForRoute.get(routeId) == null) {
                    List 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> entry : processorsForRoute.entrySet()) {
            Collections.sort(entry.getValue(), Comparator.comparing(ManagedProcessorMBean::getIndex));
        }

        return processorsForRoute;
    }

    /**
     * Gathers test details as xml.
     */
    private String gatherTestDetailsAsXml(String testClass, String testName, long timeTaken) {
        StringBuilder sb = new StringBuilder();
        sb.append("\n");
        sb.append("  ").append(testClass).append("\n");
        sb.append("  ").append(testName).append("\n");
        sb.append("  \n");
        sb.append("\n");
        return sb.toString();
    }

    /**
     * Logs route coverage summary, including which routes are uncovered and what is the coverage of each processor in
     * each route.
     */
    private void logCoverageSummary(ManagedCamelContextMBean managedCamelContext, ModelCamelContext context) throws Exception {
        StringBuilder builder = new StringBuilder("\nCoverage summary\n");

        int routes = managedCamelContext.getTotalRoutes();

        long contextExchangesTotal = managedCamelContext.getExchangesTotal();

        List uncoveredRoutes = new ArrayList<>();

        StringBuilder routesSummary = new StringBuilder();
        routesSummary.append("\tProcessor coverage\n");

        MBeanServer server = context.getManagementStrategy().getManagementAgent().getMBeanServer();

        Map> processorsForRoute = findProcessorsForEachRoute(server, context);

        // log processor coverage for each route
        for (Route route : context.getRoutes()) {
            ManagedRouteMBean managedRoute = context.getCamelContextExtension().getContextPlugin(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 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.isEmpty()) {
            builder.append("\t\tUncovered routes: ").append(String.join(", ", uncoveredRoutes))
                    .append("\n");
        }

        builder.append(routesSummary);
        LOG.info(builder.toString());
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy