/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.view.worker;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNotSame;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.opengamma.engine.marketdata.spec.MarketData;
import com.opengamma.engine.view.ViewDefinition;
import com.opengamma.engine.view.execution.ExecutionFlags;
import com.opengamma.engine.view.execution.ExecutionOptions;
import com.opengamma.engine.view.execution.ViewExecutionOptions;
import com.opengamma.engine.view.worker.ParallelRecompilationViewProcessWorker.AbstractViewProcessWorkerContext;
import com.opengamma.util.test.TestGroup;
/**
* Tests the {@link ParallelRecompilationViewProcessWorker} class.
*/
@Test(groups = TestGroup.UNIT)
public class ParallelRecompilationViewProcessWorkerTest {
@Test(expectedExceptions = IllegalStateException.class)
public void testIllegalStart_alreadyRunning() {
final ViewProcessWorkerFactory workerFactory = Mockito.mock(ViewProcessWorkerFactory.class);
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
worker.startParallel(options);
worker.startParallel(options);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testIllegalStart_terminated() {
final ViewProcessWorkerFactory workerFactory = Mockito.mock(ViewProcessWorkerFactory.class);
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
worker.startParallel(options);
worker.terminate();
worker.startParallel(options);
}
public void testTriggerCycle() {
// Creates workers that will trigger on the first cycle, ignore the second, and then terminate on the third
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
Mockito.when(worker.triggerCycle()).thenAnswer(new Answer<Boolean>() {
private int _count = 0;
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
_count++;
if (_count == 3) {
context.workerCompleted();
}
return (_count == 1);
}
});
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// With no worker
assertFalse(worker.triggerCycle());
// With a primary worker that responds TRUE (first time)
worker.startParallel(options);
assertTrue(worker.triggerCycle());
// With a primary worker that responds FALSE (second time)
worker.startSecondaryWorker(worker.getPrimary(), options.getExecutionSequence());
assertFalse(worker.triggerCycle());
// With a primary worker that returns FALSE, causes secondary promotion, and that returns TRUE (first time)
assertTrue(worker.triggerCycle());
// With a primary worker that responds FALSE (second time)
assertFalse(worker.triggerCycle());
assertFalse(worker.isTerminated());
// With a primary worker that returns FALSE because of termination
assertFalse(worker.triggerCycle());
assertTrue(worker.isTerminated());
// After explicit termination
worker.terminate();
assertFalse(worker.triggerCycle());
}
public void testRequestCycle() {
// Creates workers that will honor the request on the first cycle, ignore the second, and then terminate on the third
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
Mockito.when(worker.requestCycle()).thenAnswer(new Answer<Boolean>() {
private int _count = 0;
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
_count++;
if (_count == 3) {
context.workerCompleted();
}
return (_count == 1);
}
});
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// With no worker
assertFalse(worker.requestCycle());
// With a primary worker that responds TRUE (first time)
worker.startParallel(options);
assertTrue(worker.requestCycle());
// With a primary worker that responds FALSE (second time)
worker.startSecondaryWorker(worker.getPrimary(), options.getExecutionSequence());
assertFalse(worker.requestCycle());
// With a primary worker that returns FALSE, causes secondary promotion, and that returns TRUE (first time)
assertTrue(worker.requestCycle());
// With a primary worker that responds FALSE (second time)
assertFalse(worker.requestCycle());
assertFalse(worker.isTerminated());
// With a primary worker that returns FALSE because of termination
assertFalse(worker.requestCycle());
assertTrue(worker.isTerminated());
// After explicit termination
worker.terminate();
assertFalse(worker.requestCycle());
}
public void testUpdateViewDefinition() {
final List<ViewDefinition> viewDefinitions = ImmutableList.of(Mockito.mock(ViewDefinition.class), Mockito.mock(ViewDefinition.class), Mockito.mock(ViewDefinition.class),
Mockito.mock(ViewDefinition.class));
final List<ViewProcessWorker> workers = new ArrayList<ViewProcessWorker>(3);
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
workers.add(worker);
assertSame(viewDefinition, viewDefinitions.get(workers.size()));
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinitions.get(0));
AbstractViewProcessWorkerContext primary, secondary;
// With no current workers
assertNull(worker.getPrimary());
assertNull(worker.getSecondary());
worker.updateViewDefinition(viewDefinitions.get(1));
// With a primary worker only
worker.startParallel(options);
assertEquals(workers.size(), 1);
primary = worker.getPrimary();
assertNotNull(primary);
assertNull(worker.getSecondary());
worker.updateViewDefinition(viewDefinitions.get(2));
assertEquals(workers.size(), 2);
assertSame(worker.getPrimary(), primary);
secondary = worker.getSecondary();
assertNotNull(secondary);
// With a secondary worker - should replace the previous
worker.updateViewDefinition(viewDefinitions.get(3));
assertEquals(workers.size(), 3);
assertSame(worker.getPrimary(), primary);
assertNotSame(worker.getSecondary(), secondary);
Mockito.verify(workers.get(0), Mockito.never()).terminate();
Mockito.verify(workers.get(1), Mockito.atLeastOnce()).terminate();
Mockito.verify(workers.get(2), Mockito.never()).terminate();
}
public void testTerminate() {
final List<ViewProcessWorkerContext> workerContexts = new ArrayList<ViewProcessWorkerContext>(2);
final List<ViewProcessWorker> workers = new ArrayList<ViewProcessWorker>(2);
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
workerContexts.add(context);
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
workers.add(worker);
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// Initially "terminated"
assertTrue(worker.isTerminated());
// Spawn workers
worker.startParallel(options);
worker.startSecondaryWorker(worker.getPrimary(), options.getExecutionSequence());
assertFalse(worker.isTerminated());
// Terminate
worker.terminate();
assertFalse(worker.isTerminated());
Mockito.verify(workers.get(0), Mockito.atLeastOnce()).terminate();
Mockito.verify(workers.get(1), Mockito.atLeastOnce()).terminate();
workerContexts.get(0).workerCompleted();
assertFalse(worker.isTerminated());
workerContexts.get(1).workerCompleted();
assertTrue(worker.isTerminated());
// Already terminated
worker.terminate();
assertTrue(worker.isTerminated());
}
@Test(timeOut = 10000)
public void testJoin_noWorkers() throws InterruptedException {
final ViewProcessWorkerFactory workerFactory = Mockito.mock(ViewProcessWorkerFactory.class);
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// No-op
worker.join();
}
@Test(timeOut = 10000)
public void testJoin_workersTerminateBefore() throws InterruptedException {
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
try {
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
context.workerCompleted();
return null;
}
}).when(worker).join();
} catch (InterruptedException e) {
// Doesn't get thrown
}
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// Start workers
worker.startParallel(options);
worker.startSecondaryWorker(worker.getPrimary(), options.getExecutionSequence());
// Join on the first worker will see the secondary worker promoted, that will join and this will complete
worker.join();
assertNull(worker.getPrimary());
assertNull(worker.getSecondary());
}
@Test(timeOut = 10000)
public void testJoin_workersTerminateAfter() throws InterruptedException {
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
return Mockito.mock(ViewProcessWorker.class);
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// Start workers
worker.startParallel(options);
worker.startSecondaryWorker(worker.getPrimary(), options.getExecutionSequence());
// Join on the first worker will see the secondary worker promoted, that will join and this will complete
worker.join();
assertNull(worker.getPrimary());
assertNull(worker.getSecondary());
}
@Test(timeOut = 10000)
public void testJoin_timeout_noWorkers() throws InterruptedException {
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
try {
Mockito.when(worker.join(Mockito.anyLong())).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
assertTrue(((Long) invocation.getArguments()[0]) <= 20000);
return Boolean.TRUE;
}
});
} catch (InterruptedException e) {
// Doesn't get thrown
}
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// No-op
assertTrue(worker.join(20000));
}
@Test(timeOut = 10000)
public void testJoin_timeout_workersTerminateBefore() throws InterruptedException {
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
try {
Mockito.doAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
assertTrue(((Long) invocation.getArguments()[0]) <= 20000);
context.workerCompleted();
return Boolean.TRUE;
}
}).when(worker).join(Mockito.anyLong());
} catch (InterruptedException e) {
// Doesn't get thrown
}
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// Start workers
worker.startParallel(options);
worker.startSecondaryWorker(worker.getPrimary(), options.getExecutionSequence());
// Join on the first worker will see the secondary worker promoted, that will join and this will complete
assertTrue(worker.join(20000));
assertNull(worker.getPrimary());
assertNull(worker.getSecondary());
}
@Test(timeOut = 10000)
public void testJoin_timeout_workersTerminateAfter() throws InterruptedException {
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
try {
Mockito.when(worker.join(Mockito.anyLong())).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
assertTrue(((Long) invocation.getArguments()[0]) <= 20000);
return Boolean.TRUE;
}
});
} catch (InterruptedException e) {
// Doesn't get thrown
}
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// Start workers
worker.startParallel(options);
worker.startSecondaryWorker(worker.getPrimary(), options.getExecutionSequence());
// Join on the first worker will see the secondary worker promoted, that will join and this will complete
assertTrue(worker.join(20000));
assertNull(worker.getPrimary());
assertNull(worker.getSecondary());
}
@Test(timeOut = 10000)
public void testJoin_timeout() throws InterruptedException {
final ViewProcessWorkerFactory workerFactory = new ViewProcessWorkerFactory() {
@Override
public ViewProcessWorker createWorker(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition) {
final ViewProcessWorker worker = Mockito.mock(ViewProcessWorker.class);
try {
Mockito.when(worker.join(Mockito.anyLong())).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
assertTrue(((Long) invocation.getArguments()[0]) <= 20000);
return Boolean.FALSE;
}
});
} catch (InterruptedException e) {
// Doesn't get thrown
}
return worker;
}
};
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final ViewExecutionOptions options = ExecutionOptions.infinite(MarketData.live(), ExecutionFlags.none().ignoreCompilationValidity().get());
final ViewDefinition viewDefinition = Mockito.mock(ViewDefinition.class);
final ParallelRecompilationViewProcessWorker worker = new ParallelRecompilationViewProcessWorker(workerFactory, context, options, viewDefinition);
// Start workers
worker.startParallel(options);
worker.startSecondaryWorker(worker.getPrimary(), options.getExecutionSequence());
// Join on the first worker will see the secondary worker promoted, that will join and this will complete
assertFalse(worker.join(20000));
assertNotNull(worker.getPrimary());
assertNotNull(worker.getSecondary());
assertFalse(worker.join(0));
assertNotNull(worker.getPrimary());
assertNotNull(worker.getSecondary());
}
}