You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2017/12/07 21:31:05 UTC
svn commit: r1817424 [2/2] - in /jmeter/trunk:
src/core/org/apache/jmeter/services/ src/jorphan/org/apache/jorphan/reflect/
test/src/org/apache/jmeter/assertions/ test/src/org/apache/jmeter/config/
test/src/org/apache/jmeter/functions/ test/src/org/apa...
Modified: jmeter/trunk/test/src/org/apache/jorphan/test/AllTests.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jorphan/test/AllTests.java?rev=1817424&r1=1817423&r2=1817424&view=diff
==============================================================================
--- jmeter/trunk/test/src/org/apache/jorphan/test/AllTests.java (original)
+++ jmeter/trunk/test/src/org/apache/jorphan/test/AllTests.java Thu Dec 7 21:31:04 2017
@@ -13,44 +13,50 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package org.apache.jorphan.test;
+import javax.crypto.Cipher;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
-import javax.crypto.Cipher;
+import junit.framework.TestCase;
+import org.apache.commons.lang3.time.StopWatch;
import org.apache.jmeter.junit.categories.ExcludeCategoryFilter;
import org.apache.jmeter.junit.categories.NeedGuiTests;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.reflect.ClassFilter;
import org.apache.jorphan.reflect.ClassFinder;
import org.apache.jorphan.util.JOrphanUtils;
-import org.junit.internal.RealSystem;
+import org.junit.experimental.ParallelComputer;
import org.junit.internal.TextListener;
import org.junit.runner.Computer;
+import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;
+import org.junit.runner.notification.RunListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spock.lang.Specification;
-import junit.framework.TestCase;
-
/**
- * Provides a quick and easy way to run all <a href="http://http://junit.org">junit</a>
+ * Provides a quick and easy way to run all <a href="http://http://junit.org">junit</a>
* unit tests (including Spock tests) in your Java project.
* It will find all unit test classes and run all their test methods.
* There is no need to configure it in any way to find these classes except to
@@ -59,9 +65,9 @@ import junit.framework.TestCase;
* Here is an example Ant target (See Ant at <a
* href="http://ant.apache.org">Apache Ant</a>) that runs all your unit
* tests:
- *
+ *
* <pre>
- *
+ *
* <target name="test" depends="compile">
* <java classname="org.apache.jorphan.test.AllTests" fork="yes">
* <classpath>
@@ -73,34 +79,34 @@ import junit.framework.TestCase;
* <arg value="NAME_OF_UNITTESTMANAGER_CLASS"/>
* </java>
* </target>
- *
+ *
* </pre>
- *
+ *
* <dl>
* <dt>YOUR_CLASSPATH</dt>
* <dd>Refers to the classpath that includes all jars and libraries need to run
* your unit tests</dd>
- *
+ *
* <dt>ROOT_DIR_OF_YOUR_COMPILED_CLASSES</dt>
* <dd>The classpath should include the directory where all your project's
* classes are compiled to, if it doesn't already.</dd>
- *
+ *
* <dt>SEARCH_PATH</dt>
* <dd>The first argument tells AllTests where to look for unit test classes to
* execute. In most cases, it is identical to ROOT_DIR_OF_YOUR_COMPILED_CLASSES.
* You can specify multiple directories or jars to search by providing a
* comma-delimited list.</dd>
- *
+ *
* <dt>PROPERTY_FILE</dt>
* <dd>A simple property file that sets logging parameters. It is optional and
* is only relevant if you use the same logging packages that JOrphan uses.</dd>
- *
+ *
* <dt>NAME_OF_UNITTESTMANAGER_CLASS</dt>
* <dd>If your system requires some configuration to run correctly, you can
* implement the {@link UnitTestManager} interface and be given an opportunity
* to initialize your system from a configuration file.</dd>
* </dl>
- *
+ *
* @see UnitTestManager
*/
public final class AllTests {
@@ -132,16 +138,15 @@ public final class AllTests {
* implements the UnitTestManager interface. This provides a means of
* initializing your application with a configuration file prior to the
* start of any unit tests.
- *
- * @param args
- * the command line arguments
+ *
+ * @param args the command line arguments
*/
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("You must specify a comma-delimited list of paths to search " + "for unit tests");
return;
}
-
+
String home = new File(System.getProperty("user.dir")).getParent();
System.out.println("Setting JMeterHome: "+home);
JMeterUtils.setJMeterHome(home);
@@ -169,7 +174,7 @@ public final class AllTests {
logprop("os.version", true);
logprop("os.arch");
logprop("java.class.version");
-
+
String cp = System.getProperty("java.class.path");
String[] cpe = JOrphanUtils.split(cp, java.io.File.pathSeparator);
StringBuilder sb = new StringBuilder(3000);
@@ -194,52 +199,111 @@ public final class AllTests {
System.out.println("+++++++++++");
logprop("java.awt.headless", true);
logprop("java.awt.graphicsenv", true);
-
+
System.out.println("------------");
+ JUnitCore jUnitCore = new JUnitCore();
+ // this listener is in the internal junit package
+ // if it breaks, replace it with a custom text listener
+ jUnitCore.addListener(new TextListener(System.out));
+ // this will time each unit test and then print to file
+ // TODO: put behind a flag
+ jUnitCore.addListener(new TimePrinter());
+
+ System.out.println("Searching junit tests in : "+args[0]);
+
try {
- System.out.println("Searching junit tests in : "+args[0]);
List<String> tests = findJMeterJUnitTests(args[0]);
- Class<?>[] classes = asClasses(tests);
- JUnitCore jUnitCore = new JUnitCore();
-
- // this listener is in the internal junit package
- // if it breaks, replace it with a custom text listener
- jUnitCore.addListener(new TextListener(new RealSystem()));
-
- Request request = Request.classes(new Computer(), classes);
- if(GraphicsEnvironment.isHeadless()) {
- request = request.filterWith(new ExcludeCategoryFilter(NeedGuiTests.class));
- }
- Result result = jUnitCore.run(request);
-
- System.exit(result.wasSuccessful() ? 0 : 1);
+ List<Class<?>> classes = asClasses(tests);
+
+ Result parallelResults = jUnitCore.run(getParallelTests(classes));
+ Result serialResults = jUnitCore.run(getSerialTests(classes));
+
+ boolean allTestsSuccessful =
+ parallelResults.wasSuccessful() && serialResults.wasSuccessful();
+ System.exit(allTestsSuccessful ? 0 : 1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
- private static Class<?>[] asClasses(List<String> tests) throws ClassNotFoundException {
- Class<?>[] classes = new Class<?>[tests.size()];
- for (int i = 0; i < classes.length; i++) {
- String test = tests.get(i);
- classes[i] = Class.forName(test, true, Thread.currentThread().getContextClassLoader());
+ private static Request getParallelTests(List<Class<?>> classes) {
+ Request parallelRequest = Request.classes(
+ ParallelComputer.methods(), // ParallelComputer.classes() causes failures
+ classes.stream()
+ .filter(c -> !JMeterSerialTest.class.isAssignableFrom(c))
+ .toArray(Class<?>[]::new));
+ return filterGUITests(parallelRequest);
+ }
+
+ private static Request getSerialTests(List<Class<?>> classes) {
+ Request serialRequest = Request.classes(Computer.serial(),
+ classes.stream()
+ .filter(JMeterSerialTest.class::isAssignableFrom)
+ .toArray(Class<?>[]::new));
+ return filterGUITests(serialRequest);
+ }
+
+ private static Request filterGUITests(Request request) {
+ if (GraphicsEnvironment.isHeadless()) {
+ return request.filterWith(new ExcludeCategoryFilter(NeedGuiTests.class));
+ } else {
+ return request;
+ }
+ }
+
+ private static List<Class<?>> asClasses(List<String> tests) {
+ return tests.stream()
+ .map(AllTests::asClass)
+ .collect(Collectors.toList());
+ }
+
+ private static Class<?> asClass(String test) {
+ try {
+ return Class.forName(test, true, Thread.currentThread().getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
}
+ }
- return classes;
+ /**
+ * Used to time each unit test and then write the results to file
+ */
+ private static class TimePrinter extends RunListener {
+ private ConcurrentHashMap<Description, StopWatch> testTimers = new ConcurrentHashMap<>();
+ private List<String> logLines = new ArrayList<>();
+
+ @Override
+ public void testStarted(Description description) {
+ StopWatch sw = new StopWatch();
+ sw.start();
+ testTimers.put(description, sw);
+ }
+
+ @Override
+ public void testFinished(Description desc) {
+ StopWatch sw = testTimers.get(desc);
+ sw.stop();
+ logLines.add(desc.getClassName() + "." + desc.getMethodName() + "\t" + sw.getNanoTime());
+ }
+
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ Files.write(Paths.get("unit-test-perf.log"), logLines);
+ }
}
/**
* An overridable method that instantiates a UnitTestManager (if one
* was specified in the command-line arguments), and hands it the name of
* the properties file to use to configure the system.
- *
+ *
* @param args arguments with the initialization parameter
* arg[0] - not used
* arg[1] - relative name of properties file
* arg[2] - used as label
*/
- protected static void initializeManager(String[] args) {
+ private static void initializeManager(String[] args) {
if (args.length >= 3) {
try {
System.out.println("Using initializeProperties() from " + args[2]);
Added: jmeter/trunk/test/src/org/apache/jorphan/test/JMeterSerialTest.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jorphan/test/JMeterSerialTest.java?rev=1817424&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jorphan/test/JMeterSerialTest.java (added)
+++ jmeter/trunk/test/src/org/apache/jorphan/test/JMeterSerialTest.java Thu Dec 7 21:31:04 2017
@@ -0,0 +1,8 @@
+package org.apache.jorphan.test;
+
+/**
+ * Used to tag tests which need to be run on their own (in serial) because
+ * either, they cause other tests to fail, or they fail when run in parallel.
+ */
+public interface JMeterSerialTest {
+}
Propchange: jmeter/trunk/test/src/org/apache/jorphan/test/JMeterSerialTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jmeter/trunk/test/src/org/apache/jorphan/test/JMeterSerialTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1817424&r1=1817423&r2=1817424&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Thu Dec 7 21:31:04 2017
@@ -202,6 +202,7 @@ Summary
<li><pr>334</pr>Enable running of JUnit tests from within IntelliJ with default config. Contributed by Graham Russell (graham at ham1.co.uk)</li>
<li><pr>335</pr>Removed <code>functions.util.*</code> as they don't seem to be used (for many years). Contributed by Graham Russell (graham at ham1.co.uk)</li>
<li><bug>61867</bug><pr>345</pr>Updated to latest checkstyle (v8.5), Added many more rules to checkstyle, Included checking of test files and more file types. Contributed by Graham Russell (graham at ham1.co.uk)</li>
+ <li><pr>350</pr> Parallelised unit tests</li>
</ul>
<!-- =================== Bug fixes =================== -->