• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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