• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    */
LaunchSuite(boolean isTemp)37   protected LaunchSuite(boolean isTemp) {
38     m_temporary = isTemp;
39   }
40 
41   /**
42    * Returns the temporary state.
43    * @return the temporary state.
44    */
isTemporary()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    */
save(File directory)56   public abstract File save(File directory);
57 
getSuiteBuffer()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      */
ExistingSuite(File path)76     public ExistingSuite(File path) {
77       super(false);
78 
79       m_suitePath = path;
80     }
81 
82     @Override
getSuiteBuffer()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
save(File directory)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      */
CustomizedSuite(final String projectName, final String className, final Map<String, String> parameters, final String annotationType)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      */
createContentBuffer()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
getSuiteBuffer()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      */
initContentBuffer(XMLStringBuffer suiteBuffer)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
save(File directory)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      */
saveSuiteContent(final File file, final XMLStringBuffer content)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      */
MethodsSuite(final String projectName, final String className, final Collection<String> methodNames, final Map<String, String> parameters, final String annotationType, final int logLevel)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
initContentBuffer(XMLStringBuffer suiteBuffer)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 
ClassesAndMethodsSuite(final String projectName, final Map<String, Collection<String>> classes, final Map<String, String> parameters, final String annotationType, final int logLevel)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
initContentBuffer(XMLStringBuffer suiteBuffer)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 
sanitize(Collection<String> source)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 
ClassListSuite(final String projectName, final Collection<String> packageNames, final Collection<String> classNames, final Collection<String> groupNames, final Map<String, String> parameters, final String annotationType, final int logLevel)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
initContentBuffer(XMLStringBuffer suiteBuffer)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