OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 | |
5 package org.chromium.chrome.browser.superviseduser; | |
6 | |
7 import static org.hamcrest.CoreMatchers.is; | |
8 import static org.junit.Assert.assertThat; | |
9 import static org.mockito.Matchers.any; | |
10 import static org.mockito.Matchers.anyLong; | |
11 import static org.mockito.Matchers.anyString; | |
12 import static org.mockito.Matchers.eq; | |
13 import static org.mockito.Mockito.doAnswer; | |
14 import static org.mockito.Mockito.times; | |
15 import static org.mockito.Mockito.verify; | |
16 | |
17 import android.os.Handler; | |
18 import android.os.Looper; | |
19 import android.util.Pair; | |
20 | |
21 import org.chromium.testing.local.LocalRobolectricTestRunner; | |
22 import org.junit.Before; | |
23 import org.junit.Test; | |
24 import org.junit.runner.RunWith; | |
25 import org.mockito.Mockito; | |
26 import org.mockito.invocation.InvocationOnMock; | |
27 import org.mockito.stubbing.Answer; | |
28 import org.robolectric.Robolectric; | |
29 import org.robolectric.annotation.Config; | |
30 import org.robolectric.annotation.Implementation; | |
31 import org.robolectric.annotation.Implements; | |
32 | |
33 import java.util.concurrent.CountDownLatch; | |
34 | |
35 /** | |
36 * Tests of SupervisedUserContentProvider. This is tested as a simple class, not as a content | |
37 * provider. The content provider aspects are tested with WebRestrictionsContent ProviderTest. | |
38 */ | |
39 @RunWith(LocalRobolectricTestRunner.class) | |
40 @Config(manifest = Config.NONE, | |
41 shadows = {SupervisedUserContentProviderUnitTest.ShadowHander.class}) | |
42 public class SupervisedUserContentProviderUnitTest { | |
43 private static CountDownLatch sLatch; | |
44 | |
45 /** | |
46 * Special Handler shadow class that allows the test to wait for a post() ca ll. | |
47 */ | |
48 @Implements(Handler.class) | |
49 public static class ShadowHander extends org.robolectric.shadows.ShadowHandl er { | |
50 @Override | |
51 @Implementation | |
52 public boolean post(Runnable r) { | |
53 boolean result = super.post(r); | |
54 // If the test wants to wait it should initialize sLatch before post is called. | |
55 if (sLatch != null) sLatch.countDown(); | |
56 return result; | |
57 } | |
58 } | |
59 | |
60 private SupervisedUserContentProvider mSupervisedUserContentProvider; | |
61 private Looper mNativeCallLooper; | |
62 | |
63 @Before | |
64 public void setUp() { | |
65 sLatch = null; | |
66 mNativeCallLooper = null; | |
67 mSupervisedUserContentProvider = Mockito.spy(new SupervisedUserContentPr ovider()); | |
68 mSupervisedUserContentProvider.setNativeSupervisedUserContentProviderFor Testing(1234L); | |
69 } | |
70 | |
71 @Test | |
72 public void testShouldProceed() throws InterruptedException { | |
73 // Runnable for test thread. | |
74 class TestRunnable implements Runnable { | |
75 private Pair<Boolean, String> mResult; | |
76 | |
77 @Override | |
78 public void run() { | |
79 this.mResult = mSupervisedUserContentProvider.shouldProceed("url "); | |
80 } | |
81 | |
82 public Pair<Boolean, String> getResult() { | |
83 return mResult; | |
84 } | |
85 } | |
86 // Mock the native call for a permitted URL | |
87 doAnswer(new Answer<Void>() { | |
88 | |
89 @Override | |
90 public Void answer(InvocationOnMock invocation) throws Throwable { | |
91 Object args[] = invocation.getArguments(); | |
92 mNativeCallLooper = Looper.myLooper(); | |
93 ((SupervisedUserContentProvider.SupervisedUserQueryReply) args[1 ]) | |
94 .onQueryComplete(true, null); | |
95 return null; | |
96 } | |
97 | |
98 }) | |
99 .when(mSupervisedUserContentProvider) | |
100 .nativeShouldProceed(anyLong(), | |
101 any(SupervisedUserContentProvider.SupervisedUserQueryRep ly.class), | |
102 anyString()); | |
103 TestRunnable r1 = new TestRunnable(); | |
104 // Because SupervisedUserContentProvider uses a CountDownLatch (which is a java.util | |
105 // class, so can't be shadowed or mocked) we need to make the calls to s houldProceed on a | |
106 // real thread. This can't be the main thread because Robolectric emulat es UI event handling | |
107 // on the main thread. | |
Bernhard Bauer
2015/12/17 11:13:21
We could actually make this single-threaded now. W
aberent
2015/12/17 14:59:08
Doesn't this just move the complexity around? Anyw
Bernhard Bauer
2015/12/17 15:18:51
Well, it would remove the complexity of having to
| |
108 Thread t1 = new Thread(r1); | |
109 sLatch = new CountDownLatch(1); | |
110 t1.start(); | |
111 // Wait for the event to be posted to the emulated UI thread. | |
112 sLatch.await(); | |
113 Robolectric.runUiThreadTasks(); | |
114 t1.join(); | |
115 verify(mSupervisedUserContentProvider) | |
116 .nativeShouldProceed(eq(1234L), | |
117 any(SupervisedUserContentProvider.SupervisedUserQueryRep ly.class), | |
118 eq("url")); | |
119 // Assert has to be on main thread for failures to cause test failure. | |
120 assertThat(r1.getResult(), is(new Pair<Boolean, String>(true, null))); | |
121 // Check that the native code was called on the right thread. | |
122 assertThat(mNativeCallLooper, is(Looper.getMainLooper())); | |
123 // Mock the native call for a forbidden URL | |
124 doAnswer(new Answer<Void>() { | |
125 | |
126 @Override | |
127 public Void answer(InvocationOnMock invocation) throws Throwable { | |
128 Object args[] = invocation.getArguments(); | |
129 mNativeCallLooper = Looper.myLooper(); | |
130 ((SupervisedUserContentProvider.SupervisedUserQueryReply) args[1 ]) | |
131 .onQueryComplete(false, "Hello"); | |
132 return null; | |
133 } | |
134 | |
135 }) | |
136 .when(mSupervisedUserContentProvider) | |
137 .nativeShouldProceed(anyLong(), | |
138 any(SupervisedUserContentProvider.SupervisedUserQueryRep ly.class), | |
139 anyString()); | |
140 TestRunnable r2 = new TestRunnable(); | |
141 // Create a new thread for the second call | |
142 Thread t2 = new Thread(r2); | |
143 sLatch = new CountDownLatch(1); | |
144 t2.start(); | |
145 // Wait for the event to be posted to the emulated UI thread. | |
146 sLatch.await(); | |
147 Robolectric.runUiThreadTasksIncludingDelayedTasks(); | |
148 t2.join(); | |
149 assertThat(r2.getResult(), is(new Pair<Boolean, String>(false, "Hello")) ); | |
150 // Check that the native code was called on the UI thread. | |
151 assertThat(mNativeCallLooper, is(Looper.getMainLooper())); | |
152 } | |
153 | |
154 @Test | |
155 public void testRequestInsert() throws InterruptedException { | |
156 // Runnable for test thread. | |
157 class TestRunnable implements Runnable { | |
158 private boolean mResult; | |
159 | |
160 @Override | |
161 public void run() { | |
162 this.mResult = mSupervisedUserContentProvider.requestInsert("url "); | |
163 } | |
164 | |
165 public boolean getResult() { | |
166 return mResult; | |
167 } | |
168 } | |
169 // Mock native call. | |
170 doAnswer(new Answer<Void>() { | |
171 | |
172 @Override | |
173 public Void answer(InvocationOnMock invocation) throws Throwable { | |
174 Object args[] = invocation.getArguments(); | |
175 mNativeCallLooper = Looper.myLooper(); | |
176 ((SupervisedUserContentProvider.SupervisedUserInsertReply) args[ 1]) | |
177 .onInsertRequestSendComplete(true); | |
178 return null; | |
179 } | |
180 | |
181 }) | |
182 .when(mSupervisedUserContentProvider) | |
183 .nativeRequestInsert(anyLong(), | |
184 any(SupervisedUserContentProvider.SupervisedUserInsertRe ply.class), | |
185 anyString()); | |
186 TestRunnable r1 = new TestRunnable(); | |
187 Thread t1 = new Thread(r1); | |
188 sLatch = new CountDownLatch(1); | |
189 t1.start(); | |
190 sLatch.await(); | |
191 Robolectric.runUiThreadTasks(); | |
192 t1.join(); | |
193 verify(mSupervisedUserContentProvider) | |
194 .nativeRequestInsert(eq(1234L), | |
195 any(SupervisedUserContentProvider.SupervisedUserInsertRe ply.class), | |
196 eq("url")); | |
197 assertThat(r1.getResult(), is(true)); | |
198 assertThat(mNativeCallLooper, is(Looper.getMainLooper())); | |
199 doAnswer(new Answer<Void>() { | |
200 | |
201 @Override | |
202 public Void answer(InvocationOnMock invocation) throws Throwable { | |
203 Object args[] = invocation.getArguments(); | |
204 mNativeCallLooper = Looper.myLooper(); | |
205 ((SupervisedUserContentProvider.SupervisedUserInsertReply) args[ 1]) | |
206 .onInsertRequestSendComplete(false); | |
207 return null; | |
208 } | |
209 | |
210 }) | |
211 .when(mSupervisedUserContentProvider) | |
212 .nativeRequestInsert(anyLong(), | |
213 any(SupervisedUserContentProvider.SupervisedUserInsertRe ply.class), | |
214 anyString()); | |
215 TestRunnable r2 = new TestRunnable(); | |
216 Thread t2 = new Thread(r2); | |
217 sLatch = new CountDownLatch(1); | |
218 t2.start(); | |
219 sLatch.await(); | |
220 Robolectric.runUiThreadTasks(); | |
221 t2.join(); | |
222 Robolectric.runUiThreadTasks(); | |
223 verify(mSupervisedUserContentProvider, times(2)) | |
224 .nativeRequestInsert(eq(1234L), | |
225 any(SupervisedUserContentProvider.SupervisedUserInsertRe ply.class), | |
226 eq("url")); | |
227 assertThat(r2.getResult(), is(false)); | |
228 assertThat(mNativeCallLooper, is(Looper.getMainLooper())); | |
229 } | |
230 } | |
OLD | NEW |