Running your tests with multiple threads does not work. Bugs depend on a specific thread interleaving, which is often impossible to reach by simply rerunning your test multiple times. And data races only occur on specific hardware architectures and JVMs.
Therefore vmlens uses the Java Memory Model to execute all possible thread interleavings and to check for data races in the program flow. This blog post describes how vmlens uses the Java Memory Model to test all thread interleavings.
Using vmlens is easy.
Surround your test with a while loop iterating over all thread interleavings using the class AllInterleaving.
The following example shows how to write multi-threaded tests with vmlens:
import com.vmlens.api.AllInterleavings;
public class TestUpdateWrong {
public void update(ConcurrentHashMap<Integer, Integer> map) {
Integer result = map.get(1);
if (result == null) {
map.put(1, 1);
} else {
map.put(1, result + 1);
}
}
@Test
public void testUpdate() throws InterruptedException {
try (AllInterleavings allInterleavings =
new AllInterleavings("TestUpdateWrong");) {
// surround the test with a while loop, iterationg over
// the class AllInterleavings
while (allInterleavings.hasNext()) {
final ConcurrentHashMap<Integer, Integer> map =
new ConcurrentHashMap<Integer, Integer>();
Thread first = new Thread(() -> {
update(map);
});
Thread second = new Thread(() -> {
update(map);
});
first.start();
second.start();
first.join();
second.join();
assertEquals(2,map.get(1).intValue());
}
}
}
}
In your test method, you surround the code you want to test with a while loop iterating over the class AllInterleavings. vmlens executes the block inside the while loop multiple times, for each thread interleaving once. If the test fails vmlens shows the thread interleaving which led to the failure. If the test succeeds vmlens shows the last thread interleaving.
The above example test fails, and vmlens reports the interleaving which led to the failed assertion:
In maven, you can see this report by clicking on the link TestUpdateWrong in the file target/interleave/elements.html. In eclipse you can see the report by clicking on the link TestUpdateWrong in the view under Window -> Show View -> Other... -> vmlens -> vmlens Explorer.
The maven reports are described here. The eclipse views are described here.
You can run the test in eclipse using the vmlens run short cut for JUnit. Right click on the JUnit class -> Run As -> JUnit Test traced with vmlens.
To run the test with maven put the vmlens interleave plugin in your maven pom.xml as described here.
Read here more about how to use vmlens for testing multi-threaded software. And download and run the example tests.
Install from marketplace:
Or install directly from the update site:
- Start Eclipse
- Select Help>Install New Software…
- Work with: https://vmlens.com/download/site/
To use the class AllInterleavings you need to include the jar api-1.1.5.jar into your classpath. You can download this jar from maven central here.
The usage of the eclipse plugin is described here.
To use vmlens with maven, configure a plugin tag to tell maven that the vmlens plugin should be executed at the test phase. And include the jar com.vmlens.api as test dependency.
<project>
<!-- to include the class AllInterleavings into the test class path. -->
<dependency>
<groupId>com.vmlens</groupId>
<artifactId>api</artifactId>
<version>1.1.5</version>
<scope>test</scope>
</dependency>
<build>
<plugins>
<!-- to run the vmlens maven plugin during the maven test phase -->
<plugin>
<groupId>com.vmlens</groupId>
<artifactId>interleave</artifactId>
<version>1.1.5</version>
<executions>
<execution>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
...
</project>
The usage of the maven plugin is described here.
Post an issue in our issue tracker or send a message to our mailing list.
Follow @ThomasKrieger and join our mailing list.
To build vmlens, go to vmlens and run
mvn clean install
You need JDK 11 or higher and a toolchains.xml containing a tag for JDK 8. Example toolchains.xml:
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<!-- JDK toolchains -->
<toolchain>
<type>jdk</type>
<provides>
<version>1.8</version>
<vendor>sun</vendor>
</provides>
<configuration>
<jdkHome>/path/to/jdk/1.8</jdkHome>
</configuration>
</toolchain>
</toolchains>