Replace LooperExecutor with built-in class in Android AppRTC Demo

LooperExecutor is only truly needed in WebSocketChannelClient because of
WebSocketClient from autobanh requiring thread to have a looper. So
LooperExecutor was left there but replaced everywhere else with built-in
singleThreadExecutor/singleThreadScheduledExecutor.

Motivation behind this change is that built-in class behaves better
under testing environment and doesn't require hacky
RobolectricLooperExecutor.

Review-Url: https://codereview.webrtc.org/1992213002
Cr-Commit-Position: refs/heads/master@{#12823}
This commit is contained in:
sakal
2016-05-20 02:41:02 -07:00
committed by Commit bot
parent 04ebea3629
commit 7cf11476b9
10 changed files with 79 additions and 199 deletions

View File

@ -10,9 +10,6 @@
package org.appspot.apprtc;
import android.util.Log;
import org.appspot.apprtc.util.RobolectricLooperExecutor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -56,8 +53,8 @@ public class DirectRTCClientTest {
clientEvents = mock(AppRTCClient.SignalingEvents.class);
serverEvents = mock(AppRTCClient.SignalingEvents.class);
client = new DirectRTCClient(clientEvents, new RobolectricLooperExecutor());
server = new DirectRTCClient(serverEvents, new RobolectricLooperExecutor());
client = new DirectRTCClient(clientEvents);
server = new DirectRTCClient(serverEvents);
}
@Test

View File

@ -10,7 +10,7 @@
package org.appspot.apprtc;
import org.appspot.apprtc.util.RobolectricLooperExecutor;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -21,6 +21,11 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLog;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@ -38,13 +43,14 @@ public class TCPChannelClientTest {
private static final int CONNECT_TIMEOUT = 100;
private static final int SEND_TIMEOUT = 100;
private static final int DISCONNECT_TIMEOUT = 100;
private static final int TERMINATION_TIMEOUT = 1000;
private static final String TEST_MESSAGE_SERVER = "Hello, Server!";
private static final String TEST_MESSAGE_CLIENT = "Hello, Client!";
@Mock TCPChannelClient.TCPChannelEvents serverEvents;
@Mock TCPChannelClient.TCPChannelEvents clientEvents;
private RobolectricLooperExecutor executor;
private ExecutorService executor;
private TCPChannelClient server;
private TCPChannelClient client;
@ -55,15 +61,14 @@ public class TCPChannelClientTest {
MockitoAnnotations.initMocks(this);
executor = new RobolectricLooperExecutor();
executor.requestStart();
executor = Executors.newSingleThreadExecutor();
}
@After
public void tearDown() {
verifyNoMoreEvents();
executor.executeAndWait(new Runnable() {
executeAndWait(new Runnable() {
@Override
public void run() {
client.disconnect();
@ -72,9 +77,9 @@ public class TCPChannelClientTest {
});
// Stop the executor thread
executor.requestStop();
executor.shutdown();
try {
executor.join();
executor.awaitTermination(TERMINATION_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
fail(e.getMessage());
}
@ -112,7 +117,7 @@ public class TCPChannelClientTest {
public void testSendData() {
testConnectIPv4();
executor.executeAndWait(new Runnable() {
executeAndWait(new Runnable() {
@Override
public void run() {
client.send(TEST_MESSAGE_SERVER);
@ -127,7 +132,7 @@ public class TCPChannelClientTest {
@Test
public void testDisconnectServer() {
testConnectIPv4();
executor.executeAndWait(new Runnable() {
executeAndWait(new Runnable() {
@Override
public void run() {
server.disconnect();
@ -141,7 +146,7 @@ public class TCPChannelClientTest {
@Test
public void testDisconnectClient() {
testConnectIPv4();
executor.executeAndWait(new Runnable() {
executeAndWait(new Runnable() {
@Override
public void run() {
client.disconnect();
@ -183,4 +188,15 @@ public class TCPChannelClientTest {
verifyNoMoreInteractions(serverEvents);
verifyNoMoreInteractions(clientEvents);
}
/**
* Queues runnable to be run and waits for it to be executed by the executor thread
*/
public void executeAndWait(Runnable runnable) {
try {
executor.submit(runnable).get();
} catch (Exception e) {
fail(e.getMessage());
}
}
}

View File

@ -1,118 +0,0 @@
/*
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.appspot.apprtc.util;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import static org.junit.Assert.fail;
/**
* LooperExecutor that doesn't use Looper because its implementation in Robolectric is not suited
* for our needs. Also implements executeAndWait that can be used to wait until the runnable has
* been executed.
*/
public class RobolectricLooperExecutor extends LooperExecutor {
private volatile boolean running = false;
private static final int RUNNABLE_QUEUE_CAPACITY = 256;
private final BlockingQueue<Runnable> runnableQueue
= new ArrayBlockingQueue<>(RUNNABLE_QUEUE_CAPACITY);
private long threadId;
/**
* Executes the runnable passed to the constructor and sets isDone flag afterwards.
*/
private static class ExecuteAndWaitRunnable implements Runnable {
public boolean isDone = false;
private final Runnable runnable;
ExecuteAndWaitRunnable(Runnable runnable) {
this.runnable = runnable;
}
@Override
public void run() {
runnable.run();
synchronized (this) {
isDone = true;
notifyAll();
}
}
}
@Override
public void run() {
threadId = Thread.currentThread().getId();
while (running) {
final Runnable runnable;
try {
runnable = runnableQueue.take();
} catch (InterruptedException e) {
if (running) {
fail(e.getMessage());
}
return;
}
runnable.run();
}
}
@Override
public synchronized void requestStart() {
if (running) {
return;
}
running = true;
start();
}
@Override
public synchronized void requestStop() {
running = false;
interrupt();
}
@Override
public synchronized void execute(Runnable runnable) {
try {
runnableQueue.put(runnable);
} catch (InterruptedException e) {
fail(e.getMessage());
}
}
/**
* Queues runnable to be run and waits for it to be executed by the executor thread
*/
public void executeAndWait(Runnable runnable) {
ExecuteAndWaitRunnable executeAndWaitRunnable = new ExecuteAndWaitRunnable(runnable);
execute(executeAndWaitRunnable);
synchronized (executeAndWaitRunnable) {
while (!executeAndWaitRunnable.isDone) {
try {
executeAndWaitRunnable.wait();
} catch (InterruptedException e) {
fail(e.getMessage());
}
}
}
}
@Override
public boolean checkOnLooperThread() {
return (Thread.currentThread().getId() == threadId);
}
}