diff --git a/.github/workflows/fapi-oidc-conformance-test.yml b/.github/workflows/fapi-oidc-conformance-test.yml index 4f368e4a22..1a47e0419f 100644 --- a/.github/workflows/fapi-oidc-conformance-test.yml +++ b/.github/workflows/fapi-oidc-conformance-test.yml @@ -272,7 +272,7 @@ jobs: - name: Generate Jacoco Report run: | - java -jar ./product-is/modules/integration/tests-common/jacoco-report-generator/target/${{ env.JAR_NAME }} ./jacoco.exec ./product-is/oidc-conformance-tests/${{ env.PRODUCT_IS_DIR }}/repository/deployment/server/webapps ./product-is/oidc-conformance-tests/${{ env.PRODUCT_IS_DIR }}/repository/components/plugins ./product-is/oidc-conformance-tests/${{ env.PRODUCT_IS_DIR }}/repository/components/dropins ./product-is/oidc-conformance-tests/${{ env.PRODUCT_IS_DIR }}/lib/runtimes/cxf3 + java -jar ./product-is/modules/integration/tests-common/jacoco-report-generator/target/${{ env.JAR_NAME }} ./jacoco.exec ./product-is/oidc-fapi-conformance-tests/${{ env.PRODUCT_IS_DIR }}/repository/deployment/server/webapps ./product-is/oidc-fapi-conformance-tests/${{ env.PRODUCT_IS_DIR }}/repository/components/plugins ./product-is/oidc-fapi-conformance-tests/${{ env.PRODUCT_IS_DIR }}/repository/components/dropins ./product-is/oidc-fapi-conformance-tests/${{ env.PRODUCT_IS_DIR }}/lib/runtimes/cxf3 - name: Archive Jacoco report uses: actions/upload-artifact@v4 diff --git a/modules/integration/tests-common/jacoco-report-generator/src/main/java/org/wso2/carbon/identity/jacoco/CodeCoverageUtils.java b/modules/integration/tests-common/jacoco-report-generator/src/main/java/org/wso2/carbon/identity/jacoco/CodeCoverageUtils.java index b18a61ccfa..3eec7c2b4d 100644 --- a/modules/integration/tests-common/jacoco-report-generator/src/main/java/org/wso2/carbon/identity/jacoco/CodeCoverageUtils.java +++ b/modules/integration/tests-common/jacoco-report-generator/src/main/java/org/wso2/carbon/identity/jacoco/CodeCoverageUtils.java @@ -26,52 +26,52 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +/** + * Utility class for code coverage related operations. + */ public class CodeCoverageUtils { + private static final int BUFFER_SIZE = 1024; + private static final String INVALID_EXTENSION_ERROR = "Invalid extension: %s is invalid"; + private static final String EXTRACTION_ERROR = "Error on archive extraction"; + /** * Extract jar files given at jar file path * - * @param jarFilePath - Jar file patch + * @param jarFilePath - Jar file path + * @param tempDir - Temporary directory to extract jar file * @return - Jar file extracted directory. * @throws IOException - Throws if jar extraction fails */ - public synchronized static String extractJarFile(String jarFilePath, File tempDir) - throws IOException { + public synchronized static String extractJarFile(String jarFilePath, File tempDir) throws IOException { if (!jarFilePath.endsWith(".war") && !jarFilePath.endsWith(".jar")) { - throw new IllegalArgumentException("Invalid extension" + jarFilePath + " is invalid"); + throw new IllegalArgumentException(String.format(INVALID_EXTENSION_ERROR, jarFilePath)); } - String fileSeparator = (File.separatorChar == '\\') ? "\\" : File.separator; - String jarFileName = jarFilePath; - - if (jarFilePath.lastIndexOf(fileSeparator) != -1) { - jarFileName = jarFilePath.substring(jarFilePath.lastIndexOf(fileSeparator) + 1); - } + String jarFileName = new File(jarFilePath).getName(); + String tempExtractedDir = new File(tempDir, jarFileName.substring(0, jarFileName.lastIndexOf('.'))).getPath(); - String tempExtractedDir = null; try { - tempExtractedDir = tempDir + File.separator + - jarFileName.substring(0, jarFileName.lastIndexOf('.')); - extractFile(jarFilePath, tempExtractedDir); } catch (IOException e) { - System.out.println("Could not extract the file " + jarFileName); + throw new IOException("Could not extract the file " + jarFileName, e); } return tempExtractedDir; } /** - * Method to scan given directory for include and exclude patterns. + * Scan given directory for include and exclude patterns. * - * @param jarExtractedDir - Patch to check for given include/exclude pattern + * @param jarExtractedDir - Path to check for given include/exclude pattern * @param includes - Include pattern array * @param excludes - Exclude class pattern array * @return - Included files - * @throws IOException - Throws if given directory patch cannot be found. + * @throws IOException - Throws if given directory path cannot be found. */ public static String[] scanDirectory(String jarExtractedDir, String[] includes, String[] excludes) throws IOException { + DirectoryScanner ds = new DirectoryScanner(); ds.setIncludes(includes); @@ -83,58 +83,33 @@ public static String[] scanDirectory(String jarExtractedDir, String[] includes, return ds.getIncludedFiles(); } - public static void extractFile(String sourceFilePath, String extractedDir) throws IOException { - FileOutputStream fileoutputstream = null; - String fileDestination = extractedDir + File.separator; - byte[] buf = new byte[1024]; - ZipInputStream zipinputstream = null; - ZipEntry zipentry; - try { - zipinputstream = new ZipInputStream(new FileInputStream(sourceFilePath)); - zipentry = zipinputstream.getNextEntry(); - while (zipentry != null) { - //for each entry to be extracted - String entryName = fileDestination + zipentry.getName(); - entryName = entryName.replace('/', File.separatorChar); - entryName = entryName.replace('\\', File.separatorChar); - int n; - File newFile = new File(entryName); - if (zipentry.isDirectory()) { - if (!newFile.exists()) { - if (!newFile.mkdirs()) { - throw new IOException("Error occurred created new directory"); - } + private static void extractFile(String sourceFilePath, String extractedDir) throws IOException { + + byte[] buf = new byte[BUFFER_SIZE]; + try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(sourceFilePath))) { + ZipEntry zipEntry; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + File newFile = new File(extractedDir, zipEntry.getName()); + if (zipEntry.isDirectory()) { + if (!newFile.isDirectory() && !newFile.mkdirs()) { + throw new IOException("Failed to create directory " + newFile); } - zipentry = zipinputstream.getNextEntry(); - continue; } else { - File resourceFile = - new File(entryName.substring(0, entryName.lastIndexOf(File.separator))); - if (!resourceFile.exists()) { - if (!resourceFile.mkdirs()) { - break; + File parent = newFile.getParentFile(); + if (!parent.isDirectory() && !parent.mkdirs()) { + throw new IOException("Failed to create directory " + parent); + } + try (FileOutputStream fos = new FileOutputStream(newFile)) { + int len; + while ((len = zipInputStream.read(buf)) > 0) { + fos.write(buf, 0, len); } } } - fileoutputstream = new FileOutputStream(entryName); - while ((n = zipinputstream.read(buf, 0, 1024)) > -1) { - fileoutputstream.write(buf, 0, n); - } - fileoutputstream.close(); - zipinputstream.closeEntry(); - zipentry = zipinputstream.getNextEntry(); + zipInputStream.closeEntry(); } - zipinputstream.close(); } catch (IOException e) { - System.out.println("Error on archive extraction "); - throw new IOException("Error on archive extraction ", e); - } finally { - if (fileoutputstream != null) { - fileoutputstream.close(); - } - if (zipinputstream != null) { - zipinputstream.close(); - } + throw new IOException(EXTRACTION_ERROR, e); } } } diff --git a/modules/integration/tests-common/jacoco-report-generator/src/main/java/org/wso2/carbon/identity/jacoco/ReportGenerator.java b/modules/integration/tests-common/jacoco-report-generator/src/main/java/org/wso2/carbon/identity/jacoco/ReportGenerator.java index eab96a1498..6f4b0dc02f 100644 --- a/modules/integration/tests-common/jacoco-report-generator/src/main/java/org/wso2/carbon/identity/jacoco/ReportGenerator.java +++ b/modules/integration/tests-common/jacoco-report-generator/src/main/java/org/wso2/carbon/identity/jacoco/ReportGenerator.java @@ -29,9 +29,12 @@ import java.io.File; import java.io.FileOutputStream; -import java.io.FilenameFilter; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * This will create an XML report projects based on a @@ -39,170 +42,157 @@ */ public class ReportGenerator { - public static final String CLASS_FILE_PATTERN = "**/*.class"; - - private final String title; - - private final File executionDataFile; - private final Set classDirectories; - private final File xmlReport; - private final File tempDirectory; - - private ExecFileLoader execFileLoader; - - /** - * Create a new generator based for the given project. - * - * @param executionDataFile the execution data file - * @param classDirectories the set of class directories - */ - public ReportGenerator(File executionDataFile, Set classDirectories) { - this.title = "something"; - this.executionDataFile = executionDataFile; - this.classDirectories = classDirectories; - this.xmlReport = new File("./report/jacoco.xml"); - this.tempDirectory = new File("./tmp"); - - // Create report directory if it does not exist - File reportDir = this.xmlReport.getParentFile(); - if (!reportDir.exists()) { - if (!reportDir.mkdirs()) { - throw new RuntimeException("Failed to create report directory: " + reportDir.getAbsolutePath()); - } - } - } - - /** - * 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 XMLFormatter xmlFormatter = new XMLFormatter(); - final IReportVisitor visitor = xmlFormatter.createVisitor(new FileOutputStream(xmlReport)); - - // Initialize the report with all 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(null, "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); - - List jarFilesToAnalyze = new ArrayList<>(); - List classFilesToAnalyze = new ArrayList<>(); - - for (File classDirectory : classDirectories) { - // Jar files to analyze - File [] files = classDirectory.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.startsWith("org.wso2.carbon") && !name.contains(".stub_"); - } - }); + public static final String CLASS_FILE_PATTERN = "**/*.class"; + + private final String title; + private final File executionDataFile; + private final Set classDirectories; + private final File xmlReport; + private final File tempDirectory; + + private ExecFileLoader execFileLoader; + + /** + * Create a new generator based for the given project. + * + * @param executionDataFile the execution data file + * @param classDirectories the set of class directories + */ + public ReportGenerator(File executionDataFile, Set classDirectories) { + + this.title = "Jacoco Coverage Report"; + this.executionDataFile = executionDataFile; + this.classDirectories = classDirectories; + this.xmlReport = new File("./report/jacoco.xml"); + this.tempDirectory = new File("./tmp"); + + // Create report directory if it does not exist + File reportDir = this.xmlReport.getParentFile(); + if (!reportDir.exists() && !reportDir.mkdirs()) { + throw new RuntimeException("Failed to create report directory: " + reportDir.getAbsolutePath()); + } + } + + /** + * 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 + try (FileOutputStream fos = new FileOutputStream(xmlReport)) { + final XMLFormatter xmlFormatter = new XMLFormatter(); + final IReportVisitor visitor = xmlFormatter.createVisitor(fos); + + // Initialize the report with all 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(null, "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); + List jarFilesToAnalyze = new ArrayList<>(); + List classFilesToAnalyze = new ArrayList<>(); + + for (File classDirectory : classDirectories) { + // Jar files to analyze + File[] files = classDirectory.listFiles((dir, name) -> name.startsWith("org.wso2.carbon") && !name.contains(".stub_")); if (files != null) { jarFilesToAnalyze.addAll(Arrays.asList(files)); } - // Class files to analyze - files = classDirectory.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".class"); - } - }); - - if (files != null) { - classFilesToAnalyze.addAll(Arrays.asList(files)); - } + // Class files to analyze + files = classDirectory.listFiles((dir, name) -> name.endsWith(".class")); + if (files != null) { + classFilesToAnalyze.addAll(Arrays.asList(files)); + } } - String[] includes = {CLASS_FILE_PATTERN}; - String[] excludes = {"-*.stub*", "-*.stub_", "-*.stub_4.0.0", "-*.stub-"}; - - for (final File jarFile : jarFilesToAnalyze) { - - String extractedDir = CodeCoverageUtils.extractJarFile(jarFile.getAbsolutePath(), tempDirectory); - String[] classFiles = CodeCoverageUtils.scanDirectory(extractedDir, includes, excludes); - - for (String classFile : classFiles) { - analyzer.analyzeAll(new File(extractedDir + File.separator + classFile)); - } - FileUtils.forceDelete(new File(extractedDir)); - } - - for (final File classFile : classFilesToAnalyze) { - analyzer.analyzeAll(classFile); - } - - return coverageBuilder.getBundle(title); - } - - /** - * Starts the report generation process - * - * @param args Arguments to the report generation. - * [ ...] - * @throws IOException - */ - public static void main(final String[] args) throws IOException { - if (args.length < 2) { - System.err.println("Usage: java -jar ReportGenerator.jar [ ...]"); - System.exit(1); - } - - File executionDataFile = new File(args[0]); - Set classDirectories = new HashSet(); - for (int i = 1; i < args.length; i++) { - classDirectories.add(new File(args[i])); - } - - try { - final ReportGenerator generator = new ReportGenerator(executionDataFile, classDirectories); - generator.create(); - } catch (Exception e) { - System.err.println("Error while creating report: " + e.getMessage()); - } - } + String[] includes = {CLASS_FILE_PATTERN}; + String[] excludes = {"-*.stub*", "-*.stub_", "-*.stub_4.0.0", "-*.stub-"}; + + for (final File jarFile : jarFilesToAnalyze) { + String extractedDir = CodeCoverageUtils.extractJarFile(jarFile.getAbsolutePath(), tempDirectory); + String[] classFiles = CodeCoverageUtils.scanDirectory(extractedDir, includes, excludes); + + for (String classFile : classFiles) { + analyzer.analyzeAll(new File(extractedDir + File.separator + classFile)); + } + FileUtils.forceDelete(new File(extractedDir)); + } + + for (final File classFile : classFilesToAnalyze) { + analyzer.analyzeAll(classFile); + } + + return coverageBuilder.getBundle(title); + } + + /** + * Starts the report generation process + * + * @param args Arguments to the report generation. + * [ ...] + * @throws IOException + */ + public static void main(final String[] args) throws IOException { + + if (args.length < 2) { + System.err.println("Usage: java -jar ReportGenerator.jar [ ...]"); + System.exit(1); + } + + File executionDataFile = new File(args[0]); + Set classDirectories = new HashSet<>(); + for (int i = 1; i < args.length; i++) { + classDirectories.add(new File(args[i])); + } + + try { + final ReportGenerator generator = new ReportGenerator(executionDataFile, classDirectories); + generator.create(); + } catch (Exception e) { + System.err.println("Error while creating report: " + e.getMessage()); + } + } }