1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.arch.core.executor.testing; 18 19 import static org.hamcrest.CoreMatchers.is; 20 import static org.hamcrest.MatcherAssert.assertThat; 21 22 import androidx.arch.core.executor.ArchTaskExecutor; 23 import androidx.test.ext.junit.runners.AndroidJUnit4; 24 import androidx.test.filters.LargeTest; 25 26 import org.junit.Rule; 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.concurrent.CountDownLatch; 33 import java.util.concurrent.Semaphore; 34 import java.util.concurrent.TimeUnit; 35 import java.util.concurrent.TimeoutException; 36 37 @RunWith(AndroidJUnit4.class) 38 @LargeTest 39 public class CountingTaskExecutorRuleTest { 40 private final Semaphore mOnIdleCount = new Semaphore(0); 41 42 @Rule 43 public CountingTaskExecutorRule mRule = new CountingTaskExecutorRule() { 44 @Override 45 protected void onIdle() { 46 super.onIdle(); 47 mOnIdleCount.release(1); 48 } 49 }; 50 51 @Test initialIdle()52 public void initialIdle() { 53 assertThat(mRule.isIdle(), is(true)); 54 } 55 56 @Test busyIO()57 public void busyIO() throws InterruptedException { 58 LatchRunnable task = runOnIO(); 59 singleTaskTest(task); 60 } 61 62 @Test busyMain()63 public void busyMain() throws InterruptedException { 64 LatchRunnable task = runOnMain(); 65 singleTaskTest(task); 66 } 67 68 @Test multipleTasks()69 public void multipleTasks() throws InterruptedException { 70 List<LatchRunnable> latches = new ArrayList<>(10); 71 for (int i = 0; i < 5; i++) { 72 latches.add(runOnIO()); 73 latches.add(runOnMain()); 74 } 75 assertNotIdle(); 76 for (int i = 0; i < 9; i++) { 77 latches.get(i).start(); 78 } 79 for (int i = 0; i < 9; i++) { 80 latches.get(i).await(); 81 } 82 assertNotIdle(); 83 84 LatchRunnable another = runOnIO(); 85 latches.get(9).startAndFinish(); 86 assertNotIdle(); 87 88 another.startAndFinish(); 89 assertBecomeIdle(); 90 91 LatchRunnable oneMore = runOnMain(); 92 93 assertNotIdle(); 94 95 oneMore.startAndFinish(); 96 assertBecomeIdle(); 97 } 98 assertNotIdle()99 private void assertNotIdle() throws InterruptedException { 100 assertThat(mOnIdleCount.tryAcquire(300, TimeUnit.MILLISECONDS), is(false)); 101 assertThat(mRule.isIdle(), is(false)); 102 } 103 assertBecomeIdle()104 private void assertBecomeIdle() throws InterruptedException { 105 assertThat(mOnIdleCount.tryAcquire(1, TimeUnit.SECONDS), is(true)); 106 assertThat(mRule.isIdle(), is(true)); 107 } 108 singleTaskTest(LatchRunnable task)109 private void singleTaskTest(LatchRunnable task) 110 throws InterruptedException { 111 assertNotIdle(); 112 task.startAndFinish(); 113 assertBecomeIdle(); 114 } 115 runOnIO()116 private LatchRunnable runOnIO() { 117 LatchRunnable latchRunnable = new LatchRunnable(); 118 ArchTaskExecutor.getInstance().executeOnDiskIO(latchRunnable); 119 return latchRunnable; 120 } 121 runOnMain()122 private LatchRunnable runOnMain() { 123 LatchRunnable latchRunnable = new LatchRunnable(); 124 ArchTaskExecutor.getInstance().executeOnMainThread(latchRunnable); 125 return latchRunnable; 126 } 127 128 @Test drainFailure()129 public void drainFailure() throws InterruptedException { 130 runOnIO(); 131 try { 132 mRule.drainTasks(300, TimeUnit.MILLISECONDS); 133 throw new AssertionError("drain should fail"); 134 } catch (TimeoutException ignored) { 135 } 136 } 137 138 @Test drainSuccess()139 public void drainSuccess() throws TimeoutException, InterruptedException { 140 final LatchRunnable task = runOnIO(); 141 new Thread(new Runnable() { 142 @Override 143 public void run() { 144 try { 145 Thread.sleep(300); 146 } catch (InterruptedException ignored) { 147 } 148 task.start(); 149 } 150 }).start(); 151 mRule.drainTasks(1, TimeUnit.SECONDS); 152 } 153 154 private static class LatchRunnable implements Runnable { 155 private final CountDownLatch mStart = new CountDownLatch(1); 156 private final CountDownLatch mEnd = new CountDownLatch(1); 157 158 @Override run()159 public void run() { 160 try { 161 mStart.await(10, TimeUnit.SECONDS); 162 mEnd.countDown(); 163 } catch (InterruptedException e) { 164 throw new AssertionError(e); 165 } 166 } 167 await()168 void await() throws InterruptedException { 169 mEnd.await(10, TimeUnit.SECONDS); 170 } 171 start()172 void start() { 173 mStart.countDown(); 174 } 175 startAndFinish()176 private void startAndFinish() throws InterruptedException { 177 start(); 178 await(); 179 } 180 } 181 } 182