Sunday, November 15, 2009

Mycila Event

These days I was working hard on a new library: Mycila Event. This library is an in-memory event system. For those who know EventBus, this library brings many more features and advanced concept such as complex dispatching strategies.
  • Topics management and Topic matchers: you can subscribe to many topics using Ant expression, or using and(), or(), not(), anyOf(), to compose them
  • Veto system: you can register some vetoers to control wheter events should be published or not
  • Exception handling: you can define or use pre-existing strategies on how to to when a subscriber throw and exception: fail immediately, fail after the whole publishing, ignore them, ...
  • Event types: you can send in one topic several events. Your subscribers must specify to which event to listen to.
  • Annotation support: Mycila Event has a very good annotation support, to control your publishing, veto and subscribing methods. Also, the library has the ability to completely generate for you publishers based on an annotated interface.
  • Dispatching strategies: Mycila Event comes with a lot of dispatching strategies, and you can create your own ones. Dispatching strategies control how the publishing is done, how the listeners are called and how the events are sent using the current thread, a thread pool or else.
  • DI integration: The annotation support of Mycila Event is best suited to integrate with a DI library such as Google Guice. Mycila Event provides a Guice module you can use to directly detect annotated classed and inject / create publishers, subscribers and vetoers.
The library is deployed as a snapshot and is not yet released. It will be finalized within the next weeks and a 1.0 release should be deployed in the Maven Central Repository at the end of November.

If you have any questions / issues, you can see:
Mathieu.

Wednesday, November 4, 2009

Writing your own JUnit extensions using @Rule

This article follows the previous one concerning the really useful and undocumented features of Junit. One that is really interesting is @Rule.
This annotation allows you to annotate a public field in your test class, which is of type MethodRule. This binding will intercept test method calls like an AOP framework would do and redefine the execution, skip it, or do anything else.
In example, suppose you want to run some concurrency test: you may need to execute your test method on 15 threads each starting at the same time, and then wait for all threads to finish. All this plumbing can now be resumed by one annotation:

@Test
@Concurrent(15)
public void myTestMethod() throws InterruptedException {
System.out.println("Thread " + Thread.currentThread().getName() + " started !");
int n = new Random().nextInt(5000);
System.out.println("Thread " + Thread.currentThread().getName() + " wait " + n + "ms");
Thread.sleep(n);
System.out.println("Thread " + Thread.currentThread().getName() + " finished");

But who manages this annotation ? It will be our MethodRule, and it is used like this:

public final class ConcurrentTest {

@Rule
public ConcurrentRule concurrentRule = new ConcurrentRule();

@Test
@Concurrent(15)
public void myTestMethod() throws InterruptedException {
System.out.println("Thread " + Thread.currentThread().getName() + " started !");
int n = new Random().nextInt(5000);
System.out.println("Thread " + Thread.currentThread().getName() + " wait " + n + "ms");
Thread.sleep(n);
System.out.println("Thread " + Thread.currentThread().getName() + " finished");
}
}

MethodRule are simplier instances that will intercept all test calls. They are mere instance variable that can benefit of parametrization. In example, we may want in a test class to have a ConcurrentRule with a timeout of 10 seconds, and 2 seconds in another class.
In our case, the ConcurrentRule I made simply check if the test method intercepted has a Concurrent annotation. If yes, it will spawn the number of thread requested and launch the test method for each thread.
Here is the annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Concurrent {
int value() default 10;
}

And the MethodRule implementation:

import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import java.util.concurrent.CountDownLatch;

public final class ConcurrentRule implements MethodRule {
@Override
public Statement apply(Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Concurrent concurrent = frameworkMethod.getAnnotation(Concurrent.class);
if (concurrent == null)
statement.evaluate();
else {
final String name = frameworkMethod.getName();
final Thread[] threads = new Thread[concurrent.value()];
final CountDownLatch go = new CountDownLatch(1);
final CountDownLatch finished = new CountDownLatch(threads.length);
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
try {
go.await();
statement.evaluate();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Throwable throwable) {
if (throwable instanceof RuntimeException)
throw (RuntimeException) throwable;
if (throwable instanceof Error)
throw (Error) throwable;
RuntimeException r = new RuntimeException(throwable.getMessage(), throwable);
r.setStackTrace(throwable.getStackTrace());
throw r;
} finally {
finished.countDown();
}
}
}, name + "-Thread-" + i);
threads[i].start();
}
go.countDown();
finished.await();
}
}
};
}
}

All the code is available in Mycila sandbox here.

Update: 2009-12-23
A suggestion in the comments below was to be able to retrieve the exception if the test fail and rethrow it just after in the main thread. This can be done easily using Java Concurrent API, with FutureTask or CompletionService like this:

import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;

/**
* @author Mathieu Carbou (mathieu.carbou@gmail.com)
*/
public final class ConcurrentThrowingRule implements MethodRule {
@Override
public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Concurrent concurrent = frameworkMethod.getAnnotation(Concurrent.class);
if (concurrent == null)
statement.evaluate();
else {
// create an executor which cimply spawns threads to execute runnables
Executor executor = new Executor() {
final String name = frameworkMethod.getName();
int count = 0;

@Override
public void execute(Runnable command) {
new Thread(command, name + "-Thread-" + count++).start();
}
};
// create a completion service to get jobs in the order they finish, to be able
// to cancel remaining jobs as fast as possible if an exception occurs
CompletionService<Void> completionService = new ExecutorCompletionService<Void>(executor);
// latch used to pause all threads and start all of them (nearly) at the same time
final CountDownLatch go = new CountDownLatch(1);
// create the tasks
for (int i = 0; i < concurrent.value(); i++) {
completionService.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
try {
go.await();
statement.evaluate();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Throwable throwable) {
if (throwable instanceof Exception)
throw (Exception) throwable;
if (throwable instanceof Error)
throw (Error) throwable;
// case of exceptions directly subclassing Throwable
// (should not occur - bad programming)
RuntimeException r = new RuntimeException(throwable.getMessage(), throwable);
r.setStackTrace(throwable.getStackTrace());
throw r;
}
return null;
}
});
}
go.countDown();
Throwable throwable = null;
for (int i = 0; i < concurrent.value(); i++) {
try {
completionService.take().get();
} catch (ExecutionException e) {
// only keep the first exception, but wait for all threads to finish
if(throwable == null)
throwable = e.getCause();
}
}
if(throwable != null) throw throwable;
}
}
};
}
}

Then you can use the expected attribute in your Junit test:

public final class ConcurrentThrowingTest {

@Rule
public ConcurrentThrowingRule concurrentRule = new ConcurrentThrowingRule();

@Test(expected = NumberFormatException.class)
@Concurrent(10)
public void myTestMethod_failing() throws InterruptedException {
System.out.println("Thread " + Thread.currentThread().getName() + " started !");
int n = new Random().nextInt(5000);
System.out.println("Thread " + Thread.currentThread().getName() + " wait " + n + "ms");
Thread.sleep(n);
Integer.parseInt("blabla");
}
}

Monday, November 2, 2009

Junit hidden feature

I was surprised to see how many hidden and undocumented features Junit has. In the new release (4.7) you have access to a lot of interesting stuff (still in development for some).

Running tests in parallel (by using a scheduling strategy)


public static class Example {
@Test public void one() throws InterruptedException {
Thread.sleep(1000);
}
@Test public void two() throws InterruptedException {
Thread.sleep(1000);
}
}

@Test public void testsRunInParallel() {
long start= System.currentTimeMillis();
Result result= JUnitCore.runClasses(ParallelComputer.methods(),
Example.class);
assertTrue(result.wasSuccessful());
long end= System.currentTimeMillis();
assertThat(end - start, betweenInclusive(1000, 1500));
}


See here for more details.

Intercept test method call with @Rule


public static class HasGlobalTimeout {
public static String log;

@Rule
public MethodRule globalTimeout= new Timeout(20);

@Test
public void testInfiniteLoop1() {
log+= "ran1";
for (;;) {...}
}

@Test
public void testInfiniteLoop2() {
log+= "ran2";
for (;;) {...}
}
}


See here for more details.

Maven License Plugin 1.5.0 released !

Hi,

I've released yesterday the new Maven License Plugin version: 1.5.0. It's been a while since i didn't have any time to work on this project.

I fixed several issues relative to license header detection and added other features such as:
  • Ability to modify the keywords used to detect license header
  • dryRun option
  • Added to boolean attributes to header style definition: isMultiline and allowBlankLines
The plugin is available in Maven Central Repository:


<groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId>
<version>1.5.0</version>