summaryrefslogtreecommitdiffstats
path: root/base/test
diff options
context:
space:
mode:
authorjcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-13 20:02:38 +0000
committerjcivelli@chromium.org <jcivelli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-13 20:02:38 +0000
commitb1ac1410fc53c8b30332ebfecff98578941c21c3 (patch)
treeccc0c743ad08a255358d31c92db5b0ffcba7267e /base/test
parent094020855126721827342da98992a8c057d1a135 (diff)
downloadchromium_src-b1ac1410fc53c8b30332ebfecff98578941c21c3.zip
chromium_src-b1ac1410fc53c8b30332ebfecff98578941c21c3.tar.gz
chromium_src-b1ac1410fc53c8b30332ebfecff98578941c21c3.tar.bz2
Adding a new utility class for instrumentation tests.
Some instrumentation tests that exercise class that post tasks require the message loop to be flushed. This TestThread provides a way to run that class on a different thread that takes care of processing all pending events. BUG= TEST= Review URL: https://chromiumcodereview.appspot.com/11473014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@172942 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/test')
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java143
1 files changed, 143 insertions, 0 deletions
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java
new file mode 100644
index 0000000..11e6afd
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class is usefull when writing instrumentation tests that exercise code that posts tasks
+ * (to the same thread).
+ * Since the test code is run in a single thread, the posted tasks are never executed.
+ * The TestThread class lets you run that code on a specific thread synchronously and flush the
+ * message loop on that thread.
+ *
+ * Example of test using this:
+ *
+ * public void testMyAwesomeClass() {
+ * TestThread testThread = new TestThread();
+ * testThread.startAndWaitForReadyState();
+ *
+ * testThread.runOnTestThreadSyncAndProcessPendingTasks(new Runnable() {
+ * @Override
+ * public void run() {
+ * MyAwesomeClass.doStuffAsync();
+ * }
+ * });
+ * // Once we get there we know doStuffAsync has been executed and all the tasks it posted.
+ * assertTrue(MyAwesomeClass.stuffWasDone());
+ * }
+ *
+ * Notes:
+ * - this is only for tasks posted to the same thread. Anyway if you were posting to a different
+ * thread, you'd probably need to set that other thread up.
+ * - this only supports tasks posted using Handler.post(), it won't work with postDelayed and
+ * postAtTime.
+ * - if your test instanciates an object and that object is the one doing the posting of tasks, you
+ * probably want to instanciate it on the test thread as it might create the Handler it posts
+ * tasks to in the constructor.
+ */
+
+public class TestThread extends Thread {
+ private Object mThreadReadyLock;
+ private AtomicBoolean mThreadReady;
+ private Handler mMainThreadHandler;
+ private Handler mTestThreadHandler;
+
+ public TestThread() {
+ mMainThreadHandler = new Handler();
+ // We can't use the AtomicBoolean as the lock or findbugs will freak out...
+ mThreadReadyLock = new Object();
+ mThreadReady = new AtomicBoolean();
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mTestThreadHandler = new Handler();
+ mTestThreadHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mThreadReadyLock) {
+ mThreadReady.set(true);
+ mThreadReadyLock.notify();
+ }
+ }
+ });
+ Looper.loop();
+ }
+
+ /**
+ * Starts this TestThread and blocks until it's ready to accept calls.
+ */
+ public void startAndWaitForReadyState() {
+ checkOnMainThread();
+ start();
+ synchronized (mThreadReadyLock) {
+ try {
+ // Note the mThreadReady and while are not really needed.
+ // There are there so findbugs don't report warnings.
+ while (!mThreadReady.get()) {
+ mThreadReadyLock.wait();
+ }
+ } catch (InterruptedException ie) {
+ System.err.println("Error starting TestThread.");
+ ie.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Runs the passed Runnable synchronously on the TestThread and returns when all pending
+ * runnables have been excuted.
+ * Should be called from the main thread.
+ */
+ public void runOnTestThreadSyncAndProcessPendingTasks(Runnable r) {
+ checkOnMainThread();
+
+ runOnTestThreadSync(r);
+
+ // Run another task, when it's done it means all pendings tasks have executed.
+ runOnTestThreadSync(null);
+ }
+
+ /**
+ * Runs the passed Runnable on the test thread and blocks until it has finished executing.
+ * Should be called from the main thread.
+ * @param r The runnable to be executed.
+ */
+ public void runOnTestThreadSync(final Runnable r) {
+ checkOnMainThread();
+ final Object lock = new Object();
+ // Task executed is not really needed since we are only on one thread, it is here to appease
+ // findbugs.
+ final AtomicBoolean taskExecuted = new AtomicBoolean();
+ mTestThreadHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (r != null) r.run();
+ synchronized (lock) {
+ taskExecuted.set(true);
+ lock.notify();
+ }
+ }
+ });
+ synchronized (lock) {
+ try {
+ while (!taskExecuted.get()) {
+ lock.wait();
+ }
+ } catch (InterruptedException ie) {
+ ie.printStackTrace();
+ }
+ }
+ }
+
+ private void checkOnMainThread() {
+ assert Looper.myLooper() == mMainThreadHandler.getLooper();
+ }
+}