blob: 016e402c69f41e3fcd759ebd342c05d1be898254 [file] [log] [blame]
Fabian Kozynski86fb5b42018-08-17 14:53:21 -04001package com.android.systemui.statusbar.policy;
2
3
Brett Chabot84151d92019-02-27 15:37:59 -08004import static org.junit.Assert.fail;
Fabian Kozynski86fb5b42018-08-17 14:53:21 -04005import static org.mockito.Mockito.mock;
6import static org.mockito.Mockito.never;
7import static org.mockito.Mockito.times;
8import static org.mockito.Mockito.verify;
9import static org.mockito.Mockito.when;
10
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040011import android.media.MediaRouter;
12import android.media.projection.MediaProjectionInfo;
13import android.media.projection.MediaProjectionManager;
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040014import android.testing.AndroidTestingRunner;
15import android.testing.TestableLooper;
16
Brett Chabot84151d92019-02-27 15:37:59 -080017import androidx.test.filters.SmallTest;
18
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040019import com.android.systemui.SysuiTestCase;
20import com.android.systemui.statusbar.policy.CastController.Callback;
21
22import org.junit.Before;
Brett Chabot84151d92019-02-27 15:37:59 -080023import org.junit.Test;
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040024import org.junit.runner.RunWith;
25import org.mockito.Mock;
26import org.mockito.MockitoAnnotations;
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040027
Fabian Kozynskiaacde142018-08-20 17:54:24 -040028import java.util.ConcurrentModificationException;
29import java.util.concurrent.CountDownLatch;
30import java.util.concurrent.TimeUnit;
31import java.util.concurrent.atomic.AtomicBoolean;
32
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040033@SmallTest
34@RunWith(AndroidTestingRunner.class)
35@TestableLooper.RunWithLooper
36public class CastControllerImplTest extends SysuiTestCase {
37
38 @Mock
39 MediaRouter mMediaRouter;
40 @Mock
41 MediaProjectionManager mMediaProjectionManager;
42 @Mock
43 MediaProjectionInfo mProjection;
44
45 private CastControllerImpl mController;
46
47 @Before
48 public void setUp() {
49 MockitoAnnotations.initMocks(this);
50 mContext.addMockSystemService(MediaRouter.class, mMediaRouter);
51 mContext.addMockSystemService(MediaProjectionManager.class, mMediaProjectionManager);
52 when(mMediaProjectionManager.getActiveProjectionInfo()).thenReturn(mProjection);
53
54 mController = new CastControllerImpl(mContext);
55 }
56
57 @Test
Fabian Kozynskiaacde142018-08-20 17:54:24 -040058 public void testAddCallback() {
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040059 Callback mockCallback = mock(Callback.class);
60
61 mController.addCallback(mockCallback);
Fabian Kozynskiaacde142018-08-20 17:54:24 -040062 verify(mockCallback, times(1)).onCastDevicesChanged();
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040063 }
64
65 @Test
Fabian Kozynskiaacde142018-08-20 17:54:24 -040066 public void testRemoveCallback() {
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040067 Callback mockCallback = mock(Callback.class);
68
69 mController.addCallback(mockCallback);
70 verify(mockCallback, times(1)).onCastDevicesChanged();
71
72 mController.removeCallback(mockCallback);
73 verify(mockCallback, times(1)).onCastDevicesChanged();
74 }
75
76 @Test
Fabian Kozynskiaacde142018-08-20 17:54:24 -040077 public void testRemoveCallbackFromEmptyList() {
Fabian Kozynski86fb5b42018-08-17 14:53:21 -040078 Callback mockCallback = mock(Callback.class);
79
80 mController.removeCallback(mockCallback);
81 verify(mockCallback, never()).onCastDevicesChanged();
82 }
Fabian Kozynskiaacde142018-08-20 17:54:24 -040083
84 @Test
85 public void testAddCallbackRemoveCallback_concurrently() throws InterruptedException {
86 int callbackCount = 20;
87 int numThreads = 2 * callbackCount;
88 CountDownLatch startThreadsLatch = new CountDownLatch(1);
89 CountDownLatch threadsDone = new CountDownLatch(numThreads);
90 Callback[] callbackList = new Callback[callbackCount];
91 mController.setDiscovering(true);
92 AtomicBoolean error = new AtomicBoolean(false);
93 for (int cbIndex = 0; cbIndex < callbackCount; cbIndex++) {
94 callbackList[cbIndex] = mock(Callback.class);
95 }
96 for (int i = 0; i < numThreads; i++) {
97 final Callback mCallback = callbackList[i / 2];
98 final boolean shouldAdd = (i % 2 == 0);
99 new Thread() {
100 public void run() {
101 try {
102 startThreadsLatch.await(10, TimeUnit.SECONDS);
103 } catch (InterruptedException e) {
104 throw new RuntimeException(e);
105 }
106 try {
107 if (shouldAdd) {
108 mController.addCallback(mCallback);
109 } else {
110 mController.removeCallback(mCallback);
111 }
112 mController.fireOnCastDevicesChanged();
113 } catch (ConcurrentModificationException exc) {
114 error.compareAndSet(false, true);
115 } finally {
116 threadsDone.countDown();
117 }
118 }
119 }.start();
120 }
121 startThreadsLatch.countDown();
122 threadsDone.await(10, TimeUnit.SECONDS);
123 if (error.get()) {
124 fail("Concurrent modification exception");
125 }
126 }
Fabian Kozynski86fb5b42018-08-17 14:53:21 -0400127}