package com.workshare.msnos.soup.threading;
import static com.workshare.msnos.core.CoreHelper.sleep;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
public class MulticasterTest {
private StringBuffer trace;
private Multicaster<Observer, Object> caster;
private ExecutorService executor;
@Before
public void init() {
trace = new StringBuffer();
}
@Test
public void shouldInvokeAListeners() {
caster().addListener(newTraceAppendingListener());
caster().dispatch("one");
caster().dispatch("two");
assertTraceContains("one");
assertTraceContains("two");
}
@Test
public void shouldInvokeAllListeners() {
caster().addListener(newTraceAppendingListener("alfa"));
caster().addListener(newTraceAppendingListener("beta"));
caster().dispatch("one");
caster().dispatch("two");
assertTraceContains("alfaone");
assertTraceContains("alfatwo");
assertTraceContains("betaone");
assertTraceContains("betatwo");
}
@Test
public void shouldRemoveListeners() {
Observer beta = newTraceAppendingListener("beta");
caster().addListener(beta);
caster().addListener(newTraceAppendingListener("alfa"));
caster().removeListener(beta);
caster().dispatch("one");
caster().dispatch("two");
assertTraceContains("alfaone");
assertTraceContains("alfatwo");
assertTraceNotContains("betaone");
assertTraceNotContains("betatwo");
}
@Test
public void shouldWorkAsynchronously() throws Exception {
executor = ExecutorServices.newFixedDaemonThreadPool(3);
caster().addListener(newTraceAppendingListener("AAA"));
final String name = "XYZ";
final long delay = 250l;
caster().addListener(new Observer() {
@Override
public void update(Observable o, Object event) {
sleep(delay, TimeUnit.MILLISECONDS);
trace.append(name+event);
}
});
caster().dispatch("one");
sleep(100l, TimeUnit.MILLISECONDS);
caster().dispatch("two");
shutdown(executor);
assertEquals("AAAoneAAAtwoXYZoneXYZtwo", trace.toString());
}
@Test
public void shouldInvokePiorityListenersBeforeNormalListeners() throws Exception {
executor = ExecutorServices.newFixedDaemonThreadPool(3);
caster().addSynchronousListener(newTraceAppendingListener("PRIORITY", 200l));
caster().addListener(newTraceAppendingListener("-STANDARD", 0l));
caster().addListener(newTraceAppendingListener("-STANDARD", 0l));
caster().dispatch("");
shutdown(executor);
assertEquals("PRIORITY-STANDARD-STANDARD", trace.toString());
}
private void shutdown(ExecutorService executor) throws InterruptedException {
executor.shutdown();
executor.awaitTermination(10, TimeUnit.SECONDS);
}
private Multicaster<Observer, Object> caster() {
if (caster == null)
caster = new Multicaster<Observer, Object>(executor()) {
@Override
protected void dispatch(Observer listener, Object message) {
listener.update(null, message);
}
};
return caster;
}
private void assertTraceContains(final String text) {
assertTrue(trace.indexOf(text) != -1);
}
private void assertTraceNotContains(final String text) {
assertTrue(trace.indexOf(text) == -1);
}
private Executor executor() {
if (executor != null)
return executor;
return new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
}
private Observer newTraceAppendingListener() {
return newTraceAppendingListener(null, 0l);
}
private Observer newTraceAppendingListener(final String name) {
return newTraceAppendingListener(name, 0l);
}
private Observer newTraceAppendingListener(final String name, final long delay) {
return new Observer() {
@Override
public void update(Observable o, Object message) {
if (delay != 0l)
sleep(delay, TimeUnit.MILLISECONDS);
if (name == null)
trace.append(message);
else
trace.append(name + message);
}
};
}
}