55
66import java .io .*;
77import java .nio .charset .StandardCharsets ;
8+ import java .util .concurrent .CountDownLatch ;
89import java .util .logging .Level ;
910
1011import com .google .gson .GsonBuilder ;
2223import org .apache .maven .project .DefaultProjectBuildingRequest ;
2324import org .apache .maven .project .ProjectBuildingException ;
2425import org .apache .maven .project .ProjectBuildingRequest ;
26+ import org .eclipse .jetty .server .Server ;
27+ import org .eclipse .jetty .server .ServerConnector ;
28+ import org .eclipse .jetty .server .handler .ResourceHandler ;
29+ import org .eclipse .jetty .util .component .AbstractLifeCycle ;
30+ import org .eclipse .jetty .util .component .LifeCycle ;
31+ import org .eclipse .jetty .util .resource .Resource ;
2532import org .openqa .selenium .JavascriptExecutor ;
2633import org .openqa .selenium .WebDriver ;
2734import org .openqa .selenium .chrome .ChromeDriver ;
@@ -224,7 +231,6 @@ public void execute() throws MojoExecutionException, MojoFailureException {
224231 String testClass = testFilePathWithoutSuffix .replaceAll ("/" , "." );
225232
226233 // Synthesize a new project which only depends on the last one, and only contains the named test's .testsuite content, remade into a one-off JS file
227-
228234 ArrayList <CachedProject > finalChildren = new ArrayList <>(e .getChildren ());
229235 finalChildren .add (e );
230236 CachedProject t = new CachedProject (diskCache , project .getArtifact (), project , finalChildren , Collections .singletonList (tmp .toString ()), Collections .emptyList ());
@@ -241,56 +247,86 @@ public void execute() throws MojoExecutionException, MojoFailureException {
241247 // write a simple html file to that output dir
242248 //TODO parallelize this - run once each is done, possibly concurrently
243249 //TODO don't fail on the first test that doesn't work
244- String startupHtmlFile ;
250+ Path startupHtmlFile ;
245251 try {
252+ Path webappDirPath = Paths .get (webappDirectory );
253+ Path outputJsPath = webappDirPath .resolve (config .getInitialScriptFilename ());
246254 File outputJs = new File (new File (webappDirectory ), config .getInitialScriptFilename ());
247- Path junitStartupFile = Paths . get ( outputJs . getParent (), outputJs . getName ().substring (0 , outputJs .getName ().length () - 2 ) + "html" );
248- Files .createDirectories (junitStartupFile .getParent ());
255+ Path junitStartupPath = outputJsPath . resolveSibling ( outputJsPath . getFileName (). toString ().substring (0 , outputJs .getName ().length () - 2 ) + "html" );
256+ Files .createDirectories (junitStartupPath .getParent ());
249257 String fileContents = CharStreams .toString (new InputStreamReader (TestMojo .class .getResourceAsStream ("/junit.html" )));
250258 fileContents = fileContents .replace ("<TEST_SCRIPT>" , outputJs .getName ());
251259
252- Files .write (junitStartupFile , fileContents .getBytes (StandardCharsets .UTF_8 ), StandardOpenOption .CREATE , StandardOpenOption .TRUNCATE_EXISTING );
253- startupHtmlFile = junitStartupFile . toAbsolutePath (). toString ( );
260+ Files .write (junitStartupPath , fileContents .getBytes (StandardCharsets .UTF_8 ), StandardOpenOption .CREATE , StandardOpenOption .TRUNCATE_EXISTING );
261+ startupHtmlFile = webappDirPath . relativize ( junitStartupPath );
254262 } catch (IOException ex ) {
255263 throw new UncheckedIOException (ex );
256264 }
257- // assuming that was successful, start htmlunit to run the test
265+
266+ // Start a webserver TODO start just once for all tests
267+ Server server = new Server (0 );
268+
269+ // Tell jetty how to serve our compiled content
270+ ResourceHandler resourceHandler = new ResourceHandler ();
271+ resourceHandler .setDirectoriesListed (true );//enabled for easier debugging, if we introduce a "manual" mode
272+ resourceHandler .setBaseResource (Resource .newResource (webappDirectory ));
273+
274+ server .setHandler (resourceHandler );
275+ server .start ();
276+
277+ // With the server started, start a browser too so they work in parallel
258278 WebDriver driver = createBrowser ();
279+
280+ // Wait until server is ready
281+ if (!server .isStarted ()) {
282+ CountDownLatch started = new CountDownLatch (1 );
283+ server .addLifeCycleListener (new AbstractLifeCycle .AbstractLifeCycleListener () {
284+ @ Override
285+ public void lifeCycleStarted (LifeCycle event ) {
286+ started .countDown ();
287+ }
288+ });
289+ started .await ();
290+ }
291+ int port = ((ServerConnector ) server .getConnectors ()[0 ]).getLocalPort ();
292+
259293 try {
260- driver .get ("file://" + startupHtmlFile );
261- // loop and poll if tests are done
294+ String url = "http://localhost:" + port + "/" + startupHtmlFile .toString ();
295+ System .out .println ("fetching " + url );
296+ driver .get (url );
297+
298+ // Loop and poll if tests are done
262299 new FluentWait <>(driver )
263300 .withTimeout (Duration .ofMinutes (1 ))
264- .withMessage ("Tests failed to finish in timeout" )
301+ .withMessage ("Tests failed to finish before timeout" )
265302 .pollingEvery (Duration .ofMillis (100 ))
266303 .until (d -> isFinished (d ));
267- // check for success
304+ // Check for success
268305 if (!isSuccess (driver )) {
269- // print the content of the browser console to the log
306+ // Print the content of the browser console to the log
270307 this .analyzeLog (driver );
271- failedTests .put (config .getTest (), startupHtmlFile );
308+ failedTests .put (config .getTest (), generatedTest );
272309 getLog ().error ("Test failed!" );
273310 } else {
274311 getLog ().info ("Test passed!" );
275312 }
276313 } catch (Exception ex ) {
277- failedTests .put (config .getTest (), startupHtmlFile );
278- if (!Objects .isNull (driver )) {
279- this .analyzeLog (driver );
280- }
314+ failedTests .put (config .getTest (), generatedTest );
315+ this .analyzeLog (driver );
281316 getLog ().error ("Test failed!" );
282- getLog ().error (cleanForMavenLog (String . format ( ex .getMessage () )));
317+ getLog ().error (cleanForMavenLog (ex .getMessage ()));
283318 } finally {
284- if (driver != null ) {
285- driver .quit ();
286- }
319+ driver .quit ();
287320 }
288321 }
289322 } catch (ProjectBuildingException | IOException e ) {
290323 throw new MojoExecutionException ("Failed to build project structure" , e );
324+ } catch (Exception e ) {
325+ //TODO refine this, possibly remove
326+ throw new MojoExecutionException ("Failed on test server start" , e );
291327 }
292328
293- if (failedTests .isEmpty ()) {
329+ if (failedTests .isEmpty ()) {
294330 getLog ().info ("All tests were passed successfully!" );
295331 } else {
296332 failedTests .forEach ((name , startupHtmlFile ) -> getLog ().error (String .format ("Test %s failed, please try manually %s" , name , startupHtmlFile )));
0 commit comments