NetworkScoreServiceTest.java revision 3d18c621cbff73fb6fe4bf68ae55c17c8545d3e9
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_SSID"; 236 wifiConfiguration.BSSID = "testRequestRecommendation_resultReturned_BSSID"; 237 final RecommendationResult providerResult = RecommendationResult 238 .createConnectRecommendation(wifiConfiguration); 239 final Bundle bundle = new Bundle(); 240 bundle.putParcelable(EXTRA_RECOMMENDATION_RESULT, providerResult); 241 doAnswer(invocation -> { 242 bundle.putInt(EXTRA_SEQUENCE, invocation.getArgumentAt(2, int.class)); 243 invocation.getArgumentAt(1, IRemoteCallback.class).sendResult(bundle); 244 return null; 245 }).when(mRecommendationProvider) 246 .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class), 247 anyInt()); 248 249 final RecommendationResult result = 250 mNetworkScoreService.requestRecommendation(mRecommendationRequest); 251 assertNotNull(result); 252 assertEquals(providerResult.getWifiConfiguration().SSID, 253 result.getWifiConfiguration().SSID); 254 assertEquals(providerResult.getWifiConfiguration().BSSID, 255 result.getWifiConfiguration().BSSID); 256 } 257 258 @Test 259 public void testUpdateScores_notActiveScorer() { 260 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false); 261 262 try { 263 mNetworkScoreService.updateScores(new ScoredNetwork[0]); 264 fail("SecurityException expected"); 265 } catch (SecurityException e) { 266 // expected 267 } 268 } 269 270 @Test 271 public void testUpdateScores_oneRegisteredCache() throws RemoteException { 272 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true); 273 274 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, 275 mNetworkScoreCache, CACHE_FILTER_NONE); 276 277 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 278 279 verify(mNetworkScoreCache).updateScores(mScoredNetworkCaptor.capture()); 280 281 assertEquals(1, mScoredNetworkCaptor.getValue().size()); 282 assertEquals(SCORED_NETWORK, mScoredNetworkCaptor.getValue().get(0)); 283 } 284 285 @Test 286 public void testUpdateScores_twoRegisteredCaches() throws RemoteException { 287 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true); 288 289 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, 290 mNetworkScoreCache, CACHE_FILTER_NONE); 291 mNetworkScoreService.registerNetworkScoreCache( 292 NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE); 293 294 // updateScores should update both caches 295 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 296 297 verify(mNetworkScoreCache).updateScores(anyListOf(ScoredNetwork.class)); 298 verify(mNetworkScoreCache2).updateScores(anyListOf(ScoredNetwork.class)); 299 300 mNetworkScoreService.unregisterNetworkScoreCache( 301 NetworkKey.TYPE_WIFI, mNetworkScoreCache2); 302 303 // updateScores should only update the first cache since the 2nd has been unregistered 304 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 305 306 verify(mNetworkScoreCache, times(2)).updateScores(anyListOf(ScoredNetwork.class)); 307 308 mNetworkScoreService.unregisterNetworkScoreCache( 309 NetworkKey.TYPE_WIFI, mNetworkScoreCache); 310 311 // updateScores should not update any caches since they are both unregistered 312 mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); 313 314 // The register and unregister calls grab the binder from the score cache. 315 verify(mNetworkScoreCache, atLeastOnce()).asBinder(); 316 verify(mNetworkScoreCache2, atLeastOnce()).asBinder(); 317 verifyNoMoreInteractions(mNetworkScoreCache, mNetworkScoreCache2); 318 } 319 320 @Test 321 public void testClearScores_notActiveScorer_noBroadcastNetworkPermission() { 322 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false); 323 when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED)) 324 .thenReturn(PackageManager.PERMISSION_DENIED); 325 try { 326 mNetworkScoreService.clearScores(); 327 fail("SecurityException expected"); 328 } catch (SecurityException e) { 329 // expected 330 } 331 } 332 333 @Test 334 public void testClearScores_activeScorer_noBroadcastNetworkPermission() { 335 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true); 336 when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED)) 337 .thenReturn(PackageManager.PERMISSION_DENIED); 338 339 mNetworkScoreService.clearScores(); 340 } 341 342 @Test 343 public void testClearScores_activeScorer() throws RemoteException { 344 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true); 345 346 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, 347 CACHE_FILTER_NONE); 348 mNetworkScoreService.clearScores(); 349 350 verify(mNetworkScoreCache).clearScores(); 351 } 352 353 @Test 354 public void testClearScores_notActiveScorer_hasBroadcastNetworkPermission() 355 throws RemoteException { 356 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false); 357 when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED)) 358 .thenReturn(PackageManager.PERMISSION_GRANTED); 359 360 mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, 361 CACHE_FILTER_NONE); 362 mNetworkScoreService.clearScores(); 363 364 verify(mNetworkScoreCache).clearScores(); 365 } 366 367 @Test 368 public void testSetActiveScorer_noScoreNetworksPermission() { 369 doThrow(new SecurityException()).when(mContext) 370 .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString()); 371 372 try { 373 mNetworkScoreService.setActiveScorer(null); 374 fail("SecurityException expected"); 375 } catch (SecurityException e) { 376 // expected 377 } 378 } 379 380 @Test 381 public void testDisableScoring_notActiveScorer_noBroadcastNetworkPermission() { 382 when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false); 383 when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED)) 384 .thenReturn(PackageManager.PERMISSION_DENIED); 385 386 try { 387 mNetworkScoreService.disableScoring(); 388 fail("SecurityException expected"); 389 } catch (SecurityException e) { 390 // expected 391 } 392 } 393 394 @Test 395 public void testRegisterNetworkScoreCache_noBroadcastNetworkPermission() { 396 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 397 eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString()); 398 399 try { 400 mNetworkScoreService.registerNetworkScoreCache( 401 NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE); 402 fail("SecurityException expected"); 403 } catch (SecurityException e) { 404 // expected 405 } 406 } 407 408 @Test 409 public void testUnregisterNetworkScoreCache_noBroadcastNetworkPermission() { 410 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 411 eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString()); 412 413 try { 414 mNetworkScoreService.unregisterNetworkScoreCache( 415 NetworkKey.TYPE_WIFI, mNetworkScoreCache); 416 fail("SecurityException expected"); 417 } catch (SecurityException e) { 418 // expected 419 } 420 } 421 422 @Test 423 public void testDump_noDumpPermission() { 424 doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission( 425 eq(permission.DUMP), anyString()); 426 427 try { 428 mNetworkScoreService.dump( 429 new FileDescriptor(), new PrintWriter(new StringWriter()), new String[0]); 430 fail("SecurityException expected"); 431 } catch (SecurityException e) { 432 // expected 433 } 434 } 435 436 @Test 437 public void testDump_doesNotCrash() { 438 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER); 439 StringWriter stringWriter = new StringWriter(); 440 441 mNetworkScoreService.dump( 442 new FileDescriptor(), new PrintWriter(stringWriter), new String[0]); 443 444 assertFalse(stringWriter.toString().isEmpty()); 445 } 446 447 // "injects" the mock INetworkRecommendationProvider into the NetworkScoreService. 448 private void injectProvider() { 449 final ComponentName componentName = new ComponentName(NEW_SCORER.packageName, 450 NEW_SCORER.recommendationServiceClassName); 451 when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER); 452 when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(), 453 isA(UserHandle.class))).thenAnswer(new Answer<Boolean>() { 454 @Override 455 public Boolean answer(InvocationOnMock invocation) throws Throwable { 456 IBinder mockBinder = mock(IBinder.class); 457 when(mockBinder.queryLocalInterface(anyString())) 458 .thenReturn(mRecommendationProvider); 459 invocation.getArgumentAt(1, ServiceConnection.class) 460 .onServiceConnected(componentName, mockBinder); 461 return true; 462 } 463 }); 464 mNetworkScoreService.systemRunning(); 465 } 466} 467