• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.testng.remote;
2 
3 import static org.testng.internal.Utils.defaultIfStringEmpty;
4 
5 import com.beust.jcommander.JCommander;
6 import com.beust.jcommander.ParameterException;
7 
8 import org.testng.CommandLineArgs;
9 import org.testng.IClassListener;
10 import org.testng.IInvokedMethodListener;
11 import org.testng.ISuite;
12 import org.testng.ISuiteListener;
13 import org.testng.ITestRunnerFactory;
14 import org.testng.TestNG;
15 import org.testng.TestNGException;
16 import org.testng.TestRunner;
17 import org.testng.collections.Lists;
18 import org.testng.remote.strprotocol.GenericMessage;
19 import org.testng.remote.strprotocol.IMessageSender;
20 import org.testng.remote.strprotocol.MessageHelper;
21 import org.testng.remote.strprotocol.MessageHub;
22 import org.testng.remote.strprotocol.RemoteTestListener;
23 import org.testng.remote.strprotocol.SerializedMessageSender;
24 import org.testng.remote.strprotocol.StringMessageSender;
25 import org.testng.remote.strprotocol.SuiteMessage;
26 import org.testng.reporters.JUnitXMLReporter;
27 import org.testng.reporters.TestHTMLReporter;
28 import org.testng.xml.XmlSuite;
29 import org.testng.xml.XmlTest;
30 
31 import java.util.Arrays;
32 import java.util.Collection;
33 import java.util.List;
34 
35 /**
36  * Extension of TestNG registering a remote TestListener.
37  *
38  * @author Cedric Beust <cedric@beust.com>
39  */
40 public class RemoteTestNG extends TestNG {
41   private static final String LOCALHOST = "localhost";
42 
43   // The following constants are referenced by the Eclipse plug-in, make sure you
44   // modify the plug-in as well if you change any of them.
45   public static final String DEBUG_PORT = "12345";
46   public static final String DEBUG_SUITE_FILE = "testng-customsuite.xml";
47   public static final String DEBUG_SUITE_DIRECTORY = System.getProperty("java.io.tmpdir");
48   public static final String PROPERTY_DEBUG = "testng.eclipse.debug";
49   public static final String PROPERTY_VERBOSE = "testng.eclipse.verbose";
50   // End of Eclipse constants.
51 
52   private ITestRunnerFactory m_customTestRunnerFactory;
53   private String m_host;
54 
55   /** Port used for the string protocol */
56   private Integer m_port = null;
57 
58   /** Port used for the serialized protocol */
59   private static Integer m_serPort = null;
60 
61   private static boolean m_debug;
62 
63   private static boolean m_dontExit;
64 
65   private static boolean m_ack;
66 
setHost(String host)67   public void setHost(String host) {
68     m_host = defaultIfStringEmpty(host, LOCALHOST);
69   }
70 
calculateAllSuites(List<XmlSuite> suites, List<XmlSuite> outSuites)71   private void calculateAllSuites(List<XmlSuite> suites, List<XmlSuite> outSuites) {
72     for (XmlSuite s : suites) {
73       outSuites.add(s);
74 //      calculateAllSuites(s.getChildSuites(), outSuites);
75     }
76   }
77 
78   @Override
run()79   public void run() {
80     IMessageSender sender = m_serPort != null
81         ? new SerializedMessageSender(m_host, m_serPort, m_ack)
82         : new StringMessageSender(m_host, m_port);
83     final MessageHub msh = new MessageHub(sender);
84     msh.setDebug(isDebug());
85     try {
86       msh.connect();
87       // We couldn't do this until now in debug mode since the .xml file didn't exist yet.
88       // Now that we have connected with the Eclipse client, we know that it created the .xml
89       // file so we can proceed with the initialization
90       initializeSuitesAndJarFile();
91 
92       List<XmlSuite> suites = Lists.newArrayList();
93       calculateAllSuites(m_suites, suites);
94 //      System.out.println("Suites: " + m_suites.get(0).getChildSuites().size()
95 //          + " and:" + suites.get(0).getChildSuites().size());
96       if(suites.size() > 0) {
97 
98         int testCount= 0;
99 
100         for (XmlSuite suite : suites) {
101           testCount += suite.getTests().size();
102         }
103 
104         GenericMessage gm= new GenericMessage(MessageHelper.GENERIC_SUITE_COUNT);
105         gm.setSuiteCount(suites.size());
106         gm.setTestCount(testCount);
107         msh.sendMessage(gm);
108 
109         addListener(new RemoteSuiteListener(msh));
110         setTestRunnerFactory(new DelegatingTestRunnerFactory(buildTestRunnerFactory(), msh));
111 
112 //        System.out.println("RemoteTestNG starting");
113         super.run();
114       }
115       else {
116         System.err.println("No test suite found. Nothing to run");
117       }
118     }
119     catch(Throwable cause) {
120       cause.printStackTrace(System.err);
121     }
122     finally {
123 //      System.out.println("RemoteTestNG finishing: " + (getEnd() - getStart()) + " ms");
124       msh.shutDown();
125       if (! m_debug && ! m_dontExit) {
126         System.exit(0);
127       }
128     }
129   }
130 
131   /**
132    * Override by the plugin if you need to configure differently the <code>TestRunner</code>
133    * (usually this is needed if different listeners/reporters are needed).
134    * <b>Note</b>: you don't need to worry about the wiring listener, because it is added
135    * automatically.
136    */
buildTestRunnerFactory()137   protected ITestRunnerFactory buildTestRunnerFactory() {
138     if(null == m_customTestRunnerFactory) {
139       m_customTestRunnerFactory= new ITestRunnerFactory() {
140           @Override
141           public TestRunner newTestRunner(ISuite suite, XmlTest xmlTest,
142               Collection<IInvokedMethodListener> listeners, List<IClassListener> classListeners) {
143             TestRunner runner =
144               new TestRunner(getConfiguration(), suite, xmlTest,
145                   false /*skipFailedInvocationCounts */,
146                   listeners, classListeners);
147             if (m_useDefaultListeners) {
148               runner.addListener(new TestHTMLReporter());
149               runner.addListener(new JUnitXMLReporter());
150             }
151 
152             return runner;
153           }
154         };
155     }
156 
157     return m_customTestRunnerFactory;
158   }
159 
main(String[] args)160   public static void main(String[] args) throws ParameterException {
161     CommandLineArgs cla = new CommandLineArgs();
162     RemoteArgs ra = new RemoteArgs();
163     new JCommander(Arrays.asList(cla, ra), args);
164     m_dontExit = ra.dontExit;
165     if (cla.port != null && ra.serPort != null) {
166       throw new TestNGException("Can only specify one of " + CommandLineArgs.PORT
167           + " and " + RemoteArgs.PORT);
168     }
169     m_debug = cla.debug;
170     m_ack = ra.ack;
171     if (m_debug) {
172 //      while (true) {
173         initAndRun(args, cla, ra);
174 //      }
175     }
176     else {
177       initAndRun(args, cla, ra);
178     }
179   }
180 
initAndRun(String[] args, CommandLineArgs cla, RemoteArgs ra)181   private static void initAndRun(String[] args, CommandLineArgs cla, RemoteArgs ra) {
182     RemoteTestNG remoteTestNg = new RemoteTestNG();
183     if (m_debug) {
184       // In debug mode, override the port and the XML file to a fixed location
185       cla.port = Integer.parseInt(DEBUG_PORT);
186       ra.serPort = cla.port;
187       cla.suiteFiles = Arrays.asList(new String[] {
188           DEBUG_SUITE_DIRECTORY + DEBUG_SUITE_FILE
189       });
190     }
191     remoteTestNg.configure(cla);
192     remoteTestNg.setHost(cla.host);
193     m_serPort = ra.serPort;
194     remoteTestNg.m_port = cla.port;
195     if (isVerbose()) {
196       StringBuilder sb = new StringBuilder("Invoked with ");
197       for (String s : args) {
198         sb.append(s).append(" ");
199       }
200       p(sb.toString());
201 //      remoteTestNg.setVerbose(1);
202 //    } else {
203 //      remoteTestNg.setVerbose(0);
204     }
205     validateCommandLineParameters(cla);
206     remoteTestNg.run();
207 //    if (m_debug) {
208 //      // Run in a loop if in debug mode so it is possible to run several launches
209 //      // without having to relauch RemoteTestNG.
210 //      while (true) {
211 //        remoteTestNg.run();
212 //        remoteTestNg.configure(cla);
213 //      }
214 //    } else {
215 //      remoteTestNg.run();
216 //    }
217   }
218 
p(String s)219   private static void p(String s) {
220     if (isVerbose()) {
221       System.out.println("[RemoteTestNG] " + s);
222     }
223   }
224 
isVerbose()225   public static boolean isVerbose() {
226     boolean result = System.getProperty(PROPERTY_VERBOSE) != null || isDebug();
227     return result;
228   }
229 
isDebug()230   public static boolean isDebug() {
231     return m_debug || System.getProperty(PROPERTY_DEBUG) != null;
232   }
233 
getHost()234   private String getHost() {
235     return m_host;
236   }
237 
getPort()238   private int getPort() {
239     return m_port;
240   }
241 
242   /** A ISuiteListener wiring the results using the internal string-based protocol. */
243   private static class RemoteSuiteListener implements ISuiteListener {
244     private final MessageHub m_messageSender;
245 
RemoteSuiteListener(MessageHub smsh)246     RemoteSuiteListener(MessageHub smsh) {
247       m_messageSender= smsh;
248     }
249 
250     @Override
onFinish(ISuite suite)251     public void onFinish(ISuite suite) {
252       m_messageSender.sendMessage(new SuiteMessage(suite, false /*start*/));
253     }
254 
255     @Override
onStart(ISuite suite)256     public void onStart(ISuite suite) {
257       m_messageSender.sendMessage(new SuiteMessage(suite, true /*start*/));
258     }
259   }
260 
261   private static class DelegatingTestRunnerFactory implements ITestRunnerFactory {
262     private final ITestRunnerFactory m_delegateFactory;
263     private final MessageHub m_messageSender;
264 
DelegatingTestRunnerFactory(ITestRunnerFactory trf, MessageHub smsh)265     DelegatingTestRunnerFactory(ITestRunnerFactory trf, MessageHub smsh) {
266       m_delegateFactory= trf;
267       m_messageSender= smsh;
268     }
269 
270     @Override
newTestRunner(ISuite suite, XmlTest test, Collection<IInvokedMethodListener> listeners, List<IClassListener> classListeners)271     public TestRunner newTestRunner(ISuite suite, XmlTest test,
272         Collection<IInvokedMethodListener> listeners, List<IClassListener> classListeners) {
273       TestRunner tr = m_delegateFactory.newTestRunner(suite, test, listeners, classListeners);
274       tr.addListener(new RemoteTestListener(suite, test, m_messageSender));
275       return tr;
276     }
277   }
278 }
279