11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2007 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License");
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License.
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS,
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License.
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.util.concurrent;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.testing.NullPointerTester;
220888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.common.util.concurrent.ExecutionList;
230888a09821a98ac0680fad765217302858e70fa4Paul Duffin
240888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport junit.framework.TestCase;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.CountDownLatch;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Executor;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.Executors;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.TimeUnit;
307dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.atomic.AtomicInteger;
317dd252788645e940eada959bdde927426e2531c9Paul Duffin
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unit tests for {@link ExecutionList}.
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Nishant Thakkar
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Sven Mawson
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class ExecutionListTest extends TestCase {
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
407dd252788645e940eada959bdde927426e2531c9Paul Duffin  private final ExecutionList list = new ExecutionList();
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRunOnPopulatedList() throws Exception {
437dd252788645e940eada959bdde927426e2531c9Paul Duffin    Executor exec = Executors.newCachedThreadPool();
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountDownLatch countDownLatch = new CountDownLatch(3);
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    list.add(new MockRunnable(countDownLatch), exec);
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    list.add(new MockRunnable(countDownLatch), exec);
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    list.add(new MockRunnable(countDownLatch), exec);
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(countDownLatch.getCount(), 3L);
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    list.execute();
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // Verify that all of the runnables execute in a reasonable amount of time.
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(countDownLatch.await(1L, TimeUnit.SECONDS));
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
567dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testExecute_idempotent() {
577dd252788645e940eada959bdde927426e2531c9Paul Duffin    final AtomicInteger runCalled = new AtomicInteger();
587dd252788645e940eada959bdde927426e2531c9Paul Duffin    list.add(new Runnable() {
597dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override public void run() {
607dd252788645e940eada959bdde927426e2531c9Paul Duffin        runCalled.getAndIncrement();
617dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
627dd252788645e940eada959bdde927426e2531c9Paul Duffin    }, MoreExecutors.sameThreadExecutor());
637dd252788645e940eada959bdde927426e2531c9Paul Duffin    list.execute();
647dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(1, runCalled.get());
657dd252788645e940eada959bdde927426e2531c9Paul Duffin    list.execute();
667dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(1, runCalled.get());
677dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
687dd252788645e940eada959bdde927426e2531c9Paul Duffin
697dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testExecute_idempotentConcurrently() throws InterruptedException {
707dd252788645e940eada959bdde927426e2531c9Paul Duffin    final CountDownLatch okayToRun = new CountDownLatch(1);
717dd252788645e940eada959bdde927426e2531c9Paul Duffin    final AtomicInteger runCalled = new AtomicInteger();
727dd252788645e940eada959bdde927426e2531c9Paul Duffin    list.add(new Runnable() {
737dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override public void run() {
747dd252788645e940eada959bdde927426e2531c9Paul Duffin        try {
757dd252788645e940eada959bdde927426e2531c9Paul Duffin          okayToRun.await();
767dd252788645e940eada959bdde927426e2531c9Paul Duffin        } catch (InterruptedException e) {
777dd252788645e940eada959bdde927426e2531c9Paul Duffin          Thread.currentThread().interrupt();
787dd252788645e940eada959bdde927426e2531c9Paul Duffin          throw new RuntimeException(e);
797dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
807dd252788645e940eada959bdde927426e2531c9Paul Duffin        runCalled.getAndIncrement();
817dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
827dd252788645e940eada959bdde927426e2531c9Paul Duffin    }, MoreExecutors.sameThreadExecutor());
837dd252788645e940eada959bdde927426e2531c9Paul Duffin    Runnable execute = new Runnable() {
847dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override public void run() {
857dd252788645e940eada959bdde927426e2531c9Paul Duffin        list.execute();
867dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
877dd252788645e940eada959bdde927426e2531c9Paul Duffin    };
887dd252788645e940eada959bdde927426e2531c9Paul Duffin    Thread thread1 = new Thread(execute);
897dd252788645e940eada959bdde927426e2531c9Paul Duffin    Thread thread2 = new Thread(execute);
907dd252788645e940eada959bdde927426e2531c9Paul Duffin    thread1.start();
917dd252788645e940eada959bdde927426e2531c9Paul Duffin    thread2.start();
927dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(0, runCalled.get());
937dd252788645e940eada959bdde927426e2531c9Paul Duffin    okayToRun.countDown();
947dd252788645e940eada959bdde927426e2531c9Paul Duffin    thread1.join();
957dd252788645e940eada959bdde927426e2531c9Paul Duffin    thread2.join();
967dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(1, runCalled.get());
977dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
987dd252788645e940eada959bdde927426e2531c9Paul Duffin
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testAddAfterRun() throws Exception {
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // Run the previous test
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    testRunOnPopulatedList();
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    // If it passed, then verify an Add will be executed without calling run
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountDownLatch countDownLatch = new CountDownLatch(1);
1057dd252788645e940eada959bdde927426e2531c9Paul Duffin    list.add(new MockRunnable(countDownLatch),  Executors.newCachedThreadPool());
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(countDownLatch.await(1L, TimeUnit.SECONDS));
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1090888a09821a98ac0680fad765217302858e70fa4Paul Duffin  public void testOrdering() throws Exception {
1100888a09821a98ac0680fad765217302858e70fa4Paul Duffin    final AtomicInteger integer = new AtomicInteger();
1110888a09821a98ac0680fad765217302858e70fa4Paul Duffin    for (int i = 0; i < 10; i++) {
1120888a09821a98ac0680fad765217302858e70fa4Paul Duffin      final int expectedCount = i;
1130888a09821a98ac0680fad765217302858e70fa4Paul Duffin      list.add(
1140888a09821a98ac0680fad765217302858e70fa4Paul Duffin          new Runnable() {
1150888a09821a98ac0680fad765217302858e70fa4Paul Duffin            @Override public void run() {
1160888a09821a98ac0680fad765217302858e70fa4Paul Duffin              integer.compareAndSet(expectedCount, expectedCount + 1);
1170888a09821a98ac0680fad765217302858e70fa4Paul Duffin            }
1180888a09821a98ac0680fad765217302858e70fa4Paul Duffin          },
1190888a09821a98ac0680fad765217302858e70fa4Paul Duffin          MoreExecutors.sameThreadExecutor());
1200888a09821a98ac0680fad765217302858e70fa4Paul Duffin    }
1210888a09821a98ac0680fad765217302858e70fa4Paul Duffin    list.execute();
1220888a09821a98ac0680fad765217302858e70fa4Paul Duffin    assertEquals(10, integer.get());
1230888a09821a98ac0680fad765217302858e70fa4Paul Duffin  }
1240888a09821a98ac0680fad765217302858e70fa4Paul Duffin
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private class MockRunnable implements Runnable {
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    CountDownLatch countDownLatch;
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    MockRunnable(CountDownLatch countDownLatch) {
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.countDownLatch = countDownLatch;
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1327dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public void run() {
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      countDownLatch.countDown();
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testExceptionsCaught() {
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    list.add(THROWING_RUNNABLE, sameThreadExecutor());
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    list.execute();
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    list.add(THROWING_RUNNABLE, sameThreadExecutor());
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1437dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testNulls() {
1447dd252788645e940eada959bdde927426e2531c9Paul Duffin    new NullPointerTester().testAllPublicInstanceMethods(new ExecutionList());
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final Runnable THROWING_RUNNABLE = new Runnable() {
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public void run() {
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new RuntimeException();
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  };
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
153