diff --git a/README.md b/README.md
index 107d0bec..5ed91b92 100644
--- a/README.md
+++ b/README.md
@@ -104,13 +104,13 @@ With all listeners we have, we can take measure in different places
8. response body start received ( ContentListener#onContent() )
9. response body completed ( CompleteListener#onComplete() )
-#### Response Time
+#### Latency Time
-The responseTime is the time taken just before 1. and 9.
+The latencyTime is the time taken just before 2. and 6. (time to get the first byte of the response)
-#### Latency Time
+#### Response Time
-The latencyTime is the time taken just before 2. and 6.
+The responseTime is the time taken just before 1. and 9. (time to get the last byte of the response)
### Using uber jar
diff --git a/jetty-load-generator-client/pom.xml b/jetty-load-generator-client/pom.xml
index 03e4db6d..ec09d886 100644
--- a/jetty-load-generator-client/pom.xml
+++ b/jetty-load-generator-client/pom.xml
@@ -129,4 +129,23 @@
+
+
+ debug
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ DEBUG
+
+
+
+
+
+
+
+
diff --git a/jetty-load-generator-client/src/main/java/org/mortbay/jetty/load/generator/LoadGenerator.java b/jetty-load-generator-client/src/main/java/org/mortbay/jetty/load/generator/LoadGenerator.java
index eea4c894..15870ab9 100644
--- a/jetty-load-generator-client/src/main/java/org/mortbay/jetty/load/generator/LoadGenerator.java
+++ b/jetty-load-generator-client/src/main/java/org/mortbay/jetty/load/generator/LoadGenerator.java
@@ -294,6 +294,7 @@ public void failed(Throwable x) {
logger.debug("failed tree for {}", resource);
}
callback.failed(x);
+ LoadGenerator.this.interrupt();
}
}, nodes);
Sender sender = new Sender(client, warmup, treeCallback);
diff --git a/jetty-load-generator-client/src/test/java/org/mortbay/jetty/load/generator/FailFastTest.java b/jetty-load-generator-client/src/test/java/org/mortbay/jetty/load/generator/FailFastTest.java
new file mode 100644
index 00000000..4b4f80bb
--- /dev/null
+++ b/jetty-load-generator-client/src/test/java/org/mortbay/jetty/load/generator/FailFastTest.java
@@ -0,0 +1,162 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.mortbay.jetty.load.generator;
+
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.StatisticsHandler;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.servlet.StatisticsServlet;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class FailFastTest
+{
+
+ private static final Logger LOGGER = Log.getLogger( FailFastTest.class );
+ protected Resource resource;
+ protected Server server;
+ protected ServerConnector connector;
+ TestHandler testHandler;
+
+
+ @Before
+ public void startJetty()
+ throws Exception
+ {
+ StatisticsHandler statisticsHandler = new StatisticsHandler();
+ QueuedThreadPool serverThreads = new QueuedThreadPool();
+ serverThreads.setName( "server" );
+ server = new Server( serverThreads );
+ connector = new ServerConnector( server, new HttpConnectionFactory( new HttpConfiguration() ) );
+ server.addConnector( connector );
+ server.setHandler( statisticsHandler );
+ ServletContextHandler statsContext = new ServletContextHandler( statisticsHandler, "/" );
+ statsContext.addServlet( new ServletHolder( new StatisticsServlet() ), "/stats" );
+ testHandler = new TestHandler();
+ testHandler.server = server;
+ statsContext.addServlet( new ServletHolder( testHandler ), "/" );
+ statsContext.setSessionHandler( new SessionHandler() );
+ server.start();
+ }
+
+ @After
+ public void stopJetty()
+ throws Exception
+ {
+ if ( server.isRunning() )
+ {
+ server.stop();
+ }
+ }
+
+ @Test
+ public void should_fail_fast()
+ throws Exception
+ {
+ AtomicInteger onFailure = new AtomicInteger( 0 ), onCommit = new AtomicInteger( 0 );
+ LoadGenerator.Builder builder = //
+ new LoadGenerator.Builder() //
+ .host( "localhost" ) //
+ .port( connector.getLocalPort() ) //
+ .resource( new Resource( "/index.html?fail=5" ) ) //
+ .warmupIterationsPerThread( 1 ) //
+ .usersPerThread( 1 ) //
+ .threads( 1 ) //
+ .resourceRate( 5 )
+ .iterationsPerThread( 25 ) //
+ //.runFor( 10, TimeUnit.SECONDS ) //
+ .requestListener( new Request.Listener.Adapter() {
+ @Override
+ public void onFailure( Request request, Throwable failure )
+ {
+ LOGGER.info( "fail: {}", onFailure.incrementAndGet() );
+ }
+
+ @Override
+ public void onCommit( Request request )
+ {
+ LOGGER.info( "onCommit: {}", onCommit.incrementAndGet() );
+ }
+ } );
+ boolean exception = false;
+ try
+ {
+ builder.build().begin().get();
+ }
+ catch ( Exception e )
+ {
+ exception = true;
+ }
+ Assert.assertTrue( exception );
+ LOGGER.info( "onFailure: {}, onCommit: {}", onFailure, onCommit);
+ int onFailureCall = onFailure.get();
+ Assert.assertTrue("onFailureCall is " + onFailureCall, onFailureCall < 5);
+ }
+
+
+ static class TestHandler
+ extends HttpServlet
+ {
+
+ AtomicInteger getNumber = new AtomicInteger( 0 );
+ Server server;
+
+ @Override
+ protected void service( HttpServletRequest request, HttpServletResponse response )
+ throws ServletException, IOException
+ {
+ String fail = request.getParameter( "fail" );
+ if ( getNumber.get() >= Integer.parseInt( fail ) )
+ {
+ try
+ {
+ server.stop();
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( e.getMessage(), e );
+ }
+ }
+ response.getOutputStream().write( "Jetty rocks!!".getBytes() );
+ response.flushBuffer();
+ getNumber.addAndGet( 1 );
+ }
+ }
+
+}
diff --git a/jetty-load-generator-starter/pom.xml b/jetty-load-generator-starter/pom.xml
index 641c613f..bab8bbf8 100644
--- a/jetty-load-generator-starter/pom.xml
+++ b/jetty-load-generator-starter/pom.xml
@@ -106,16 +106,27 @@
-
- org.apache.maven.plugins
- maven-surefire-plugin
-
-
- DEBUG
-
-
-
+
+
+ debug
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ DEBUG
+ DEBUG
+
+
+
+
+
+
+
+
diff --git a/jetty-load-generator-starter/simple_profile.groovy b/jetty-load-generator-starter/simple_profile.groovy
deleted file mode 100644
index e4cb9fda..00000000
--- a/jetty-load-generator-starter/simple_profile.groovy
+++ /dev/null
@@ -1,3 +0,0 @@
-import org.mortbay.jetty.load.generator.Resource
-
-return new Resource(new Resource("index.html"), new Resource("hello"))
diff --git a/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/AbstractLoadGeneratorStarter.java b/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/AbstractLoadGeneratorStarter.java
index e7e0c23e..eae035b9 100644
--- a/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/AbstractLoadGeneratorStarter.java
+++ b/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/AbstractLoadGeneratorStarter.java
@@ -60,6 +60,8 @@ public abstract class AbstractLoadGeneratorStarter
private Resource resource;
+ private Request.Listener[] listeners;
+
public AbstractLoadGeneratorStarter( LoadGeneratorStarterArgs runnerArgs )
{
this.starterArgs = runnerArgs;
@@ -83,6 +85,11 @@ public void run()
.warmupIterationsPerThread( starterArgs.getWarmupNumber() ) //
.scheme( starterArgs.getScheme() ); //
+ if (starterArgs.getThreads() > 0)
+ {
+ loadGeneratorBuilder.threads( starterArgs.getThreads() );
+ }
+
if ( starterArgs.getMaxRequestsQueued() > 0 )
{
loadGeneratorBuilder.maxRequestsQueued( starterArgs.getMaxRequestsQueued() );
@@ -159,7 +166,12 @@ protected Resource.Listener[] getResourceListeners()
protected Request.Listener[] getListeners()
{
- return new Request.Listener[0];
+ return listeners == null ? new Request.Listener[0] : this.listeners;
+ }
+
+ protected void setListeners(Request.Listener[] listeners)
+ {
+ this.listeners = listeners;
}
public ExecutorService getExecutorService()
diff --git a/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarter.java b/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarter.java
index 9248dacf..939a6da2 100644
--- a/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarter.java
+++ b/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarter.java
@@ -19,6 +19,8 @@
package org.mortbay.jetty.load.generator.starter;
import com.beust.jcommander.JCommander;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
/**
*
@@ -27,6 +29,8 @@ public class LoadGeneratorStarter
extends AbstractLoadGeneratorStarter
{
+ private static final Logger LOGGER = Log.getLogger( LoadGeneratorStarter.class);
+
public LoadGeneratorStarter( LoadGeneratorStarterArgs runnerArgs )
{
super( runnerArgs );
@@ -67,9 +71,8 @@ public static void main( String[] args )
}
catch ( Exception e )
{
- e.printStackTrace();
+ LOGGER.info( "error happened", e);
new JCommander( runnerArgs ).usage();
- System.exit( 1 );
}
}
diff --git a/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarterArgs.java b/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarterArgs.java
index 4f3e2d61..eb2e1f0e 100644
--- a/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarterArgs.java
+++ b/jetty-load-generator-starter/src/main/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarterArgs.java
@@ -49,6 +49,9 @@ public class LoadGeneratorStarterArgs
@Parameter( names = { "--users", "-u" }, description = "Simulated users number" )
private int users = 1;
+ @Parameter( names = { "--threads" }, description = "Threads number" )
+ private int threads = 0;
+
@Parameter( names = { "--transaction-rate", "-tr" }, description = "Transaction rate / second" )
private int transactionRate = 1;
@@ -358,18 +361,28 @@ public void setMaxRequestsQueued( int maxRequestsQueued )
this.maxRequestsQueued = maxRequestsQueued;
}
+ public int getThreads()
+ {
+ return threads;
+ }
+
+ public void setThreads( int threads )
+ {
+ this.threads = threads;
+ }
+
@Override
public String toString()
{
return "LoadGeneratorStarterArgs{" + "profileXmlPath='" + profileXmlPath + '\'' + ", profileJsonPath='"
+ profileJsonPath + '\'' + ", profileGroovyPath='" + profileGroovyPath + '\'' + ", host='" + host + '\''
- + ", port=" + port + ", users=" + users + ", transactionRate=" + transactionRate + ", transport='"
- + transport + '\'' + ", selectors=" + selectors + ", runningTime=" + runningTime + ", runningTimeUnit='"
- + runningTimeUnit + '\'' + ", runIteration=" + runIteration + ", reportHost='" + reportHost + '\''
- + ", scheme='" + scheme + '\'' + ", reportPort=" + reportPort + ", notInterrupt=" + notInterrupt
- + ", statsFile='" + statsFile + '\'' + ", params=" + params + ", help=" + help + ", displayStatsAtEnd="
- + displayStatsAtEnd + ", collectServerStats=" + collectServerStats + ", warmupNumber=" + warmupNumber
- + ", maxRequestsQueued=" + maxRequestsQueued + '}';
+ + ", port=" + port + ", users=" + users + ", threads=" + threads + ", transactionRate=" + transactionRate
+ + ", transport='" + transport + '\'' + ", selectors=" + selectors + ", runningTime=" + runningTime
+ + ", runningTimeUnit='" + runningTimeUnit + '\'' + ", runIteration=" + runIteration + ", reportHost='"
+ + reportHost + '\'' + ", scheme='" + scheme + '\'' + ", reportPort=" + reportPort + ", notInterrupt="
+ + notInterrupt + ", statsFile='" + statsFile + '\'' + ", params=" + params + ", help=" + help
+ + ", displayStatsAtEnd=" + displayStatsAtEnd + ", collectServerStats=" + collectServerStats
+ + ", warmupNumber=" + warmupNumber + ", maxRequestsQueued=" + maxRequestsQueued + '}';
}
public enum Transport {
diff --git a/jetty-load-generator-starter/src/test/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarterTest.java b/jetty-load-generator-starter/src/test/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarterTest.java
index 25620e1b..587eb417 100644
--- a/jetty-load-generator-starter/src/test/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarterTest.java
+++ b/jetty-load-generator-starter/src/test/java/org/mortbay/jetty/load/generator/starter/LoadGeneratorStarterTest.java
@@ -16,7 +16,8 @@
package org.mortbay.jetty.load.generator.starter;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import com.beust.jcommander.JCommander;
+import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
@@ -27,6 +28,8 @@
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.StatisticsServlet;
import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.After;
import org.junit.Assert;
@@ -42,7 +45,6 @@
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
-import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
@@ -54,6 +56,7 @@
*/
public class LoadGeneratorStarterTest
{
+ private static final Logger LOGGER = Log.getLogger( LoadGeneratorStarterTest.class);
Server server;
@@ -80,19 +83,24 @@ public void startJetty()
statsContext.addServlet( new ServletHolder( new StatisticsServlet() ), "/stats" );
testHandler = new TestHandler();
+ testHandler.server = server;
statsContext.addServlet( new ServletHolder( testHandler ), "/" );
statsContext.setSessionHandler( new SessionHandler() );
server.start();
+
}
@After
public void stopJetty()
throws Exception
{
- server.stop();
+ if (server.isRunning())
+ {
+ server.stop();
+ }
}
@Test
@@ -119,15 +127,75 @@ public void simpletest()
args.add( "3" );
args.add( "--profile-groovy-path" );
args.add( "src/test/resources/loadgenerator_profile.groovy" );
-
LoadGeneratorStarter.main( args.toArray( new String[args.size()] ) );
-
int getNumber = testHandler.getNumber.get();
-
+ LOGGER.debug( "received get: {}", getNumber );
Assert.assertTrue( "getNumber return: " + getNumber, getNumber > 10 );
}
+ @Test
+ public void fail_fast()
+ throws Exception
+ {
+
+ List args = new ArrayList<>();
+ args.add( "--warmup-number" );
+ args.add( "10" );
+ args.add( "-h" );
+ args.add( "localhost" );
+ args.add( "--port" );
+ args.add( Integer.toString( connector.getLocalPort() ) );
+ args.add( "--running-time" );
+ args.add( "10" );
+ args.add( "--running-time-unit" );
+ args.add( "s" );
+ args.add( "--transaction-rate" );
+ args.add( "3" );
+ args.add( "--transport" );
+ args.add( "http" );
+ args.add( "--users" );
+ args.add( "1" );
+ args.add( "--profile-groovy-path" );
+ args.add( "src/test/resources/single_resource.groovy" );
+
+ LoadGeneratorStarterArgs runnerArgs = new LoadGeneratorStarterArgs();
+ new JCommander( runnerArgs, args.toArray( new String[args.size()] ) );
+
+ AtomicInteger onFailure = new AtomicInteger( 0 ), onCommit = new AtomicInteger( 0 );
+ Request.Listener.Adapter adapter = new Request.Listener.Adapter() {
+ @Override
+ public void onFailure( Request request, Throwable failure )
+ {
+ LOGGER.info( "fail: {}", onFailure.incrementAndGet() );
+ }
+
+ @Override
+ public void onCommit( Request request )
+ {
+ LOGGER.info( "onCommit: {}", onCommit.incrementAndGet() );
+ }
+ };
+
+ LoadGeneratorStarter runner = new LoadGeneratorStarter( runnerArgs );
+ runner.setListeners( new Request.Listener[] { adapter } );
+ boolean exception = false;
+ try
+ {
+ runner.run();
+ }
+ catch ( Exception e )
+ {
+ exception = true;
+ }
+ LOGGER.info( "onFailure: {}, onCommit: {}", onFailure, onCommit);
+ Assert.assertTrue("not in exception", exception );
+ int getNumber = testHandler.getNumber.get();
+ LOGGER.debug( "received get: {}", getNumber );
+ Assert.assertTrue( "getNumber return: " + getNumber, getNumber == 5 );
+ Assert.assertTrue( onFailure.get() < 10 );
+ }
+
@Test
public void json_serial_deserial_from_groovy()
throws Exception
@@ -147,6 +215,8 @@ static class TestHandler
AtomicInteger getNumber = new AtomicInteger( 0 ), postNumber = new AtomicInteger( 0 );
+ Server server;
+
@Override
protected void service( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
@@ -160,6 +230,21 @@ protected void service( HttpServletRequest request, HttpServletResponse response
{
case "GET":
{
+ String fail = request.getParameter( "fail" );
+ if (fail != null)
+ {
+ if ( getNumber.get() >= Integer.parseInt( fail ) )
+ {
+ try
+ {
+ server.stop();
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( e.getMessage(), e );
+ }
+ }
+ }
response.getOutputStream().write( "Jetty rocks!!".getBytes() );
response.flushBuffer();
getNumber.addAndGet( 1 );
diff --git a/jetty-load-generator-starter/src/test/resources/single_resource.groovy b/jetty-load-generator-starter/src/test/resources/single_resource.groovy
new file mode 100644
index 00000000..5f8a1533
--- /dev/null
+++ b/jetty-load-generator-starter/src/test/resources/single_resource.groovy
@@ -0,0 +1,3 @@
+import org.mortbay.jetty.load.generator.Resource
+
+return new Resource("/index.html?fail=5")