NetworkScoreServiceTest.java revision 36d4c48496cc35c5d4f07e1793cedf4249d85826
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server; 18 19import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT; 20import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE; 21import static android.net.NetworkScoreManager.CACHE_FILTER_NONE; 22 23import static junit.framework.Assert.assertEquals; 24import static junit.framework.Assert.assertFalse; 25import static junit.framework.Assert.assertNotNull; 26import static junit.framework.Assert.assertTrue; 27import static junit.framework.Assert.fail; 28 29import static org.mockito.Matchers.any; 30import static org.mockito.Matchers.anyInt; 31import static org.mockito.Matchers.anyListOf; 32import static org.mockito.Matchers.anyString; 33import static org.mockito.Matchers.eq; 34import static org.mockito.Matchers.isA; 35import static org.mockito.Mockito.atLeastOnce; 36import static org.mockito.Mockito.doAnswer; 37import static org.mockito.Mockito.doThrow; 38import static org.mockito.Mockito.mock; 39import static org.mockito.Mockito.times; 40import static org.mockito.Mockito.verify; 41import static org.mockito.Mockito.verifyNoMoreInteractions; 42import static org.mockito.Mockito.verifyZeroInteractions; 43import static org.mockito.Mockito.when; 44 45import android.Manifest.permission; 46import android.content.ComponentName; 47import android.content.ContentResolver; 48import android.content.Context; 49import android.content.Intent; 50import android.content.ServiceConnection; 51import android.content.pm.PackageManager; 52import android.content.res.Resources; 53import android.net.INetworkRecommendationProvider; 54import android.net.INetworkScoreCache; 55import android.net.NetworkKey; 56import android.net.NetworkScorerAppManager; 57import android.net.NetworkScorerAppManager.NetworkScorerAppData; 58import android.net.RecommendationRequest; 59import android.net.RecommendationResult; 60import android.net.ScoredNetwork; 61import android.net.WifiKey; 62import android.net.wifi.WifiConfiguration; 63import android.os.Bundle; 64import android.os.IBinder; 65import android.os.IRemoteCallback; 66import android.os.Looper; 67import android.os.RemoteException; 68import android.os.UserHandle; 69import android.support.test.InstrumentationRegistry; 70import android.support.test.filters.MediumTest; 71import android.support.test.runner.AndroidJUnit4; 72 73import com.android.server.devicepolicy.MockUtils; 74 75import org.junit.Before; 76import org.junit.Test; 77import org.junit.runner.RunWith; 78import org.mockito.ArgumentCaptor; 79import org.mockito.Captor; 80import org.mockito.Mock; 81import org.mockito.MockitoAnnotations; 82import org.mockito.invocation.InvocationOnMock; 83import org.mockito.stubbing.Answer; 84 85import java.io.FileDescriptor; 86import java.io.PrintWriter; 87import java.io.StringWriter; 88import java.util.List; 89 90/** 91 * Tests for {@link NetworkScoreService}. 92 */ 93@RunWith(AndroidJUnit4.class) 94@MediumTest 95public class NetworkScoreServiceTest { 96 private static final ScoredNetwork SCORED_NETWORK = 97 new ScoredNetwork(new NetworkKey(new WifiKey("\"ssid\"", "00:00:00:00:00:00")), 98 null /* rssiCurve*/); 99 private static final NetworkScorerAppData NEW_SCORER = 100 new NetworkScorerAppData("newPackageName", 1, "newScoringServiceClass"); 101 102 @Mock private PackageManager mPackageManager; 103 @Mock private NetworkScorerAppManager mNetworkScorerAppManager; 104 @Mock private Context mContext; 105 @Mock private Resources mResources; 106 @Mock private INetworkScoreCache.Stub mNetworkScoreCache, mNetworkScoreCache2; 107 @Mock private IBinder mIBinder, mIBinder2; 108 @Mock private INetworkRecommendationProvider mRecommendationProvider; 109 @Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor; 110 111 private ContentResolver mContentResolver; 112 private NetworkScoreService mNetworkScoreService; 113 private RecommendationRequest mRecommendationRequest; 114 115 @Before 116 public void setUp() throws Exception { 117 MockitoAnnotations.initMocks(this); 118 when(mNetworkScoreCache.asBinder()).thenReturn(mIBinder); 119 when(mNetworkScoreCache2.asBinder()).thenReturn(mIBinder2); 120 mContentResolver = InstrumentationRegistry.getContext().getContentResolver(); 121 when(mContext.getContentResolver()).thenReturn(mContentResolver); 122 when(mContext.getResources()).thenReturn(mResources); 123 mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager); 124 WifiConfiguration configuration = new WifiConfiguration(); 125 mRecommendationRequest = new RecommendationRequest.Builder() 126 .setCurrentRecommendedWifiConfig(configuration).build(); 127 } 128 129 @Test 130 public void testSystemRunning() { 131 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER); 132 133 mNetworkScoreService.systemRunning(); 134 135 verify(mContext).bindServiceAsUser(MockUtils.checkIntent(new Intent().setComponent( 136 new ComponentName(NEW_SCORER.packageName, 137 NEW_SCORER.recommendationServiceClassName))), 138 any(ServiceConnection.class), 139 eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE), 140 eq(UserHandle.SYSTEM)); 141 } 142 143 @Test 144 public void testRequestScores_noPermission() throws Exception { 145 doThrow(new SecurityException()).when(mContext) 146 .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED), 147 anyString()); 148 try { 149 mNetworkScoreService.requestScores(null); 150 fail("BROADCAST_NETWORK_PRIVILEGED not enforced."); 151 } catch (SecurityException e) { 152 // expected 153 } 154 } 155 156 @Test 157 public void testRequestScores_providerNotConnected() throws Exception { 158 assertFalse(mNetworkScoreService.requestScores(new NetworkKey[0])); 159 verifyZeroInteractions(mRecommendationProvider); 160 } 161 162 @Test 163 public void testRequestScores_providerThrowsRemoteException() throws Exception { 164 injectProvider(); 165 doThrow(new RemoteException()).when(mRecommendationProvider) 166 .requestScores(any(NetworkKey[].class)); 167 168 assertFalse(mNetworkScoreService.requestScores(new NetworkKey[0])); 169 } 170 171 @Test 172 public void testRequestScores_providerAvailable() throws Exception { 173 injectProvider(); 174 175 final NetworkKey[] networks = new NetworkKey[0]; 176 assertTrue(mNetworkScoreService.requestScores(networks)); 177 verify(mRecommendationProvider).requestScores(networks); 178 } 179 180 @Test 181 public void testRequestRecommendation_noPermission() throws Exception { 182 doThrow(new SecurityException()).when(mContext) 183 .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED), 184 anyString()); 185 try { 186 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 187 fail("BROADCAST_NETWORK_PRIVILEGED not enforced."); 188 } catch (SecurityException e) { 189 // expected 190 } 191 } 192 193 @Test 194 public void testRequestRecommendation_mainThread() throws Exception { 195 when(mContext.getMainLooper()).thenReturn(Looper.myLooper()); 196 try { 197 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 198 fail("requestRecommendation run on main thread."); 199 } catch (RuntimeException e) { 200 // expected 201 } 202 } 203 204 @Test 205 public void testRequestRecommendation_providerNotConnected() throws Exception { 206 when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); 207 208 final RecommendationResult result = 209 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 210 assertNotNull(result); 211 assertEquals(mRecommendationRequest.getCurrentSelectedConfig(), 212 result.getWifiConfiguration()); 213 } 214 215 @Test 216 public void testRequestRecommendation_providerThrowsRemoteException() throws Exception { 217 injectProvider(); 218 when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); 219 doThrow(new RemoteException()).when(mRecommendationProvider) 220 .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class), 221 anyInt()); 222 223 final RecommendationResult result = 224 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 225 assertNotNull(result); 226 assertEquals(mRecommendationRequest.getCurrentSelectedConfig(), 227 result.getWifiConfiguration()); 228 } 229 230 @Test 231 public void testRequestRecommendation_resultReturned() throws Exception { 232 injectProvider(); 233 when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper()); 234 final WifiConfiguration wifiConfiguration = new WifiConfiguration(); 235 wifiConfiguration.SSID = "testRequestRecommendation_resultReturned"; 236 final RecommendationResult providerResult = 237 new RecommendationResult(wifiConfiguration); 238 final Bundle bundle = new Bundle(); 239 bundle.putParcelable(EXTRA_RECOMMENDATION_RESULT, providerResult); 240 doAnswer(invocation -> { 241 bundle.putInt(EXTRA_SEQUENCE, invocation.getArgumentAt(2, int.class)); 242 invocation.getArgumentAt(1, IRemoteCallback.class).sendResult(bundle); 243 return null; 244 }).when(mRecommendationProvider) 245 .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class), 246 anyInt()); 247 248 final RecommendationResult result = 249 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 250 assertNotNull(result); 251 assertEquals(providerResult.getWifiConfiguration().SSID, 252 result.getWifiConfiguration().SSID); 253 } 254 255 @Test 256 public void testUpdateScores_notActiveScorer() { 257 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false); 258 259 try { 260 mNetworkScoreService.updateScores(new ScoredNetwork[0]); 261 fail("SecurityException expected"); 262 } catch (SecurityException e) { 263 // expected 264 } 265 } 266 267 @Test 268 public void testUpdateScores_oneRegisteredCache() throws RemoteException { 269 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true); 270 271 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, 272 mNetworkScoreCache, CACHE_FILTER_NONE); 273 274 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 275 276 verify(mNetworkScoreCache).updateScores(mScoredNetworkCaptor.capture()); 277 278 assertEquals(1, mScoredNetworkCaptor.getValue().size()); 279 assertEquals(SCORED_NETWORK, mScoredNetworkCaptor.getValue().get(0)); 280 } 281 282 @Test 283 public void testUpdateScores_twoRegisteredCaches() throws RemoteException { 284 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true); 285 286 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, 287 mNetworkScoreCache, CACHE_FILTER_NONE); 288 mNetworkScoreService.registerNetworkScoreCache( 289 NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE); 290 291 // updateScores should update both caches 292 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 293 294 verify(mNetworkScoreCache).updateScores(anyListOf(ScoredNetwork.class)); 295 verify(mNetworkScoreCache2).updateScores(anyListOf(ScoredNetwork.class)); 296 297 mNetworkScoreService.unregisterNetworkScoreCache( 298 NetworkKey.TYPE_WIFI, mNetworkScoreCache2); 299 300 // updateScores should only update the first cache since the 2nd has been unregistered 301 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 302 303 verify(mNetworkScoreCache, times(2)).updateScores(anyListOf(ScoredNetwork.class)); 304 305 mNetworkScoreService.unregisterNetworkScoreCache( 306 NetworkKey.TYPE_WIFI, mNetworkScoreCache); 307 308 // updateScores should not update any caches since they are both unregistered 309 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 310 311 // The register and unregister calls grab the binder from the score cache. 312 verify(mNetworkScoreCache, atLeastOnce()).asBinder(); 313 verify(mNetworkScoreCache2, atLeastOnce()).asBinder(); 314 verifyNoMoreInteractions(mNetworkScoreCache, mNetworkScoreCache2); 315 } 316 317 @Test 318 public void testClearScores_notActiveScorer_noBroadcastNetworkPermission() { 319 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false); 320 when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED)) 321 .thenReturn(PackageManager.PERMISSION_DENIED); 322 try { 323 mNetworkScoreService.clearScores(); 324 fail("SecurityException expected"); 325 } catch (SecurityException e) { 326 // expected 327 } 328 } 329 330 @Test 331 public void testClearScores_activeScorer_noBroadcastNetworkPermission() { 332 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true); 333 when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED)) 334 .thenReturn(PackageManager.PERMISSION_DENIED); 335 336 mNetworkScoreService.clearScores(); 337 } 338 339 @Test 340 public void testClearScores_activeScorer() throws RemoteException { 341 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true); 342 343 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, 344 CACHE_FILTER_NONE); 345 mNetworkScoreService.clearScores(); 346 347 verify(mNetworkScoreCache).clearScores(); 348 } 349 350 @Test 351 public void testClearScores_notActiveScorer_hasBroadcastNetworkPermission() 352 throws RemoteException { 353 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false); 354 when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED)) 355 .thenReturn(PackageManager.PERMISSION_GRANTED); 356 357 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, 358 CACHE_FILTER_NONE); 359 mNetworkScoreService.clearScores(); 360 361 verify(mNetworkScoreCache).clearScores(); 362 } 363 364 @Test 365 public void testSetActiveScorer_noScoreNetworksPermission() { 366 doThrow(new SecurityException()).when(mContext) 367 .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString()); 368 369 try { 370 mNetworkScoreService.setActiveScorer(null); 371 fail("SecurityException expected"); 372 } catch (SecurityException e) { 373 // expected 374 } 375 } 376 377 @Test 378 public void testDisableScoring_notActiveScorer_noBroadcastNetworkPermission() { 379 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false); 380 when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED)) 381 .thenReturn(PackageManager.PERMISSION_DENIED); 382 383 try { 384 mNetworkScoreService.disableScoring(); 385 fail("SecurityException expected"); 386 } catch (SecurityException e) { 387 // expected 388 } 389 } 390 391 @Test 392 public void testRegisterNetworkScoreCache_noBroadcastNetworkPermission() { 393 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 394 eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString()); 395 396 try { 397 mNetworkScoreService.registerNetworkScoreCache( 398 NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE); 399 fail("SecurityException expected"); 400 } catch (SecurityException e) { 401 // expected 402 } 403 } 404 405 @Test 406 public void testUnregisterNetworkScoreCache_noBroadcastNetworkPermission() { 407 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 408 eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString()); 409 410 try { 411 mNetworkScoreService.unregisterNetworkScoreCache( 412 NetworkKey.TYPE_WIFI, mNetworkScoreCache); 413 fail("SecurityException expected"); 414 } catch (SecurityException e) { 415 // expected 416 } 417 } 418 419 @Test 420 public void testDump_noDumpPermission() { 421 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 422 eq(permission.DUMP), anyString()); 423 424 try { 425 mNetworkScoreService.dump( 426 new FileDescriptor(), new PrintWriter(new StringWriter()), new String[0]); 427 fail("SecurityException expected"); 428 } catch (SecurityException e) { 429 // expected 430 } 431 } 432 433 @Test 434 public void testDump_doesNotCrash() { 435 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER); 436 StringWriter stringWriter = new StringWriter(); 437 438 mNetworkScoreService.dump( 439 new FileDescriptor(), new PrintWriter(stringWriter), new String[0]); 440 441 assertFalse(stringWriter.toString().isEmpty()); 442 } 443 444 // "injects" the mock INetworkRecommendationProvider into the NetworkScoreService. 445 private void injectProvider() { 446 final ComponentName componentName = new ComponentName(NEW_SCORER.packageName, 447 NEW_SCORER.recommendationServiceClassName); 448 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER); 449 when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(), 450 isA(UserHandle.class))).thenAnswer(new Answer<Boolean>() { 451 @Override 452 public Boolean answer(InvocationOnMock invocation) throws Throwable { 453 IBinder mockBinder = mock(IBinder.class); 454 when(mockBinder.queryLocalInterface(anyString())) 455 .thenReturn(mRecommendationProvider); 456 invocation.getArgumentAt(1, ServiceConnection.class) 457 .onServiceConnected(componentName, mockBinder); 458 return true; 459 } 460 }); 461 mNetworkScoreService.systemRunning(); 462 } 463} 464