CallbackHelper.java revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.content.browser.test.util;
6
7import java.util.concurrent.TimeUnit;
8import java.util.concurrent.TimeoutException;
9
10/**
11 * A helper class for listening to callbacks.
12 */
13public class CallbackHelper {
14    protected static int WAIT_TIMEOUT_SECONDS = 5;
15
16    private final Object mLock = new Object();
17    protected int mCallCount = 0;
18
19    /**
20     * Gets the number of times the callback has been called.
21     *
22     * The call count can be used with the waitForCallback() method, indicating a point
23     * in time after which the caller wishes to record calls to the callback.
24     *
25     * In order to wait for a callback caused by X, the call count should be obtained
26     * before X occurs.
27     *
28     * NOTE: any call to the callback that occurs after the call count is obtained
29     * will result in the corresponding wait call to resume execution. The call count
30     * is intended to 'catch' callbacks that occur after X but before waitForCallback()
31     * is called.
32     */
33    public int getCallCount() {
34        synchronized(mLock) {
35            return mCallCount;
36        }
37    }
38
39    /**
40     * Blocks until the callback is called the specified number of
41     * times or throws an exception if we exceeded the specified time frame.
42     *
43     * This will wait for a callback to be called a specified number of times after
44     * the point in time at which the call count was obtained.  The method will return
45     * immediately if a call occurred the specified number of times after the
46     * call count was obtained but before the method was called, otherwise the method will
47     * block until the specified call count is reached.
48     *
49     * @param currentCallCount the value obtained by calling getCallCount().
50     * @param numberOfCallsToWaitFor number of calls (counting since
51     *                               currentCallCount was obtained) that we will wait for.
52     * @param timeout timeout value. We will wait the specified amount of time for a single
53     *                callback to occur so the method call may block up to
54     *                <code>numberOfCallsToWaitFor * timeout</code> units.
55     * @param unit timeout unit.
56     * @throws InterruptedException
57     * @throws TimeoutException Thrown if the method times out before onPageFinished is called.
58     */
59    public void waitForCallback(int currentCallCount, int numberOfCallsToWaitFor, long timeout,
60            TimeUnit unit) throws InterruptedException, TimeoutException {
61        assert mCallCount >= currentCallCount;
62        assert numberOfCallsToWaitFor > 0;
63        synchronized(mLock) {
64            int callCountWhenDoneWaiting = currentCallCount + numberOfCallsToWaitFor;
65            while (callCountWhenDoneWaiting > mCallCount) {
66                int callCountBeforeWait = mCallCount;
67                mLock.wait(unit.toMillis(timeout));
68                if (callCountBeforeWait == mCallCount) {
69                    throw new TimeoutException("waitForCallback timed out!");
70                }
71            }
72        }
73    }
74
75    public void waitForCallback(int currentCallCount, int numberOfCallsToWaitFor)
76            throws InterruptedException, TimeoutException {
77        waitForCallback(currentCallCount, numberOfCallsToWaitFor,
78                WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
79    }
80
81    public void waitForCallback(int currentCallCount)
82            throws InterruptedException, TimeoutException {
83        waitForCallback(currentCallCount, 1);
84    }
85
86    /**
87     * Should be called when the callback associated with this helper object is called.
88     */
89    public void notifyCalled() {
90        synchronized(mLock) {
91            mCallCount++;
92            mLock.notifyAll();
93        }
94    }
95}
96