org.wso2.carbon.automation.engine.frameworkutils.CodeCoverageUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.automation.engine.frameworkutils.CodeCoverageUtils.java

Source

/*
*  Copyright (c) 2005-2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*  WSO2 Inc. 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.wso2.carbon.automation.engine.frameworkutils;

import com.vladium.emma.Command;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.automation.engine.frameworkutils.filters.CustomFileFilter;
import org.wso2.carbon.automation.engine.frameworkutils.filters.SuffixFilter;
import org.wso2.carbon.automation.engine.frameworkutils.filters.TypeFilter;

import java.io.*;
import java.util.*;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This util class provides functionality for computing code coverage.
 */
public final class CodeCoverageUtils {
    private static final Log log = LogFactory.getLog(CodeCoverageUtils.class);
    private static ArrayList<String> direcArrayList = new ArrayList<String>();

    private CodeCoverageUtils() {
    }

    public static void init() {
        String emmaHome = System.getProperty("emma.home");
        if (emmaHome == null) {
            return;
        } else if (!emmaHome.endsWith(File.separator)) {
            emmaHome += File.separator;
        }
        try {
            if (System.getProperty("emma.properties") == null) {
                for (File file : new File(emmaHome).listFiles()) {
                    if (file.getName().startsWith("org.wso2.carbon.automation.engine")) {
                        ArchiveExtractorUtil.extractFile(file.getAbsolutePath(), emmaHome);
                    }
                }
                System.setProperty("emma.properties",
                        new File(FrameworkPathUtil.getSystemResourceLocation()).getAbsolutePath() + File.separator
                                + "emma.properties");
            }
            if (System.getProperty("emma.report.html.out.file") == null) {
                System.setProperty("emma.report.html.out.file", new File(emmaHome).getAbsolutePath()
                        + File.separator + "coverage" + File.separator + "index.html");
            }
            if (System.getProperty("emma.report.xml.out.file") == null) {
                System.setProperty("emma.report.xml.out.file", new File(emmaHome).getAbsolutePath() + File.separator
                        + "coverage" + File.separator + "coverage.xml");
            }
            if (System.getProperty("emma.rt.control.port") == null) {
                System.setProperty("emma.rt.control.port", "44444");
            }
        } catch (IOException e) {
            log.error("Cannot initialize Emma", e);
        } catch (Exception e) {
            log.error("Cannot initialize Emma", e);
        }
    }

    public static void instrument(String carbonHome) {
        String workingDir = System.getProperty("user.dir");
        try {
            System.setProperty("user.dir", carbonHome);
            String emmaHome = System.getProperty("emma.home");
            if (emmaHome == null) {
                return;
            } else if (!emmaHome.endsWith(File.separator)) {
                emmaHome += File.separator;
            }
            String emmaJarName = null;
            for (File file : new File(emmaHome).listFiles()) {
                String fileName = file.getName();
                if (fileName.startsWith("emma") && fileName.endsWith(".jar")) {
                    emmaJarName = fileName;
                }
            }
            if (emmaJarName == null) {
                return;
            }

            direcArrayList.clear();
            searchDirectoryByName(carbonHome, direcArrayList, "lib");

            for (String aDirecArrayList : direcArrayList) {
                if (aDirecArrayList
                        .contains("repository" + File.separator + "components" + File.separator + "lib")) {
                    FileUtils.copyFileToDirectory(new File(emmaHome + emmaJarName), new File(aDirecArrayList));
                }
            }

            // Load the file patterns of the bundles to be instrumented
            instrumentSelectedFiles(carbonHome);
        } catch (IOException e) {
            log.error("Cannot instrument jars", e);
        } finally {
            System.setProperty("user.dir", workingDir);
        }
    }

    private static void instrumentSelectedFiles(String carbonHome) throws IOException {
        log.info("Instrumentation of jar files in progress ...");
        File instrumentationTxt = System.getProperty("instr.file") != null
                ? new File(System.getProperty("instr.file"))
                : new File(System.getProperty("basedir") + File.separator + "src" + File.separator + "test"
                        + File.separator + "resources" + File.separator + "instrumentation.txt");
        List<String> filePatterns = new ArrayList<String>();
        if (instrumentationTxt.exists()) {
            RandomAccessFile rf = new RandomAccessFile(instrumentationTxt, "r");
            try {
                String line;
                while ((line = rf.readLine()) != null) {
                    filePatterns.add(line);
                }
            } finally {
                rf.close();
            }
        }

        // Instrument the bundles which match the specified patterns in <code>filePatterns</code>
        File plugins = null;

        direcArrayList.clear();
        searchDirectoryByName(carbonHome, direcArrayList, "plugins");

        for (String aDirecArrayList : direcArrayList) {
            if (aDirecArrayList
                    .contains("repository" + File.separator + "components" + File.separator + "plugins")) {
                plugins = new File(aDirecArrayList);
            }
        }

        //instrument the jars at plugins directory first (otherwise emma will complain about state versions of class files
        int instrumentedFileCount = 0;
        for (File file : plugins.listFiles()) {
            if (file.isFile()) {
                if (filePatterns.isEmpty()) { // If file patterns are not specified, instrument all files
                    instrument(file);
                    instrumentedFileCount++;
                } else {
                    for (String filePattern : filePatterns) {
                        if (file.getName().startsWith(filePattern)) {
                            instrument(file);
                            instrumentedFileCount++;
                        }
                    }
                }
            }
        }

        log.info("Instrumented " + instrumentedFileCount + " file(s) in plugins directory");

        direcArrayList.clear();

        //instrument the jar files in patches directory

        File patchesDir = null;

        searchDirectoryByName(carbonHome, direcArrayList, "patches");

        for (String aDirecArrayList : direcArrayList) {
            if (aDirecArrayList
                    .contains("repository" + File.separator + "components" + File.separator + "patches")) {
                patchesDir = new File(aDirecArrayList);
            }
        }

        int instrumentedPatchFileCount = 0;
        File[] patchFiles = patchesDir.listFiles();
        Map<Integer, String> patchesDirTreeMap = new TreeMap<Integer, String>();
        if (patchFiles != null) {
            for (File patchFile : patchFiles) {
                Pattern pattern = Pattern.compile("-?\\d+"); //get the number from patch directory name
                Matcher matcher = pattern.matcher(patchFile.getName());
                if (matcher.find()) {
                    patchesDirTreeMap.put(Integer.parseInt(matcher.group()), patchFile.getName());
                }
            }
            //patches directory names are sorted by patch number before instrumentation - this is because emma
            //records last instrumented file data in its metadata, so any duplicate file instrumentation will not cause
            //problems.
            for (Map.Entry entry : patchesDirTreeMap.entrySet()) {
                String filePathOfJarFiles = patchesDir.getAbsolutePath() + File.separator + entry.getValue();
                File name = new File(filePathOfJarFiles);
                log.info("Instrumenting jar files at - " + name.getName());
                Collection patchesCollection = FileUtils.listFiles(name, null, true);
                for (Object jarFile : patchesCollection) {
                    File jarFileName = new File(jarFile.toString());
                    if (jarFileName.exists()) {
                        for (String filePattern : filePatterns) {
                            if (jarFileName.getName().startsWith(filePattern)) {
                                instrument(jarFileName);
                                instrumentedPatchFileCount++;
                                break;
                            }
                        }
                    }
                }
            }
            log.info("Instrumented " + instrumentedPatchFileCount + " file(s) in patches directory");
        }
    }

    private static void printMap(Map<Integer, String> map) {
        for (Map.Entry entry : map.entrySet()) {
            System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
        }
    }

    private static void instrument(File file) throws IOException {
        addEmmaDynamicImportPackage(file.getAbsolutePath());
        doEmmaInstrumentation(file);
        if (log.isDebugEnabled()) {
            log.debug("Instrumented " + file.getAbsolutePath());
        }
    }

    private synchronized static void addEmmaDynamicImportPackage(String jarFilePath) throws IOException {
        if (!jarFilePath.endsWith(".jar")) {
            throw new IllegalArgumentException(
                    "Jar file should have the extension .jar. " + jarFilePath + " is invalid");
        }
        JarFile jarFile = new JarFile(jarFilePath);
        Manifest manifest = jarFile.getManifest();
        if (manifest == null) {
            throw new IllegalArgumentException(jarFilePath + " does not contain a MANIFEST.MF file");
        }
        String fileSeparator = (File.separatorChar == '\\') ? "\\" : File.separator;
        String jarFileName = jarFilePath;
        if (jarFilePath.lastIndexOf(fileSeparator) != -1) {
            jarFileName = jarFilePath.substring(jarFilePath.lastIndexOf(fileSeparator) + 1);
        }
        ArchiveManipulator archiveManipulator = null;
        String tempExtractedDir = null;
        try {
            archiveManipulator = new ArchiveManipulator();
            tempExtractedDir = System.getProperty("basedir") + File.separator + "target" + File.separator
                    + jarFileName.substring(0, jarFileName.lastIndexOf('.'));
            ArchiveExtractorUtil.extractFile(jarFilePath, tempExtractedDir);
        } catch (Exception e) {
            log.error("Could not extract the file", e);
        } finally {
            jarFile.close();
        }
        String dynamicImports = manifest.getMainAttributes().getValue("DynamicImport-Package");
        if (dynamicImports != null) {
            manifest.getMainAttributes().putValue("DynamicImport-Package", dynamicImports + ",com.vladium.*");
        } else {
            manifest.getMainAttributes().putValue("DynamicImport-Package", "com.vladium.*");
        }
        File newManifest = new File(
                tempExtractedDir + File.separator + "META-INF" + File.separator + "MANIFEST.MF");
        FileOutputStream manifestOut = null;
        try {
            manifestOut = new FileOutputStream(newManifest);
            manifest.write(manifestOut);
        } catch (IOException e) {
            log.error("Could not write content to new MANIFEST.MF file", e);
        } finally {
            if (manifestOut != null) {
                manifestOut.close();
            }
        }

        if (tempExtractedDir != null)
            archiveManipulator.archiveDir(jarFilePath, tempExtractedDir);

        FileUtils.forceDelete(newManifest);
    }

    private static void doEmmaInstrumentation(File file) {
        String emmaFilters = System.getProperty("filters.file");
        if (emmaFilters == null) {
            emmaFilters = System.getProperty("basedir") + File.separator + "src" + File.separator + "test"
                    + File.separator + "resources" + File.separator + "filters.txt";
        } else {
            if (!new File(emmaFilters).exists()) {
                log.warn("Emma filters file " + emmaFilters + " does not exist");
            }
        }
        File emmaFiltersFile = new File(emmaFilters);
        Command cmd = emmaFiltersFile.exists()
                ? Command.create("instr", "emmarun",
                        new String[] { "-m", "overwrite", "-ip", file.getAbsolutePath(), "-ix",
                                "@" + emmaFiltersFile.getAbsolutePath() })
                : Command.create("instr", "emmarun",
                        new String[] { "-m", "overwrite", "-ip", file.getAbsolutePath() });
        cmd.run();
    }

    public static void generateReports(List<File> carbonHomeDirs) { //-r html -in coverage.em,coverage.ec
        log.info("Generating code coverage report ...");
        String emmaHome = System.getProperty("emma.home");
        if (emmaHome == null) {
            log.error("Emma home not set properly");
            return;
        }
        String baseDir = System.getProperty("basedir");
        List<File> emmaEmFiles2 = getAllCoverageEmFiles(new File(baseDir));
        //If coverage em file not found, go one level up and search coverage em in all subdirectories
        if (emmaEmFiles2.size() == 0) {
            emmaEmFiles2 = getAllCoverageEmFiles(
                    new File(baseDir.substring(0, baseDir.lastIndexOf(File.separator))));
        }
        try {
            Thread.sleep(15000); //wait for coverage data dump
        } catch (InterruptedException e) {
            log.info("Report generation fails");
        }
        // find all coverage.ec files, and generate the report
        List<File> coverageDataFiles = new ArrayList<File>();
        for (File carbonHome : carbonHomeDirs) {
            if (carbonHome != null) {
                File[] coverageFiles = getCoverageDataFiles(carbonHome.getAbsolutePath());
                Collections.addAll(coverageDataFiles, coverageFiles);
            }
        }
        //        Collection<File> ecFiles = FileUtils.listFiles(new File(basedir), new String[]{"ec"}, true);
        StringBuilder ecFilesString = new StringBuilder();
        StringBuilder emFilesString = new StringBuilder();
        for (File ecFile : coverageDataFiles) {
            if (ecFile != null) {
                log.info("Including Coverage EC file -" + ecFile.getAbsolutePath());
                ecFilesString.append(ecFile.getAbsolutePath()).append(",");
            }
        }
        for (File emFile : emmaEmFiles2) {
            if (emFile != null) {
                log.info("Including coverage EM file -" + emFile.getAbsolutePath());
                emFilesString.append(emFile.getAbsolutePath()).append(",");
            }
        }
        Command cmd = Command.create("report", "emmarun",
                new String[] { "-r", "xml,html", "-in", emFilesString + "," + ecFilesString });
        cmd.run();
        log.info("Emma report generation completed");
    }

    private static File[] getCoverageDataFiles(String carbonHome) {

        List<File> files = (List<File>) FileUtils.listFiles(new File(carbonHome), new String[] { "ec" }, true);

        File[] coverageFiles = new File[files.size()];

        Iterator<File> itFileList = files.iterator();
        int count = 0;

        while (itFileList.hasNext()) {
            File filePath = itFileList.next();
            coverageFiles[count] = filePath;
            count++;
        }
        return coverageFiles;
    }

    public static boolean renameCoverageDataFile(String carbonHome) {
        //get all .ec fies and then find coverage.ec, after that rename those files
        File[] coverageDataFiles = getCoverageDataFiles(carbonHome);
        for (File coverageDatafile : coverageDataFiles) {
            if (coverageDatafile.getName().equals("coverage.ec")) {
                return coverageDatafile.renameTo(
                        new File(carbonHome + File.separator + "coverage" + System.currentTimeMillis() + ".ec"));
            }
        }
        return false;
    }

    public static List<File> getAllCoverageEmFiles(File directory) {
        if (directory.exists()) {
            return CustomFileFilter.getFilesRecursive(directory, new SuffixFilter(TypeFilter.FILE, ".em"));
        }
        return null;
    }

    public static ArrayList<String> searchDirectoryByName(String baseDir, ArrayList<String> directoryLists,
            String dirName) {
        File baseDirName = new File(baseDir);
        File[] fileArray = baseDirName.listFiles();
        if (fileArray != null) {
            for (int i = 0; i < fileArray.length; i++) {
                File name = fileArray[i];
                if (name.isDirectory()) {
                    if (name.toString().subSequence(name.toString().lastIndexOf("/") + 1, name.toString().length())
                            .equals(dirName)) {
                        directoryLists.add(name.getAbsolutePath());
                    }
                    searchDirectoryByName(fileArray[i].getAbsolutePath(), directoryLists, dirName);
                } else if (fileArray.length == i) {
                    return null;
                }
            }
        }
        return directoryLists;
    }
}