Package com.opengamma.engine.calcnode

Source Code of com.opengamma.engine.calcnode.JobDispatcherTest

/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.calcnode;

import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertTrue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.threeten.bp.Instant;

import com.opengamma.engine.cache.CacheSelectHint;
import com.opengamma.engine.calcnode.AbstractJobInvoker;
import com.opengamma.engine.calcnode.CalculationJob;
import com.opengamma.engine.calcnode.CalculationJobItem;
import com.opengamma.engine.calcnode.CalculationJobResult;
import com.opengamma.engine.calcnode.CalculationJobResultItem;
import com.opengamma.engine.calcnode.CalculationJobSpecification;
import com.opengamma.engine.calcnode.Capability;
import com.opengamma.engine.calcnode.JobDispatcher;
import com.opengamma.engine.calcnode.JobInvocationReceiver;
import com.opengamma.engine.calcnode.JobInvoker;
import com.opengamma.engine.calcnode.JobInvokerRegister;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.util.async.Cancelable;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.test.Timeout;

/**
*
*/
@Test(groups = TestGroup.INTEGRATION)
public class JobDispatcherTest {

  private static final Logger s_logger = LoggerFactory.getLogger(JobDispatcherTest.class);
  private static final long TIMEOUT = Timeout.standardTimeoutMillis ();

  private final ExecutorService _executorService = Executors.newCachedThreadPool();

  private static final AtomicLong s_jobId = new AtomicLong();

  protected static CalculationJobSpecification createTestJobSpec() {
    return new CalculationJobSpecification(UniqueId.of("Test", "ViewCycle"), "default", Instant.now(), s_jobId.incrementAndGet());
  }

  protected static List<CalculationJobItem> createTestJobItems() {
    return Collections.emptyList();
  }

  protected static CalculationJob createTestJob() {
    return new CalculationJob(createTestJobSpec(), 0L, VersionCorrection.LATEST, null, createTestJobItems(), CacheSelectHint.allPrivate());
  }

  protected static CalculationJobResult createTestJobResult(final CalculationJobSpecification jobSpec, final long time, final String nodeId) {
    return new CalculationJobResult(jobSpec, time, new ArrayList<CalculationJobResultItem>(), nodeId);
  }

  private class TestJobInvoker extends AbstractJobInvoker {

    private JobInvokerRegister _callback;
    private boolean _disabled;

    public TestJobInvoker(final String nodeId) {
      super (nodeId);
    }

    @Override
    public boolean invoke(final CalculationJob job, final JobInvocationReceiver receiver) {
      if (_disabled) {
        return false;
      }
      _executorService.execute(new Runnable() {
        @Override
        public void run() {
          receiver.jobCompleted(createTestJobResult(job.getSpecification(), 0, getInvokerId ()));
        }
      });
      return true;
    }

    @Override
    public boolean notifyWhenAvailable(JobInvokerRegister callback) {
      _callback = callback;
      return false;
    }

  }

  @Test
  public void registerInvokerWithJobPending() {
    s_logger.info("registerInvokerWithJobPending");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    final TestJobResultReceiver result = new TestJobResultReceiver();
    final CalculationJob job = createTestJob();
    jobDispatcher.dispatchJob(job, result);
    assertNull(result.getResult());
    final TestJobInvoker jobInvoker = new TestJobInvoker("Test");
    jobDispatcher.registerJobInvoker(jobInvoker);
    final CalculationJobResult jobResult = result.waitForResult(TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(job.getSpecification(), jobResult.getSpecification());
    assertNull(jobInvoker._callback);
  }

  @Test
  public void registerInvokerWithEmptyQueue() {
    s_logger.info("registerInvokerWithEmptyQueue");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    final TestJobInvoker jobInvoker = new TestJobInvoker("Test");
    jobDispatcher.registerJobInvoker(jobInvoker);
    final TestJobResultReceiver result = new TestJobResultReceiver();
    final CalculationJob job = createTestJob();
    jobDispatcher.dispatchJob(job, result);
    final CalculationJobResult jobResult = result.waitForResult(TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(job.getSpecification(), jobResult.getSpecification());
    assertNull(jobInvoker._callback);
  }

  private void nodeTest(final String expectedNodeId, final JobDispatcher jobDispatcher) {
    final TestJobResultReceiver result = new TestJobResultReceiver();
    final CalculationJob job = createTestJob();
    jobDispatcher.dispatchJob(job, result);
    final CalculationJobResult jobResult = result.waitForResult(TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(job.getSpecification(), jobResult.getSpecification());
    assertEquals(expectedNodeId, jobResult.getComputeNodeId());
  }

  @Test
  public void invokeInRoundRobinOrder() {
    s_logger.info("invokeInRoundRobinOrder");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    final TestJobInvoker node1 = new TestJobInvoker("1");
    final TestJobInvoker node2 = new TestJobInvoker("2");
    final TestJobInvoker node3 = new TestJobInvoker("3");
    jobDispatcher.registerJobInvoker(node1);
    jobDispatcher.registerJobInvoker(node2);
    jobDispatcher.registerJobInvoker(node3);
    nodeTest("1", jobDispatcher);
    assertNull(node1._callback);
    nodeTest("2", jobDispatcher);
    assertNull(node2._callback);
    nodeTest("3", jobDispatcher);
    assertNull(node3._callback);
    node1._disabled = true;
    nodeTest("2", jobDispatcher);
    assertNotNull(node1._callback);
    assertNull(node2._callback);
  }

  @Test
  public void saturateInvokers() {
    s_logger.info("saturateInvokers");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    final JobInvoker[] jobInvokers = new JobInvoker[3];
    for (int i = 0; i < jobInvokers.length; i++) {
      jobDispatcher.registerJobInvoker(new AbstractJobInvoker("" + (i + 1)) {

        private final Random rnd = new Random();
        private boolean _busy;
        private JobInvokerRegister _callback;

        @Override
        public boolean invoke(final CalculationJob job, final JobInvocationReceiver receiver) {
          final JobInvoker instance = this;
          synchronized (instance) {
            if (_busy) {
              return false;
            }
            _executorService.execute(new Runnable() {
              @Override
              public void run() {
                try {
                  Thread.sleep(rnd.nextInt(50));
                } catch (InterruptedException e) {
                  s_logger.warn("invoker {} interrupted", getInvokerId ());
                }
                s_logger.debug("invoker {} completed job {}", getInvokerId (), job.getSpecification());
                receiver.jobCompleted(createTestJobResult(job.getSpecification(), 0L, instance.toString()));
                synchronized (instance) {
                  _busy = false;
                  if (_callback != null) {
                    s_logger.debug("re-registering invoker {} with dispatcher", getInvokerId ());
                    final JobInvokerRegister callback = _callback;
                    _callback = null;
                    callback.registerJobInvoker(instance);
                  } else {
                    s_logger.debug("invoker {} completed job without notify", getInvokerId ());
                  }
                }
              }
            });
            _busy = true;
            return true;
          }
        }

        @Override
        public boolean notifyWhenAvailable(final JobInvokerRegister callback) {
          synchronized (this) {
            if (_busy) {
              assertNull(_callback);
              s_logger.debug("invoker {} busy - storing callback", getInvokerId ());
              _callback = callback;
              return false;
            } else {
              s_logger.debug("invoker {} ready - immediate callback", getInvokerId ());
              return true;
            }
          }
        }

      });
    }
    final CalculationJob[] jobs = new CalculationJob[100];
    final TestJobResultReceiver[] resultReceivers = new TestJobResultReceiver[jobs.length];
    s_logger.debug("Dispatching {} jobs to {} nodes", jobs.length, jobInvokers.length);
    for (int i = 0; i < jobs.length; i++) {
      jobDispatcher.dispatchJob(jobs[i] = createTestJob(), resultReceivers[i] = new TestJobResultReceiver());
    }
    s_logger.debug("Jobs dispatched");
    for (int i = 0; i < jobs.length; i++) {
      s_logger.debug("Waiting for result {}", i);
      final CalculationJobResult result = resultReceivers[i].waitForResult(TIMEOUT * 2);
      assertNotNull(result);
      assertEquals(jobs[i].getSpecification(), result.getSpecification());
    }
    s_logger.debug("All jobs completed");
  }

  private class FailingJobInvoker extends AbstractJobInvoker {

    private int _failureCount;
   
    public FailingJobInvoker () {
      super ("Failing");
    }

    @Override
    public boolean invoke(final CalculationJob job, final JobInvocationReceiver receiver) {
      _executorService.execute(new Runnable() {
        @Override
        public void run() {
          s_logger.debug("Failing job {}", job.getSpecification());
          _failureCount++;
          receiver.jobFailed(FailingJobInvoker.this, "Fail", null);
        }
      });
      return true;
    }

    @Override
    public boolean notifyWhenAvailable(final JobInvokerRegister callback) {
      // shouldn't get called
      Assert.fail();
      return true;
    }

  }

  @Test
  public void testJobRetry_failure() {
    s_logger.info("testJobRetry_failure");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    final TestJobResultReceiver result = new TestJobResultReceiver();
    final FailingJobInvoker failingInvoker = new FailingJobInvoker();
    jobDispatcher.registerJobInvoker(failingInvoker);
    final CalculationJob job = createTestJob();
    jobDispatcher.dispatchJob(job, result);
    CalculationJobResult jobResult = result.waitForResult(TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(2, failingInvoker._failureCount); // once failed twice at one node, job is aborted
    assertEquals(JobDispatcher.DEFAULT_JOB_FAILURE_NODE_ID, jobResult.getComputeNodeId());
  }

  @Test
  public void testJobRetry_success() {
    s_logger.info("testJobRetry_sucess");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    final TestJobResultReceiver result = new TestJobResultReceiver();
    final FailingJobInvoker failingInvoker = new FailingJobInvoker();
    final TestJobInvoker workingInvoker = new TestJobInvoker("Test");
    jobDispatcher.registerJobInvoker(failingInvoker);
    jobDispatcher.registerJobInvoker(workingInvoker);
    final CalculationJob job = createTestJob();
    jobDispatcher.dispatchJob(job, result);
    CalculationJobResult jobResult = result.waitForResult(TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(1, failingInvoker._failureCount); // fail once at this node, then retried on another
    assertEquals("Test", jobResult.getComputeNodeId());
    assertEquals(job.getSpecification(), jobResult.getSpecification());
  }

  private class BlockingJobInvoker extends AbstractJobInvoker {

    private final long _waitFor;
    private AtomicInteger _isAlive;
    private boolean _cancelled;

    private BlockingJobInvoker(final long waitFor) {
      super ("blocking");
      _waitFor = waitFor;
    }

    @Override
    public Collection<Capability> getCapabilities() {
      return Collections.emptySet();
    }

    @Override
    public boolean invoke(final CalculationJob job, final JobInvocationReceiver receiver) {
      _executorService.execute(new Runnable() {
        @Override
        public void run() {
          try {
            Thread.sleep(_waitFor);
          } catch (InterruptedException e) {
          }
          receiver.jobCompleted(createTestJobResult(job.getSpecification(), 0, getInvokerId ()));
        }
      });
      return true;
    }
   
    @Override
    public boolean isAlive (final Collection<CalculationJobSpecification> jobs) {
      if (_isAlive != null) {
        _isAlive.incrementAndGet ();
        return true;
      } else {
        return false;
      }
    }

    @Override
    public void cancel(final Collection<CalculationJobSpecification> jobs) {
      _cancelled = true;
    }

    public boolean isCancelled() {
      return _cancelled;
    }

    @Override
    public boolean notifyWhenAvailable(JobInvokerRegister callback) {
      // Shouldn't get called
      Assert.fail ();
      return false;
    }

  }

  @Test(invocationCount = 5, successPercentage = 19)
  public void testJobTimeoutFailure() {
    s_logger.info("testJobTimeoutFailure");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    jobDispatcher.setMaxJobExecutionTime(TIMEOUT);
    jobDispatcher.setMaxJobAttempts(1);
    final TestJobResultReceiver result = new TestJobResultReceiver();
    jobDispatcher.dispatchJob(createTestJob(), result);
    assertNull(result.getResult());
    final BlockingJobInvoker blockingInvoker = new BlockingJobInvoker(2 * TIMEOUT);
    jobDispatcher.registerJobInvoker(blockingInvoker);
    CalculationJobResult jobResult = result.waitForResult(2 * TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(jobDispatcher.getJobFailureNodeId(), jobResult.getComputeNodeId());
  }
 
  @Test(invocationCount = 5, successPercentage = 19)
  public void testJobTimeoutSuccess() {
    s_logger.info("testJobTimeoutSuccess");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    jobDispatcher.setMaxJobExecutionTime(3 * TIMEOUT);
    jobDispatcher.setMaxJobAttempts(1);
    final TestJobResultReceiver result = new TestJobResultReceiver();
    jobDispatcher.dispatchJob(createTestJob(), result);
    assertNull(result.getResult());
    final BlockingJobInvoker blockingInvoker = new BlockingJobInvoker(TIMEOUT);
    jobDispatcher.registerJobInvoker(blockingInvoker);
    CalculationJobResult jobResult = result.waitForResult(2 * TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(blockingInvoker.getInvokerId (), jobResult.getComputeNodeId());
  }

  @Test(invocationCount = 5, successPercentage = 19)
  public void testJobTimeoutQuerySuccess () {
    s_logger.info("testJobTimeoutQuerySuccess");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    jobDispatcher.setMaxJobExecutionTime(4 * TIMEOUT);
    jobDispatcher.setMaxJobExecutionTimeQuery(TIMEOUT);
    jobDispatcher.setMaxJobAttempts(1);
    final TestJobResultReceiver result = new TestJobResultReceiver();
    jobDispatcher.dispatchJob(createTestJob(), result);
    assertNull(result.getResult());
    final BlockingJobInvoker blockingInvoker = new BlockingJobInvoker(2 * TIMEOUT);
    blockingInvoker._isAlive = new AtomicInteger ();
    jobDispatcher.registerJobInvoker(blockingInvoker);
    CalculationJobResult jobResult = result.waitForResult(3 * TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(blockingInvoker.getInvokerId (), jobResult.getComputeNodeId());
    assertTrue (blockingInvoker._isAlive.get () > 0);
  }

  @Test(invocationCount = 5, successPercentage = 19)
  public void testJobTimeoutQueryFailure () {
    s_logger.info("testJobTimeoutQueryFailure");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    jobDispatcher.setMaxJobExecutionTime(3 * TIMEOUT);
    jobDispatcher.setMaxJobExecutionTimeQuery(TIMEOUT);
    jobDispatcher.setMaxJobAttempts(1);
    final TestJobResultReceiver result = new TestJobResultReceiver();
    jobDispatcher.dispatchJob(createTestJob(), result);
    assertNull(result.getResult());
    final BlockingJobInvoker blockingInvoker = new BlockingJobInvoker(2 * TIMEOUT);
    jobDispatcher.registerJobInvoker(blockingInvoker);
    CalculationJobResult jobResult = result.waitForResult(3 * TIMEOUT);
    assertNotNull(jobResult);
    assertEquals(jobDispatcher.getJobFailureNodeId(), jobResult.getComputeNodeId());
  }
 
  @Test(invocationCount = 5, successPercentage = 19)
  public void testJobCancel() {
    s_logger.info("testJobCancel");
    final JobDispatcher jobDispatcher = new JobDispatcher();
    jobDispatcher.setMaxJobExecutionTime(2 * TIMEOUT);
    jobDispatcher.setMaxJobAttempts(1);
    final TestJobResultReceiver result = new TestJobResultReceiver();
    Cancelable job = jobDispatcher.dispatchJob(createTestJob(), result);
    assertNotNull(job);
    assertNull(result.getResult());
    final BlockingJobInvoker blockingInvoker = new BlockingJobInvoker(TIMEOUT);
    jobDispatcher.registerJobInvoker(blockingInvoker);
    assertTrue (job.cancel (false));
    assertTrue (blockingInvoker.isCancelled ());
  }

}
TOP

Related Classes of com.opengamma.engine.calcnode.JobDispatcherTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.