Jacoco API

JacocoController.java

package com.test.testmanagement.controller;

import com.test.testmanagement.controller.jacococlient.DownloadRecursiveFolderFromSFTP;
import com.test.testmanagement.controller.jacococlient.ExecutionDataClient;
import com.test.testmanagement.controller.jacococlient.MergeDump;
import com.test.testmanagement.controller.jacococlient.ReportGenerator;
import com.test.testmanagement.model.ProjectInfo;
import com.test.testmanagement.model.TestProject;
import com.test.testmanagement.service.*;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.jacoco.core.tools.ExecDumpClient;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.IOException;
import java.util.*;

@RestController
@RequestMapping(value = "/api/jacoco")
public class JacocoController {
    private static String LOCAL_DATA_STORE = "/opt/app/mskyprocess/file/jacocoCode/"; // 源码路径
    private static String LOCAL_REPORT_DIR =  "/opt/app/mskyprocess/file/jacocoReport/"; // 报告路径

    //jenkins机器
    static String SFTPHOST = "10.5.144.210"; // SFTP Host Name or SFTP Host IP Address
    static String SFTPPORT = "22"; // SFTP Port Number
    static String SFTPUSER = "root"; // User Name
    static String SFTPPASS = "ume@20150916"; // Password

    /*Spring-Mybatis*/
    @Autowired
    private TestProjectService service;
    @Autowired
    private ProjectInfoService projectInfoService;

    static String testname = "2019-07-29";

    static Element element_project_name = null;
    static String pom_project_name = "";
    static Document root_doc = null;

    /**
     * 清空tomcat服务器的覆盖率文件
     * @param JACOCO_SERVER_IP tomcat服务器ip
     * @param JACOCO_SERVER_PORT 8080 or 8044
     * @return
     * http://127.0.0.1:8180/api/jacoco/cleantcpserver?ip=10.237.78.108&port=8080
     */
    @RequestMapping(value = "/cleantcpserver", method = RequestMethod.GET)
    public boolean CleanTcpServer(@RequestParam(value = "ip", required = false) String JACOCO_SERVER_IP,
                                  @RequestParam(value = "port") String JACOCO_SERVER_PORT,
                                  @RequestParam(value = "projectname") String PROJECT_NAME
                                  ) {
        boolean result = true;

        Map<String, Object> requestParamMap = new HashMap<String, Object>();
        requestParamMap.put("projectname", PROJECT_NAME);
        // 取tcpserver的ip 数据库表:projectinfo
        List<ProjectInfo> list = projectInfoService.findJacocoserverIpbyProjectname(requestParamMap);
//        JACOCO_SERVER_IP = list.get(0).getJacocoserverip();
        String[] ipInfo = list.get(0).getJacocoserverip().split(",");

        ExecDumpClient client = new ExecDumpClient();
        client.setReset(true);
        client.setDump(false);
        //目标机器的ip和端口,对应着运行程序时javaagent参数里的ip和端口
        try {
            for (String ipinfo : ipInfo) {
                JACOCO_SERVER_IP = ipinfo.split(":")[0];
                JACOCO_SERVER_PORT = ipinfo.split(":")[1];
                client.dump(JACOCO_SERVER_IP, Integer.parseInt(JACOCO_SERVER_PORT));
            }
        } catch (IOException e) {
            result = false;
            e.printStackTrace();
        }
        System.out.println("清除就的覆盖率文件");
        return result;
    }

    /**
     * 获取单个工程
     * 覆盖率、覆盖率报告、解析html存到DB
     * @param JACOCO_SERVER_IP tomcat服务器ip
     * @param JACOCO_SERVER_PORT 8080 or 8044
     * @param PROJECT_NAME 工程名 umemid-airport
     * @return
     * http://127.0.0.1:8180/api/jacoco/jacocoReport?ip=10.237.78.108&port=8080&projectname=umemid-airport
     */
    @RequestMapping(value = "/jacocoReport", method = RequestMethod.GET)
    public boolean JacocoReport(@RequestParam(value = "ip", required = false) String JACOCO_SERVER_IP,
                                @RequestParam(value = "port") String JACOCO_SERVER_PORT,
                                @RequestParam(value = "projectname") String PROJECT_NAME) {
        boolean result = true;
        boolean hasParenetPom = true;

        Map<String, Object> requestParamMap = new HashMap<String, Object>();
        requestParamMap.put("projectname", PROJECT_NAME);
        // 取tcpserver的ip 数据库表:projectinfo
        List<ProjectInfo> list = projectInfoService.findJacocoserverIpbyProjectname(requestParamMap);
        String[] ipInfo = list.get(0).getJacocoserverip().split(",");
        List<String> JACOCO_SERVER_IP_LIST = new ArrayList<>();
        for (String ip : ipInfo) {
            JACOCO_SERVER_IP_LIST.add(ip);
        }

        // 判断工程子pom.xml
        if (PROJECT_NAME.contains("umemid-") ||PROJECT_NAME.contains("umepsr-") ) {
            System.out.println(PROJECT_NAME +"有子pom");
        }
        else {
            hasParenetPom = false;
        }
        try {
            long for_startTime = System.currentTimeMillis();

            //Step1:创建本地src以及target目录
            init_Project_Src_Classes(PROJECT_NAME);
            long for_startTime2 = System.currentTimeMillis();
            System.out.println("创建本地目录时间:" + (for_startTime2 - for_startTime));

             //Step2:sftp下载相关src及target目录下的文件
             download_Src_Classes(SFTPHOST,SFTPPORT,SFTPUSER,SFTPPASS,hasParenetPom,PROJECT_NAME);
             long for_startTime3 = System.currentTimeMillis();
             System.out.println("下载src和claess文件时间:" + (for_startTime3 - for_startTime2));

            //Step3 socket_client后去集成测试exec文件  ExecutionDataClient.getJacocoExec(JACOCO_SERVER_IP,JACOCO_SERVER_PORT,LOCAL_DATA_STORE+PROJECT_NAME+"/jacoco-it.exec");
            //2020-04-08 改成多ip支持获取覆盖率,参数为ip+端口
            String pathdir = ExecutionDataClient.downLoadDump(JACOCO_SERVER_IP_LIST, LOCAL_DATA_STORE + PROJECT_NAME);
            // 把各个机器拿得exec文件,合并成jacoco.exec
            MergeDump.executeMerge(LOCAL_DATA_STORE + PROJECT_NAME);

            long for_startTime4 = System.currentTimeMillis();
            //Step4 生成集成测试覆盖率报告
            ReportGenerator.generateItCoverageReport(
                    LOCAL_DATA_STORE+PROJECT_NAME,
                    LOCAL_REPORT_DIR+PROJECT_NAME,
                    "jacoco.exec",
                    "target",
                    "src/main/java",
                    "it-coveragereport");
            long for_startTime5 = System.currentTimeMillis();
            System.out.println("生成覆盖率报告时间:" + (for_startTime5 - for_startTime4));

            //Step5 存取html解析到db
            JacocoReportToDB(LOCAL_REPORT_DIR + PROJECT_NAME + "/it-coveragereport/");
            long for_endTime = System.currentTimeMillis();
            System.out.println("解析html的时间:" + (for_endTime - for_startTime5));

            long consumetime = for_endTime - for_startTime;
            System.out.println("覆盖率获取时间:" + consumetime);
        } catch (Exception e) {
            result = false;
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 初始化删除创建工程的src、classes存储路径
     * @param projectname
     */
    public static void init_Project_Src_Classes(String projectname){
        try {
            //如果文件夹不存在则创建
            File project_file =new File(LOCAL_DATA_STORE + projectname);
            File project_file_src = new File(LOCAL_DATA_STORE + projectname+"/src");
            File project_file_classes = new File(LOCAL_DATA_STORE + projectname+"/target/classes");
            File project_reportfile = new File(LOCAL_REPORT_DIR + projectname);

            if  (!project_file.exists()  && !project_file.isDirectory())
            {
                System.out.println(project_file+"不存在");
                System.out.println("创建多级目录"+project_file_src+";"+project_file_classes);
                project_file_src.mkdirs();
                project_file_classes.mkdirs();
            }else
            {
                //删除文件夹
                System.out.println("删除文件夹"+project_file);
                FileUtils.deleteDirectory(project_file);
                System.out.println("创建多级目录"+project_file_src+";"+project_file_classes);
                project_file_src.mkdirs();
                project_file_classes.mkdirs();
            }

            if (!project_reportfile.exists() && !project_reportfile.isDirectory()) {
                System.out.println(project_reportfile + "不存在");
                project_reportfile.mkdirs();
            }else {
                FileUtils.deleteDirectory(project_reportfile);            }
//        //创建文件夹
//        FileUtils.
        }catch (Exception e){

        }finally {

        }

    }

    /**
     * 从打包Jenkins通过SFTF 获取class文件 & 源码
     * @param ip jenkins地址
     * @param port 22
     * @param username 登录用户 root or jboss5
     * @param password 密码
     * @param hasParenetPom 是否有子工程 true:umemid-airport  false:没有
     * @param PROJECT_NAME 工程名
     */
    public static void download_Src_Classes(String ip,String port,String username,String password,boolean hasParenetPom,String PROJECT_NAME){
        /*
        /opt/app/jenkins/workspace/Pipeline_umemid-airport/umemid-airport/src
         /opt/app/jenkins/workspace/Pipeline_umemid-airport/umemid-airport/target/classes
         */
        String srcDir ="";
        if (hasParenetPom){
            srcDir = "/opt/app/jenkins/workspace/PipelineCI_"+PROJECT_NAME+"/"+PROJECT_NAME+"/src";
            System.out.println("有子pom");
        }else{
            srcDir = "/opt/app/jenkins/workspace/PipelineCI_"+PROJECT_NAME+"/"+"src";
        }
        String local_srcDir = LOCAL_DATA_STORE+PROJECT_NAME+"/src";


        String classesDir = "";
        if(hasParenetPom){
            classesDir = "/opt/app/jenkins/workspace/PipelineCI_"+PROJECT_NAME+"/"+PROJECT_NAME+"/target/classes";
        }else {
            classesDir = "/opt/app/jenkins/workspace/PipelineCI_"+PROJECT_NAME+"/"+"target/classes";
        }
        String local_classesDir = LOCAL_DATA_STORE+PROJECT_NAME+"/target/classes";


//        String unittest_jacocoexec = "/opt/app/jenkins/workspace/Pipeline_"+PROJECT_NAME+"/"+PROJECT_NAME+"/target/jacoco.exec";
//        String local_jacoco_utexec = LOCAL_DATA_STORE+PROJECT_NAME+"/target/jacoco-ut.exec";



        DownloadRecursiveFolderFromSFTP.downloadDir(ip,port,username,password,srcDir,local_srcDir);
        DownloadRecursiveFolderFromSFTP.downloadDir(ip,port,username,password,classesDir,local_classesDir);
//        DownloadRecursiveFolderFromSFTP.downloadDir(ip,port,username,password,unittest_jacocoexec,local_jacoco_utexec);

    }

    /**
     * 存取html解析到db
     * @param htmlPath index.html路径
     * @throws Exception
     * http://127.0.0.1:8180/api/jacoco/jacocoParseHtmltoDB?htmlPath=/data/Mock/testmanagement/file/umemid-airport/it-coveragereport/
     */
    public void JacocoReportToDB(String htmlPath) throws Exception {
        File root_input = new File(htmlPath + "index.html");


        /*开始读取Jacoco覆盖率并存储到数据库*/
        TestProject testProject = new TestProject();
        testProject.setTestname(testname);
        Date d = new Date();
        testProject.setStarttime(d);//获取starttime


        root_doc = Jsoup.parse(root_input, "UTF-8");
        element_project_name = root_doc.select("H1").first();//查找第一个H1元素
        pom_project_name = element_project_name.text();
        testProject.setProjectname(pom_project_name);

        Integer project_id = service.insertTestProject(testProject);//插入项目

        //1)project_name
        //UmeTest
        System.out.println(pom_project_name);

        //2)包名
            /*
            com.umetrip.unittest.plugins.dbReporter
            com.umetrip.unittest
            com.umetrip.unittest.testcase
            com.umetrip.unittest.plugins.htmlReporter
             */
        Elements elements_index_package = root_doc.getElementsByClass("el_package");
        Integer i = 0;

        Element tfoot = root_doc.getElementsByTag("tfoot").first();
//        Element tr = tfoot.getElementsByTag("tr").first();
        Elements tds = tfoot.getElementsByTag("td");

        StringBuffer total_coverage = new StringBuffer();
        total_coverage.append(pom_project_name + "#");
        for (Element td : tds) {
            if (td.text().contains("Total")) {
                continue;
            }
            //System.out.println(td.text());

            total_coverage.append(td.text());
            total_coverage.append("#");
        }
        System.out.println("================" + pom_project_name + "项目整体覆盖");
        System.out.println(total_coverage);

        TestProject someProjectTotalSummary = new TestProject();

        someProjectTotalSummary.setId(project_id);

        someProjectTotalSummary.setMissedinstructions(total_coverage.toString().split("#")[1]);
        someProjectTotalSummary.setInstructioncoverage(total_coverage.toString().split("#")[2]);

        someProjectTotalSummary.setMissedbranches(total_coverage.toString().split("#")[3]);
        someProjectTotalSummary.setBranchcoverage(total_coverage.toString().split("#")[4]);

        someProjectTotalSummary.setMissedcxty(total_coverage.toString().split("#")[5]);
        someProjectTotalSummary.setTotalcxty(total_coverage.toString().split("#")[6]);

        someProjectTotalSummary.setMissedlines(total_coverage.toString().split("#")[7]);
        someProjectTotalSummary.setTotallines(total_coverage.toString().split("#")[8]);

        someProjectTotalSummary.setMissedmethods(total_coverage.toString().split("#")[9]);
        someProjectTotalSummary.setTotalmethods(total_coverage.toString().split("#")[10]);

        someProjectTotalSummary.setMissedclasses(total_coverage.toString().split("#")[11]);
        someProjectTotalSummary.setTotalclasses(total_coverage.toString().split("#")[12]);

        service.updateTestProjectById(someProjectTotalSummary);
    }
}

DownloadRecursiveFolderFromSFTP.java

package com.test.testmanagement.controller.jacococlient;

import com.jcraft.jsch.*;

import java.io.File;
import java.util.Vector;

/**
 * @author http://kodehelp.com
 *
 */
public class DownloadRecursiveFolderFromSFTP {

    static ChannelSftp channelSftp = null;
    static Session session = null;
    static Channel channel = null;
    static String PATHSEPARATOR = "/";


    public static void downloadDir(String ip,String port,String username,String password,String downloadDir,String localDir){

        try {
            JSch jsch = new JSch();
            session = jsch.getSession(username, ip, Integer.parseInt(port));
            session.setPassword(password);
            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect(); // Create SFTP Session
            channel = session.openChannel("sftp"); // Open SFTP Channel
            channel.connect();
            channelSftp = (ChannelSftp) channel;
            channelSftp.cd(downloadDir); // Change Directory on SFTP Server

            recursiveFolderDownload(downloadDir, localDir); // Recursive folder content download from SFTP server

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (channelSftp != null)
                channelSftp.disconnect();
            if (channel != null)
                channel.disconnect();
            if (session != null)
                session.disconnect();

        }

    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        String SFTPHOST = "10.5.144.210"; // SFTP Host Name or SFTP Host IP Address
        int SFTPPORT = 22; // SFTP Port Number
        String SFTPUSER = "root"; // User Name
        String SFTPPASS = "ume@20150916"; // Password


        String SFTPWORKINGDIR = "/opt/app/Python-2.7.15"; // Source Directory on SFTP server
        String LOCALDIRECTORY = "/data/file"; // Local Target Directory


        String  SRCDIR = "";

        try {
            JSch jsch = new JSch();
            session = jsch.getSession(SFTPUSER, SFTPHOST, SFTPPORT);
            session.setPassword(SFTPPASS);
            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect(); // Create SFTP Session
            channel = session.openChannel("sftp"); // Open SFTP Channel
            channel.connect();
            channelSftp = (ChannelSftp) channel;
            channelSftp.cd(SFTPWORKINGDIR); // Change Directory on SFTP Server

            recursiveFolderDownload(SFTPWORKINGDIR, LOCALDIRECTORY); // Recursive folder content download from SFTP server

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (channelSftp != null)
                channelSftp.disconnect();
            if (channel != null)
                channel.disconnect();
            if (session != null)
                session.disconnect();

        }

    }

    /**
     * This method is called recursively to download the folder content from SFTP server
     *
     * @param sourcePath
     * @param destinationPath
     * @throws SftpException
     */
    @SuppressWarnings("unchecked")
    private static void recursiveFolderDownload(String sourcePath, String destinationPath) throws SftpException {
        Vector<ChannelSftp.LsEntry> fileAndFolderList = channelSftp.ls(sourcePath); // Let list of folder content

        //Iterate through list of folder content
        for (ChannelSftp.LsEntry item : fileAndFolderList) {

            if (!item.getAttrs().isDir()) { // Check if it is a file (not a directory).
                if (!(new File(destinationPath + PATHSEPARATOR + item.getFilename())).exists()
                        || (item.getAttrs().getMTime() > Long
                        .valueOf(new File(destinationPath + PATHSEPARATOR + item.getFilename()).lastModified()
                                / (long) 1000)
                        .intValue())) { // Download only if changed later.

                    new File(destinationPath + PATHSEPARATOR + item.getFilename());
                    channelSftp.get(sourcePath + PATHSEPARATOR + item.getFilename(),
                            destinationPath + PATHSEPARATOR + item.getFilename()); // Download file from source (source filename, destination filename).
                }
            } else if (!(".".equals(item.getFilename()) || "..".equals(item.getFilename()))) {
                new File(destinationPath + PATHSEPARATOR + item.getFilename()).mkdirs(); // Empty folder copy.
                recursiveFolderDownload(sourcePath + PATHSEPARATOR + item.getFilename(),
                        destinationPath + PATHSEPARATOR + item.getFilename()); // Enter found folder on server to read its contents and create locally.
            }
        }
    }
}

ExecutionDataClient.java

package com.test.testmanagement.controller.jacococlient;

/*******************************************************************************
 * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Marc R. Hoffmann - initial API and implementation
 *
 *******************************************************************************/
//package org.jacoco.examples;

import org.jacoco.core.data.ExecutionDataWriter;
import org.jacoco.core.runtime.RemoteControlReader;
import org.jacoco.core.runtime.RemoteControlWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.List;

/**
 * This example connects to a coverage agent that run in output mode
 * <code>tcpserver</code> and requests execution data. The collected data is
 * dumped to a local file.
 */
public final class ExecutionDataClient {

    private static final String DESTFILE = "jacoco-client.exec";

    private static final String ADDRESS = "10.237.78.108";

    private static final int PORT = 8080;


    public static void getJacocoExec(String ip, String port, String destFile) {
        try {
            final FileOutputStream localFile = new FileOutputStream(destFile);
            final ExecutionDataWriter localWriter = new ExecutionDataWriter(
                    localFile);

            // Open a socket to the coverage agent:
            final Socket socket = new Socket(InetAddress.getByName(ip), Integer.parseInt(port));
            final RemoteControlWriter writer = new RemoteControlWriter(
                    socket.getOutputStream());
            final RemoteControlReader reader = new RemoteControlReader(
                    socket.getInputStream());
            reader.setSessionInfoVisitor(localWriter);
            reader.setExecutionDataVisitor(localWriter);


            // Send a dump command and read the response:
            writer.visitDumpCommand(true, false);
            if (!reader.read()) {
                throw new IOException("Socket closed unexpectedly.");
            }

            socket.close();
            localFile.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//            socket.close();
        }

    }

    // 相比较getJacocoExec是多个ip和端口配合的获取exec文件 2020-04-08 zmy
    public static String downLoadDump(List<String> ipPort, String destFile) {
//        int flag = 0; // 可能为了比增量
//        String getDirName = getDirNum(destFile); // 可能为了比增量
        String result = "";
        for (String getIPPort : ipPort) {
            String dirName = destFile + "/" + getIPPort.replace(":", "_") + "_jacoco.exec";
            String ip = getIPPort.split(":")[0];
            int port = Integer.parseInt(getIPPort.split(":")[1]);
            try {
                final FileOutputStream localFile = new FileOutputStream(dirName);
                final ExecutionDataWriter localWriter = new ExecutionDataWriter(
                        localFile);

                // Open a socket to the coverage agent:
                final Socket socket = new Socket(InetAddress.getByName(ip), port);
                final RemoteControlWriter writer = new RemoteControlWriter(
                        socket.getOutputStream());
                final RemoteControlReader reader = new RemoteControlReader(
                        socket.getInputStream());
                reader.setSessionInfoVisitor(localWriter);
                reader.setExecutionDataVisitor(localWriter);

                // Send a dump command and read the response:
                writer.visitDumpCommand(true, false);
                if (!reader.read()) {
                    throw new IOException("Socket closed unexpectedly.");
                }
                socket.close();
                localFile.close();
                System.out.println("Download file success....");
                System.out.println("File path is : " + dirName);
//                flag++; // 可能为了比增量
                result = result + dirName;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /*if (flag != 0) {
            return getDirName;
        } else {
            return "path";
        }*/ // 可能为了比增量
        return result;

    }


    /**
     * @param path
     * @return
     */
    private static String getDirNum(String path) {
        File file = null;
        String newPath = "";
        for (int i = 0; ; i++) {
            newPath = path + "/" + i;
//            newPath = path;
            file = new File(newPath);
            System.out.println("new path = " + newPath);
            if (!file.isDirectory()) {
                System.out.println(newPath);
                file.mkdirs();
                break;
            }
        }
        return newPath;
    }

    /**
     * Starts the execution data request.
     *
     * @param args
     * @throws IOException
     */
    public static void main(final String[] args) throws IOException {
        final FileOutputStream localFile = new FileOutputStream(DESTFILE);
        final ExecutionDataWriter localWriter = new ExecutionDataWriter(
                localFile);

        // Open a socket to the coverage agent:
        final Socket socket = new Socket(InetAddress.getByName(ADDRESS), PORT);
        final RemoteControlWriter writer = new RemoteControlWriter(
                socket.getOutputStream());
        final RemoteControlReader reader = new RemoteControlReader(
                socket.getInputStream());
        reader.setSessionInfoVisitor(localWriter);
        reader.setExecutionDataVisitor(localWriter);

        // Send a dump command and read the response:
        writer.visitDumpCommand(true, false);
        if (!reader.read()) {
            throw new IOException("Socket closed unexpectedly.");
        }

        socket.close();
        localFile.close();
    }

    private ExecutionDataClient() {
    }
}

MergeDump.java

package com.test.testmanagement.controller.jacococlient;

import org.jacoco.core.tools.ExecFileLoader;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class MergeDump {

/*    private final String path ;
    private final File destFile ;

    public MergeDump(String path){
        this.path = path;
        this.destFile = new File(path + "/jacoco.exec");
    }*/

    private static List<File> fileSets(String dir){
        System.out.println(dir);
        List<File> fileSetList = new ArrayList<File>();
        File path = new File(dir);
        if ( ! path.exists() ){
            System.out.println("No path name is :" + dir);
            return null;
        }
        File[] files = path.listFiles();
        try {
            if (files == null || files.length == 0) {
                return null;
            }
        } catch (NullPointerException npe) {
            npe.printStackTrace();
        }
        for (File file : files) {
            if (file.getName().contains(".exec")) {
                System.out.println("文件:" + file.getAbsolutePath());
                fileSetList.add(file);
            } else {
                System.out.println("非exec文件:" + file.getAbsolutePath());
            }
        }
        return fileSetList;
    }

    public static void executeMerge(String path) throws Exception {

        final ExecFileLoader loader = new ExecFileLoader();
        load(loader,path);
        save(loader,path);
        // 执行完成后,删除非必须的dump文件
        for (final File fileSet : fileSets(path)) {
            if ( ! fileSet.getName().equals("jacoco.exec") ) {
                fileSet.delete();
            }
        }
    }

    /**
     * 加载dump文件
     * @param loader
     * @param path
     * @throws Exception
     */
    public static void load(final ExecFileLoader loader, String path) throws Exception {
        for (final File fileSet : fileSets(path)) {
//            System.out.println(fileSet.getAbsoluteFile());
            final File inputFile = new File(path, fileSet.getName());
            if (inputFile.isDirectory()) {
                continue;
            }
            try {
                System.out.println("Loading execution data file " + inputFile.getAbsolutePath());
                loader.load(inputFile);
//                System.out.println(loader.getExecutionDataStore().getContents());
            } catch (final IOException e) {
                throw new Exception("Unable to read "
                        + inputFile.getAbsolutePath(), e);
            }
        }
    }

    /**
     * 执行合并文件
     * @param loader
     * @param path
     * @throws Exception
     */
    public static void save(final ExecFileLoader loader, String path) throws Exception {
        File destFile = new File(path + "/jacoco.exec");

        if (loader.getExecutionDataStore().getContents().isEmpty()) {
            System.out.println("Skipping JaCoCo merge execution due to missing execution data files");
            return;
        }

        System.out.println("Writing merged execution data to " + destFile.getAbsolutePath());
        try {
            loader.save(destFile, false);
        } catch (final IOException e) {
            throw new Exception("Unable to write merged file "
                    + destFile.getAbsolutePath(), e);
        }
    }
}

ParseJacocoReport.java

package com.test.testmanagement.controller.jacococlient;

import com.test.testmanagement.model.TestClass;
import com.test.testmanagement.model.TestMethod;
import com.test.testmanagement.model.TestPackage;
import com.test.testmanagement.model.TestProject;
import com.test.testmanagement.service.TestClassService;
import com.test.testmanagement.service.TestMethodService;
import com.test.testmanagement.service.TestPackageService;
import com.test.testmanagement.service.TestProjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.util.Date;

public class ParseJacocoReport {

    /*Spring-Mybatis*/
    @Autowired
    private TestProjectService service;
    @Autowired
    private TestPackageService packages;
    @Autowired
    private TestClassService classes;
    @Autowired
    private TestMethodService funtions;


    String testname = "2019-07-26";

//    String baseUri = "/data/Mock/testmanagement/file/umemid-airport/it-coveragereport/";


    Element element_project_name = null;
    String pom_project_name = "";
    Document root_doc = null;


    public void JacocoReportToDB(String htmlPath) throws Exception {
        File root_input = new File(htmlPath + "index.html");


        /*开始读取Jacoco覆盖率并存储到数据库*/
        TestProject testProject = new TestProject();
        testProject.setTestname(testname);
        Date d = new Date();
        testProject.setStarttime(d);//获取starttime
//        testProject.setStarttime(String.valueOf(System.currentTimeMillis()));//获取starttime


        root_doc = Jsoup.parse(root_input, "UTF-8");
        element_project_name = root_doc.select("H1").first();//查找第一个H1元素
        pom_project_name = element_project_name.text();
        testProject.setProjectname(pom_project_name);

        Integer project_id = service.insertTestProject(testProject);//插入项目

        //1)project_name
        //UmeTest
        System.out.println(pom_project_name);

        //2)包名
            /*
            com.umetrip.unittest.plugins.dbReporter
            com.umetrip.unittest
            com.umetrip.unittest.testcase
            com.umetrip.unittest.plugins.htmlReporter
             */
        Elements elements_index_package = root_doc.getElementsByClass("el_package");
        Integer i = 0;
        for (Element packagename : elements_index_package) {
            TestPackage testPackage = new TestPackage();
            /******************************************/
            System.out.println(packagename.text());//包名com.umetrip.unittest.plugins.dbReporter  ...
            testPackage.setPackagename(packagename.text());
            testPackage.setTestproject_id(project_id);
            testPackage.setTestname(testname);

            Integer packageid = packages.insertTestPackage(testPackage);//插入包


            File class_input = new File(htmlPath + packagename.text() + "/index.html");
            Document class_doc = Jsoup.parse(class_input, "UTF-8");
            Elements class_names = class_doc.getElementsByClass("el_class");

            Integer j = 0;
            for (Element class_name : class_names) {
                TestClass testClass = new TestClass();
                testClass.setClassname(class_name.text());
                testClass.setTestpackage_id(packageid);
                testClass.setTestname(testname);
                Integer classid = classes.insertTestClass(testClass);//插入类
                System.out.println("    " + class_name.text());//类名TestReportListener
                if (class_name.text().contains(".")) {
                    continue;
                }

                File method_input = new File(htmlPath + packagename.text() + "/" + class_name.text() + ".html");
                Document method_doc = Jsoup.parse(method_input, "UTF-8");
                Elements method_names = method_doc.getElementsByClass("el_method");
                TestMethod testMethod = new TestMethod();


                /********************************************************************************************/
                Element tbody = method_doc.getElementsByTag("tbody").first();
                Elements trs = tbody.getElementsByTag("tr");
                testMethod.setTestclass_id(classid);
                for (Element tr : trs) {
                    Elements tds = tr.getElementsByTag("td");

                    Integer td_counter = 0;
                    for (Element td : tds) {
                        System.out.println(td.text());
                        switch (td_counter) {
                            case 0://方法名
                                System.out.println("方法名");
                                Element methodName = td.getElementsByTag("a").first();
                                testMethod.setMethodname(methodName.text());
                                td_counter = td_counter + 1;
                                break;
                            case 1: //missedinstructions(百分比条)
                                Elements imgs = td.getElementsByTag("img");

                                StringBuffer missedInstructions = new StringBuffer();
                                for (Element img : imgs) {
                                    if (img.attr("src").contains("green")) {
                                        missedInstructions.append("|覆盖:" + img.attr("title") + "|");
                                    } else if (img.attr("src").contains("red")) {
                                        missedInstructions.append("|未覆盖:" + img.attr("title") + "|");
                                    }

                                }
                                testMethod.setMissedinstructions(missedInstructions.toString());
                                td_counter = td_counter + 1;
                                break;
                            case 2://missed coverage
                                testMethod.setInstructioncoverage(td.text());
                                td_counter = td_counter + 1;
                                break;

                            case 3://missed branches(百分比条)
                                Elements img1s = td.getElementsByTag("img");
                                StringBuffer missedBranches = new StringBuffer();
                                for (Element img : img1s) {
                                    if (img.attr("src").contains("green")) {
                                        missedBranches.append("|覆盖:" + img.attr("title") + "|");
                                    } else if (img.attr("src").contains("red")) {
                                        missedBranches.append("|未覆盖:" + img.attr("title") + "|");
                                    }
                                }
                                testMethod.setMissedbranches(missedBranches.toString());
                                td_counter = td_counter + 1;
                                break;

                            case 4://branch coverage
                                testMethod.setBranchcoverage(td.text());
                                td_counter = td_counter + 1;
                                break;

                            case 5://missed cxty
                                testMethod.setMissedcxty(td.text());
                                td_counter = td_counter + 1;
                                break;

                            case 6://cxty
                                testMethod.setTotalcxty(td.text());
                                td_counter = td_counter + 1;
                                break;

                            case 7://missed lines
                                testMethod.setMissedlines(td.text());
                                td_counter = td_counter + 1;
                                break;

                            case 8://lines
                                testMethod.setTotallines(td.text());
                                td_counter = td_counter + 1;
                                break;

                            case 9://missed method
                                testMethod.setMissedmethods(td.text());
                                td_counter = td_counter + 1;
                                break;

                            case 10://methods
                                testMethod.setTotalmethods(td.text());
                                td_counter = td_counter + 1;
                                break;

                                    /*default:
                                        //System.out.println("default");
                                        break;
                                        */
                        }
                    }
                    testMethod.setTestname(testname);
                    funtions.insertTestMethod(testMethod);
                }
                /*****************************************************************/


                Element tfoot = method_doc.getElementsByTag("tfoot").first();
                Element tr = tfoot.getElementsByTag("tr").first();
                Elements tds = tfoot.getElementsByTag("td");

                StringBuffer class_coverage = new StringBuffer();
                class_coverage.append(class_name.text() + "#");
                for (Element td : tds) {
                    if (td.text().contains("Total")) {
                        continue;
                    }
                    //System.out.println(td.text());

                    class_coverage.append(td.text());
                    class_coverage.append("#");
                }
                System.out.println("%%%%%%%%%%" + class_name.text() + "类整体覆盖");
                System.out.println(class_coverage);


                TestClass someClassTotalSummary = new TestClass();
                someClassTotalSummary.setTestname(testname);
                someClassTotalSummary.setId(classid);

                someClassTotalSummary.setMissedinstructions(class_coverage.toString().split("#")[1]);
                someClassTotalSummary.setInstructioncoverage(class_coverage.toString().split("#")[2]);

                someClassTotalSummary.setMissedbranches(class_coverage.toString().split("#")[3]);
                someClassTotalSummary.setBranchcoverage(class_coverage.toString().split("#")[4]);

                someClassTotalSummary.setMissedcxty(class_coverage.toString().split("#")[5]);
                someClassTotalSummary.setTotalcxty(class_coverage.toString().split("#")[6]);

                someClassTotalSummary.setMissedlines(class_coverage.toString().split("#")[7]);
                someClassTotalSummary.setTotallines(class_coverage.toString().split("#")[8]);

                someClassTotalSummary.setMissedmethods(class_coverage.toString().split("#")[9]);
                someClassTotalSummary.setTotalmethods(class_coverage.toString().split("#")[10]);


                classes.updateTestClass(someClassTotalSummary);//更新Class表

                j = j + 1;
            }

            Element tfoot = class_doc.getElementsByTag("tfoot").first();
            Element tr = tfoot.getElementsByTag("tr").first();
            Elements tds = tfoot.getElementsByTag("td");

            StringBuffer package_coverage = new StringBuffer();
            package_coverage.append(packagename.text() + "#");
            for (Element td : tds) {
                if (td.text().contains("Total")) {
                    continue;
                }
                //System.out.println(td.text());

                package_coverage.append(td.text());
                package_coverage.append("#");
            }
            System.out.println("&&&&&&&&&&" + packagename.text() + "包整体覆盖");
            System.out.println(package_coverage);
            //更新Package表
            TestPackage somePackageTotalSummary = new TestPackage();

            somePackageTotalSummary.setId(packageid);

            somePackageTotalSummary.setMissedinstructions(package_coverage.toString().split("#")[1]);
            somePackageTotalSummary.setInstructioncoverage(package_coverage.toString().split("#")[2]);

            somePackageTotalSummary.setMissedbranches(package_coverage.toString().split("#")[3]);
            somePackageTotalSummary.setBranchcoverage(package_coverage.toString().split("#")[4]);

            somePackageTotalSummary.setMissedcxty(package_coverage.toString().split("#")[5]);
            somePackageTotalSummary.setTotalcxty(package_coverage.toString().split("#")[6]);

            somePackageTotalSummary.setMissedlines(package_coverage.toString().split("#")[7]);
            somePackageTotalSummary.setTotallines(package_coverage.toString().split("#")[8]);

            somePackageTotalSummary.setMissedmethods(package_coverage.toString().split("#")[9]);
            somePackageTotalSummary.setTotalmethods(package_coverage.toString().split("#")[10]);

            somePackageTotalSummary.setMissedclasses(package_coverage.toString().split("#")[11]);
            somePackageTotalSummary.setTotalclasses(package_coverage.toString().split("#")[12]);

            packages.updateTestPackageById(somePackageTotalSummary);

            i = i + 1;
        }//package for

        Element tfoot = root_doc.getElementsByTag("tfoot").first();
        Element tr = tfoot.getElementsByTag("tr").first();
        Elements tds = tfoot.getElementsByTag("td");

        StringBuffer total_coverage = new StringBuffer();
        total_coverage.append(pom_project_name + "#");
        for (Element td : tds) {
            if (td.text().contains("Total")) {
                continue;
            }
            //System.out.println(td.text());

            total_coverage.append(td.text());
            total_coverage.append("#");
        }
        System.out.println("================" + pom_project_name + "项目整体覆盖");
        System.out.println(total_coverage);

        TestProject someProjectTotalSummary = new TestProject();

        someProjectTotalSummary.setId(project_id);

        someProjectTotalSummary.setMissedinstructions(total_coverage.toString().split("#")[1]);
        someProjectTotalSummary.setInstructioncoverage(total_coverage.toString().split("#")[2]);

        someProjectTotalSummary.setMissedbranches(total_coverage.toString().split("#")[3]);
        someProjectTotalSummary.setBranchcoverage(total_coverage.toString().split("#")[4]);

        someProjectTotalSummary.setMissedcxty(total_coverage.toString().split("#")[5]);
        someProjectTotalSummary.setTotalcxty(total_coverage.toString().split("#")[6]);

        someProjectTotalSummary.setMissedlines(total_coverage.toString().split("#")[7]);
        someProjectTotalSummary.setTotallines(total_coverage.toString().split("#")[8]);

        someProjectTotalSummary.setMissedmethods(total_coverage.toString().split("#")[9]);
        someProjectTotalSummary.setTotalmethods(total_coverage.toString().split("#")[10]);

        someProjectTotalSummary.setMissedclasses(total_coverage.toString().split("#")[11]);
        someProjectTotalSummary.setTotalclasses(total_coverage.toString().split("#")[12]);

        service.updateTestProjectById(someProjectTotalSummary);


    }

    public static void main(String[] args) {
        ParseJacocoReport parseJacocoReport = new ParseJacocoReport();
        try {
           parseJacocoReport.JacocoReportToDB("/data/Mock/testmanagement/file/umemid-airport/it-coveragereport/");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

ReportGenerator.java

/*******************************************************************************
 * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Brock Janiczak - initial API and implementation
 *    
 *******************************************************************************/
package com.test.testmanagement.controller.jacococlient;

import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IBundleCoverage;
import org.jacoco.core.tools.ExecFileLoader;
import org.jacoco.report.DirectorySourceFileLocator;
import org.jacoco.report.FileMultiReportOutput;
import org.jacoco.report.IReportVisitor;
import org.jacoco.report.html.HTMLFormatter;

import java.io.File;
import java.io.IOException;

/**
 * This example creates a HTML report for eclipse like projects based on a
 * single execution data store called jacoco.exec. The report contains no
 * grouping information.
 * 
 * The class files under test must be compiled with debug information, otherwise
 * source highlighting will not work.
 */
public class ReportGenerator {

	private final String title;

	private final File executionDataFile;
	private final File classesDirectory;
	private final File sourceDirectory;
	private final File reportDirectory;

	private ExecFileLoader execFileLoader;

	public static void generateItCoverageReport(String projectDirectory,
												String ReportDataFile,
												String executionDataFile,
												String classesDirectory,
												String sourceDirectory,
												String reportDirectory){
		final ReportGenerator generator = new ReportGenerator(
				projectDirectory,
				ReportDataFile,
				executionDataFile,
				classesDirectory,
				sourceDirectory,
				reportDirectory
				);
		try {
			generator.create();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public ReportGenerator(String projectDirectory,
                           String ReportDataFile,
                           String executionDataFile,
                           String classesDirectory,
                           String sourceDirectory,
                           String reportDirectory ) {
		File projectDirectory_File = new File(projectDirectory);
		File report_File = new File(ReportDataFile);
		this.title = projectDirectory_File.getName();
		this.executionDataFile = new File(projectDirectory_File, executionDataFile);
		this.classesDirectory = new File(projectDirectory_File, classesDirectory);
		this.sourceDirectory = new File(projectDirectory_File, sourceDirectory);
		this.reportDirectory = new File(report_File, reportDirectory);
	}

	/**
	 * Create a new generator based for the given project.
	 * 
	 * @param projectDirectory
	 */

	/*
	class 文件 /opt/app/jenkins/workspace/Pipeline_umemid-airport/umemid-airport/target/classes
	src 文件夹 /opt/app/jenkins/workspace/Pipeline_umemid-airport/umemid-airport/src
	 */
	public ReportGenerator(final File projectDirectory) {
		this.title = projectDirectory.getName();
		this.executionDataFile = new File(projectDirectory, "jacoco-it.exec");
		this.classesDirectory = new File(projectDirectory, "target");
		this.sourceDirectory = new File(projectDirectory, "src/main/java");
		this.reportDirectory = new File(projectDirectory, "coveragereport");
	}

	/**
	 * Create the report.
	 * 
	 * @throws IOException
	 */
	public void create() throws IOException {

		// Read the jacoco.exec file. Multiple data files could be merged
		// at this point
		loadExecutionData();

		// Run the structure analyzer on a single class folder to build up
		// the coverage model. The process would be similar if your classes
		// were in a jar file. Typically you would create a bundle for each
		// class folder and each jar you want in your report. If you have
		// more than one bundle you will need to add a grouping node to your
		// report
		final IBundleCoverage bundleCoverage = analyzeStructure();

		createReport(bundleCoverage);

	}

	private void createReport(final IBundleCoverage bundleCoverage)
			throws IOException {

		// Create a concrete report visitor based on some supplied
		// configuration. In this case we use the defaults
		final HTMLFormatter htmlFormatter = new HTMLFormatter();
		final IReportVisitor visitor = htmlFormatter
				.createVisitor(new FileMultiReportOutput(reportDirectory));

		// Initialize the report with all of the execution and session
		// information. At this point the report doesn't know about the
		// structure of the report being created
		visitor.visitInfo(execFileLoader.getSessionInfoStore().getInfos(),
				execFileLoader.getExecutionDataStore().getContents());

		// Populate the report structure with the bundle coverage information.
		// Call visitGroup if you need groups in your report.
		visitor.visitBundle(bundleCoverage, new DirectorySourceFileLocator(
				sourceDirectory, "utf-8", 4));

		// Signal end of structure information to allow report to write all
		// information out
		visitor.visitEnd();

	}

	private void loadExecutionData() throws IOException {
		execFileLoader = new ExecFileLoader();
		execFileLoader.load(executionDataFile);
	}

	private IBundleCoverage analyzeStructure() throws IOException {
		final CoverageBuilder coverageBuilder = new CoverageBuilder();
		final Analyzer analyzer = new Analyzer(
				execFileLoader.getExecutionDataStore(), coverageBuilder);

		analyzer.analyzeAll(classesDirectory);

		return coverageBuilder.getBundle(title);
	}

	/**
	 * Starts the report generation process
	 * 
	 * @param args
	 *            Arguments to the application. This will be the location of the
	 *            eclipse projects that will be used to generate reports for
	 * @throws IOException
	 */
	public static void main(final String[] args) throws IOException {
		for (int i = 0; i < args.length; i++) {
			final ReportGenerator generator = new ReportGenerator(new File(
					args[i]));
			generator.create();
		}
	}
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值