       1 /*
       2  * $Id$
       3  *
       4  * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
       5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       6  *
       7  * This code is free software; you can redistribute it and/or modify it
       8  * under the terms of the GNU General Public License version 2 only, as
       9  * published by the Free Software Foundation.  Oracle designates this
      10  * particular file as subject to the "Classpath" exception as provided
      11  * by Oracle in the LICENSE file that accompanied this code.
      12  *
      13  * This code is distributed in the hope that it will be useful, but WITHOUT
      14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16  * version 2 for more details (a copy is included in the LICENSE file that
      17  * accompanied this code).
      18  *
      19  * You should have received a copy of the GNU General Public License version
      20  * 2 along with this work; if not, write to the Free Software Foundation,
      21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      22  *
      23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      24  * or visit www.oracle.com if you need additional information or have any
      25  * questions.
      26  */
      27 package com.sun.javatest.cof;
      28
      29 import java.io.BufferedReader;
      30 import java.io.File;
      31 import java.io.IOException;
      32 import java.io.StringReader;
      33 import java.text.DateFormat;
      34 import java.text.ParseException;
      35 import java.text.SimpleDateFormat;
      36 import java.util.ArrayList;
      37 import java.util.Date;
      38 import java.util.LinkedHashMap;
      39 import java.util.List;
      40 import java.util.Vector;
      41 import java.util.regex.Matcher;
      42 import java.util.regex.Pattern;
      43
      44 import com.sun.javatest.Status;
      45 import com.sun.javatest.TestResult;
      46 import com.sun.javatest.TestResult.ReloadFault;
      47 import com.sun.javatest.TestResult.ResultFileNotFoundFault;
      48 import java.util.Iterator;
      49
      50 /*import javax.xml.bind.annotation.XmlAccessType;
      51 import javax.xml.bind.annotation.XmlAccessorType;
      52 import javax.xml.bind.annotation.XmlAttribute;
      53 import javax.xml.bind.annotation.XmlElement;
      54 import javax.xml.bind.annotation.XmlType;
      55 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
      56  */
      57 /**
      58  *
      59  *         The analysis setting is meant to allow remote groups to waive or
      60  *         accept the pass/fail status of the test using E-mail. For
      61  *         testcases, the analysis setting provides a default value to
      62  *         apply to the analysis the setting for all testcase results for
      63  *         this test.
      64  *
      65  *
      66  * <p>Java class for Test complex type.
      67  *
      68  * <p>The following schema fragment specifies the expected content contained within this class.
      69  *
      70  * <pre>
      71  * &lt;complexType name="Test">
      72  *   &lt;complexContent>
      73  *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
      74  *       &lt;sequence>
      75  *         &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
      76  *         &lt;element name="appuse" type="{http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema}IDWithColon" maxOccurs="unbounded" minOccurs="0"/>
      77  *         &lt;element name="status" type="{http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema}Status" minOccurs="0"/>
      78  *         &lt;element name="testcases" type="{http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema}TestCases" minOccurs="0"/>
      79  *         &lt;element name="starttime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
      80  *         &lt;element name="endtime" type="{http://www.w3.org/2001/XMLSchema}dateTime" minOccurs="0"/>
      81  *         &lt;element name="attributes" type="{http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema}TestAttributes" minOccurs="0"/>
      82  *         &lt;element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
      83  *       &lt;/sequence>
      84  *       &lt;attribute name="analysis" default="accept">
      85  *         &lt;simpleType>
      86  *           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}string">
      87  *             &lt;enumeration value="accept"/>
      88  *             &lt;enumeration value="waive"/>
      89  *           &lt;/restriction>
      90  *         &lt;/simpleType>
      91  *       &lt;/attribute>
      92  *       &lt;attribute name="id" use="required" type="{http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema}IDWithColon" />
      93  *     &lt;/restriction>
      94  *   &lt;/complexContent>
      95  * &lt;/complexType>
      96  * </pre>
      97  */
      98 /*@XmlAccessorType(XmlAccessType.FIELD)
      99 @XmlType(name = "Test", propOrder = {
     100 "name",
     101 "appuse",
     102 "status",
     103 "testcases",
     104 "starttime",
     105 "endtime",
     106 "attributes",
     107 "description"
     108 })*/
     109 public class COFTest extends COFItem {
     110
     111     private static final Date badDate = new Date(0);
     112     private static final String[] cofStatus = new String[Status.NUM_STATES];
     113     static long count = 0;
     114     private static DateFormat[] dateFormats;
     115     protected final static Pattern idPattern = Pattern.compile(".*[^\\w\\.\\[\\]\\(\\)\\{\\},_\\-]([\\w\\.\\[\\]\\(\\)\\{\\},_\\-]+)");
     116     static boolean noTestCases = false;
     117     protected final static Pattern testCasePattern = Pattern //.compile("^(\\S+): (Passed\\.|Failed\\.|Error\\.|Not\\ run\\.)(.*)");
     118             .compile("^(.*): (Passed\\.|Failed\\.|Error\\.|Not\\ run\\.)(.*)");
     119     static LinkedHashMap xmlAttributes;
     120     static LinkedHashMap xmlElements;
     121     static String xmlTagName;
     122
     123     static {
     124         xmlElements = new LinkedHashMap();
     125         xmlAttributes = new LinkedHashMap();
     126         xmlElements.put("name", "name");
     127         xmlElements.put("appuse", "appuse");
     128         xmlElements.put("status", "status");
     129         xmlElements.put("testcases", "testcases");
     130         xmlElements.put("starttime", "starttime");
     131         xmlElements.put("endtime", "endtime");
     132         xmlElements.put("attributes", "attributes");
     133         xmlElements.put("description", "description");
     134         //              xmlAttributes.put("analysis", "analysis");
     135         xmlAttributes.put("id", "id");
     136         xmlTagName = "test";
     137
     138         initDateFormats();
     139     }
     140
     141     static {
     142         cofStatus[Status.PASSED] = "pass";
     143         cofStatus[Status.FAILED] = "fail";
     144         cofStatus[Status.ERROR] = "error";
     145         cofStatus[Status.NOT_RUN] = "did_not_run";
     146     }
     147     //    @XmlAttribute
     148     protected String analysis;
     149     //    @XmlElement(namespace = "http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema", required = true)
     150     protected List/*<String>*/ appuse;
     151     //    @XmlElement(namespace = "http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema")
     152     protected COFTestAttributes attributes;
     153     //    @XmlElement(namespace = "http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema")
     154     protected String description;
     155     //    @XmlElement(namespace = "http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema", type = String.class)
     156     //    @XmlJavaTypeAdapter(Adapter1 .class)
     157     protected Date endtime;
     158     //    @XmlAttribute(required = true)
     159     protected String id;
     160     final long idNum = count++;
     161     //    @XmlElement(namespace = "http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema", required = true)
     162     protected String name;
     163     //    @XmlElement(namespace = "http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema", type = String.class)
     164     //    @XmlJavaTypeAdapter(Adapter1 .class)
     165     protected Date starttime;
     166     //    @XmlElement(namespace = "http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema")
     167     protected COFStatus status;
     168     //    @XmlElement(namespace = "http://qare.sfbay.sun.com/projects/COF/2003/2_0_2/Schema")
     169     protected COFTestCases testcases;
     170     private COFData cofData;
     171
     172     COFTest(TestResult tr, COFData data) {
     173         cofData = data;
     174         status = new COFStatus();
     175         status.setValue(cofStatus[tr.getStatus().getType()]);
     176         status.setActual(tr.getStatus().getReason());
     177         fillTestCases(tr);
     178         //if (tr.getStatus().isError() || tr.getStatus().isFailed()) {
     179             checkLostTestCases(tr);
     180         //}
     181         setName(tr.getTestName());
     182         if (!tr.getStatus().isNotRun()) {
     183             setStarttime(parseDate(tr, TestResult.START));
     184             setEndtime(parseDate(tr, TestResult.END));
     185         }
     186         attributes = new COFTestAttributes();
     187         attributes.getAttribute().add(
     188                 new COFTestAttribute("logfile", tr.getWorkRelativePath()));
     189         if (data.isInterviewParametersAvailable()) {
     190             try {
     191                 if (!data.getInterviewParameters().getExcludeListFilter().accepts(tr.getDescription())) {
     192                     attributes.getAttribute().add(new COFTestAttribute("isOnExcludeList", "true"));
     193                 }
     194             } catch(Exception e) {
     195             }
     196         }
     197         String jo = cofData.get("jvmopt", null);
     198         if (jo != null) {
     199             attributes.getAttribute().add(new COFTestAttribute("javaopt", jo));
     200         }
     201
     202     }
     203
     204     protected void fillTestCases(TestResult tr) {
     205         if (noTestCases) {
     206             return;
     207         }
     208         testcases = new COFTestCases();
     209         int sCount = tr.getSectionCount();
     210         if (sCount == 0 && tr.getStatus().getType() != Status.NOT_RUN) {
     211             try {
     212                 tr = new TestResult(new File(cofData.get("workdir") + File.separator + tr.getWorkRelativePath()));
     213                 sCount = tr.getSectionCount();
     214             } catch (ResultFileNotFoundFault e) {
     215                 // warning is out from somewhere else, but again
     216                 System.err.println(e.getMessage());
     217             } catch (ReloadFault e) {
     218                 System.err.println(tr.getFile());
     219             }
     220         }
     221         for (int i = 0; i < sCount; i++) {
     222             try {
     223                 String sectionOut = tr.getSection(i).getOutput("out1");
     224                 if (sectionOut == null) {
     225                     continue;
     226                 }
     227                 BufferedReader reader = new BufferedReader(new StringReader(
     228                         sectionOut));
     229                 String s = reader.readLine();
     230                 while (s != null) {
     231                     Matcher m = testCasePattern.matcher(s);
     232                     if (m.matches()) {
     233                         COFTestCase tc = new COFTestCase();
     234                         COFStatus cStatus = new COFStatus();
     235                         String tcName = fixIncorrectTestCaseName(m.group(1));
     236                         if (tcName == null) {
     237                             s = reader.readLine();
     238                             continue;
     239                         }
     240                         tc.setName(tcName);
     241                         cStatus.setValue(cofStatus[Status.parse(m.group(2)).getType()]);
     242                         cStatus.setActual(m.group(3));
     243                         tc.setStatus(cStatus);
     244                         testcases.getTestcase().add(tc);
     245                     }
     246                     s = reader.readLine();
     247                 }
     248             } catch (ReloadFault e) {
     249                 // TODO Auto-generated catch block
     250                 e.printStackTrace();
     251             } catch (IOException e) {
     252                 // TODO Auto-generated catch block
     253                 e.printStackTrace();
     254             }
     255         }
     256     }
     257
     258     private void checkLostTestCases(TestResult tr) {
     259         MTL mtl = cofData.getMtl();
     260
     261         if (mtl == null) {
     262             // mtl is not specified
     263             return;
     264         }
     265
     266         List  /*<COFTestCase>*/ jtrCases = testcases.getTestcase();
     267         List  /*<String>*/ mtlTestCases = mtl.getTestCases(tr.getTestName());
     268         if (mtlTestCases != null && mtlTestCases.size() > 0) {
     269             // for (COFTestCase jtrCase : jtrCases) {
     270             Iterator it = jtrCases.iterator();
     271             while (it.hasNext()) {
     272                 COFTestCase jtrCase = (COFTestCase) it.next();
     273                 mtlTestCases.remove(jtrCase.name);
     274             }
     275             if (mtlTestCases.size() > 0) {
     276                 //for (String testCaseName : mtlTestCases) {
     277                 it = mtlTestCases.iterator();
     278                 while(it.hasNext()) {
     279                     String testCaseName = (String) it.next();
     280                     COFTestCase nTc = new COFTestCase();
     281                     COFStatus nStatus = new COFStatus();
     282                     nTc.setName(testCaseName);
     283                     String strS = cofStatus[tr.getStatus().getType()];
     284                     nStatus.setValue(strS);
     285                     //System.out.println("+ " + tr.getTestName() + " " + tcName + " " + strS );
     286                     testcases.getTestcase().add(testCaseName);
     287                 }
     288             }
     289         }
     290     }
     291
     292     /**
     293      * Gets the value of the analysis property.
     294      *
     295      * @return
     296      *     possible object is
     297      *     {@link String }
     298      *
     299      */
     300     public String getAnalysis() {
     301         if (analysis == null) {
     302             return "accept";
     303         } else {
     304             return analysis;
     305         }
     306     }
     307
     308     /**
     309      * Gets the value of the appuse property.
     310      *
     311      * <p>
     312      * This accessor method returns a reference to the live list,
     313      * not a snapshot. Therefore any modification you make to the
     314      * returned list will be present inside the JAXB object.
     315      * This is why there is not a <CODE>set</CODE> method for the appuse property.
     316      *
     317      * <p>
     318      * For example, to add a new item, do as follows:
     319      * <pre>
     320      *    getAppuse().add(newItem);
     321      * </pre>
     322      *
     323      *
     324      * <p>
     325      * Objects of the following type(s) are allowed in the list
     326      * {@link String }
     327      *
     328      *
     329      */
     330     public List/*<String>*/ getAppuse() {
     331         if (appuse == null) {
     332             appuse = new ArrayList/*<String>*/();
     333         }
     334         return this.appuse;
     335     }
     336
     337     /**
     338      * Gets the value of the attributes property.
     339      *
     340      * @return
     341      *     possible object is
     342      *     {@link COFTestAttributes }
     343      *
     344      */
     345     public COFTestAttributes getAttributes() {
     346         return attributes;
     347     }
     348
     349     /**
     350      * Gets the value of the description property.
     351      *
     352      * @return
     353      *     possible object is
     354      *     {@link String }
     355      *
     356      */
     357     public String getDescription() {
     358         return description;
     359     }
     360
     361     /**
     362      * Gets the value of the endtime property.
     363      *
     364      * @return
     365      *     possible object is
     366      *     {@link String }
     367      *
     368      */
     369     public Date getEndtime() {
     370         return endtime;
     371     }
     372
     373     /**
     374      * Gets the value of the id property.
     375      *
     376      * @return
     377      *     possible object is
     378      *     {@link String }
     379      *
     380      */
     381     public String getId() {
     382         if (id != null) {
     383             return id;
     384         }
     385         if (name == null) {
     386             throw new IllegalStateException("Name was not set.");
     387         }
     388         Matcher m = idPattern.matcher(name);
     389         if (m.matches()) {
     390             id = m.group(1) + ":" + idNum;
     391         } else {
     392             id = "test:" + idNum;
     393         }
     394         return id;
     395     }
     396
     397     LinkedHashMap getItemAttributes() {
     398         return xmlAttributes;
     399     }
     400
     401     LinkedHashMap getItemElements() {
     402         return xmlElements;
     403     }
     404
     405     String getItemTagName() {
     406         return xmlTagName;
     407     }
     408
     409     /**
     410      * Gets the value of the name property.
     411      *
     412      * @return
     413      *     possible object is
     414      *     {@link String }
     415      *
     416      */
     417     public String getName() {
     418         return name;
     419     }
     420
     421     /**
     422      * Gets the value of the starttime property.
     423      *
     424      * @return
     425      *     possible object is
     426      *     {@link String }
     427      *
     428      */
     429     public Date getStarttime() {
     430         return starttime;
     431     }
     432
     433     /**
     434      * Gets the value of the status property.
     435      *
     436      * @return
     437      *     possible object is
     438      *     {@link COFStatus }
     439      *
     440      */
     441     public COFStatus getStatus() {
     442         return status;
     443     }
     444
     445     /**
     446      * Gets the value of the testcases property.
     447      *
     448      * @return
     449      *     possible object is
     450      *     {@link COFTestCases }
     451      *
     452      */
     453     public COFTestCases getTestcases() {
     454         return testcases;
     455     }
     456
     457     /**
     458      * Sets the value of the id property.
     459      *
     460      * @param value
     461      *     allowed object is
     462      *     {@link String }
     463      *
     464      */
     465     //  public void setId(String value) {
     466     //          this.id = value;
     467     //  }
     468     private static void initDateFormats() {
     469         Vector v = new Vector();
     470
     471         // generic Java default
     472         // 10-Sep-99 3:25:11 PM
     473         v.addElement(DateFormat.getDateTimeInstance());
     474
     475         // standard IETF date syntax
     476         // Fri, 10 September 1999 03:25:12 PDT
     477         v.addElement(new SimpleDateFormat("EEE, dd MMMM yyyy HH:mm:ss zzz"));
     478
     479         // Unix C time
     480         // Fri Sep 10 14:41:37 PDT 1999
     481         v.addElement(new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"));
     482
     483         // XML time
     484         // 1999-09-10T03:25:12.123 (ISO 8601, sect 5.4)
     485         v.addElement(new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS"));
     486
     487         // allow user-specified format
     488         String s = System.getProperty("javatest.date.format");
     489         if (s != null) {
     490             v.addElement(new SimpleDateFormat(s));
     491         }
     492
     493         dateFormats = new DateFormat[v.size()];
     494         v.copyInto(dateFormats);
     495     }
     496
     497     private static Date parseDate(String s) {
     498         for (int i = 0; i < dateFormats.length; i++) {
     499             try {
     500                 Date d = dateFormats[i].parse(s);
     501                 // successfully parsed the date; shuffle the format to the front
     502                 // to speed up future parses, assuming dates will likely be similar
     503                 if (i > 0) {
     504                     DateFormat tmp = dateFormats[i];
     505                     System.arraycopy(dateFormats, 0, dateFormats, 1, i);
     506                     dateFormats[0] = tmp;
     507                 }
     508                 return d;
     509             } catch (ParseException e) {
     510                 //System.err.println("pattern: " + ((SimpleDateFormat)dateFormats[i]).toPattern());
     511                 //System.err.println("  value: " + s);
     512                 //System.err.println("example: " + dateFormats[i].format(new Date()));
     513             }
     514         }
     515
     516         return badDate;
     517     }
     518
     519     private static Date parseDate(TestResult tr, String key) {
     520         try {
     521             String s = tr.getProperty(key);
     522             if (s != null && s.length() > 0) {
     523                 return parseDate(s);
     524             }
     525         } catch (TestResult.Fault e) {
     526             System.err.println(e);
     527         }
     528         // default, if no entry in test result, or if error reloading test result
     529         return badDate;
     530     }
     531
     532     /**
     533      * Sets the value of the analysis property.
     534      *
     535      * @param value
     536      *     allowed object is
     537      *     {@link String }
     538      *
     539      */
     540     public void setAnalysis(String value) {
     541         this.analysis = value;
     542     }
     543
     544     /**
     545      * Sets the value of the attributes property.
     546      *
     547      * @param value
     548      *     allowed object is
     549      *     {@link COFTestAttributes }
     550      *
     551      */
     552     public void setAttributes(COFTestAttributes value) {
     553         this.attributes = value;
     554     }
     555
     556     /**
     557      * Sets the value of the description property.
     558      *
     559      * @param value
     560      *     allowed object is
     561      *     {@link String }
     562      *
     563      */
     564     public void setDescription(String value) {
     565         this.description = value;
     566     }
     567
     568     /**
     569      * Sets the value of the endtime property.
     570      *
     571      * @param value
     572      *     allowed object is
     573      *     {@link String }
     574      *
     575      */
     576     public void setEndtime(Date value) {
     577         this.endtime = value;
     578     }
     579
     580     /**
     581      * Sets the value of the name property.
     582      *
     583      * @param value
     584      *     allowed object is
     585      *     {@link String }
     586      *
     587      */
     588     public void setName(String value) {
     589         this.name = value;
     590     }
     591
     592     /**
     593      * Sets the value of the starttime property.
     594      *
     595      * @param value
     596      *     allowed object is
     597      *     {@link String }
     598      *
     599      */
     600     public void setStarttime(Date value) {
     601         this.starttime = value;
     602     }
     603
     604     /**
     605      * Sets the value of the status property.
     606      *
     607      * @param value
     608      *     allowed object is
     609      *     {@link COFStatus }
     610      *
     611      */
     612     public void setStatus(COFStatus value) {
     613         this.status = value;
     614     }
     615
     616     /**
     617      * Sets the value of the testcases property.
     618      *
     619      * @param value
     620      *     allowed object is
     621      *     {@link COFTestCases }
     622      *
     623      */
     624     public void setTestcases(COFTestCases value) {
     625         this.testcases = value;
     626     }
     627
     628     private String fixIncorrectTestCaseName(String tcn) {
     629         return cofData.getCustomFilter().transformTestCaseName(tcn);
     630     }
     631 }