1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base.task; 6 7 import androidx.annotation.NonNull; 8 import androidx.test.filters.SmallTest; 9 10 import org.hamcrest.CoreMatchers; 11 import org.junit.Rule; 12 import org.junit.Test; 13 import org.junit.rules.ExpectedException; 14 import org.junit.runner.RunWith; 15 16 import org.chromium.base.test.BaseJUnit4ClassRunner; 17 18 import java.util.concurrent.ArrayBlockingQueue; 19 import java.util.concurrent.Executor; 20 import java.util.concurrent.RejectedExecutionException; 21 import java.util.concurrent.ThreadFactory; 22 import java.util.concurrent.TimeUnit; 23 24 /** 25 * Tests for our AsyncTask modifications 26 * 27 * Not a robolectric test because the reflection doesn't work with ShadowAsyncTask. 28 */ 29 @RunWith(BaseJUnit4ClassRunner.class) 30 public class AsyncTaskTest { 31 private static class SpecialChromeAsyncTask extends BackgroundOnlyAsyncTask<Void> { 32 @Override doInBackground()33 protected Void doInBackground() { 34 return null; 35 } 36 } 37 38 @SuppressWarnings("NoAndroidAsyncTaskCheck") 39 private static class SpecialOsAsyncTask extends android.os.AsyncTask<Void, Void, Void> { 40 @Override doInBackground(Void... params)41 protected Void doInBackground(Void... params) { 42 return null; 43 } 44 } 45 46 private static class SpecialRunnable implements Runnable { 47 @Override run()48 public void run() {} 49 } 50 51 private static final int QUEUE_SIZE = 40; 52 53 @Rule public ExpectedException thrown = ExpectedException.none(); 54 55 /** 56 * Test filling the queue with basic Runnables, then add a final AsyncTask to overfill it, and 57 * ensure the Runnable is the one blamed in the exception message. 58 */ 59 @Test 60 @SmallTest testChromeThreadPoolExecutorRunnables()61 public void testChromeThreadPoolExecutorRunnables() { 62 Executor executor = 63 new ChromeThreadPoolExecutor( 64 1, 65 1, 66 1, 67 TimeUnit.SECONDS, 68 new ArrayBlockingQueue<Runnable>(QUEUE_SIZE), 69 new ThreadFactory() { 70 @Override 71 public Thread newThread(@NonNull Runnable r) { 72 return null; 73 } 74 }); 75 for (int i = 0; i < QUEUE_SIZE; i++) { 76 executor.execute(new SpecialRunnable()); 77 } 78 thrown.expect(RejectedExecutionException.class); 79 thrown.expectMessage( 80 CoreMatchers.containsString( 81 "org.chromium.base.task.AsyncTaskTest$SpecialRunnable")); 82 thrown.expectMessage( 83 CoreMatchers.not(CoreMatchers.containsString("SpecialChromeAsyncTask"))); 84 new SpecialChromeAsyncTask().executeOnExecutor(executor); 85 } 86 87 /** 88 * Test filling the queue with Chrome AsyncTasks, then add a final OS AsyncTask to 89 * overfill it and ensure the Chrome AsyncTask is the one blamed in the exception message. 90 */ 91 @Test 92 @SmallTest testChromeThreadPoolExecutorChromeAsyncTask()93 public void testChromeThreadPoolExecutorChromeAsyncTask() { 94 Executor executor = 95 new ChromeThreadPoolExecutor( 96 1, 97 1, 98 1, 99 TimeUnit.SECONDS, 100 new ArrayBlockingQueue<Runnable>(QUEUE_SIZE), 101 new ThreadFactory() { 102 @Override 103 public Thread newThread(@NonNull Runnable r) { 104 return null; 105 } 106 }); 107 for (int i = 0; i < QUEUE_SIZE; i++) { 108 new SpecialChromeAsyncTask().executeOnExecutor(executor); 109 } 110 thrown.expect(RejectedExecutionException.class); 111 thrown.expectMessage( 112 CoreMatchers.containsString( 113 "org.chromium.base.task.AsyncTaskTest$SpecialChromeAsyncTask")); 114 thrown.expectMessage(CoreMatchers.not(CoreMatchers.containsString("SpecialOsAsyncTask"))); 115 new SpecialOsAsyncTask().executeOnExecutor(executor); 116 } 117 118 /** 119 * Test filling the queue with android.os.AsyncTasks, then add a final ChromeAsyncTask to 120 * overfill it and ensure the OsAsyncTask is the one blamed in the exception message. 121 */ 122 @Test 123 @SmallTest testChromeThreadPoolExecutorOsAsyncTask()124 public void testChromeThreadPoolExecutorOsAsyncTask() { 125 Executor executor = 126 new ChromeThreadPoolExecutor( 127 1, 128 1, 129 1, 130 TimeUnit.SECONDS, 131 new ArrayBlockingQueue<Runnable>(QUEUE_SIZE), 132 new ThreadFactory() { 133 @Override 134 public Thread newThread(@NonNull Runnable r) { 135 return null; 136 } 137 }); 138 for (int i = 0; i < QUEUE_SIZE; i++) { 139 new SpecialOsAsyncTask().executeOnExecutor(executor); 140 } 141 thrown.expect(RejectedExecutionException.class); 142 thrown.expectMessage( 143 CoreMatchers.containsString( 144 "org.chromium.base.task.AsyncTaskTest$SpecialOsAsyncTask")); 145 thrown.expectMessage( 146 CoreMatchers.not(CoreMatchers.containsString("SpecialChromeAsyncTask"))); 147 new SpecialChromeAsyncTask().executeOnExecutor(executor); 148 } 149 150 /** 151 * Test verifying that tasks which specify that they are not using onPostExecute 152 * don't trigger it. 153 */ 154 @Test 155 @SmallTest testTaskNotNeedingPostExecutionDoesNotTriggerIt()156 public void testTaskNotNeedingPostExecutionDoesNotTriggerIt() { 157 new BackgroundOnlyAsyncTask<Void>() { 158 @Override 159 protected Void doInBackground() { 160 return null; 161 } 162 // Calling onPostExecute on this class causes failure. 163 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 164 } 165 166 // TODO(ksolt): do we need any post execution tests here? 167 } 168