package org.marketcetera.metrics;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.util.misc.NamedThreadFactory;
import org.marketcetera.core.LoggerConfiguration;
import org.marketcetera.module.ExpectedFailure;
import org.junit.Test;
import org.junit.BeforeClass;
import static org.junit.Assert.assertEquals;
import java.util.concurrent.Callable;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
/* $License$ */
/**
* Tests {@link ConditionsFactory}
*
* @author anshul@marketcetera.com
* @version $Id: ConditionsFactoryTest.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: ConditionsFactoryTest.java 16154 2012-07-14 16:34:05Z colin $")
public class ConditionsFactoryTest {
@BeforeClass
public static void setup() {
LoggerConfiguration.logSetup();
}
/**
* Tests expected failures.
* @throws Exception if there were errors.
*/
@Test
public void invalidInterval() throws Exception {
new ExpectedFailure<IllegalArgumentException>("0 <= 0"){
@Override
protected void run() throws Exception {
ConditionsFactory.createSamplingCondition(0,"dontmatter");
}
};
new ExpectedFailure<IllegalArgumentException>("-1 <= 0"){
@Override
protected void run() throws Exception {
ConditionsFactory.createSamplingCondition(-1,"dontmatter");
}
};
}
/**
* Tests sampling in a single thread.
*
* @throws Exception if there were errors.
*/
@Test
public void simpleSampling() throws Exception {
for (int interval = 1; interval < 50; interval++) {
Callable<Boolean> condition = ConditionsFactory.
createSamplingCondition(interval, "sample");
for(int i = 1; i < 100; i++) {
assertEquals("Interval " + interval + " iteration " + i,
i % interval == 0, condition.call());
}
}
}
/**
* Tests using the sampling condition instance from multiple threads.
*
* @throws Exception if there were errors.
*/
@Test
public void multiThreadSampling() throws Exception {
final int maxIterations = 100;
for (int j = 1; j < 37; j++) {
final int interval = j;
final Callable<Boolean> condition = ConditionsFactory.
createSamplingCondition(interval, "sample");
List<ExceptionThread> threads = new LinkedList<ExceptionThread>();
for(int i = 0; i < 20; i++) {
//Create a new thread instead of using a thread pool as
//thread reuse may lead to test failures.
final ExceptionThread<Integer> thread = new ExceptionThread<Integer>("TestCondition:" + i) {
@Override
public Integer call() throws Exception {
int i;
for (i = 1; i < maxIterations; i++) {
assertEquals("Thread " + Thread.currentThread().getName() +
" Interval " + interval +
" iteration " + i, i % interval == 0,
condition.call());
//slow them down to encourage concurrency.
Thread.sleep(1);
}
return i;
}
};
threads.add(thread);
}
//Start all the threads
for(ExceptionThread thread: threads) {
thread.start();
}
//Wait for all threads to end.
for(ExceptionThread thread: threads) {
assertEquals(maxIterations, thread.get());
}
}
}
/**
* A Thread subclass that produces a result when it's done. This thread
* can be subclassed to run operations that return results or fail with
* an exception.
*
* @param <T> the type of result generated by the thread.
*/
private static abstract class ExceptionThread<T> extends Thread
implements Callable<T> {
/**
* Creates an instance.
*
* @param name the thread name.
*/
public ExceptionThread(String name) {
super(name);
}
@Override
public abstract T call() throws Exception;
@Override
public void run() {
try {
mResult = call();
} catch(Exception t) {
mFailure = t;
}
}
/**
* Returns the result of {@link #call()} if it succeeded or
* throws the exception if it failed.
*
* @return the result.
*
* @throws Exception the failure exception.
*/
public T get() throws Exception {
//Wait for thread to finish.
join();
if(mFailure != null) {
throw mFailure;
}
return mResult;
}
private volatile T mResult;
private volatile Exception mFailure;
}
/**
* Tests integration of the sampling condition with {@link Configurator}.
*
* @throws Exception if there were errors.
*/
@Test
public void samplingConfiguration() throws Exception {
//Configure a mock configurator.
Map<String,String> properties = new HashMap<String, String>();
final String validInterval = "sample.interval";
properties.put(validInterval, "7");
final String invalidInterval = "sample.invalid.interval";
properties.put(invalidInterval, "value");
Configurator.setInstance(new ConfiguratorTest.MockConfigurator(properties));
//Test a sampler with a valid default configuration.
Callable<Boolean> c = ConditionsFactory.createSamplingCondition(10, validInterval);
for(int i = 1; i < 100; i++) {
assertEquals(" iteration " + i, i % 7 == 0, c.call());
}
//Test a sampler with invalid default configuration.
c = ConditionsFactory.createSamplingCondition(13, invalidInterval);
for(int i = 1; i < 100; i++) {
assertEquals(" iteration " + i, i % 13 == 0, c.call());
}
}
}