Package com.nokia.dempsy.executor

Source Code of com.nokia.dempsy.executor.TestDempsyExecutor$Task

package com.nokia.dempsy.executor;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.nokia.dempsy.TestUtils;
import com.nokia.dempsy.executor.DempsyExecutor.Rejectable;

public class TestDempsyExecutor
{
   private static long baseTimeoutMillis = 20000;

   DefaultDempsyExecutor executor = null;
   static AtomicLong numRejected = new AtomicLong(0);
  
   @Before
   public void initExecutor()
   {
      numRejected.set(0);
      executor = new DefaultDempsyExecutor();
   }
  
   @After
   public void shutdownExecutor()
   {
      if (executor != null)
         executor.shutdown();
      executor = null;
   }
  
   public class Task implements Rejectable<Boolean>
   {
      final AtomicBoolean latch;
      final AtomicLong count;
     
      Task(AtomicBoolean latch, AtomicLong count) { this.latch = latch; this.count = count; }
     
      @Override
      public Boolean call() throws Exception
      {
         if (latch != null)
         {
            synchronized(latch)
            {
               while (!latch.get())
                  try { latch.wait(); } catch (InterruptedException ie) {}
            }
         }
        
         if (count != null) count.incrementAndGet();
         return true;
      }

      @Override
      public void rejected()
      {
         // we don't need to do anything as the Future will have "null" if this gets called
         numRejected.incrementAndGet();
      }
     
   }
  
   @Test
   public void testSimple() throws Throwable
   {
      executor.start();
     
      Task task = new Task(null,null);
      Future<Boolean> result = executor.submit(task);
     
      assertTrue(result.get().booleanValue());
     
      result = executor.submitLimited(task);
      assertTrue(result.get().booleanValue());
   }
  
   @Test
   public void testLimited() throws Throwable
   {
      executor.start();
     
      final AtomicBoolean latch = new AtomicBoolean(false);
      try
      {
         int numThreads = executor.getNumThreads();

         Task task = new Task(latch,null);

         // submit a limited task for every thread.
         for (int i = 0; i < numThreads; i++)
            executor.submitLimited(task);

         // submit twice as many.
         for (int i = 0; i < numThreads; i++)
            executor.submitLimited(task);

         // none should be rejected yet.
         assertEquals(0,numRejected.get());

         // now submit until they start getting rejected.
         TestUtils.poll(baseTimeoutMillis, task, new TestUtils.Condition<Task>()
         {  @Override
            public boolean conditionMet(Task task) throws Throwable
            {
               executor.submitLimited(task); executor.submitLimited(task);executor.submitLimited(task);
               synchronized(task.latch) { task.latch.set(true); task.latch.notify(); }
               return numRejected.get() > 0;
            }
         });
      }
      finally
      {
         synchronized(latch) { latch.set(true); latch.notifyAll(); }
      }
   }
  
   @Test
   public void testExactLimited() throws Throwable
   {
      executor.start();
     
      final int maxQueued = executor.getMaxNumberOfQueuedLimitedTasks();
     
      final AtomicBoolean latch = new AtomicBoolean(false);
      try
      {
         final int numThreads = executor.getNumThreads();
         final AtomicLong execCount = new AtomicLong(0);

         Task blockingTask = new Task(latch,execCount);
         Task nonblockingTask = new Task(null,execCount);

         // submit a limited task for every thread.
         for (int i = 0; i < numThreads; i++)
            executor.submitLimited(blockingTask);

         // none should be queued
         Thread.sleep(10);
         assertEquals(0,executor.getNumberPending());
        
         // now submit one more
         executor.submitLimited(nonblockingTask);

         // now the pending tasks should go to one.
         assertTrue(TestUtils.poll(baseTimeoutMillis, executor, new TestUtils.Condition<DefaultDempsyExecutor>() {
            @Override public boolean conditionMet(DefaultDempsyExecutor executor) throws Throwable
            {  
               return executor.getNumberPending() == 1 && executor.getNumberLimitedPending() == 1;
            }
         }));

         // and should stay there
         Thread.sleep(100);
         assertEquals(1,executor.getNumberPending());

         // this should also be reflected in the "limited" count.
         assertEquals(1,executor.getNumberLimitedPending());

         // now I should be able to submit a non-limited and it should wait.
         executor.submit(new Callable<Object>() { @Override public Object call() { return null; } });

         // now the pending tasks should go to two.
         assertTrue(TestUtils.poll(baseTimeoutMillis, executor, new TestUtils.Condition<DefaultDempsyExecutor>() {
            @Override public boolean conditionMet(DefaultDempsyExecutor executor) throws Throwable
            {  
               return executor.getNumberPending() == 2;
            }
         }));

         // and should stay there
         Thread.sleep(100);
         assertEquals(2,executor.getNumberPending());

         // this should NOT be reflected in the "limited" count.
         assertEquals(1,executor.getNumberLimitedPending());

         // now I should be able to overflow it. This should move the number pending right to the max allowed
         for (int i = 1; i < maxQueued; i++)
            executor.submitLimited(nonblockingTask);

         // now the number limited pending should be the maxQueued
         assertTrue(TestUtils.poll(baseTimeoutMillis, executor, new TestUtils.Condition<DefaultDempsyExecutor>() {
            @Override public boolean conditionMet(DefaultDempsyExecutor executor) throws Throwable
            {  
               return executor.getNumberLimitedPending() == maxQueued;
            }
         }));

         // The queue math is conservative and can handle one more before it would actually throw any away.
         // This is because the counter is decremented and then compared 'less than or equal to' with the
         // max. If this test ever fails below this point, please review that this is still the case.
         executor.submitLimited(nonblockingTask);

         // let them all go.
         synchronized(latch) { latch.set(true);  latch.notifyAll(); }
        
         final int totalCountingExecs = numThreads + 1 + (maxQueued - 1) + 1;

         // wait until they all execute
         assertTrue(TestUtils.poll(baseTimeoutMillis, execCount, new TestUtils.Condition<AtomicLong>() {
            @Override public boolean conditionMet(AtomicLong c) { return totalCountingExecs == c.intValue(); }
         }));
        
         // we should have discarded none.
         // now the number limited pending should be the maxQueued
         Thread.sleep(10);
         assertEquals(0,numRejected.intValue());
      }
      finally
      {
         synchronized(latch) { latch.set(true); latch.notifyAll(); }
      }
   }
  

   @Test
   public void testExactLimitedOverflow() throws Throwable
   {
      executor.start();
     
      final int maxQueued = executor.getMaxNumberOfQueuedLimitedTasks();
     
      final AtomicBoolean latch = new AtomicBoolean(false);
      try
      {
         final AtomicLong execCount = new AtomicLong(0);
         int numThreads = executor.getNumThreads();

         Task blockingTask = new Task(latch,execCount);
         Task nonblockingTask = new Task(null,execCount);

         // submit a limited task for every thread.
         for (int i = 0; i < numThreads; i++)
            executor.submitLimited(blockingTask);

         // none should be queued
         assertTrue(TestUtils.poll(baseTimeoutMillis, executor, new TestUtils.Condition<DefaultDempsyExecutor>() {
            @Override public boolean conditionMet(DefaultDempsyExecutor executor) throws Throwable
            {  
               return executor.getNumberPending() == 0;
            }
         }));

         // now submit one more
         executor.submitLimited(nonblockingTask);

         // now the pending tasks should go to one.
         assertTrue(TestUtils.poll(baseTimeoutMillis, executor, new TestUtils.Condition<DefaultDempsyExecutor>() {
            @Override public boolean conditionMet(DefaultDempsyExecutor executor) throws Throwable
            {  
               return executor.getNumberPending() == 1 && executor.getNumberLimitedPending() == 1;
            }
         }));

         // and should stay there
         Thread.sleep(100);
         assertEquals(1,executor.getNumberPending());

         // this should also be reflected in the "limited" count.
         assertEquals(1,executor.getNumberLimitedPending());

         // now I should be able to submit a non-limited and it should wait.
         executor.submit(new Callable<Object>() { @Override public Object call() { return null; } });

         // now the pending tasks should go to one.
         assertTrue(TestUtils.poll(baseTimeoutMillis, executor, new TestUtils.Condition<DefaultDempsyExecutor>() {
            @Override public boolean conditionMet(DefaultDempsyExecutor executor) throws Throwable
            {  
               return executor.getNumberPending() == 2;
            }
         }));

         // and should stay there
         Thread.sleep(100);
         assertEquals(2,executor.getNumberPending());

         // this should NOT be reflected in the "limited" count.
         assertEquals(1,executor.getNumberLimitedPending());

         // now I should be able to overflow it. This should move the number pending right to the max allowed
         for (int i = 1; i < maxQueued; i++)
            executor.submitLimited(nonblockingTask);

         // now the number limited pending should be the maxQueued
         assertTrue(TestUtils.poll(baseTimeoutMillis, executor, new TestUtils.Condition<DefaultDempsyExecutor>() {
            @Override public boolean conditionMet(DefaultDempsyExecutor executor) throws Throwable
            {  
               return executor.getNumberLimitedPending() == maxQueued;
            }
         }));

         // The queue math is conservative and can handle one more before it would actually throw any away.
         // This is because the counter is decremented and then compared 'less than or equal to' with the
         // max. If this test ever fails below this point, please review that this is still the case.
         executor.submitLimited(nonblockingTask);

         // now if I add one more I should see exactly one discard.
         executor.submitLimited(nonblockingTask);

         // let them all go.
         synchronized(latch) { latch.set(true); latch.notifyAll(); }
        
         // The additional one added causes one not to count since it's rejected.
         final int totalCountingExecs = numThreads + 1 + (maxQueued - 1) + 1;
        
         // wait until they all execute
         assertTrue(TestUtils.poll(baseTimeoutMillis, execCount, new TestUtils.Condition<AtomicLong>() {
            @Override public boolean conditionMet(AtomicLong c) { return totalCountingExecs == c.intValue(); }
         }));

         Thread.sleep(10);
         assertEquals(1,numRejected.intValue());

         // and eventually none should be queued
         assertTrue(TestUtils.poll(baseTimeoutMillis, executor, new TestUtils.Condition<DefaultDempsyExecutor>() {
            @Override public boolean conditionMet(DefaultDempsyExecutor executor) { return executor.getNumberPending() == 0; }
         }));
      }
      finally
      {
         synchronized(latch) { latch.set(true); latch.notifyAll(); }
      }
   }
}
TOP

Related Classes of com.nokia.dempsy.executor.TestDempsyExecutor$Task

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.