/**
* 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.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import org.mockito.Mockito;
import org.testng.annotations.Test;
import org.threeten.bp.Instant;
import com.opengamma.engine.view.ViewComputationResultModel;
import com.opengamma.engine.view.ViewDefinition;
import com.opengamma.engine.view.compilation.CompiledViewDefinitionWithGraphs;
import com.opengamma.engine.view.cycle.ViewCycle;
import com.opengamma.engine.view.cycle.ViewCycleMetadata;
import com.opengamma.engine.view.execution.ArbitraryViewCycleExecutionSequence;
import com.opengamma.engine.view.execution.ExecutionOptions;
import com.opengamma.engine.view.execution.InfiniteViewCycleExecutionSequence;
import com.opengamma.engine.view.execution.ViewCycleExecutionOptions;
import com.opengamma.engine.view.execution.ViewCycleExecutionSequence;
import com.opengamma.engine.view.execution.ViewExecutionFlags;
import com.opengamma.engine.view.execution.ViewExecutionOptions;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.test.Timeout;
/**
* Tests the {@link SequencePartitioningViewProcessWorker} class
*/
@Test(groups = TestGroup.UNIT)
public class SequencePartitioningViewProcessWorkerTest {
private class ViewProcessWorkerMock implements ViewProcessWorker, Runnable {
private final Thread _thread;
private final ViewProcessWorkerContext _context;
private final ViewExecutionOptions _options;
private final int _delay;
private volatile ViewDefinition _viewDefinition;
private volatile boolean _terminated;
public ViewProcessWorkerMock(final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions, final ViewDefinition viewDefinition, final int delay) {
_context = context;
_options = executionOptions;
_viewDefinition = viewDefinition;
_delay = delay;
_thread = new Thread(this);
_thread.start();
}
// ViewProcessWorker
@Override
public boolean triggerCycle() {
fail();
return false;
}
@Override
public boolean requestCycle() {
fail();
return false;
}
@Override
public void updateViewDefinition(ViewDefinition viewDefinition) {
_viewDefinition = viewDefinition;
}
@Override
public void terminate() {
_terminated = true;
_thread.interrupt();
}
@Override
public void join() throws InterruptedException {
_thread.join();
}
@Override
public boolean join(long timeout) throws InterruptedException {
_thread.join(timeout);
return !_thread.isAlive();
}
@Override
public boolean isTerminated() {
return !_thread.isAlive();
}
@Override
public void forceGraphRebuild() {
// do nothing
}
// Runnable
@Override
public void run() {
boolean compiled = false;
do {
ViewCycleExecutionOptions options = _options.getExecutionSequence().poll(_options.getDefaultExecutionOptions());
if (options == null) {
_context.workerCompleted();
return;
}
_context.cycleStarted(Mockito.mock(ViewCycleMetadata.class));
if (!compiled) {
compiled = true;
_context.viewDefinitionCompiled(Mockito.mock(ViewExecutionDataProvider.class), Mockito.mock(CompiledViewDefinitionWithGraphs.class));
}
_context.cycleFragmentCompleted(Mockito.mock(ViewComputationResultModel.class), _viewDefinition);
if (_delay > 0) {
try {
Thread.sleep(_delay);
} catch (InterruptedException e) {
break;
}
}
_context.cycleFragmentCompleted(Mockito.mock(ViewComputationResultModel.class), _viewDefinition);
_context.cycleCompleted(Mockito.mock(ViewCycle.class));
} while (!_terminated);
_context.workerCompleted();
}
}
private class ViewProcessWorkerFactoryMock implements ViewProcessWorkerFactory {
private final int _delay;
public ViewProcessWorkerFactoryMock(final int delay) {
_delay = delay;
}
@Override
public ViewProcessWorker createWorker(ViewProcessWorkerContext context, ViewExecutionOptions executionOptions, ViewDefinition viewDefinition) {
return new ViewProcessWorkerMock(context, executionOptions, viewDefinition, _delay);
}
}
public void testFiniteSequence() throws InterruptedException {
final ViewProcessWorkerFactoryMock underlying = new ViewProcessWorkerFactoryMock(0);
final Instant t = Instant.now();
final List<ViewCycleExecutionOptions> cycles = new ArrayList<ViewCycleExecutionOptions>(20);
for (int i = 0; i < 37; i++) {
cycles.add(ViewCycleExecutionOptions.builder().setValuationTime(t.plusSeconds(i)).create());
}
final ViewCycleExecutionSequence sequence = new ArbitraryViewCycleExecutionSequence(cycles);
final ViewExecutionOptions options = ExecutionOptions.of(sequence, EnumSet.of(ViewExecutionFlags.RUN_AS_FAST_AS_POSSIBLE));
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final SequencePartitioningViewProcessWorker worker = new SequencePartitioningViewProcessWorker(underlying, context, options, Mockito.mock(ViewDefinition.class), 10, 2);
assertTrue(worker.join(4 * Timeout.standardTimeoutMillis()));
assertTrue(worker.isTerminated());
Mockito.verify(context, Mockito.times(cycles.size())).cycleStarted(Mockito.any(ViewCycleMetadata.class));
// Total of four workers spawned
Mockito.verify(context, Mockito.times(4)).viewDefinitionCompiled(Mockito.any(ViewExecutionDataProvider.class), Mockito.any(CompiledViewDefinitionWithGraphs.class));
Mockito.verify(context, Mockito.times(2 * cycles.size())).cycleFragmentCompleted(Mockito.any(ViewComputationResultModel.class), Mockito.any(ViewDefinition.class));
Mockito.verify(context, Mockito.times(cycles.size())).cycleCompleted(Mockito.any(ViewCycle.class));
// Only one completion acknowledgement from the top level worker
Mockito.verify(context, Mockito.times(1)).workerCompleted();
Mockito.verify(context, Mockito.times(0)).cycleExecutionFailed(Mockito.any(ViewCycleExecutionOptions.class), Mockito.any(Exception.class));
Mockito.verify(context, Mockito.times(0)).viewDefinitionCompilationFailed(Mockito.any(Instant.class), Mockito.any(Exception.class));
}
public void testInfiniteSequence() throws InterruptedException {
final ViewProcessWorkerFactoryMock underlying = new ViewProcessWorkerFactoryMock((int) (Timeout.standardTimeoutMillis() / 32));
final ViewExecutionOptions options = ExecutionOptions.of(new InfiniteViewCycleExecutionSequence(), EnumSet.of(ViewExecutionFlags.RUN_AS_FAST_AS_POSSIBLE));
final ViewProcessWorkerContext context = Mockito.mock(ViewProcessWorkerContext.class);
final SequencePartitioningViewProcessWorker worker = new SequencePartitioningViewProcessWorker(underlying, context, options, Mockito.mock(ViewDefinition.class), 10, 2);
assertFalse(worker.join(Timeout.standardTimeoutMillis()));
assertFalse(worker.isTerminated());
worker.terminate();
assertTrue(worker.join(4 * Timeout.standardTimeoutMillis()));
assertTrue(worker.isTerminated());
Mockito.verify(context, Mockito.atLeast(2)).viewDefinitionCompiled(Mockito.any(ViewExecutionDataProvider.class), Mockito.any(CompiledViewDefinitionWithGraphs.class));
}
}