Home | History | Annotate | Download | only in xml
      1 package org.testng.xml;
      2 
      3 
      4 import static org.testng.internal.Utils.isStringNotBlank;
      5 
      6 import org.testng.collections.Lists;
      7 import org.testng.internal.Utils;
      8 import org.testng.log4testng.Logger;
      9 import org.testng.remote.RemoteTestNG;
     10 import org.testng.reporters.XMLStringBuffer;
     11 
     12 import java.io.File;
     13 import java.io.FileOutputStream;
     14 import java.io.IOException;
     15 import java.io.OutputStreamWriter;
     16 import java.nio.charset.Charset;
     17 import java.util.Collection;
     18 import java.util.List;
     19 import java.util.Map;
     20 import java.util.Properties;
     21 
     22 /**
     23  * This class is used to encapsulate a launch. Various synthetic XML files are created
     24  * depending on whether the user is trying to launch a suite, a class, a method, etc...
     25  */
     26 public abstract class LaunchSuite {
     27   /** This class's log4testng Logger. */
     28   private static final Logger LOGGER = Logger.getLogger(LaunchSuite.class);
     29 
     30   protected boolean m_temporary;
     31 
     32   /**
     33    * Constructs a <code>LaunchSuite</code>
     34    *
     35    * @param isTemp the temporary status
     36    */
     37   protected LaunchSuite(boolean isTemp) {
     38     m_temporary = isTemp;
     39   }
     40 
     41   /**
     42    * Returns the temporary state.
     43    * @return the temporary state.
     44    */
     45   public boolean isTemporary() {
     46     return m_temporary;
     47   }
     48 
     49   /**
     50    * Saves the suite file in the specified directory and returns the file
     51    * pathname.
     52    *
     53    * @param directory the directory where the suite file is to be saved.
     54    * @return the file pathname of the saved file.
     55    */
     56   public abstract File save(File directory);
     57 
     58   public abstract XMLStringBuffer getSuiteBuffer();
     59 
     60   /**
     61    * <code>ExistingSuite</code> is a non-temporary LaunchSuite based on an existing
     62    * file.
     63    */
     64   public static class ExistingSuite extends LaunchSuite {
     65 
     66     /**
     67      * The existing suite path (either relative to the project root or an absolute path)
     68      */
     69     private File m_suitePath;
     70 
     71     /**
     72      * Constructs a <code>ExistingSuite</code> based on an existing file
     73      *
     74      * @param path the path to the existing Launch suite.
     75      */
     76     public ExistingSuite(File path) {
     77       super(false);
     78 
     79       m_suitePath = path;
     80     }
     81 
     82     @Override
     83     public XMLStringBuffer getSuiteBuffer() {
     84       throw new UnsupportedOperationException("Not implemented yet");
     85     }
     86 
     87     /**
     88      * Trying to run an existing XML file: copy its content to where the plug-in
     89      * expects it.
     90      */
     91     @Override
     92     public File save(File directory) {
     93       if (RemoteTestNG.isDebug()) {
     94         File result = new File(directory, RemoteTestNG.DEBUG_SUITE_FILE);
     95         Utils.copyFile(m_suitePath, result);
     96         return result;
     97       } else {
     98         return m_suitePath;
     99       }
    100     }
    101   }
    102 
    103   /**
    104    * <code>CustomizedSuite</code> TODO cquezel JavaDoc.
    105    */
    106   private abstract static class CustomizedSuite extends LaunchSuite {
    107     protected String m_projectName;
    108     protected String m_suiteName;
    109 
    110     /** The annotation type. May be null. */
    111     protected Map<String, String> m_parameters;
    112 
    113     /** The string buffer used to write the XML file. */
    114     private XMLStringBuffer m_suiteBuffer;
    115 
    116     /**
    117      * Constructs a <code>CustomizedSuite</code> TODO cquezel JavaDoc.
    118      *
    119      * @param projectName
    120      * @param className
    121      * @param parameters
    122      * @param annotationType
    123      */
    124     private CustomizedSuite(final String projectName,
    125         final String className,
    126         final Map<String, String> parameters,
    127         final String annotationType)
    128     {
    129       super(true);
    130 
    131       m_projectName = projectName;
    132       m_suiteName = className;
    133       m_parameters = parameters;
    134     }
    135 
    136     /**
    137      * TODO cquezel JavaDoc
    138      *
    139      * @return
    140      */
    141     protected XMLStringBuffer createContentBuffer() {
    142       XMLStringBuffer suiteBuffer = new XMLStringBuffer();
    143       suiteBuffer.setDocType("suite SYSTEM \"" + Parser.TESTNG_DTD_URL + "\"");
    144 
    145       Properties attrs = new Properties();
    146       attrs.setProperty("parallel", XmlSuite.ParallelMode.NONE.toString());
    147       attrs.setProperty("name", m_suiteName);
    148       suiteBuffer.push("suite", attrs);
    149 
    150       if (m_parameters != null) {
    151         for (Map.Entry<String, String> entry : m_parameters.entrySet()) {
    152           Properties paramAttrs = new Properties();
    153           paramAttrs.setProperty("name", entry.getKey());
    154           paramAttrs.setProperty("value", entry.getValue());
    155           suiteBuffer.push("parameter", paramAttrs);
    156           suiteBuffer.pop("parameter");
    157         }
    158       }
    159 
    160       initContentBuffer(suiteBuffer);
    161 
    162       suiteBuffer.pop("suite");
    163 
    164       return suiteBuffer;
    165     }
    166 
    167     /**
    168      * TODO cquezel JavaDoc
    169      *
    170      * @return
    171      */
    172     @Override
    173     public XMLStringBuffer getSuiteBuffer() {
    174       if (null == m_suiteBuffer) {
    175         m_suiteBuffer = createContentBuffer();
    176       }
    177 
    178       return m_suiteBuffer;
    179     }
    180 
    181     /**
    182      * Initializes the content of the xml string buffer.
    183      *
    184      * @param suiteBuffer the string buffer to initialize.
    185      */
    186     protected abstract void initContentBuffer(XMLStringBuffer suiteBuffer);
    187 
    188     /**
    189      * {@inheritDoc} This implementation saves the suite to the "temp-testng-customsuite.xml"
    190      * file in the specified directory.
    191      */
    192     @Override
    193     public File save(File directory) {
    194       final File suiteFile = new File(directory, "temp-testng-customsuite.xml");
    195 
    196       saveSuiteContent(suiteFile, getSuiteBuffer());
    197 
    198       return suiteFile;
    199     }
    200 
    201     /**
    202      * Saves the content of the string buffer to the specified file.
    203      *
    204      * @param file the file to write to.
    205      * @param content the content to write to the file.
    206      */
    207     protected void saveSuiteContent(final File file, final XMLStringBuffer content) {
    208 
    209       try {
    210         OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file), Charset.forName("UTF-8"));
    211         try {
    212           fw.write(content.getStringBuffer().toString());
    213         }
    214         finally {
    215           fw.close();
    216         }
    217       }
    218       catch (IOException ioe) {
    219         // TODO CQ is this normal to swallow exception here
    220         LOGGER.error("IO Exception", ioe);
    221       }
    222     }
    223   }
    224 
    225   /**
    226    * A <code>MethodsSuite</code> is a suite made up of methods.
    227    */
    228   static class MethodsSuite extends CustomizedSuite {
    229     protected Collection<String> m_methodNames;
    230     protected String m_className;
    231     protected int m_logLevel;
    232 
    233     /**
    234      * Constructs a <code>MethodsSuite</code> TODO cquezel JavaDoc.
    235      *
    236      * @param projectName
    237      * @param className
    238      * @param methodNames
    239      * @param parameters
    240      * @param annotationType (may be null)
    241      * @param logLevel
    242      */
    243     MethodsSuite(final String projectName,
    244         final String className,
    245         final Collection<String> methodNames,
    246         final Map<String, String> parameters,
    247         final String annotationType,
    248         final int logLevel) {
    249       super(projectName, className, parameters, annotationType);
    250 
    251       m_className = className;
    252       m_methodNames = methodNames;
    253       m_logLevel = logLevel;
    254     }
    255 
    256     /**
    257      * {@inheritDoc}
    258      */
    259     @Override
    260     protected void initContentBuffer(XMLStringBuffer suiteBuffer) {
    261       Properties testAttrs = new Properties();
    262       testAttrs.setProperty("name", m_className);
    263       testAttrs.setProperty("verbose", String.valueOf(m_logLevel));
    264 
    265       suiteBuffer.push("test", testAttrs);
    266 
    267       suiteBuffer.push("classes");
    268 
    269       Properties classAttrs = new Properties();
    270       classAttrs.setProperty("name", m_className);
    271 
    272       if ((null != m_methodNames) && (m_methodNames.size() > 0)) {
    273         suiteBuffer.push("class", classAttrs);
    274 
    275         suiteBuffer.push("methods");
    276 
    277         for (Object methodName : m_methodNames) {
    278           Properties methodAttrs = new Properties();
    279           methodAttrs.setProperty("name", (String) methodName);
    280           suiteBuffer.addEmptyElement("include", methodAttrs);
    281         }
    282 
    283         suiteBuffer.pop("methods");
    284         suiteBuffer.pop("class");
    285       }
    286       else {
    287         suiteBuffer.addEmptyElement("class", classAttrs);
    288       }
    289       suiteBuffer.pop("classes");
    290       suiteBuffer.pop("test");
    291     }
    292   }
    293 
    294   static class ClassesAndMethodsSuite extends CustomizedSuite {
    295     protected Map<String, Collection<String>> m_classes;
    296     protected int m_logLevel;
    297 
    298     ClassesAndMethodsSuite(final String projectName,
    299         final Map<String, Collection<String>> classes,
    300         final Map<String, String> parameters,
    301         final String annotationType,
    302         final int logLevel) {
    303       super(projectName, "Custom suite", parameters, annotationType);
    304       m_classes = classes;
    305       m_logLevel = logLevel;
    306     }
    307 
    308     /**
    309      * {@inheritDoc}
    310      */
    311     @Override
    312     protected void initContentBuffer(XMLStringBuffer suiteBuffer) {
    313       Properties testAttrs = new Properties();
    314       testAttrs.setProperty("name", m_projectName);
    315       testAttrs.setProperty("verbose", String.valueOf(m_logLevel));
    316 
    317       suiteBuffer.push("test", testAttrs);
    318 
    319       suiteBuffer.push("classes");
    320 
    321       for(Map.Entry<String, Collection<String>> entry : m_classes.entrySet()) {
    322         Properties classAttrs = new Properties();
    323         classAttrs.setProperty("name", entry.getKey());
    324 
    325         Collection<String> methodNames= sanitize(entry.getValue());
    326         if ((null != methodNames) && (methodNames.size() > 0)) {
    327           suiteBuffer.push("class", classAttrs);
    328 
    329           suiteBuffer.push("methods");
    330 
    331           for (String methodName : methodNames) {
    332             Properties methodAttrs = new Properties();
    333             methodAttrs.setProperty("name", methodName);
    334             suiteBuffer.addEmptyElement("include", methodAttrs);
    335           }
    336 
    337           suiteBuffer.pop("methods");
    338           suiteBuffer.pop("class");
    339         }
    340         else {
    341           suiteBuffer.addEmptyElement("class", classAttrs);
    342         }
    343       }
    344       suiteBuffer.pop("classes");
    345       suiteBuffer.pop("test");
    346     }
    347 
    348     private Collection<String> sanitize(Collection<String> source) {
    349       if(null == source) {
    350         return null;
    351       }
    352 
    353       List<String> result= Lists.newArrayList();
    354       for(String name: source) {
    355         if(isStringNotBlank(name)) {
    356           result.add(name);
    357         }
    358       }
    359 
    360       return result;
    361     }
    362   }
    363 
    364   /**
    365    * <code>ClassListSuite</code> TODO cquezel JavaDoc.
    366    */
    367   static class ClassListSuite extends CustomizedSuite {
    368     protected Collection<String> m_packageNames;
    369     protected Collection<String> m_classNames;
    370     protected Collection<String> m_groupNames;
    371     protected int m_logLevel;
    372 
    373     ClassListSuite(final String projectName,
    374         final Collection<String> packageNames,
    375         final Collection<String> classNames,
    376         final Collection<String> groupNames,
    377         final Map<String, String> parameters,
    378         final String annotationType,
    379         final int logLevel) {
    380       super(projectName, "Custom suite", parameters, annotationType);
    381 
    382       m_packageNames = packageNames;
    383       m_classNames = classNames;
    384       m_groupNames = groupNames;
    385       m_logLevel = logLevel;
    386     }
    387 
    388     /**
    389      * {@inheritDoc}
    390      */
    391     @Override
    392     protected void initContentBuffer(XMLStringBuffer suiteBuffer) {
    393       Properties testAttrs = new Properties();
    394       testAttrs.setProperty("name", m_projectName);
    395       testAttrs.setProperty("verbose", String.valueOf(m_logLevel));
    396 
    397       suiteBuffer.push("test", testAttrs);
    398 
    399       if (null != m_groupNames) {
    400         suiteBuffer.push("groups");
    401         suiteBuffer.push("run");
    402 
    403         for (String groupName : m_groupNames) {
    404           Properties includeAttrs = new Properties();
    405           includeAttrs.setProperty("name", groupName);
    406           suiteBuffer.addEmptyElement("include", includeAttrs);
    407         }
    408 
    409         suiteBuffer.pop("run");
    410         suiteBuffer.pop("groups");
    411       }
    412 
    413       // packages belongs to suite according to the latest DTD
    414       if ((m_packageNames != null) && (m_packageNames.size() > 0)) {
    415         suiteBuffer.push("packages");
    416 
    417         for (String packageName : m_packageNames) {
    418           Properties packageAttrs = new Properties();
    419           packageAttrs.setProperty("name", packageName);
    420           suiteBuffer.addEmptyElement("package", packageAttrs);
    421         }
    422         suiteBuffer.pop("packages");
    423       }
    424 
    425       if ((m_classNames != null) && (m_classNames.size() > 0)) {
    426         suiteBuffer.push("classes");
    427 
    428         for (String className : m_classNames) {
    429           Properties classAttrs = new Properties();
    430           classAttrs.setProperty("name", className);
    431           suiteBuffer.addEmptyElement("class", classAttrs);
    432         }
    433 
    434         suiteBuffer.pop("classes");
    435       }
    436       suiteBuffer.pop("test");
    437     }
    438   }
    439 }
    440