| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.os.cts; |
| |
| import android.support.annotation.NonNull; |
| import android.os.AsyncTask; |
| import android.test.InstrumentationTestCase; |
| |
| import com.android.compatibility.common.util.PollingCheck; |
| |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.Executor; |
| import java.util.concurrent.TimeUnit; |
| |
| public class AsyncTaskTest extends InstrumentationTestCase { |
| private static final long COMPUTE_TIME = 1000; |
| private static final long RESULT = 1000; |
| private static final Integer[] UPDATE_VALUE = { 0, 1, 2 }; |
| private static final long DURATION = 2000; |
| private static final String[] PARAM = { "Test" }; |
| |
| private static AsyncTask mAsyncTask; |
| private static MyAsyncTask mMyAsyncTask; |
| |
| public void testAsyncTask() throws Throwable { |
| doTestAsyncTask(0); |
| } |
| |
| public void testAsyncTaskWithTimeout() throws Throwable { |
| doTestAsyncTask(DURATION); |
| } |
| |
| private void doTestAsyncTask(final long timeout) throws Throwable { |
| startAsyncTask(); |
| if (timeout > 0) { |
| assertEquals(RESULT, mMyAsyncTask.get(DURATION, TimeUnit.MILLISECONDS).longValue()); |
| } else { |
| assertEquals(RESULT, mMyAsyncTask.get().longValue()); |
| } |
| |
| // wait for the task to finish completely (including onPostResult()). |
| new PollingCheck(DURATION) { |
| protected boolean check() { |
| return mMyAsyncTask.getStatus() == AsyncTask.Status.FINISHED; |
| } |
| }.run(); |
| |
| assertTrue(mMyAsyncTask.isOnPreExecuteCalled); |
| assert(mMyAsyncTask.hasRun); |
| assertEquals(PARAM.length, mMyAsyncTask.parameters.length); |
| for (int i = 0; i < PARAM.length; i++) { |
| assertEquals(PARAM[i], mMyAsyncTask.parameters[i]); |
| } |
| // even though the background task has run, the onPostExecute() may not have been |
| // executed yet and the progress update may not have been processed. Wait until the task |
| // has completed, which guarantees that onPostExecute has been called. |
| |
| assertEquals(RESULT, mMyAsyncTask.postResult.longValue()); |
| assertEquals(AsyncTask.Status.FINISHED, mMyAsyncTask.getStatus()); |
| |
| if (mMyAsyncTask.exception != null) { |
| throw mMyAsyncTask.exception; |
| } |
| |
| // wait for progress update to be processed (happens asynchronously) |
| new PollingCheck(DURATION) { |
| protected boolean check() { |
| return mMyAsyncTask.updateValue != null; |
| } |
| }.run(); |
| assertEquals(UPDATE_VALUE.length, mMyAsyncTask.updateValue.length); |
| for (int i = 0; i < UPDATE_VALUE.length; i++) { |
| assertEquals(UPDATE_VALUE[i], mMyAsyncTask.updateValue[i]); |
| } |
| |
| runTestOnUiThread(new Runnable() { |
| public void run() { |
| try { |
| // task should not be allowed to execute twice |
| mMyAsyncTask.execute(PARAM); |
| fail("Failed to throw exception!"); |
| } catch (IllegalStateException e) { |
| // expected |
| } |
| } |
| }); |
| } |
| |
| public void testCancelWithInterrupt() throws Throwable { |
| startAsyncTask(); |
| Thread.sleep(COMPUTE_TIME / 2); |
| assertTrue(mMyAsyncTask.cancel(true)); |
| // already cancelled |
| assertFalse(mMyAsyncTask.cancel(true)); |
| Thread.sleep(DURATION); |
| assertTrue(mMyAsyncTask.isCancelled()); |
| assertTrue(mMyAsyncTask.isOnCancelledCalled); |
| assertNotNull(mMyAsyncTask.exception); |
| assertTrue(mMyAsyncTask.exception instanceof InterruptedException); |
| } |
| |
| public void testCancel() throws Throwable { |
| startAsyncTask(); |
| Thread.sleep(COMPUTE_TIME / 2); |
| assertTrue(mMyAsyncTask.cancel(false)); |
| // already cancelled |
| assertFalse(mMyAsyncTask.cancel(false)); |
| Thread.sleep(DURATION); |
| assertTrue(mMyAsyncTask.isCancelled()); |
| assertTrue(mMyAsyncTask.isOnCancelledCalled); |
| assertNull(mMyAsyncTask.exception); |
| } |
| |
| public void testCancelTooLate() throws Throwable { |
| startAsyncTask(); |
| Thread.sleep(DURATION); |
| assertFalse(mMyAsyncTask.cancel(false)); |
| assertTrue(mMyAsyncTask.isCancelled()); |
| assertFalse(mMyAsyncTask.isOnCancelledCalled); |
| assertNull(mMyAsyncTask.exception); |
| } |
| |
| public void testCancellationWithException() throws Throwable { |
| final CountDownLatch readyToCancel = new CountDownLatch(1); |
| final CountDownLatch readyToThrow = new CountDownLatch(1); |
| final CountDownLatch calledOnCancelled = new CountDownLatch(1); |
| runTestOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| mAsyncTask = new AsyncTask() { |
| @Override |
| protected Object doInBackground(Object... params) { |
| readyToCancel.countDown(); |
| try { |
| readyToThrow.await(); |
| } catch (InterruptedException e) {} |
| // This exception is expected to be caught and ignored |
| throw new RuntimeException(); |
| } |
| |
| @Override |
| protected void onCancelled(Object o) { |
| calledOnCancelled.countDown(); |
| } |
| }; |
| } |
| }); |
| |
| mAsyncTask.execute(); |
| if (!readyToCancel.await(5, TimeUnit.SECONDS)) { |
| fail("Test failure: doInBackground did not run in time."); |
| } |
| mAsyncTask.cancel(false); |
| readyToThrow.countDown(); |
| if (!calledOnCancelled.await(5, TimeUnit.SECONDS)) { |
| fail("onCancelled not called!"); |
| } |
| } |
| |
| public void testException() throws Throwable { |
| final CountDownLatch calledOnCancelled = new CountDownLatch(1); |
| runTestOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| mAsyncTask = new AsyncTask() { |
| @Override |
| protected Object doInBackground(Object... params) { |
| throw new RuntimeException(); |
| } |
| |
| @Override |
| protected void onPostExecute(Object o) { |
| fail("onPostExecute should not be called"); |
| } |
| |
| @Override |
| protected void onCancelled(Object o) { |
| calledOnCancelled.countDown(); |
| } |
| }; |
| } |
| }); |
| |
| mAsyncTask.executeOnExecutor(new Executor() { |
| @Override |
| public void execute(@NonNull Runnable command) { |
| try { |
| command.run(); |
| fail("Exception not thrown"); |
| } catch (Throwable tr) { |
| // expected |
| } |
| } |
| }); |
| |
| if (!calledOnCancelled.await(5, TimeUnit.SECONDS)) { |
| fail("onCancelled not called!"); |
| } |
| } |
| |
| private void startAsyncTask() throws Throwable { |
| runTestOnUiThread(new Runnable() { |
| public void run() { |
| mMyAsyncTask = new MyAsyncTask(); |
| assertEquals(AsyncTask.Status.PENDING, mMyAsyncTask.getStatus()); |
| assertEquals(mMyAsyncTask, mMyAsyncTask.execute(PARAM)); |
| assertEquals(AsyncTask.Status.RUNNING, mMyAsyncTask.getStatus()); |
| } |
| }); |
| } |
| |
| private static class MyAsyncTask extends AsyncTask<String, Integer, Long> { |
| public boolean isOnCancelledCalled; |
| public boolean isOnPreExecuteCalled; |
| public boolean hasRun; |
| public Exception exception; |
| public Long postResult; |
| public Integer[] updateValue; |
| public String[] parameters; |
| |
| @Override |
| protected Long doInBackground(String... params) { |
| hasRun = true; |
| parameters = params; |
| try { |
| publishProgress(UPDATE_VALUE); |
| Thread.sleep(COMPUTE_TIME); |
| } catch (Exception e) { |
| exception = e; |
| } |
| return RESULT; |
| } |
| |
| @Override |
| protected void onCancelled() { |
| super.onCancelled(); |
| isOnCancelledCalled = true; |
| } |
| |
| @Override |
| protected void onPostExecute(Long result) { |
| super.onPostExecute(result); |
| postResult = result; |
| } |
| |
| @Override |
| protected void onPreExecute() { |
| super.onPreExecute(); |
| isOnPreExecuteCalled = true; |
| } |
| |
| @Override |
| protected void onProgressUpdate(Integer... values) { |
| super.onProgressUpdate(values); |
| updateValue = values; |
| } |
| } |
| } |