Home » geronimo-2.2-source-release » org.apache.geronimo.mavenplugins.geronimo.reporting » [javadoc | source]

    1   /**
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
   10    *    http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    *  Unless required by applicable law or agreed to in writing,
   13    *  software distributed under the License is distributed on an
   14    *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    *  KIND, either express or implied.  See the License for the
   16    *  specific language governing permissions and limitations
   17    *  under the License.
   18    */
   19   
   20   package org.apache.geronimo.mavenplugins.geronimo.reporting;
   21   
   22   import java.io.BufferedInputStream;
   23   import java.io.BufferedWriter;
   24   import java.io.File;
   25   import java.io.FileInputStream;
   26   import java.io.FileNotFoundException;
   27   import java.io.FileOutputStream;
   28   import java.io.IOException;
   29   import java.io.InputStream;
   30   import java.io.OutputStreamWriter;
   31   import java.io.PrintWriter;
   32   import java.io.UnsupportedEncodingException;
   33   import java.io.FileWriter;
   34   import java.text.NumberFormat;
   35   import java.util.ArrayList;
   36   import java.util.Collections;
   37   import java.util.Enumeration;
   38   import java.util.Iterator;
   39   import java.util.List;
   40   import java.util.Locale;
   41   import java.util.Properties;
   42   
   43   import org.slf4j.Logger;
   44   import org.slf4j.LoggerFactory;
   45   
   46   import org.apache.maven.surefire.report.ReporterException;
   47   import org.apache.maven.surefire.util.PrettyPrintXMLWriter;
   48   
   49   import org.codehaus.plexus.util.FileUtils;
   50   import org.codehaus.plexus.util.IOUtil;
   51   import org.codehaus.plexus.util.StringUtils;
   52   import org.codehaus.plexus.util.xml.Xpp3Dom;
   53   import org.codehaus.plexus.util.xml.Xpp3DomWriter;
   54   
   55   /**
   56    * A reporter that generates Surefire result data, so the Surefire report can be used.
   57    *
   58    * @version $Rev: 651684 $ $Date: 2008-04-25 12:11:52 -0700 (Fri, 25 Apr 2008) $
   59    */
   60   public class SurefireReporter
   61       implements Reporter
   62   {
   63       private final Logger log = LoggerFactory.getLogger(getClass());
   64   
   65       private static final String LS = System.getProperty("line.separator");
   66   
   67       /**
   68        * The name of the test (goal name).
   69        */
   70       private String testName;
   71   
   72       /**
   73        * The input log file, may or may not exist.
   74        */
   75       private File logFile;
   76   
   77       /**
   78        * The failure cause.
   79        */
   80       private Throwable failureCause;
   81   
   82       /**
   83        * @parameter expression="${project.build.directory}/surefire-reports"
   84        */
   85       private File reportsDirectory = null;
   86       
   87       /**
   88        * The file where the test output text will be written.
   89        */
   90       private File outputFile;
   91   
   92       /**
   93        * The file where the text result xml will be written.
   94        */
   95       private File reportFile;
   96   
   97       /**
   98        * The time when the test started.
   99        */
  100       private long startTime;
  101   
  102       /**
  103        * The number of errors.
  104        */
  105       private int numErrors = 0;
  106   
  107       private static final int MS_PER_SEC = 1000;
  108   
  109       private NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH);
  110   
  111       private List results = Collections.synchronizedList(new ArrayList());
  112   
  113       //
  114       // Reporter
  115       //
  116   
  117       public void reportBegin(final Reportable source) {
  118           assert source != null;
  119   
  120           logFile = source.getLogFile();
  121           testName = source.getName();
  122           startTime = source.getStartTime().getTime();
  123   
  124           try {
  125               FileUtils.forceMkdir(reportsDirectory);
  126           }
  127           catch (IOException e) {
  128               //
  129               // HACK: Maybe need to add a throws to beginReport() ?
  130               //
  131               
  132               log.error("Failed to make reports directory: " + reportsDirectory, e);
  133           }
  134   
  135           outputFile = new File(reportsDirectory, testName + ".txt");
  136           reportFile = new File(reportsDirectory, "TEST-" + testName + ".xml");
  137           if (reportFile.exists()) {
  138               reportFile.delete();
  139           }
  140       }
  141   
  142       public void reportError(final Throwable cause) {
  143           assert cause != null;
  144   
  145           log.debug("Capturing failed report from cause", cause);
  146           
  147           this.failureCause = cause;
  148       }
  149   
  150       public void reportEnd() {
  151           try {
  152               if (logFile.exists()) {
  153                   FileUtils.copyFile(logFile, outputFile);
  154               }
  155           }
  156           catch (Exception e) {
  157               log.warn("Failed to update outputFile", e);
  158           }
  159           
  160           if (failureCause != null) {
  161               try {
  162                   boolean append = outputFile.exists();
  163                   PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(outputFile, append)));
  164                   try {
  165                       writer.println("Exception Detail");
  166                       writer.println("================");
  167                       failureCause.printStackTrace(writer);
  168                       writer.flush();
  169                   }
  170                   finally {
  171                       writer.close();
  172                   }
  173               }
  174               catch (Exception e) {
  175                   log.warn("Failed to append error detail to outputFile", e);    
  176               }
  177   
  178               testFailed();
  179           }
  180           else {
  181               testSucceeded();
  182           }
  183   
  184           try {
  185               testSetCompleted();
  186           }
  187           catch (ReporterException e) {
  188               log.warn("Failed to set test completed", e);
  189           }
  190       }
  191   
  192       //
  193       // Surefire Support
  194       //
  195   
  196       private void testSetCompleted() throws ReporterException {
  197           long runTime = System.currentTimeMillis() - this.startTime;
  198   
  199           Xpp3Dom testSuite = createTestElement("testsuite", testName, runTime);
  200   
  201           showProperties(testSuite);
  202   
  203           testSuite.setAttribute("tests", "1");
  204           testSuite.setAttribute("errors", String.valueOf(numErrors));
  205           testSuite.setAttribute("skipped", "0");
  206           testSuite.setAttribute("failures", "0");
  207   
  208           for (Iterator i = results.iterator(); i.hasNext();) {
  209               Xpp3Dom testcase = (Xpp3Dom) i.next();
  210               testSuite.addChild(testcase);
  211           }
  212   
  213           PrintWriter writer = null;
  214   
  215           try {
  216               writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(reportFile), "UTF-8")));
  217               writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + LS);
  218               Xpp3DomWriter.write(new PrettyPrintXMLWriter(writer), testSuite);
  219           }
  220           catch (UnsupportedEncodingException e) {
  221               throw new ReporterException("Unable to use UTF-8 encoding", e);
  222           }
  223           catch (FileNotFoundException e) {
  224               throw new ReporterException("Unable to create file: " + e.getMessage(), e);
  225           }
  226           finally {
  227               IOUtil.close(writer);
  228           }
  229       }
  230   
  231       private Xpp3Dom createTestElement(String element, String testName, long runTime) {
  232           Xpp3Dom testCase = new Xpp3Dom(element);
  233           testCase.setAttribute("name", testName);
  234           testCase.setAttribute("time", elapsedTimeAsString(runTime));
  235   
  236           return testCase;
  237       }
  238   
  239       private Xpp3Dom createElement(Xpp3Dom element, String testName) {
  240           Xpp3Dom component = new Xpp3Dom(testName);
  241           element.addChild(component);
  242   
  243           return component;
  244       }
  245   
  246       private void testSucceeded() {
  247           long runTime = System.currentTimeMillis() - this.startTime;
  248           Xpp3Dom testCase = createTestElement("testcase", testName, runTime);
  249           results.add(testCase);
  250       }
  251   
  252       private void testFailed() {
  253           ++numErrors;
  254   
  255           try {
  256               InputStream input = new BufferedInputStream(new FileInputStream(outputFile));
  257               int length = input.available();
  258               byte[] b = new byte[length];
  259               input.read(b, 0, length);
  260               writeTestProblems(testName, new String(b));
  261           }
  262           catch (IOException e) {
  263               log.error("Failed to write test problems", e);
  264           }
  265       }
  266   
  267       private void writeTestProblems(String testName, String stdErr) {
  268           long runTime = System.currentTimeMillis() - this.startTime;
  269   
  270           Xpp3Dom testCase = createTestElement("testcase", testName, runTime);
  271           Xpp3Dom element = createElement(testCase, "failure");
  272   
  273           element.setAttribute("message", escapeAttribute(getMessage(stdErr)));
  274           element.setAttribute("type", getType(stdErr));
  275           element.setValue(stdErr);
  276   
  277           results.add(testCase);
  278       }
  279   
  280       /**
  281        * Adds system properties to the XML report.
  282        */
  283       private void showProperties(Xpp3Dom testSuite) {
  284           Xpp3Dom properties = createElement(testSuite, "properties");
  285   
  286           Properties systemProperties = System.getProperties();
  287   
  288           if (systemProperties != null) {
  289               Enumeration propertyKeys = systemProperties.propertyNames();
  290   
  291               while (propertyKeys.hasMoreElements()) {
  292                   String key = (String) propertyKeys.nextElement();
  293                   String value = systemProperties.getProperty(key);
  294   
  295                   if (value == null) {
  296                       value = "null";
  297                   }
  298   
  299                   Xpp3Dom property = createElement(properties, "property");
  300   
  301                   property.setAttribute("name", key);
  302                   property.setAttribute("value", escapeAttribute(value));
  303               }
  304           }
  305       }
  306   
  307       private static String escapeAttribute(String attribute) {
  308           // Shouldn't Xpp3Dom do this itself?
  309           String s = StringUtils.replace(attribute, "<", "&lt;");
  310           return StringUtils.replace(s, ">", "&gt;");
  311       }
  312   
  313       private Iterator getResults() {
  314           return results.iterator();
  315       }
  316   
  317       private String elapsedTimeAsString(long runTime) {
  318           return numberFormat.format((double) runTime / MS_PER_SEC);
  319       }
  320   
  321       /**
  322        * Gets the messages following the exception type.
  323        */
  324       private String getMessage(String stdErr) {
  325           int beginMarker = stdErr.indexOf("Exception:") + 10;
  326           int endMarker = stdErr.indexOf("\n", beginMarker);
  327           return stdErr.substring(beginMarker, endMarker);
  328       }
  329   
  330       /**
  331        * Gets the type of exception from the stacktrace.
  332        */
  333       private String getType(String stdErr) {
  334           int endMarker = stdErr.indexOf("Exception:") + 9;
  335           int beginMarker = stdErr.lastIndexOf("\n", endMarker) + 1;
  336           return stdErr.substring(beginMarker, endMarker);
  337       }
  338   
  339       /** 
  340        * The generated reports xml file for surefire..
  341        * 
  342        * @return generated reports xml file
  343        */
  344       public File getReportsFile() {
  345           return this.reportFile;
  346       }
  347   
  348       /**
  349        * The text file which holds the stdout or stderr.
  350        *
  351        * @return File
  352        */
  353       public File getOutputFile() {
  354           return this.outputFile;
  355       }
  356   }

Home » geronimo-2.2-source-release » org.apache.geronimo.mavenplugins.geronimo.reporting » [javadoc | source]