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