1 /* 2 * Copyright (C) 2009 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 android.os.cts; 18 19 import androidx.annotation.NonNull; 20 import android.os.AsyncTask; 21 import android.test.InstrumentationTestCase; 22 23 import com.android.compatibility.common.util.PollingCheck; 24 25 import java.util.concurrent.CountDownLatch; 26 import java.util.concurrent.Executor; 27 import java.util.concurrent.TimeUnit; 28 29 public class AsyncTaskTest extends InstrumentationTestCase { 30 private static final long COMPUTE_TIME = 1000; 31 private static final long RESULT = 1000; 32 private static final Integer[] UPDATE_VALUE = { 0, 1, 2 }; 33 private static final long DURATION = 2000; 34 private static final String[] PARAM = { "Test" }; 35 36 private static AsyncTask mAsyncTask; 37 private static MyAsyncTask mMyAsyncTask; 38 39 public void testAsyncTask() throws Throwable { 40 doTestAsyncTask(0); 41 } 42 43 public void testAsyncTaskWithTimeout() throws Throwable { 44 doTestAsyncTask(DURATION); 45 } 46 47 private void doTestAsyncTask(final long timeout) throws Throwable { 48 startAsyncTask(); 49 if (timeout > 0) { 50 assertEquals(RESULT, mMyAsyncTask.get(DURATION, TimeUnit.MILLISECONDS).longValue()); 51 } else { 52 assertEquals(RESULT, mMyAsyncTask.get().longValue()); 53 } 54 55 // wait for the task to finish completely (including onPostResult()). 56 new PollingCheck(DURATION) { 57 protected boolean check() { 58 return mMyAsyncTask.getStatus() == AsyncTask.Status.FINISHED; 59 } 60 }.run(); 61 62 assertTrue(mMyAsyncTask.isOnPreExecuteCalled); 63 assert(mMyAsyncTask.hasRun); 64 assertEquals(PARAM.length, mMyAsyncTask.parameters.length); 65 for (int i = 0; i < PARAM.length; i++) { 66 assertEquals(PARAM[i], mMyAsyncTask.parameters[i]); 67 } 68 // even though the background task has run, the onPostExecute() may not have been 69 // executed yet and the progress update may not have been processed. Wait until the task 70 // has completed, which guarantees that onPostExecute has been called. 71 72 assertEquals(RESULT, mMyAsyncTask.postResult.longValue()); 73 assertEquals(AsyncTask.Status.FINISHED, mMyAsyncTask.getStatus()); 74 75 if (mMyAsyncTask.exception != null) { 76 throw mMyAsyncTask.exception; 77 } 78 79 // wait for progress update to be processed (happens asynchronously) 80 new PollingCheck(DURATION) { 81 protected boolean check() { 82 return mMyAsyncTask.updateValue != null; 83 } 84 }.run(); 85 assertEquals(UPDATE_VALUE.length, mMyAsyncTask.updateValue.length); 86 for (int i = 0; i < UPDATE_VALUE.length; i++) { 87 assertEquals(UPDATE_VALUE[i], mMyAsyncTask.updateValue[i]); 88 } 89 90 runTestOnUiThread(new Runnable() { 91 public void run() { 92 try { 93 // task should not be allowed to execute twice 94 mMyAsyncTask.execute(PARAM); 95 fail("Failed to throw exception!"); 96 } catch (IllegalStateException e) { 97 // expected 98 } 99 } 100 }); 101 } 102 103 public void testCancelWithInterrupt() throws Throwable { 104 startAsyncTask(); 105 Thread.sleep(COMPUTE_TIME / 2); 106 assertTrue(mMyAsyncTask.cancel(true)); 107 // already cancelled 108 assertFalse(mMyAsyncTask.cancel(true)); 109 Thread.sleep(DURATION); 110 assertTrue(mMyAsyncTask.isCancelled()); 111 assertTrue(mMyAsyncTask.isOnCancelledCalled); 112 assertNotNull(mMyAsyncTask.exception); 113 assertTrue(mMyAsyncTask.exception instanceof InterruptedException); 114 } 115 116 public void testCancel() throws Throwable { 117 startAsyncTask(); 118 Thread.sleep(COMPUTE_TIME / 2); 119 assertTrue(mMyAsyncTask.cancel(false)); 120 // already cancelled 121 assertFalse(mMyAsyncTask.cancel(false)); 122 Thread.sleep(DURATION); 123 assertTrue(mMyAsyncTask.isCancelled()); 124 assertTrue(mMyAsyncTask.isOnCancelledCalled); 125 assertNull(mMyAsyncTask.exception); 126 } 127 128 public void testCancelTooLate() throws Throwable { 129 startAsyncTask(); 130 Thread.sleep(DURATION); 131 assertFalse(mMyAsyncTask.cancel(false)); 132 assertTrue(mMyAsyncTask.isCancelled()); 133 assertFalse(mMyAsyncTask.isOnCancelledCalled); 134 assertNull(mMyAsyncTask.exception); 135 } 136 137 public void testCancellationWithException() throws Throwable { 138 final CountDownLatch readyToCancel = new CountDownLatch(1); 139 final CountDownLatch readyToThrow = new CountDownLatch(1); 140 final CountDownLatch calledOnCancelled = new CountDownLatch(1); 141 runTestOnUiThread(new Runnable() { 142 @Override 143 public void run() { 144 mAsyncTask = new AsyncTask() { 145 @Override 146 protected Object doInBackground(Object... params) { 147 readyToCancel.countDown(); 148 try { 149 readyToThrow.await(); 150 } catch (InterruptedException e) {} 151 // This exception is expected to be caught and ignored 152 throw new RuntimeException(); 153 } 154 155 @Override 156 protected void onCancelled(Object o) { 157 calledOnCancelled.countDown(); 158 } 159 }; 160 } 161 }); 162 163 mAsyncTask.execute(); 164 if (!readyToCancel.await(5, TimeUnit.SECONDS)) { 165 fail("Test failure: doInBackground did not run in time."); 166 } 167 mAsyncTask.cancel(false); 168 readyToThrow.countDown(); 169 if (!calledOnCancelled.await(5, TimeUnit.SECONDS)) { 170 fail("onCancelled not called!"); 171 } 172 } 173 174 public void testException() throws Throwable { 175 final CountDownLatch calledOnCancelled = new CountDownLatch(1); 176 runTestOnUiThread(new Runnable() { 177 @Override 178 public void run() { 179 mAsyncTask = new AsyncTask() { 180 @Override 181 protected Object doInBackground(Object... params) { 182 throw new RuntimeException(); 183 } 184 185 @Override 186 protected void onPostExecute(Object o) { 187 fail("onPostExecute should not be called"); 188 } 189 190 @Override 191 protected void onCancelled(Object o) { 192 calledOnCancelled.countDown(); 193 } 194 }; 195 } 196 }); 197 198 mAsyncTask.executeOnExecutor(new Executor() { 199 @Override 200 public void execute(@NonNull Runnable command) { 201 try { 202 command.run(); 203 fail("Exception not thrown"); 204 } catch (Exception tr) { 205 // expected 206 } 207 } 208 }); 209 210 if (!calledOnCancelled.await(5, TimeUnit.SECONDS)) { 211 fail("onCancelled not called!"); 212 } 213 } 214 215 private void startAsyncTask() throws Throwable { 216 runTestOnUiThread(new Runnable() { 217 public void run() { 218 mMyAsyncTask = new MyAsyncTask(); 219 assertEquals(AsyncTask.Status.PENDING, mMyAsyncTask.getStatus()); 220 assertEquals(mMyAsyncTask, mMyAsyncTask.execute(PARAM)); 221 assertEquals(AsyncTask.Status.RUNNING, mMyAsyncTask.getStatus()); 222 } 223 }); 224 } 225 226 private static class MyAsyncTask extends AsyncTask<String, Integer, Long> { 227 public boolean isOnCancelledCalled; 228 public boolean isOnPreExecuteCalled; 229 public boolean hasRun; 230 public Exception exception; 231 public Long postResult; 232 public Integer[] updateValue; 233 public String[] parameters; 234 235 @Override 236 protected Long doInBackground(String... params) { 237 hasRun = true; 238 parameters = params; 239 try { 240 publishProgress(UPDATE_VALUE); 241 Thread.sleep(COMPUTE_TIME); 242 } catch (Exception e) { 243 exception = e; 244 } 245 return RESULT; 246 } 247 248 @Override 249 protected void onCancelled() { 250 super.onCancelled(); 251 isOnCancelledCalled = true; 252 } 253 254 @Override 255 protected void onPostExecute(Long result) { 256 super.onPostExecute(result); 257 postResult = result; 258 } 259 260 @Override 261 protected void onPreExecute() { 262 super.onPreExecute(); 263 isOnPreExecuteCalled = true; 264 } 265 266 @Override 267 protected void onProgressUpdate(Integer... values) { 268 super.onProgressUpdate(values); 269 updateValue = values; 270 } 271 } 272 } 273