Package com.facebook.concurrency

Source Code of com.facebook.concurrency.TestUnstoppableExecutorService

/*
* Copyright (C) 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.concurrency;

import com.facebook.logging.Logger;
import com.facebook.logging.LoggerImpl;
import com.facebook.testing.Function;
import com.facebook.testing.MockExecutor;
import com.facebook.testing.TestUtils;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class TestUnstoppableExecutorService {
  private static final Logger LOG = LoggerImpl.getLogger(TestUnstoppableExecutorService.class);
  private static final Runnable NO_OP = new Runnable() {
    @Override
    public void run() {
    }
  };

  private ExecutorService executor;
  private MockExecutor mockExecutor;

  @BeforeMethod(alwaysRun = true)
  public void setUp() throws Exception {
    mockExecutor = new MockExecutor();
    executor = new UnstoppableExecutorService(mockExecutor);
  }

  @Test(groups = "fast")
  public void testShutdown() throws Exception {
    executor.shutdown();

    Assert.assertFalse(
      mockExecutor.isShutdown(), "mockExecutor should not be shutdown"
    );
    Assert.assertTrue(
      executor.isShutdown(), "executor should be shut down"
    );
  }

  @Test(groups = "fast")
  public void testShutdownNow() throws Exception {
    Assert.assertTrue(
      executor.shutdownNow().isEmpty(),
      "shutdownNow should return empty list"
    );

    Assert.assertFalse(
      mockExecutor.isShutdown(), "mockExecutor should not be shutdown"
    );
    Assert.assertTrue(
      executor.isShutdown(), "executor should be shut down"
    );
  }

  @Test(groups = "fast")
  public void testAwaitTermination() throws Exception {
    Assert.assertFalse(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor is terminated"
    );

    executor.shutdown();
    mockExecutor.drain();

    Assert.assertTrue(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor should be terminated"
    );

    Assert.assertTrue(
      executor.isTerminated(),
      "executor should be terminated"
    );
  }

  @Test(groups = "fast")
  public void testAwaitTerminationForExecute() throws Exception {
    Assert.assertFalse(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor is terminated"
    );

    AtomicInteger completed = TestUtils.countCompletedRunnables(
      10,
      new Function<Runnable>() {
        @Override
        public void execute(Runnable argument) {
          executor.execute(argument);
        }
      }
    );

    executor.shutdown();
    mockExecutor.drain();

    Assert.assertTrue(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor should be terminated"
    );

    Assert.assertEquals(completed.get(), 10);

    Assert.assertTrue(
      executor.isTerminated(),
      "executor should be terminated"
    );
  }

  @Test(groups = "fast")
  public void testAwaitTerminationForSubmitRunnable1() throws Exception {
    Assert.assertFalse(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor is terminated"
    );

    AtomicInteger completed = TestUtils.countCompletedRunnables(
      10,
      new Function<Runnable>() {
        @Override
        public void execute(Runnable argument) {
          executor.submit(argument);
        }
      }
    );

    executor.shutdown();
    mockExecutor.drain();

    Assert.assertTrue(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor should be terminated"
    );

    Assert.assertEquals(completed.get(), 10);

    Assert.assertTrue(
      executor.isTerminated(),
      "executor should be terminated"
    );
  }

  @Test(groups = "fast")
  public void testAwaitTerminationForSubmitRunnable2() throws Exception {
    Assert.assertFalse(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor is terminated"
    );

    AtomicInteger completed = TestUtils.countCompletedRunnables(
      10,
      new Function<Runnable>() {
        @Override
        public void execute(Runnable argument) {
          executor.submit(argument, new Object());
        }
      }
    );

    executor.shutdown();
    mockExecutor.drain();

    Assert.assertTrue(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor should be terminated"
    );

    Assert.assertEquals(completed.get(), 10);

    Assert.assertTrue(
      executor.isTerminated(),
      "executor should be terminated"
    );
  }

  @Test(groups = "fast")
  public void testAwaitTerminationForSubmitCallable() throws Exception {
    Assert.assertFalse(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor is terminated"
    );

    AtomicInteger completed = TestUtils.<Void>countCompletedCallables(
      10,
      new Function<Callable<Void>>() {
        @Override
        public void execute(Callable<Void> argument) {
          executor.submit(argument);
        }
      }
    );

    executor.shutdown();
    mockExecutor.drain();

    Assert.assertEquals(completed.get(), 10);
    Assert.assertTrue(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor should be terminated"
    );


    Assert.assertTrue(
      executor.isTerminated(),
      "executor should be terminated"
    );
  }

  @Test(groups = "fast")
  public void testTaskCompletesThenCancel() throws Exception {
    final AtomicReference<Future> future = new AtomicReference<Future>();
    AtomicInteger completed = TestUtils.<Void>countCompletedCallables(
      10,
      new Function<Callable<Void>>() {
        @Override
        public void execute(Callable<Void> argument) {
          future.compareAndSet(null, executor.submit(argument));
        }
      }
    );

    executor.shutdown();
    mockExecutor.drain();

    // this makes sure if we cancel an already completed task, it won't
    // affect the awaitTermination check
    future.get().cancel(false);

    Assert.assertEquals(completed.get(), 10);
    Assert.assertTrue(
      executor.awaitTermination(1, TimeUnit.NANOSECONDS),
      "executor should be terminated"
    );
  }

  @Test(groups = "fast")
  public void testSubmission() throws Exception {
    executor.execute(NO_OP);
    Assert.assertEquals(mockExecutor.getNumPendingTasks(), 1);
    executor.submit(NO_OP);
    Assert.assertEquals(mockExecutor.getNumPendingTasks(), 2);
    executor.submit(NO_OP);
    Assert.assertEquals(mockExecutor.getNumPendingTasks(), 3);
    executor.submit(NO_OP, new Object());
    Assert.assertEquals(mockExecutor.getNumPendingTasks(), 4);
  }

  @Test(groups = "fast")
  public void testRejectedAfterShutdown() throws Exception {
    executor.shutdown();

    try {
      executor.submit(NO_OP);
      Assert.fail("expected exception");
    } catch (RejectedExecutionException e) {
      // success
      Assert.assertEquals(executor.isShutdown(), true);
      Assert.assertEquals(mockExecutor.isShutdown(), false);
    }
  }

  @Test(groups = "fast")
  public void testRate() throws Exception {
    int numTasks = 1000000;
    // use enough threads to induce lock contention
    int numThreads = 6;
    final AtomicInteger count = new AtomicInteger(0);
    ExecutorService realExecutor = Executors.newFixedThreadPool(numThreads);
    executor = new UnstoppableExecutorService(realExecutor);
    LatchTask blockedNoOp = new LatchTask(
      new Runnable() {
        @Override
        public void run() {
          count.incrementAndGet();
        }
      }
    );

    LOG.info("generating %d tasks", numTasks);

    for (int i = 0; i < numTasks; i++) {
      executor.submit(blockedNoOp);
    }

    executor.shutdown();
    LOG.info("starting tasks");
    long start = System.nanoTime();

    blockedNoOp.proceed();
    boolean terminated = executor.awaitTermination(5, TimeUnit.MINUTES);
    long end = System.nanoTime();

    Assert.assertTrue(terminated);
    Assert.assertEquals(count.get(), numTasks);

    double timeTakenMillis = (end - start) / (double) 1000000;
    // rate is primarily affected by rate that executor and get tasks to queues, ie pull from
    // the queue
    LOG.info(
      "%d tasks with %d threads took %f ms", numTasks, numThreads, timeTakenMillis
    );

    realExecutor.shutdown();
  }
}
TOP

Related Classes of com.facebook.concurrency.TestUnstoppableExecutorService

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.