1f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev/*
2f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Copyright (C) 2014 The Android Open Source Project
3f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev *
4f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Licensed under the Apache License, Version 2.0 (the "License");
5f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * you may not use this file except in compliance with the License.
6f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * You may obtain a copy of the License at
7f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev *
8f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev *   http://www.apache.org/licenses/LICENSE-2.0
9f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev *
10f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Unless required by applicable law or agreed to in writing, software
11f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * distributed under the License is distributed on an "AS IS" BASIS,
12f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * See the License for the specific language governing permissions and
14f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * limitations under the License.
15f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev */
16f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
17f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevpackage com.google.android.apps.common.testing.ui.espresso.base;
18f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
19f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport junit.framework.TestCase;
20f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
21f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.Callable;
22f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.CountDownLatch;
23f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.FutureTask;
24f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.LinkedBlockingQueue;
25f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.ThreadPoolExecutor;
26f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.TimeUnit;
27f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevimport java.util.concurrent.atomic.AtomicBoolean;
28f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
29f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev/**
30f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev * Unit test for {@link AsyncTaskPoolMonitor}
31f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev */
32f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelevpublic class AsyncTaskPoolMonitorTest extends TestCase {
33f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
34f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  private final ThreadPoolExecutor testThreadPool = new ThreadPoolExecutor(
35f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      4, 4, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
36f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
37f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  private AsyncTaskPoolMonitor monitor = new AsyncTaskPoolMonitor(testThreadPool);
38f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
39f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  @Override
40f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  public void tearDown() throws Exception {
41f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    testThreadPool.shutdownNow();
42f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    super.tearDown();
43f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  }
44f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
45f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  public void testIsIdle_onEmptyPool() throws Exception {
46f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(monitor.isIdleNow());
47f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final AtomicBoolean isIdle = new AtomicBoolean(false);
48f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    // since we're already idle, this should be ran immedately on our thread.
49f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    monitor.notifyWhenIdle(new Runnable() {
50f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
51f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public void run() {
52f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        isIdle.set(true);
53f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
54f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
55f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(isIdle.get());
56f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  }
57f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
58f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  public void testIsIdle_withRunningTask() throws Exception {
59f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch runLatch = new CountDownLatch(1);
60f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    testThreadPool.submit(new Runnable() {
61f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
62f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public void run() {
63f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        runLatch.countDown();
64f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        try {
65f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev          Thread.sleep(50000);
66f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        } catch (InterruptedException ie) {
67f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev          throw new RuntimeException(ie);
68f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        }
69f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
70f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
71f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(runLatch.await(1, TimeUnit.SECONDS));
72f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertFalse(monitor.isIdleNow());
73f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
74f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final AtomicBoolean isIdle = new AtomicBoolean(false);
75f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    monitor.notifyWhenIdle(new Runnable() {
76f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
77f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public void run() {
78f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        isIdle.set(true);
79f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
80f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
81f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    // runnable shouldn't be run ever..
82f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertFalse(isIdle.get());
83f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  }
84f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
85f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
86f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  public void testIdleNotificationAndRestart() throws Exception {
87f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
88f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    FutureTask<Thread> workerThreadFetchTask = new FutureTask<Thread>(new Callable<Thread>() {
89f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
90f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public Thread call() {
91f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        return Thread.currentThread();
92f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
93f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
94f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    testThreadPool.submit(workerThreadFetchTask);
95f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
96f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    Thread workerThread = workerThreadFetchTask.get();
97f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
98f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch runLatch = new CountDownLatch(1);
99f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch exitLatch = new CountDownLatch(1);
100f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
101f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    testThreadPool.submit(new Runnable() {
102f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
103f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public void run() {
104f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        runLatch.countDown();
105f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        try {
106f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev          exitLatch.await();
107f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        } catch (InterruptedException ie) {
108f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev          throw new RuntimeException(ie);
109f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        }
110f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
111f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
112f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
113f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(runLatch.await(1, TimeUnit.SECONDS));
114f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch notificationLatch = new CountDownLatch(1);
115f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    monitor.notifyWhenIdle(new Runnable() {
116f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
117f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public void run() {
118f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        notificationLatch.countDown();
119f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
120f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
121f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    // give some time for the idle detection threads to spin up.
122f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    Thread.sleep(2000);
123f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    // interrupt one of them
124f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    workerThread.interrupt();
125f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    Thread.sleep(1000);
126f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    // unblock the dummy work item.
127f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    exitLatch.countDown();
128f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(notificationLatch.await(1, TimeUnit.SECONDS));
129f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(monitor.isIdleNow());
130f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  }
131f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
132f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  public void testIdleNotification_extraWork() throws Exception {
133f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch firstRunLatch = new CountDownLatch(1);
134f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch firstExitLatch = new CountDownLatch(1);
135f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
136f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    testThreadPool.submit(new Runnable() {
137f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
138f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public void run() {
139f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        firstRunLatch.countDown();
140f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        try {
141f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev          firstExitLatch.await();
142f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        } catch (InterruptedException ie) {
143f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev          throw new RuntimeException(ie);
144f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        }
145f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
146f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
147f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
148f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(firstRunLatch.await(1, TimeUnit.SECONDS));
149f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
150f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch notificationLatch = new CountDownLatch(1);
151f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    monitor.notifyWhenIdle(new Runnable() {
152f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
153f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public void run() {
154f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        notificationLatch.countDown();
155f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
156f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
157f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
158f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch secondRunLatch = new CountDownLatch(1);
159f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    final CountDownLatch secondExitLatch = new CountDownLatch(1);
160f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    testThreadPool.submit(new Runnable() {
161f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      @Override
162f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      public void run() {
163f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        secondRunLatch.countDown();
164f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        try {
165f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev          secondExitLatch.await();
166f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        } catch (InterruptedException ie) {
167f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev          throw new RuntimeException(ie);
168f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev        }
169f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev      }
170f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    });
171f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev
172f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertFalse(notificationLatch.await(10, TimeUnit.MILLISECONDS));
173f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    firstExitLatch.countDown();
174f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertFalse(notificationLatch.await(500, TimeUnit.MILLISECONDS));
175f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    secondExitLatch.countDown();
176f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(notificationLatch.await(1, TimeUnit.SECONDS));
177f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev    assertTrue(monitor.isIdleNow());
178f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev  }
179f69eb9ac2856f470cb79f57141f711ed3ceed99dNick Korostelev}
180