Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit a606f61
Showing
13 changed files
with
587 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.idea | ||
target | ||
loadtest.iml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// run: java -jar loadtest.jar -n 10 -d 1000 Example1.groovy | ||
try { | ||
HTTP.get("http://google.com", "http://facebook.com"); | ||
} catch (Throwable thr) { | ||
System.err.println(thr); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This file was created by IntelliJ IDEA 10.5.2 for binding GitHub repository |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
h1. Web load test tool v1.0 | ||
|
||
Tool could be used to test load your web application using different scenarios. Scripts are written in groovy using special test environment. | ||
|
||
h2. Run | ||
|
||
Copy one loadtest-1.0.jar and Example*.groovy from repository to one of directories on your computer. Use java to run it from commandline: | ||
|
||
java -jar loadtest-1.0.jar Example1.groovy | ||
|
||
h2. Environment | ||
|
||
In groovy following classes avialable: HTTP and Variations. | ||
|
||
h2. License | ||
|
||
Load test tool is distributed on terms of BSD-license. Look at src/main/resources/BSD-LICENSE.txt for details. | ||
|
||
Groovy used internally by load test tool is licensed under the Apache 2 license: | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0.html |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<groupId>org.loadtest</groupId> | ||
<artifactId>loadtest</artifactId> | ||
<packaging>jar</packaging> | ||
<version>1.0</version> | ||
<name>Web load test</name> | ||
<url>http://maven.apache.org</url> | ||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
</properties> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.codehaus.groovy</groupId> | ||
<artifactId>groovy</artifactId> | ||
<version>1.8.3</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>args4j</groupId> | ||
<artifactId>args4j</artifactId> | ||
<version>2.0.16</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-dependency-plugin</artifactId> | ||
<version>2.3</version> | ||
<executions> | ||
<execution> | ||
<id>unpack</id> | ||
<phase>prepare-package</phase> | ||
<goals> | ||
<goal>unpack-dependencies</goal> | ||
</goals> | ||
<configuration> | ||
<excludes>META-INF/MANIFEST.MF,META-INF/LICENSE.txt,META-INF/maven/**</excludes> | ||
<outputDirectory>${project.build.outputDirectory}</outputDirectory> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-jar-plugin</artifactId> | ||
<version>2.3.1</version> | ||
<configuration> | ||
<archive> | ||
<index>true</index> | ||
<manifest> | ||
<mainClass>org.loadtest.LoadTest</mainClass> | ||
</manifest> | ||
</archive> | ||
</configuration> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.codehaus.mojo</groupId> | ||
<artifactId>versions-maven-plugin</artifactId> | ||
<version>1.2</version> | ||
<configuration> | ||
<newVersion>${parsedVersion.majorVersion}.${parsedVersion.minorVersion}</newVersion> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package org.loadtest; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
/** | ||
* Object used by scripts to interchange values | ||
*/ | ||
public class Globals { | ||
private Map values = new HashMap(); | ||
|
||
public synchronized void put(String name, Object value) { | ||
values.put(name, value); | ||
} | ||
|
||
public synchronized Object get(String name) { | ||
return values.get(name); | ||
} | ||
public synchronized long increment(String name) { | ||
Number num = (Number)values.get(name); | ||
if (num == null) { | ||
num = 0L; | ||
} | ||
long res = num.longValue(); | ||
values.put(name, res + 1); | ||
return res; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package org.loadtest; | ||
|
||
import org.kohsuke.args4j.Argument; | ||
import org.kohsuke.args4j.CmdLineException; | ||
import org.kohsuke.args4j.CmdLineParser; | ||
import org.kohsuke.args4j.Option; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Scanner; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.ScheduledExecutorService; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* Tool to run test load specified by script using several threads. | ||
* Main entry point. | ||
*/ | ||
public class LoadTest { | ||
private Options options; | ||
private ScheduledExecutorService executor; | ||
private ScheduledExecutorService printExecutor; | ||
private ScriptRunner scriptRunner; | ||
|
||
public LoadTest(int threads, long delay, File script) { | ||
this.options = new Options(threads, delay, script); | ||
} | ||
public LoadTest(Options options) { | ||
this.options = options; | ||
} | ||
|
||
public synchronized void start() { | ||
if (executor != null) { | ||
return; | ||
} | ||
scriptRunner = new ScriptRunner(this, options.scripts); | ||
executor = Executors.newScheduledThreadPool(options.threads); | ||
for (int i = 0; i < options.threads; i++) { | ||
executor.scheduleWithFixedDelay(scriptRunner, | ||
options.delay * i / options.threads, | ||
options.delay, | ||
TimeUnit.MILLISECONDS); | ||
} | ||
|
||
printExecutor = Executors.newSingleThreadScheduledExecutor(); | ||
printExecutor.scheduleWithFixedDelay(new StatsPrinter(), | ||
500L, | ||
1000L, | ||
TimeUnit.MILLISECONDS); | ||
} | ||
|
||
public synchronized void stop() { | ||
if (executor == null) { return; } | ||
executor.shutdownNow(); | ||
executor = null; | ||
printExecutor.shutdownNow(); | ||
printExecutor = null; | ||
scriptRunner = null; | ||
} | ||
|
||
public boolean isStopped() { | ||
return executor == null; | ||
} | ||
|
||
public static void main(String[] args) throws IOException { | ||
LoadTest testload = new LoadTest(new Options().parse(args)); | ||
Scanner scanner = new Scanner(System.in); | ||
try { | ||
do { | ||
System.out.println("Starting(press q[ENTER] - to quit, [ENTER] - to stop)"); | ||
testload.start(); | ||
if (scanner.nextLine().equals("q")) { | ||
break; | ||
} | ||
System.out.println("Stopping(press q[ENTER] - to quit, [ENTER] - to start)"); | ||
testload.stop(); | ||
} while (!scanner.nextLine().equals("q")); | ||
} catch (Throwable thr) { | ||
System.out.println("Breaked"); | ||
} | ||
} | ||
|
||
public synchronized ScriptRunner getScriptRunner() { | ||
return scriptRunner; | ||
} | ||
|
||
private static class Options { | ||
@Option(name="-n", usage="number of threads") | ||
private int threads = 1; | ||
|
||
@Option(name="-d", usage="delay between requests") | ||
private long delay = 1; | ||
|
||
@Option(name="-s", usage="number of the slowest queries to show in statistics") | ||
private int slowQueriesToShow = 24; | ||
|
||
@Argument | ||
private List<File> scripts = new ArrayList(); | ||
|
||
public Options(int threads, long delay, File script) { | ||
this.threads = threads; | ||
this.delay = delay; | ||
this.scripts.add(script); | ||
} | ||
|
||
public Options() { | ||
} | ||
|
||
public Options parse(String[] args) { | ||
CmdLineParser parser = new CmdLineParser(this); | ||
try { | ||
parser.parseArgument(args); | ||
if (scripts.isEmpty()) { | ||
usage(parser, new CmdLineException(parser, "specify one or more scripts")); | ||
} | ||
} catch (CmdLineException e) { | ||
usage(parser, e); | ||
} | ||
return this; | ||
} | ||
|
||
private void usage(CmdLineParser parser, CmdLineException e) { | ||
System.err.println(e.getMessage()); | ||
System.err.println("java -jar loadtest.jar [options...] scripts..."); | ||
parser.printUsage(System.err); | ||
System.exit(1); | ||
} | ||
} | ||
|
||
private class StatsPrinter implements Runnable { | ||
public void run() { | ||
ScriptRunner runner = getScriptRunner(); | ||
if (runner != null) { | ||
runner.getStats().report(options.slowQueriesToShow); | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package org.loadtest; | ||
|
||
import groovy.lang.Binding; | ||
import groovy.lang.GroovyCodeSource; | ||
import groovy.lang.GroovyShell; | ||
import org.codehaus.groovy.control.CompilationFailedException; | ||
|
||
import java.io.File; | ||
import java.util.List; | ||
import java.util.Random; | ||
|
||
/** | ||
* Runs scripts in environment produced by "Classes.groovy" and three bindings: | ||
* GLOBAL - global variables interchanger, | ||
* STATS - statistics object, | ||
* RANDOM - random object | ||
*/ | ||
public class ScriptRunner implements Runnable { | ||
private LoadTest load; | ||
private List scripts; | ||
private Stats stats = new Stats(); | ||
private Globals globals = new Globals(); | ||
private Random random = new Random(); | ||
private static ThreadLocal local = new ThreadLocal(); | ||
|
||
public ScriptRunner(LoadTest load, List scripts) { | ||
this.load = load; | ||
this.scripts = scripts; | ||
} | ||
|
||
protected Binding createNewBinding() { | ||
Binding binding = new Binding(); | ||
binding.setVariable("STATS", stats); | ||
binding.setVariable("GLOBALS", globals); | ||
binding.setVariable("RANDOM", random); | ||
return binding; | ||
} | ||
|
||
public void run() { | ||
Binding binding = createNewBinding(); | ||
GroovyShell shell = new GroovyShell(binding); | ||
stats.addRun(); | ||
try { | ||
local.set(shell); | ||
GroovyCodeSource functions = new GroovyCodeSource(ScriptRunner.class.getResource("Classes.groovy")); | ||
shell.evaluate(functions); | ||
for (Object script : scripts) { | ||
shell.evaluate((File)script); | ||
} | ||
} catch (CompilationFailedException e) { | ||
stats.addError(); | ||
errorCase(e); | ||
} catch (Throwable e) { | ||
stats.addError(); | ||
} finally { | ||
local.remove(); | ||
} | ||
} | ||
|
||
private void errorCase(Exception e) { | ||
if (!load.isStopped()) { | ||
e.printStackTrace(); | ||
load.stop(); | ||
} | ||
} | ||
|
||
public Stats getStats() { | ||
return stats; | ||
} | ||
|
||
public static GroovyShell getGroovyShell() { | ||
return (GroovyShell) local.get(); | ||
} | ||
} |
Oops, something went wrong.