1 // Copyright 2014 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.
5 package org.chromium.components.devtools_bridge;
7 import java.util.concurrent.BlockingQueue;
8 import java.util.concurrent.Callable;
9 import java.util.concurrent.ExecutionException;
10 import java.util.concurrent.ExecutorService;
11 import java.util.concurrent.Executors;
12 import java.util.concurrent.LinkedBlockingDeque;
13 import java.util.concurrent.ScheduledExecutorService;
14 import java.util.concurrent.ScheduledFuture;
15 import java.util.concurrent.TimeUnit;
16 import java.util.concurrent.atomic.AtomicInteger;
19 * Convinience class for tests. Like WebRTC threads supports posts
20 * and synchronous invokes.
22 class SignalingThreadMock {
23 // TODO: use scaleTimeout when natives for org.chromium.base get available.
24 private static final int EXECUTION_TIME_LIMIT_MS = 5000;
26 private final AtomicInteger mInvokationCounter = new AtomicInteger(0);
27 private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
28 private final ScheduledExecutorService mWatchDogExecutor =
29 Executors.newSingleThreadScheduledExecutor();
30 private ScheduledFuture<?> mWatchDogFuture;
31 private final Thread mThread;
32 private final BlockingQueue<Runnable> mExecutionQueue = new LinkedBlockingDeque<Runnable>();
34 public SignalingThreadMock() {
35 mThread = new Thread() {
40 } catch (InterruptedException e) {
48 private void runExecutionLoop() throws InterruptedException {
50 mExecutionQueue.take().run();
54 public void invoke(final Runnable runnable) {
56 invoke(new TestUtils.RunnableAdapter(runnable));
57 } catch (Exception e) {
58 throw new RuntimeException(e);
62 public <T> T invoke(final Callable<T> callable) throws Exception {
63 if (isOnThread()) return callable.call();
66 return new InvokeWrapper<T>(callable).invoke();
67 } catch (InterruptedException e) {
68 throw new RuntimeException(e);
69 } catch (ExecutionException e) {
70 throw (Exception) e.getCause();
74 public void post(Runnable runnable) {
75 boolean success = mExecutionQueue.offer(new PostWrapper(runnable));
79 public void dispose() {
80 mWatchDogExecutor.shutdown();
84 } catch (InterruptedException e) {
85 Thread.currentThread().interrupt();
89 public boolean isOnThread() {
90 return Thread.currentThread() == mThread;
93 private void onStartedExecution(final int index, final Exception timeoutException) {
94 mWatchDogFuture = mWatchDogExecutor.schedule(new Runnable() {
97 throw new RuntimeException(
98 "Time limit on " + Integer.toString(index) + " invocation",
101 }, EXECUTION_TIME_LIMIT_MS, TimeUnit.MILLISECONDS);
104 private void onFinishedExecution() {
105 mWatchDogFuture.cancel(false);
108 private abstract class WrapperBase implements Runnable {
109 private final int mIndex;
110 private final Exception mTimeoutException;
112 protected WrapperBase() {
113 mIndex = mInvokationCounter.incrementAndGet();
114 mTimeoutException = new Exception("Timeout exception");
118 public final void run() {
119 onStartedExecution(mIndex, mTimeoutException);
123 onFinishedExecution();
127 protected abstract void runWrapped();
130 private class InvokeWrapper<T> extends WrapperBase {
131 private final Callable<T> mWrapped;
132 private final TestUtils.InvokeHelper<T> mHelper = new TestUtils.InvokeHelper<T>();
134 public InvokeWrapper(Callable<T> wrapped) {
139 protected void runWrapped() {
140 mHelper.runOnTargetThread(mWrapped);
143 public T invoke() throws Exception {
144 boolean success = mExecutionQueue.offer(this);
146 return mHelper.takeResult();
150 private class PostWrapper extends WrapperBase {
151 private final Runnable mWrapped;
153 public PostWrapper(Runnable wrapped) {
158 protected void runWrapped() {