/** * 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.openejb.config.rules; import org.apache.openejb.config.rules.KeysAnnotationVisitor.ClassInfo; import org.apache.openejb.config.rules.KeysAnnotationVisitor.MethodInfo; import org.apache.openejb.loader.IO; import org.apache.xbean.asm5.ClassReader; import org.apache.xbean.asm5.ClassWriter; import org.codehaus.swizzle.confluence.Confluence; import org.codehaus.swizzle.confluence.Page; import org.junit.BeforeClass; import org.junit.Test; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.HashSet; import java.util.Map.Entry; import java.util.ResourceBundle; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import static org.apache.openejb.util.URLs.toFile; /** * This class is not meant to be a container for tests. Its an audit tool which generates a report of how many of the keys listed in * org.apache.openejb.config.rules.Messages.properties have tests written for them */ public class ValidationKeysAuditorTest { private static Set<String> allKeys; @BeforeClass public static void init() { final ResourceBundle bundle = ResourceBundle.getBundle("org.apache.openejb.config.rules.Messages"); allKeys = bundle.keySet(); allKeys = stripPrefixes(allKeys); } @Test public void audit() { final URL resource = ValidationKeysAuditorTest.class.getResource("/org/apache/openejb/config/rules/Keys.class"); final File file = toFile(resource); final KeysAnnotationVisitor visitor = new KeysAnnotationVisitor(); dir(file.getParentFile(), visitor); try { generateReport(file, visitor); final String confluenceOutput = generateConfluenceReport(file, visitor); writeToConfluence(confluenceOutput); } catch (final IOException e) { // ignore it e.printStackTrace(); } } /** * This method will write to confluence only if you supply the system properties confluenceUsername and confluencePassword example usage mvn test * -Dtest=ValidationKeysAuditorTest -DconfluenceUsername=<<your username>> -DconfluencePassword=<<your password>> * * @param confluenceOutput */ private void writeToConfluence(final String confluenceOutput) { final String username = System.getProperty("confluenceUsername"); final String password = System.getProperty("confluencePassword"); if (validate(username) && validate(password)) { try { final String endpoint = "https://cwiki.apache.org/confluence/rpc/xmlrpc"; final Confluence confluence = new Confluence(endpoint); confluence.login(username, password); final Page page = confluence.getPage("OPENEJB", "Validation Keys Audit Report"); page.setContent(confluenceOutput); confluence.storePage(page); confluence.logout(); } catch (final Exception e) { e.printStackTrace(); } } } private boolean validate(final String str) { if (str == null) return false; if ("true".equalsIgnoreCase(str)) return false; if ("false".equalsIgnoreCase(str)) return false; if (str.trim().length() == 0) return false; return true; } private String generateConfluenceReport(final File file, final KeysAnnotationVisitor visitor) throws IOException { final StringBuilder output = new StringBuilder(); final String newLine = System.getProperty("line.separator"); final Set<String> testedKeys = getTestedKeys(visitor.classInfos); Set<String> untestedKeys = getUntestedKeys(testedKeys); untestedKeys = new TreeSet<String>(untestedKeys);// sort the keys prepareConfluenceSummary(untestedKeys, output, newLine); prepareConfluenceUntestedKeyList(untestedKeys, output, newLine); prepareConfluenceTestedKeysDetailedReport(visitor.classInfos, output, newLine); writeToFile(file, output, "ValidationKeyAuditReportConfluence.txt"); return output.toString(); } private void prepareConfluenceTestedKeysDetailedReport(final HashSet<ClassInfo> classInfos, final StringBuilder output, final String newLine) { final TreeMap<String, TreeSet<String>> info = new TreeMap<String, TreeSet<String>>(); output.append("h2.List of keys which have been tested.").append(newLine); output.append("{table-plus:autoNumber=true}").append(newLine); output.append("|| Key | Method which tests the key ||").append(newLine); for (final ClassInfo classInfo : classInfos) { final HashSet<MethodInfo> methuds = classInfo.methuds; for (final MethodInfo methodInfo : methuds) { final HashSet<String> keys = methodInfo.keys; for (final String key : keys) { if (!info.containsKey(key)) { final TreeSet<String> set = new TreeSet<String>(); set.add(createConfluenceLink(classInfo.clazz + "." + methodInfo.methud + "()")); info.put(key, set); } else { final TreeSet<String> set = info.get(key); set.add(createConfluenceLink(classInfo.clazz + "." + methodInfo.methud + "()")); } } } } final Set<Entry<String, TreeSet<String>>> entrySet = info.entrySet(); for (final Entry<String, TreeSet<String>> entry : entrySet) { final String key = entry.getKey(); output.append("| ").append(key).append(" | "); int count = 0; final TreeSet<String> values = entry.getValue(); for (final String value : values) { if (count > 0) { output.append(" \\\\ "); } output.append(value); ++count; } output.append(newLine); } output.append("{table-plus}").append(newLine); } private String createConfluenceLink(final String string) { String link = "[" + string + " | "; final String temp = string.substring(0, string.lastIndexOf(".")); final String location = "https://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/test/java/" + temp + ".java?revision=HEAD&view=markup ]"; link = link + location; return link; } private void prepareConfluenceUntestedKeyList(final Set<String> untestedKeys, final StringBuilder output, final String newLine) { output.append("{table-plus:autoNumber=true}").append(newLine); output.append("|| h2.List of untested keys \\\\ ||").append(newLine); for (final String key : untestedKeys) { output.append(" | ").append(key).append(" | ").append(newLine); } output.append("{table-plus}").append(newLine); } private void prepareConfluenceSummary(final Set<String> untestedKeys, final StringBuilder output, final String newLine) { final int total = allKeys.size(); final int untested = untestedKeys.size(); final int tested = total - untested; final double coverage = (((tested + 0.0) / (total + 0.0)) * 100); output.append("{warning:title=Warning}This page is auto-generated. Any manual changes would be over-written the next time this page is regenerated{warning}").append( newLine); output.append("{info:title=Audit Result}h2.Out of a total of ").append(total).append(" keys, ").append(tested).append(" have been tested. Test coverage for keys is ").append(coverage).append(" %.{info}") .append(newLine); } private void generateReport(final File file, final KeysAnnotationVisitor visitor) throws IOException { final StringBuilder output = new StringBuilder(); final String newLine = System.getProperty("line.separator"); final Set<String> testedKeys = getTestedKeys(KeysAnnotationVisitor.classInfos); Set<String> untestedKeys = getUntestedKeys(testedKeys); untestedKeys = new TreeSet<String>(untestedKeys);// sort the keys prepareSummary(untestedKeys, output, newLine); prepareUntestedKeyList(untestedKeys, output, newLine); prepareTestedKeysDetailedReport(KeysAnnotationVisitor.classInfos, output, newLine); writeToFile(file, output, "ValidationKeyAuditReport.txt"); } private void prepareTestedKeysDetailedReport(final HashSet<ClassInfo> classInfos, final StringBuilder output, final String newLine) throws IOException { output.append("================================================================================================").append(newLine); output.append("List of all keys tested. Next to each is the the test method which tests the key").append(newLine); output.append("================================================================================================").append(newLine); final TreeMap<String, TreeSet<String>> info = new TreeMap<String, TreeSet<String>>(); for (final ClassInfo classInfo : classInfos) { final HashSet<MethodInfo> methuds = classInfo.methuds; for (final MethodInfo methodInfo : methuds) { final HashSet<String> keys = methodInfo.keys; for (final String key : keys) { if (!info.containsKey(key)) { final TreeSet<String> set = new TreeSet<String>(); set.add(classInfo.clazz + "." + methodInfo.methud + "()"); info.put(key, set); } else { final TreeSet<String> set = info.get(key); set.add(classInfo.clazz + "." + methodInfo.methud + "()"); } } } } final Set<Entry<String, TreeSet<String>>> entrySet = info.entrySet(); for (final Entry<String, TreeSet<String>> entry : entrySet) { final String key = entry.getKey(); output.append(key).append(" --> "); int count = 0; final TreeSet<String> values = entry.getValue(); for (final String value : values) { if (count > 0) { // put as many spaces as there are characters in the key to indent and align multiple values for the same key final StringBuilder spaces = new StringBuilder(); for (int i = 0; i < key.length(); i++) { spaces.append(" "); } output.append(spaces).append(" --> "); } output.append(value).append(newLine); ++count; } } } private void writeToFile(final File file, final StringBuilder output, final String fileName) throws IOException { final File surefireReports = new File(dir(file), "surefire-reports"); if (!surefireReports.exists()) { surefireReports.mkdir(); } final File auditResults = new File(surefireReports, fileName); BufferedWriter bw = null; try { final FileWriter writer = new FileWriter(auditResults); bw = new BufferedWriter(writer); bw.append(output.toString()); } finally { if (bw != null) { try { bw.flush(); } catch (final Throwable e) { //Ignore } } if (bw != null) { try { bw.close(); } catch (final Throwable e) { //Ignore } } } } private void prepareUntestedKeyList(final Set<String> untestedKeys, final StringBuilder output, final String newLine) { output.append("================================================================================================").append(newLine); output.append("List of all keys which have not been tested yet.").append(newLine); output.append("================================================================================================").append(newLine); for (final String key : untestedKeys) { output.append(key).append(newLine); } } private Set<String> getUntestedKeys(final Set<String> testedKeys) { final Set<String> untestedKeys = new HashSet<String>(); for (final String key : allKeys) { if (!testedKeys.contains(key)) untestedKeys.add(key); } return untestedKeys; } private Set<String> getTestedKeys(final HashSet<ClassInfo> classInfos) { final Set<String> testedKeys = new HashSet<String>(); for (final ClassInfo classInfo : classInfos) { final HashSet<MethodInfo> methuds = classInfo.methuds; for (final MethodInfo methodInfo : methuds) { testedKeys.addAll(methodInfo.keys); } } return testedKeys; } private static Set<String> stripPrefixes(final Set<String> allKeys) { final Set<String> keys = new HashSet<String>(); for (String key : allKeys) { key = key.substring(key.indexOf(".") + 1); if (!keys.contains(key)) keys.add(key); } return keys; } private void prepareSummary(final Set<String> untestedKeys, final StringBuilder output, final String newLine) { final int total = allKeys.size(); final int untested = untestedKeys.size(); final int tested = total - untested; final double coverage = (((tested + 0.0) / (total + 0.0)) * 100); output.append("================================================================================================").append(newLine); output.append("Out of a total of ").append(total).append(" keys, ").append(tested).append(" have been tested. Test coverage for keys is ").append(coverage).append(" %.").append(newLine); output.append("================================================================================================").append(newLine); } private File dir(File file) { file = file.getParentFile(); while (file.isDirectory()) { if (!file.getName().equals("target")) { file = file.getParentFile(); continue; } return file; } return null; } private static void dir(final File dir, final KeysAnnotationVisitor visitor) { final File[] files = dir.listFiles(); if (files != null) { for (final File file : files) { if (file.isDirectory()) { dir(file, visitor); } else if (file.getName().endsWith(".class")) { file(file, visitor); } } } } private static void file(final File file, final KeysAnnotationVisitor visitor) { try { final InputStream in = IO.read(file); try { final ClassReader classReader = new ClassReader(in); classReader.accept(visitor, ClassWriter.COMPUTE_FRAMES); } finally { IO.close(in); } } catch (final IOException e) { e.printStackTrace(); } } }