diff --git a/webrtc/examples/androidapp/src/org/appspot/apprtc/util/LooperExecutor.java b/webrtc/examples/androidapp/src/org/appspot/apprtc/util/LooperExecutor.java index 6e2b251133..4db807a3a6 100644 --- a/webrtc/examples/androidapp/src/org/appspot/apprtc/util/LooperExecutor.java +++ b/webrtc/examples/androidapp/src/org/appspot/apprtc/util/LooperExecutor.java @@ -72,7 +72,7 @@ public class LooperExecutor extends Thread implements Executor { handler.post(new Runnable() { @Override public void run() { - Looper.myLooper().quit(); + handler.getLooper().quit(); Log.d(TAG, "Looper thread finished."); } }); @@ -131,4 +131,10 @@ public class LooperExecutor extends Thread implements Executor { } } + /** + * Access to the handler for testing purposes. + */ + Handler getHandler() { + return handler; + } } diff --git a/webrtc/examples/androidjunit/src/org/appspot/apprtc/util/LooperExecutorTest.java b/webrtc/examples/androidjunit/src/org/appspot/apprtc/util/LooperExecutorTest.java new file mode 100644 index 0000000000..31c97ae31a --- /dev/null +++ b/webrtc/examples/androidjunit/src/org/appspot/apprtc/util/LooperExecutorTest.java @@ -0,0 +1,122 @@ +/* + * 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 org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowLooper; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.robolectric.Robolectric.shadowOf; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class LooperExecutorTest { + private final static int RUN_TIMES = 10; + + @Mock private Runnable mockRunnable; + private LooperExecutor executor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + executor = new LooperExecutor(); + } + + @After + public void tearDown() { + executor.requestStop(); + executePendingRunnables(); + } + + @Test + public void testExecute() { + executor.requestStart(); + + for (int i = 0; i < RUN_TIMES; i++) { + executor.execute(mockRunnable); + } + + verifyNoMoreInteractions(mockRunnable); + executePendingRunnables(); + verify(mockRunnable, times(RUN_TIMES)).run(); + } + + /** + * Test that runnables executed before requestStart are ignored. + */ + @Test + public void testExecuteBeforeStart() { + executor.execute(mockRunnable); + + executor.requestStart(); + executePendingRunnables(); + + verifyNoMoreInteractions(mockRunnable); + } + + /** + * Test that runnables executed after requestStop are not executed. + */ + @Test + public void testExecuteAfterStop() { + executor.requestStart(); + executor.requestStop(); + + executor.execute(mockRunnable); + executePendingRunnables(); + + verifyNoMoreInteractions(mockRunnable); + } + + /** + * Test multiple requestStart calls are just ignored. + */ + @Test + public void testMultipleStarts() { + executor.requestStart(); + testExecute(); + } + + /** + * Test multiple requestStop calls are just ignored. + */ + @Test + public void testMultipleStops() { + executor.requestStart(); + executor.requestStop(); + executor.requestStop(); + executePendingRunnables(); + } + + /** + * Calls ShadowLooper's idle method in order to execute pending runnables. + */ + private void executePendingRunnables() { + ShadowLooper shadowLooper = getShadowLooper(); + shadowLooper.idle(); + } + + /** + * Get ShadowLooper of the executor thread. + */ + private ShadowLooper getShadowLooper() { + return shadowOf(executor.getHandler().getLooper()); + } +} diff --git a/webrtc/examples/androidtests/src/org/appspot/apprtc/test/LooperExecutorTest.java b/webrtc/examples/androidtests/src/org/appspot/apprtc/test/LooperExecutorTest.java deleted file mode 100644 index 60d3c1cbc0..0000000000 --- a/webrtc/examples/androidtests/src/org/appspot/apprtc/test/LooperExecutorTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2015 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.test; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import org.appspot.apprtc.util.LooperExecutor; - -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.Log; - -public class LooperExecutorTest extends InstrumentationTestCase { - private static final String TAG = "LooperTest"; - private static final int WAIT_TIMEOUT = 5000; - - @SmallTest - public void testLooperExecutor() throws InterruptedException { - Log.d(TAG, "testLooperExecutor"); - final int counter[] = new int[1]; - final int expectedCounter = 10; - final CountDownLatch looperDone = new CountDownLatch(1); - - Runnable counterIncRunnable = new Runnable() { - @Override - public void run() { - counter[0]++; - Log.d(TAG, "Run " + counter[0]); - } - }; - LooperExecutor executor = new LooperExecutor(); - - // Try to execute a counter increment task before starting an executor. - executor.execute(counterIncRunnable); - - // Start the executor and run expected amount of counter increment task. - executor.requestStart(); - for (int i = 0; i < expectedCounter; i++) { - executor.execute(counterIncRunnable); - } - executor.execute(new Runnable() { - @Override - public void run() { - looperDone.countDown(); - } - }); - executor.requestStop(); - - // Try to execute a task after stopping the executor. - executor.execute(counterIncRunnable); - - // Wait for final looper task and make sure the counter increment task - // is executed expected amount of times. - looperDone.await(WAIT_TIMEOUT, TimeUnit.MILLISECONDS); - assertTrue (looperDone.getCount() == 0); - assertTrue (counter[0] == expectedCounter); - - Log.d(TAG, "testLooperExecutor done"); - } -}