1 /* 2 * Copyright (C) 2021 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 17 package com.android.server.vcn.routeselection; 18 19 import static com.android.server.vcn.VcnTestUtils.setupSystemService; 20 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT; 21 import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertNotEquals; 25 import static org.mockito.ArgumentMatchers.any; 26 import static org.mockito.ArgumentMatchers.eq; 27 import static org.mockito.Mockito.any; 28 import static org.mockito.Mockito.doNothing; 29 import static org.mockito.Mockito.eq; 30 import static org.mockito.Mockito.mock; 31 import static org.mockito.Mockito.reset; 32 import static org.mockito.Mockito.spy; 33 import static org.mockito.Mockito.times; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.verifyNoMoreInteractions; 36 import static org.mockito.Mockito.when; 37 38 import android.content.Context; 39 import android.net.ConnectivityManager; 40 import android.net.LinkProperties; 41 import android.net.Network; 42 import android.net.NetworkCapabilities; 43 import android.net.NetworkRequest; 44 import android.net.TelephonyNetworkSpecifier; 45 import android.net.vcn.VcnGatewayConnectionConfigTest; 46 import android.os.ParcelUuid; 47 import android.os.test.TestLooper; 48 import android.telephony.CarrierConfigManager; 49 import android.telephony.SubscriptionInfo; 50 import android.telephony.TelephonyManager; 51 import android.util.ArraySet; 52 53 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; 54 import com.android.server.vcn.VcnContext; 55 import com.android.server.vcn.VcnNetworkProvider; 56 import com.android.server.vcn.routeselection.UnderlyingNetworkController.NetworkBringupCallback; 57 import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; 58 import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener; 59 60 import org.junit.Before; 61 import org.junit.Test; 62 import org.mockito.ArgumentCaptor; 63 import org.mockito.Captor; 64 import org.mockito.Mock; 65 import org.mockito.MockitoAnnotations; 66 67 import java.util.Arrays; 68 import java.util.Set; 69 import java.util.UUID; 70 71 public class UnderlyingNetworkControllerTest { 72 private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); 73 private static final int INITIAL_SUB_ID_1 = 1; 74 private static final int INITIAL_SUB_ID_2 = 2; 75 private static final int UPDATED_SUB_ID = 3; 76 77 private static final Set<Integer> INITIAL_SUB_IDS = 78 new ArraySet<>(Arrays.asList(INITIAL_SUB_ID_1, INITIAL_SUB_ID_2)); 79 private static final Set<Integer> UPDATED_SUB_IDS = 80 new ArraySet<>(Arrays.asList(UPDATED_SUB_ID)); 81 82 private static final NetworkCapabilities INITIAL_NETWORK_CAPABILITIES = 83 new NetworkCapabilities.Builder() 84 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 85 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 86 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) 87 .build(); 88 private static final NetworkCapabilities SUSPENDED_NETWORK_CAPABILITIES = 89 new NetworkCapabilities.Builder(INITIAL_NETWORK_CAPABILITIES) 90 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 91 .build(); 92 private static final NetworkCapabilities UPDATED_NETWORK_CAPABILITIES = 93 new NetworkCapabilities.Builder() 94 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 95 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 96 .build(); 97 98 private static final LinkProperties INITIAL_LINK_PROPERTIES = 99 getLinkPropertiesWithName("initial_iface"); 100 private static final LinkProperties UPDATED_LINK_PROPERTIES = 101 getLinkPropertiesWithName("updated_iface"); 102 103 @Mock private Context mContext; 104 @Mock private VcnNetworkProvider mVcnNetworkProvider; 105 @Mock private ConnectivityManager mConnectivityManager; 106 @Mock private TelephonyManager mTelephonyManager; 107 @Mock private CarrierConfigManager mCarrierConfigManager; 108 @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; 109 @Mock private UnderlyingNetworkControllerCallback mNetworkControllerCb; 110 @Mock private Network mNetwork; 111 112 @Captor private ArgumentCaptor<UnderlyingNetworkListener> mUnderlyingNetworkListenerCaptor; 113 114 private TestLooper mTestLooper; 115 private VcnContext mVcnContext; 116 private UnderlyingNetworkController mUnderlyingNetworkController; 117 118 @Before setUp()119 public void setUp() { 120 MockitoAnnotations.initMocks(this); 121 122 mTestLooper = new TestLooper(); 123 mVcnContext = 124 spy( 125 new VcnContext( 126 mContext, 127 mTestLooper.getLooper(), 128 mVcnNetworkProvider, 129 false /* isInTestMode */)); 130 resetVcnContext(); 131 132 setupSystemService( 133 mContext, 134 mConnectivityManager, 135 Context.CONNECTIVITY_SERVICE, 136 ConnectivityManager.class); 137 setupSystemService( 138 mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); 139 setupSystemService( 140 mContext, 141 mCarrierConfigManager, 142 Context.CARRIER_CONFIG_SERVICE, 143 CarrierConfigManager.class); 144 145 when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS); 146 147 mUnderlyingNetworkController = 148 new UnderlyingNetworkController( 149 mVcnContext, 150 VcnGatewayConnectionConfigTest.buildTestConfig(), 151 SUB_GROUP, 152 mSubscriptionSnapshot, 153 mNetworkControllerCb); 154 } 155 resetVcnContext()156 private void resetVcnContext() { 157 reset(mVcnContext); 158 doNothing().when(mVcnContext).ensureRunningOnLooperThread(); 159 } 160 161 // Package private for use in NetworkPriorityClassifierTest getLinkPropertiesWithName(String iface)162 static LinkProperties getLinkPropertiesWithName(String iface) { 163 LinkProperties linkProperties = new LinkProperties(); 164 linkProperties.setInterfaceName(iface); 165 return linkProperties; 166 } 167 getSubscriptionInfoForSubId(int subId)168 private SubscriptionInfo getSubscriptionInfoForSubId(int subId) { 169 SubscriptionInfo subInfo = mock(SubscriptionInfo.class); 170 when(subInfo.getSubscriptionId()).thenReturn(subId); 171 return subInfo; 172 } 173 174 @Test testNetworkCallbacksRegisteredOnStartup()175 public void testNetworkCallbacksRegisteredOnStartup() { 176 verifyNetworkRequestsRegistered(INITIAL_SUB_IDS); 177 } 178 179 @Test testNetworkCallbacksRegisteredOnStartupForTestMode()180 public void testNetworkCallbacksRegisteredOnStartupForTestMode() { 181 final ConnectivityManager cm = mock(ConnectivityManager.class); 182 setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); 183 final VcnContext vcnContext = 184 new VcnContext( 185 mContext, 186 mTestLooper.getLooper(), 187 mVcnNetworkProvider, 188 true /* isInTestMode */); 189 190 new UnderlyingNetworkController( 191 vcnContext, 192 VcnGatewayConnectionConfigTest.buildTestConfig(), 193 SUB_GROUP, 194 mSubscriptionSnapshot, 195 mNetworkControllerCb); 196 197 verify(cm) 198 .registerNetworkCallback( 199 eq(getTestNetworkRequest(INITIAL_SUB_IDS)), 200 any(UnderlyingNetworkListener.class), 201 any()); 202 } 203 verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds)204 private void verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds) { 205 verify(mConnectivityManager) 206 .requestBackgroundNetwork( 207 eq(getWifiRequest(expectedSubIds)), 208 any(NetworkBringupCallback.class), 209 any()); 210 for (final int subId : expectedSubIds) { 211 verify(mConnectivityManager) 212 .requestBackgroundNetwork( 213 eq(getCellRequestForSubId(subId)), 214 any(NetworkBringupCallback.class), any()); 215 } 216 217 verify(mConnectivityManager) 218 .registerNetworkCallback( 219 eq(getRouteSelectionRequest(expectedSubIds)), 220 any(UnderlyingNetworkListener.class), 221 any()); 222 verify(mConnectivityManager) 223 .registerNetworkCallback( 224 eq(getWifiEntryRssiThresholdRequest(expectedSubIds)), 225 any(NetworkBringupCallback.class), 226 any()); 227 verify(mConnectivityManager) 228 .registerNetworkCallback( 229 eq(getWifiExitRssiThresholdRequest(expectedSubIds)), 230 any(NetworkBringupCallback.class), 231 any()); 232 } 233 234 @Test testUpdateSubscriptionSnapshot()235 public void testUpdateSubscriptionSnapshot() { 236 // Verify initial cell background requests filed 237 verifyNetworkRequestsRegistered(INITIAL_SUB_IDS); 238 239 TelephonySubscriptionSnapshot subscriptionUpdate = 240 mock(TelephonySubscriptionSnapshot.class); 241 when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS); 242 243 mUnderlyingNetworkController.updateSubscriptionSnapshot(subscriptionUpdate); 244 245 // verify that initially-filed bringup requests are unregistered (cell + wifi) 246 verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 3)) 247 .unregisterNetworkCallback(any(NetworkBringupCallback.class)); 248 verify(mConnectivityManager) 249 .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); 250 verifyNetworkRequestsRegistered(UPDATED_SUB_IDS); 251 } 252 getWifiRequest(Set<Integer> netCapsSubIds)253 private NetworkRequest getWifiRequest(Set<Integer> netCapsSubIds) { 254 return getExpectedRequestBase() 255 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) 256 .setSubscriptionIds(netCapsSubIds) 257 .build(); 258 } 259 getWifiEntryRssiThresholdRequest(Set<Integer> netCapsSubIds)260 private NetworkRequest getWifiEntryRssiThresholdRequest(Set<Integer> netCapsSubIds) { 261 // TODO (b/187991063): Add tests for carrier-config based thresholds 262 return getExpectedRequestBase() 263 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) 264 .setSubscriptionIds(netCapsSubIds) 265 .setSignalStrength(WIFI_ENTRY_RSSI_THRESHOLD_DEFAULT) 266 .build(); 267 } 268 getWifiExitRssiThresholdRequest(Set<Integer> netCapsSubIds)269 private NetworkRequest getWifiExitRssiThresholdRequest(Set<Integer> netCapsSubIds) { 270 // TODO (b/187991063): Add tests for carrier-config based thresholds 271 return getExpectedRequestBase() 272 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) 273 .setSubscriptionIds(netCapsSubIds) 274 .setSignalStrength(WIFI_EXIT_RSSI_THRESHOLD_DEFAULT) 275 .build(); 276 } 277 getCellRequestForSubId(int subId)278 private NetworkRequest getCellRequestForSubId(int subId) { 279 return getExpectedRequestBase() 280 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 281 .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) 282 .build(); 283 } 284 getRouteSelectionRequest(Set<Integer> netCapsSubIds)285 private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) { 286 return getExpectedRequestBase() 287 .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) 288 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 289 .setSubscriptionIds(netCapsSubIds) 290 .build(); 291 } 292 getTestNetworkRequest(Set<Integer> netCapsSubIds)293 private NetworkRequest getTestNetworkRequest(Set<Integer> netCapsSubIds) { 294 return new NetworkRequest.Builder() 295 .clearCapabilities() 296 .addTransportType(NetworkCapabilities.TRANSPORT_TEST) 297 .setSubscriptionIds(netCapsSubIds) 298 .build(); 299 } 300 getExpectedRequestBase()301 private NetworkRequest.Builder getExpectedRequestBase() { 302 final NetworkRequest.Builder builder = 303 new NetworkRequest.Builder() 304 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 305 .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) 306 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 307 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); 308 309 return builder; 310 } 311 312 @Test testTeardown()313 public void testTeardown() { 314 mUnderlyingNetworkController.teardown(); 315 316 // Expect 5 NetworkBringupCallbacks to be unregistered: 1 for WiFi, 2 for Cellular (1x for 317 // each subId), and 1 for each of the Wifi signal strength thresholds 318 verify(mConnectivityManager, times(5)) 319 .unregisterNetworkCallback(any(NetworkBringupCallback.class)); 320 verify(mConnectivityManager) 321 .unregisterNetworkCallback(any(UnderlyingNetworkListener.class)); 322 } 323 324 @Test testUnderlyingNetworkRecordEquals()325 public void testUnderlyingNetworkRecordEquals() { 326 UnderlyingNetworkRecord recordA = 327 new UnderlyingNetworkRecord( 328 mNetwork, 329 INITIAL_NETWORK_CAPABILITIES, 330 INITIAL_LINK_PROPERTIES, 331 false /* isBlocked */); 332 UnderlyingNetworkRecord recordB = 333 new UnderlyingNetworkRecord( 334 mNetwork, 335 INITIAL_NETWORK_CAPABILITIES, 336 INITIAL_LINK_PROPERTIES, 337 false /* isBlocked */); 338 UnderlyingNetworkRecord recordC = 339 new UnderlyingNetworkRecord( 340 mNetwork, 341 UPDATED_NETWORK_CAPABILITIES, 342 UPDATED_LINK_PROPERTIES, 343 false /* isBlocked */); 344 345 assertEquals(recordA, recordB); 346 assertNotEquals(recordA, recordC); 347 } 348 349 @Test testRecordTrackerCallbackNotifiedForNetworkChange()350 public void testRecordTrackerCallbackNotifiedForNetworkChange() { 351 verifyRegistrationOnAvailableAndGetCallback(); 352 } 353 verifyRegistrationOnAvailableAndGetCallback()354 private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() { 355 return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); 356 } 357 buildResponseNwCaps( NetworkCapabilities requestNetworkCaps, Set<Integer> netCapsSubIds)358 private static NetworkCapabilities buildResponseNwCaps( 359 NetworkCapabilities requestNetworkCaps, Set<Integer> netCapsSubIds) { 360 final TelephonyNetworkSpecifier telephonyNetworkSpecifier = 361 new TelephonyNetworkSpecifier.Builder() 362 .setSubscriptionId(netCapsSubIds.iterator().next()) 363 .build(); 364 return new NetworkCapabilities.Builder(requestNetworkCaps) 365 .setNetworkSpecifier(telephonyNetworkSpecifier) 366 .build(); 367 } 368 verifyRegistrationOnAvailableAndGetCallback( NetworkCapabilities networkCapabilities)369 private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback( 370 NetworkCapabilities networkCapabilities) { 371 verify(mConnectivityManager) 372 .registerNetworkCallback( 373 eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), 374 mUnderlyingNetworkListenerCaptor.capture(), 375 any()); 376 377 UnderlyingNetworkListener cb = mUnderlyingNetworkListenerCaptor.getValue(); 378 cb.onAvailable(mNetwork); 379 380 final NetworkCapabilities responseNetworkCaps = 381 buildResponseNwCaps(networkCapabilities, INITIAL_SUB_IDS); 382 cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); 383 cb.onLinkPropertiesChanged(mNetwork, INITIAL_LINK_PROPERTIES); 384 cb.onBlockedStatusChanged(mNetwork, false /* isFalse */); 385 386 UnderlyingNetworkRecord expectedRecord = 387 new UnderlyingNetworkRecord( 388 mNetwork, 389 responseNetworkCaps, 390 INITIAL_LINK_PROPERTIES, 391 false /* isBlocked */); 392 verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); 393 return cb; 394 } 395 396 @Test testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange()397 public void testRecordTrackerCallbackNotifiedForNetworkCapabilitiesChange() { 398 UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); 399 400 final NetworkCapabilities responseNetworkCaps = 401 buildResponseNwCaps(UPDATED_NETWORK_CAPABILITIES, UPDATED_SUB_IDS); 402 cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); 403 404 UnderlyingNetworkRecord expectedRecord = 405 new UnderlyingNetworkRecord( 406 mNetwork, 407 responseNetworkCaps, 408 INITIAL_LINK_PROPERTIES, 409 false /* isBlocked */); 410 verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); 411 } 412 413 @Test testRecordTrackerCallbackNotifiedForLinkPropertiesChange()414 public void testRecordTrackerCallbackNotifiedForLinkPropertiesChange() { 415 UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); 416 417 cb.onLinkPropertiesChanged(mNetwork, UPDATED_LINK_PROPERTIES); 418 419 UnderlyingNetworkRecord expectedRecord = 420 new UnderlyingNetworkRecord( 421 mNetwork, 422 buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS), 423 UPDATED_LINK_PROPERTIES, 424 false /* isBlocked */); 425 verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); 426 } 427 428 @Test testRecordTrackerCallbackNotifiedForNetworkSuspended()429 public void testRecordTrackerCallbackNotifiedForNetworkSuspended() { 430 UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); 431 432 final NetworkCapabilities responseNetworkCaps = 433 buildResponseNwCaps(SUSPENDED_NETWORK_CAPABILITIES, UPDATED_SUB_IDS); 434 cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); 435 436 UnderlyingNetworkRecord expectedRecord = 437 new UnderlyingNetworkRecord( 438 mNetwork, 439 responseNetworkCaps, 440 INITIAL_LINK_PROPERTIES, 441 false /* isBlocked */); 442 verify(mNetworkControllerCb, times(1)) 443 .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); 444 // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't 445 // change. 446 cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); 447 verify(mNetworkControllerCb, times(1)) 448 .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); 449 } 450 451 @Test testRecordTrackerCallbackNotifiedForNetworkResumed()452 public void testRecordTrackerCallbackNotifiedForNetworkResumed() { 453 UnderlyingNetworkListener cb = 454 verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES); 455 456 final NetworkCapabilities responseNetworkCaps = 457 buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS); 458 cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); 459 460 UnderlyingNetworkRecord expectedRecord = 461 new UnderlyingNetworkRecord( 462 mNetwork, 463 responseNetworkCaps, 464 INITIAL_LINK_PROPERTIES, 465 false /* isBlocked */); 466 verify(mNetworkControllerCb, times(1)) 467 .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); 468 // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't 469 // change. 470 cb.onCapabilitiesChanged(mNetwork, responseNetworkCaps); 471 verify(mNetworkControllerCb, times(1)) 472 .onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); 473 } 474 475 @Test testRecordTrackerCallbackNotifiedForBlocked()476 public void testRecordTrackerCallbackNotifiedForBlocked() { 477 UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); 478 479 cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); 480 481 UnderlyingNetworkRecord expectedRecord = 482 new UnderlyingNetworkRecord( 483 mNetwork, 484 buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS), 485 INITIAL_LINK_PROPERTIES, 486 true /* isBlocked */); 487 verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord)); 488 } 489 490 @Test testRecordTrackerCallbackNotifiedForNetworkLoss()491 public void testRecordTrackerCallbackNotifiedForNetworkLoss() { 492 UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); 493 494 cb.onLost(mNetwork); 495 496 verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null); 497 } 498 499 @Test testRecordTrackerCallbackIgnoresDuplicateRecord()500 public void testRecordTrackerCallbackIgnoresDuplicateRecord() { 501 UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); 502 503 cb.onCapabilitiesChanged( 504 mNetwork, buildResponseNwCaps(INITIAL_NETWORK_CAPABILITIES, INITIAL_SUB_IDS)); 505 506 // Verify no more calls to the UnderlyingNetworkControllerCallback when the 507 // UnderlyingNetworkRecord does not actually change 508 verifyNoMoreInteractions(mNetworkControllerCb); 509 } 510 511 @Test testRecordTrackerCallbackNotifiedAfterTeardown()512 public void testRecordTrackerCallbackNotifiedAfterTeardown() { 513 UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); 514 mUnderlyingNetworkController.teardown(); 515 516 cb.onCapabilitiesChanged( 517 mNetwork, buildResponseNwCaps(UPDATED_NETWORK_CAPABILITIES, INITIAL_SUB_IDS)); 518 519 // Verify that the only call was during onAvailable() 520 verify(mNetworkControllerCb, times(1)).onSelectedUnderlyingNetworkChanged(any()); 521 } 522 523 // TODO (b/187991063): Add tests for network prioritization 524 } 525