Chromium Code Reviews| 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 |