/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.view.impl; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertTrue; import static org.threeten.bp.temporal.ChronoUnit.MINUTES; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.mockito.Mock; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.threeten.bp.Instant; import com.opengamma.engine.marketdata.spec.MarketData; import com.opengamma.engine.resource.EngineResourceReference; import com.opengamma.engine.test.ViewProcessorTestEnvironment; import com.opengamma.engine.view.ViewComputationResultModel; import com.opengamma.engine.view.ViewDeltaResultModel; import com.opengamma.engine.view.client.ViewClient; import com.opengamma.engine.view.cycle.ViewCycle; import com.opengamma.engine.view.execution.ArbitraryViewCycleExecutionSequence; import com.opengamma.engine.view.execution.ExecutionFlags; 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.ViewExecutionOptions; import com.opengamma.engine.view.listener.AbstractViewResultListener; import com.opengamma.engine.view.listener.ViewResultListener; import com.opengamma.engine.view.listener.ViewResultListenerFactory; import com.opengamma.engine.view.worker.ViewProcessWorker; import com.opengamma.id.UniqueId; import com.opengamma.livedata.UserPrincipal; import com.opengamma.util.test.TestGroup; import com.opengamma.util.test.TestLifecycle; import com.opengamma.util.test.Timeout; /** * Tests ViewProcessor */ @Test(groups = TestGroup.UNIT) public class ViewProcessorTest { @Mock private ViewResultListenerFactory viewResultListenerFactoryStub; @Mock private ViewResultListener viewResultListenerMock; @BeforeMethod public void setUp() throws Exception { initMocks(this); when(viewResultListenerFactoryStub.createViewResultListener(ViewProcessorTestEnvironment.TEST_USER)).thenReturn(viewResultListenerMock); } public void testCreateViewProcessor() { TestLifecycle.begin(); try { final ViewProcessorTestEnvironment env = new ViewProcessorTestEnvironment(); env.init(); final ViewProcessorImpl vp = env.getViewProcessor(); assertTrue(vp.isRunning()); assertTrue(vp.getViewProcesses().isEmpty()); vp.stop(); assertFalse(vp.isRunning()); } finally { TestLifecycle.end(); } } @Test public void testAttachToView() { TestLifecycle.begin(); try { final ViewProcessorTestEnvironment env = new ViewProcessorTestEnvironment(); env.init(); final ViewProcessorImpl vp = env.getViewProcessor(); vp.start(); final ViewClient client = vp.createViewClient(ViewProcessorTestEnvironment.TEST_USER); client.attachToViewProcess(env.getViewDefinition().getUniqueId(), ExecutionOptions.infinite(MarketData.live())); vp.stop(); } finally { TestLifecycle.end(); } } private void waitForCompletionAndShutdown(final ViewProcessorImpl vp, final ViewClient client, final ViewProcessorTestEnvironment env) throws InterruptedException { client.waitForCompletion(); // Note: notification of client completion happens before the client computation thread terminates and performs its postRunCycle - must wait for this to happen final ViewProcessWorker worker = env.getCurrentWorker(env.getViewProcess(vp, client.getUniqueId())); client.shutdown(); worker.join(); } @Test public void testSuspend_viewExists() throws InterruptedException, ExecutionException { TestLifecycle.begin(); final ExecutorService executor = Executors.newCachedThreadPool(); try { final ViewProcessorTestEnvironment env = new ViewProcessorTestEnvironment(); env.init(); final ViewProcessorImpl vp = env.getViewProcessor(); vp.start(); final Runnable resume; resume = vp.suspend(executor).get(); assertNotNull(resume); final CountDownLatch latch = new CountDownLatch(1); final ViewClient client2 = vp.createViewClient(ViewProcessorTestEnvironment.TEST_USER); executor.submit(new Runnable() { @Override public void run() { client2.attachToViewProcess(env.getViewDefinition().getUniqueId(), ExecutionOptions.infinite(MarketData.live())); client2.shutdown(); latch.countDown(); } }); assertFalse(latch.await(Timeout.standardTimeoutMillis(), TimeUnit.MILLISECONDS)); resume.run(); assertTrue(latch.await(Timeout.standardTimeoutMillis(), TimeUnit.MILLISECONDS)); vp.stop(); } finally { executor.shutdown(); TestLifecycle.end(); } } @Test public void testSuspend_viewNotExists() throws InterruptedException, ExecutionException { TestLifecycle.begin(); final ExecutorService executor = Executors.newCachedThreadPool(); try { final ViewProcessorTestEnvironment env = new ViewProcessorTestEnvironment(); env.init(); final ViewProcessorImpl vp = env.getViewProcessor(); vp.start(); final Runnable resume = vp.suspend(executor).get(); assertNotNull(resume); final ViewClient client2 = vp.createViewClient(ViewProcessorTestEnvironment.TEST_USER); final CountDownLatch latch = new CountDownLatch(1); executor.submit(new Runnable() { @Override public void run() { client2.attachToViewProcess(env.getViewDefinition().getUniqueId(), ExecutionOptions.infinite(MarketData.live())); client2.shutdown(); latch.countDown(); } }); assertFalse(latch.await(Timeout.standardTimeoutMillis(), TimeUnit.MILLISECONDS)); resume.run(); assertTrue(latch.await(Timeout.standardTimeoutMillis(), TimeUnit.MILLISECONDS)); vp.stop(); } finally { executor.shutdown(); TestLifecycle.end(); } } @Test public void testCycleManagement_realTimeInterrupted() throws InterruptedException { TestLifecycle.begin(); try { final ViewProcessorTestEnvironment env = new ViewProcessorTestEnvironment(); env.init(); final ViewProcessorImpl vp = env.getViewProcessor(); vp.start(); final ViewClient client = vp.createViewClient(ViewProcessorTestEnvironment.TEST_USER); final CycleCountingViewResultListener listener = new CycleCountingViewResultListener(10); client.setResultListener(listener); final ViewExecutionOptions executionOptions = ExecutionOptions.of(new InfiniteViewCycleExecutionSequence(), ViewCycleExecutionOptions.builder().setMarketDataSpecification(MarketData.live()).create(), ExecutionFlags.none().runAsFastAsPossible().get()); client.attachToViewProcess(env.getViewDefinition().getUniqueId(), executionOptions); listener.awaitCycles(10 * Timeout.standardTimeoutMillis()); final ViewProcessImpl viewProcess = env.getViewProcess(vp, client.getUniqueId()); final ViewProcessWorker worker = env.getCurrentWorker(viewProcess); client.shutdown(); worker.join(); assertEquals(0, vp.getViewCycleManager().getResourceCount()); } finally { TestLifecycle.end(); } } @Test public void testCycleManagement_processCompletes() throws InterruptedException { TestLifecycle.begin(); try { final ViewProcessorTestEnvironment env = new ViewProcessorTestEnvironment(); env.setViewResultListenerFactory(viewResultListenerFactoryStub); env.init(); final ViewProcessorImpl vp = env.getViewProcessor(); vp.start(); final ViewClient client = vp.createViewClient(ViewProcessorTestEnvironment.TEST_USER); final ViewExecutionOptions executionOptions = ExecutionOptions.batch(generateExecutionSequence(10), ViewCycleExecutionOptions.builder().setMarketDataSpecification(MarketData.live()) .create()); client.attachToViewProcess(env.getViewDefinition().getUniqueId(), executionOptions); waitForCompletionAndShutdown(vp, client, env); assertEquals(0, vp.getViewCycleManager().getResourceCount()); } finally { TestLifecycle.end(); } } public void testCycleManagement_processCompletesWithReferences() throws InterruptedException { TestLifecycle.begin(); try { final ViewProcessorTestEnvironment env = new ViewProcessorTestEnvironment(); env.setViewResultListenerFactory(viewResultListenerFactoryStub); env.init(); final ViewProcessorImpl vp = env.getViewProcessor(); vp.start(); final ViewClient client = vp.createViewClient(ViewProcessorTestEnvironment.TEST_USER); client.setViewCycleAccessSupported(true); final List<EngineResourceReference<? extends ViewCycle>> references = new ArrayList<EngineResourceReference<? extends ViewCycle>>(); final ViewResultListener resultListener = new AbstractViewResultListener() { @Override public void cycleCompleted(final ViewComputationResultModel fullResult, final ViewDeltaResultModel deltaResult) { final EngineResourceReference<? extends ViewCycle> reference = client.createLatestCycleReference(); if (reference != null) { references.add(reference); } } @Override public UserPrincipal getUser() { return UserPrincipal.getTestUser(); } }; client.setResultListener(resultListener); final ViewExecutionOptions executionOptions = ExecutionOptions.batch(generateExecutionSequence(10), ViewCycleExecutionOptions.builder().setMarketDataSpecification(MarketData.live()) .create()); client.attachToViewProcess(env.getViewDefinition().getUniqueId(), executionOptions); final ViewProcessImpl viewProcess = env.getViewProcess(vp, client.getUniqueId()); final UniqueId viewProcessId = viewProcess.getUniqueId(); waitForCompletionAndShutdown(vp, client, env); assertEquals(10, references.size()); assertEquals(10, vp.getViewCycleManager().getResourceCount()); final Set<UniqueId> cycleIds = new HashSet<UniqueId>(); for (final EngineResourceReference<? extends ViewCycle> reference : references) { assertEquals(viewProcessId, reference.get().getViewProcessId()); cycleIds.add(reference.get().getUniqueId()); reference.release(); } // Expect distinct cycles assertEquals(10, cycleIds.size()); assertEquals(0, vp.getViewCycleManager().getResourceCount()); } finally { TestLifecycle.end(); } } private ViewCycleExecutionSequence generateExecutionSequence(final int cycleCount) { final Collection<Instant> valuationTimes = new ArrayList<Instant>(cycleCount); final Instant now = Instant.now(); for (int i = 0; i < cycleCount; i++) { valuationTimes.add(now.plus(i, MINUTES)); } return ArbitraryViewCycleExecutionSequence.of(valuationTimes); } private class CycleCountingViewResultListener extends AbstractViewResultListener { private final CountDownLatch _cycleLatch; public CycleCountingViewResultListener(final int requiredCycleCount) { _cycleLatch = new CountDownLatch(requiredCycleCount); } @Override public void cycleCompleted(final ViewComputationResultModel fullResult, final ViewDeltaResultModel deltaResult) { _cycleLatch.countDown(); } public void awaitCycles(final long timeoutMillis) throws InterruptedException { _cycleLatch.await(timeoutMillis, TimeUnit.MILLISECONDS); } @Override public UserPrincipal getUser() { return UserPrincipal.getTestUser(); } } }