Home | History | Annotate | Download | only in cts
      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