1 /* 2 * Copyright (C) 2020 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.ethernet; 18 19 import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertFalse; 23 import static org.junit.Assert.assertNotSame; 24 import static org.junit.Assert.assertNull; 25 import static org.junit.Assert.assertThrows; 26 import static org.junit.Assert.assertTrue; 27 import static org.mockito.ArgumentMatchers.any; 28 import static org.mockito.ArgumentMatchers.anyString; 29 import static org.mockito.ArgumentMatchers.argThat; 30 import static org.mockito.ArgumentMatchers.eq; 31 import static org.mockito.ArgumentMatchers.same; 32 import static org.mockito.Mockito.clearInvocations; 33 import static org.mockito.Mockito.doAnswer; 34 import static org.mockito.Mockito.never; 35 import static org.mockito.Mockito.verify; 36 import static org.mockito.Mockito.when; 37 38 import android.annotation.NonNull; 39 import android.app.test.MockAnswerUtil.AnswerWithArguments; 40 import android.content.Context; 41 import android.content.res.Resources; 42 import android.net.ConnectivityManager; 43 import android.net.EthernetNetworkManagementException; 44 import android.net.EthernetNetworkSpecifier; 45 import android.net.INetworkInterfaceOutcomeReceiver; 46 import android.net.IpConfiguration; 47 import android.net.LinkAddress; 48 import android.net.LinkProperties; 49 import android.net.Network; 50 import android.net.NetworkAgentConfig; 51 import android.net.NetworkCapabilities; 52 import android.net.NetworkProvider; 53 import android.net.NetworkProvider.NetworkOfferCallback; 54 import android.net.NetworkRequest; 55 import android.net.StaticIpConfiguration; 56 import android.net.ip.IpClientCallbacks; 57 import android.net.ip.IpClientManager; 58 import android.os.Handler; 59 import android.os.IBinder; 60 import android.os.Looper; 61 import android.os.test.TestLooper; 62 63 import androidx.test.filters.SmallTest; 64 import androidx.test.runner.AndroidJUnit4; 65 66 import com.android.net.module.util.InterfaceParams; 67 import com.android.testutils.DevSdkIgnoreRule; 68 69 import org.junit.After; 70 import org.junit.Before; 71 import org.junit.Test; 72 import org.junit.runner.RunWith; 73 import org.mockito.ArgumentCaptor; 74 import org.mockito.Mock; 75 import org.mockito.MockitoAnnotations; 76 77 import java.util.Objects; 78 import java.util.concurrent.CompletableFuture; 79 import java.util.concurrent.ExecutionException; 80 import java.util.concurrent.TimeUnit; 81 82 @RunWith(AndroidJUnit4.class) 83 @SmallTest 84 public class EthernetNetworkFactoryTest { 85 private static final int TIMEOUT_MS = 2_000; 86 private static final String TEST_IFACE = "test123"; 87 private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null; 88 private static final String IP_ADDR = "192.0.2.2/25"; 89 private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR); 90 private static final String HW_ADDR = "01:02:03:04:05:06"; 91 private TestLooper mLooper; 92 private Handler mHandler; 93 private EthernetNetworkFactory mNetFactory = null; 94 private IpClientCallbacks mIpClientCallbacks; 95 private NetworkOfferCallback mNetworkOfferCallback; 96 private NetworkRequest mRequestToKeepNetworkUp; 97 @Mock private Context mContext; 98 @Mock private Resources mResources; 99 @Mock private EthernetNetworkFactory.Dependencies mDeps; 100 @Mock private IpClientManager mIpClient; 101 @Mock private EthernetNetworkAgent mNetworkAgent; 102 @Mock private InterfaceParams mInterfaceParams; 103 @Mock private Network mMockNetwork; 104 @Mock private NetworkProvider mNetworkProvider; 105 106 @Before setUp()107 public void setUp() throws Exception { 108 MockitoAnnotations.initMocks(this); 109 setupNetworkAgentMock(); 110 setupIpClientMock(); 111 setupContext(); 112 } 113 114 //TODO: Move away from usage of TestLooper in order to move this logic back into @Before. initEthernetNetworkFactory()115 private void initEthernetNetworkFactory() { 116 mLooper = new TestLooper(); 117 mHandler = new Handler(mLooper.getLooper()); 118 mNetFactory = new EthernetNetworkFactory(mHandler, mContext, mNetworkProvider, mDeps); 119 } 120 setupNetworkAgentMock()121 private void setupNetworkAgentMock() { 122 when(mDeps.makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any())) 123 .thenAnswer(new AnswerWithArguments() { 124 public EthernetNetworkAgent answer( 125 Context context, 126 Looper looper, 127 NetworkCapabilities nc, 128 LinkProperties lp, 129 NetworkAgentConfig config, 130 NetworkProvider provider, 131 EthernetNetworkAgent.Callbacks cb) { 132 when(mNetworkAgent.getCallbacks()).thenReturn(cb); 133 when(mNetworkAgent.getNetwork()) 134 .thenReturn(mMockNetwork); 135 return mNetworkAgent; 136 } 137 } 138 ); 139 } 140 setupIpClientMock()141 private void setupIpClientMock() throws Exception { 142 doAnswer(inv -> { 143 // these tests only support one concurrent IpClient, so make sure we do not accidentally 144 // create a mess. 145 assertNull("An IpClient has already been created.", mIpClientCallbacks); 146 147 mIpClientCallbacks = inv.getArgument(2); 148 mIpClientCallbacks.onIpClientCreated(null); 149 mLooper.dispatchAll(); 150 return null; 151 }).when(mDeps).makeIpClient(any(Context.class), anyString(), any()); 152 153 doAnswer(inv -> { 154 mIpClientCallbacks.onQuit(); 155 mLooper.dispatchAll(); 156 mIpClientCallbacks = null; 157 return null; 158 }).when(mIpClient).shutdown(); 159 160 when(mDeps.makeIpClientManager(any())).thenReturn(mIpClient); 161 } 162 triggerOnProvisioningSuccess()163 private void triggerOnProvisioningSuccess() { 164 mIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); 165 mLooper.dispatchAll(); 166 } 167 triggerOnProvisioningFailure()168 private void triggerOnProvisioningFailure() { 169 mIpClientCallbacks.onProvisioningFailure(new LinkProperties()); 170 mLooper.dispatchAll(); 171 } 172 triggerOnReachabilityLost()173 private void triggerOnReachabilityLost() { 174 mIpClientCallbacks.onReachabilityLost("ReachabilityLost"); 175 mLooper.dispatchAll(); 176 } 177 setupContext()178 private void setupContext() { 179 when(mDeps.getTcpBufferSizesFromResource(eq(mContext))).thenReturn(""); 180 } 181 182 @After tearDown()183 public void tearDown() { 184 // looper is shared with the network agents, so there may still be messages to dispatch on 185 // tear down. 186 mLooper.dispatchAll(); 187 } 188 createDefaultFilterCaps()189 private NetworkCapabilities createDefaultFilterCaps() { 190 return NetworkCapabilities.Builder.withoutDefaultCapabilities() 191 .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) 192 .build(); 193 } 194 createInterfaceCapsBuilder(final int transportType)195 private NetworkCapabilities.Builder createInterfaceCapsBuilder(final int transportType) { 196 return new NetworkCapabilities.Builder() 197 .addTransportType(transportType) 198 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 199 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); 200 } 201 createDefaultRequestBuilder()202 private NetworkRequest.Builder createDefaultRequestBuilder() { 203 return new NetworkRequest.Builder() 204 .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) 205 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 206 } 207 createDefaultRequest()208 private NetworkRequest createDefaultRequest() { 209 return createDefaultRequestBuilder().build(); 210 } 211 createDefaultIpConfig()212 private IpConfiguration createDefaultIpConfig() { 213 IpConfiguration ipConfig = new IpConfiguration(); 214 ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP); 215 ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE); 216 return ipConfig; 217 } 218 219 /** 220 * Create an {@link IpConfiguration} with an associated {@link StaticIpConfiguration}. 221 * 222 * @return {@link IpConfiguration} with its {@link StaticIpConfiguration} set. 223 */ createStaticIpConfig()224 private IpConfiguration createStaticIpConfig() { 225 final IpConfiguration ipConfig = new IpConfiguration(); 226 ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC); 227 ipConfig.setStaticIpConfiguration( 228 new StaticIpConfiguration.Builder().setIpAddress(LINK_ADDR).build()); 229 return ipConfig; 230 } 231 232 // creates an interface with provisioning in progress (since updating the interface link state 233 // automatically starts the provisioning process) createInterfaceUndergoingProvisioning(String iface)234 private void createInterfaceUndergoingProvisioning(String iface) { 235 // Default to the ethernet transport type. 236 createInterfaceUndergoingProvisioning(iface, NetworkCapabilities.TRANSPORT_ETHERNET); 237 } 238 createInterfaceUndergoingProvisioning( @onNull final String iface, final int transportType)239 private void createInterfaceUndergoingProvisioning( 240 @NonNull final String iface, final int transportType) { 241 final IpConfiguration ipConfig = createDefaultIpConfig(); 242 mNetFactory.addInterface(iface, HW_ADDR, ipConfig, 243 createInterfaceCapsBuilder(transportType).build()); 244 assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER)); 245 246 ArgumentCaptor<NetworkOfferCallback> captor = ArgumentCaptor.forClass( 247 NetworkOfferCallback.class); 248 verify(mNetworkProvider).registerNetworkOffer(any(), any(), any(), captor.capture()); 249 mRequestToKeepNetworkUp = createDefaultRequest(); 250 mNetworkOfferCallback = captor.getValue(); 251 mNetworkOfferCallback.onNetworkNeeded(mRequestToKeepNetworkUp); 252 253 verifyStart(ipConfig); 254 clearInvocations(mDeps); 255 clearInvocations(mIpClient); 256 clearInvocations(mNetworkProvider); 257 } 258 259 // creates a provisioned interface createAndVerifyProvisionedInterface(String iface)260 private void createAndVerifyProvisionedInterface(String iface) throws Exception { 261 // Default to the ethernet transport type. 262 createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_ETHERNET, 263 ConnectivityManager.TYPE_ETHERNET); 264 } 265 createVerifyAndRemoveProvisionedInterface(final int transportType, final int expectedLegacyType)266 private void createVerifyAndRemoveProvisionedInterface(final int transportType, 267 final int expectedLegacyType) throws Exception { 268 createAndVerifyProvisionedInterface(TEST_IFACE, transportType, 269 expectedLegacyType); 270 mNetFactory.removeInterface(TEST_IFACE); 271 } 272 createAndVerifyProvisionedInterface( @onNull final String iface, final int transportType, final int expectedLegacyType)273 private void createAndVerifyProvisionedInterface( 274 @NonNull final String iface, final int transportType, final int expectedLegacyType) 275 throws Exception { 276 createInterfaceUndergoingProvisioning(iface, transportType); 277 triggerOnProvisioningSuccess(); 278 // provisioning succeeded, verify that the network agent is created, registered, marked 279 // as connected and legacy type are correctly set. 280 final ArgumentCaptor<NetworkCapabilities> ncCaptor = ArgumentCaptor.forClass( 281 NetworkCapabilities.class); 282 verify(mDeps).makeEthernetNetworkAgent(any(), any(), ncCaptor.capture(), any(), 283 argThat(x -> x.getLegacyType() == expectedLegacyType), any(), any()); 284 assertEquals( 285 new EthernetNetworkSpecifier(iface), ncCaptor.getValue().getNetworkSpecifier()); 286 verifyNetworkAgentRegistersAndConnects(); 287 clearInvocations(mDeps); 288 clearInvocations(mNetworkAgent); 289 } 290 291 // creates an unprovisioned interface createUnprovisionedInterface(String iface)292 private void createUnprovisionedInterface(String iface) throws Exception { 293 // To create an unprovisioned interface, provision and then "stop" it, i.e. stop its 294 // NetworkAgent and IpClient. One way this can be done is by provisioning an interface and 295 // then calling onNetworkUnwanted. 296 mNetFactory.addInterface(iface, HW_ADDR, createDefaultIpConfig(), 297 createInterfaceCapsBuilder(NetworkCapabilities.TRANSPORT_ETHERNET).build()); 298 assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER)); 299 300 clearInvocations(mIpClient); 301 clearInvocations(mNetworkAgent); 302 } 303 304 @Test testUpdateInterfaceLinkStateForActiveProvisioningInterface()305 public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception { 306 initEthernetNetworkFactory(); 307 createInterfaceUndergoingProvisioning(TEST_IFACE); 308 final TestNetworkManagementListener listener = new TestNetworkManagementListener(); 309 310 // verify that the IpClient gets shut down when interface state changes to down. 311 final boolean ret = 312 mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener); 313 314 assertTrue(ret); 315 verify(mIpClient).shutdown(); 316 assertEquals(listener.expectOnResult(), TEST_IFACE); 317 } 318 319 @Test testUpdateInterfaceLinkStateForProvisionedInterface()320 public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception { 321 initEthernetNetworkFactory(); 322 createAndVerifyProvisionedInterface(TEST_IFACE); 323 final TestNetworkManagementListener listenerDown = new TestNetworkManagementListener(); 324 final TestNetworkManagementListener listenerUp = new TestNetworkManagementListener(); 325 326 final boolean retDown = 327 mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listenerDown); 328 329 assertTrue(retDown); 330 verifyStop(); 331 assertEquals(listenerDown.expectOnResult(), TEST_IFACE); 332 333 final boolean retUp = 334 mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listenerUp); 335 336 assertTrue(retUp); 337 assertEquals(listenerUp.expectOnResult(), TEST_IFACE); 338 } 339 340 @Test testUpdateInterfaceLinkStateForUnprovisionedInterface()341 public void testUpdateInterfaceLinkStateForUnprovisionedInterface() throws Exception { 342 initEthernetNetworkFactory(); 343 createUnprovisionedInterface(TEST_IFACE); 344 final TestNetworkManagementListener listener = new TestNetworkManagementListener(); 345 346 final boolean ret = 347 mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener); 348 349 assertTrue(ret); 350 // There should not be an active IPClient or NetworkAgent. 351 verify(mDeps, never()).makeIpClient(any(), any(), any()); 352 verify(mDeps, never()) 353 .makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); 354 assertEquals(listener.expectOnResult(), TEST_IFACE); 355 } 356 357 @Test testUpdateInterfaceLinkStateForNonExistingInterface()358 public void testUpdateInterfaceLinkStateForNonExistingInterface() throws Exception { 359 initEthernetNetworkFactory(); 360 final TestNetworkManagementListener listener = new TestNetworkManagementListener(); 361 362 // if interface was never added, link state cannot be updated. 363 final boolean ret = 364 mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener); 365 366 assertFalse(ret); 367 verifyNoStopOrStart(); 368 listener.expectOnError(); 369 } 370 371 @Test testUpdateInterfaceLinkStateWithNoChanges()372 public void testUpdateInterfaceLinkStateWithNoChanges() throws Exception { 373 initEthernetNetworkFactory(); 374 createAndVerifyProvisionedInterface(TEST_IFACE); 375 final TestNetworkManagementListener listener = new TestNetworkManagementListener(); 376 377 final boolean ret = 378 mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener); 379 380 assertFalse(ret); 381 verifyNoStopOrStart(); 382 listener.expectOnError(); 383 } 384 385 @Test testProvisioningLoss()386 public void testProvisioningLoss() throws Exception { 387 initEthernetNetworkFactory(); 388 when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); 389 createAndVerifyProvisionedInterface(TEST_IFACE); 390 391 triggerOnProvisioningFailure(); 392 verifyStop(); 393 // provisioning loss should trigger a retry, since the interface is still there 394 verify(mIpClient).startProvisioning(any()); 395 } 396 397 @Test testProvisioningLossForDisappearedInterface()398 public void testProvisioningLossForDisappearedInterface() throws Exception { 399 initEthernetNetworkFactory(); 400 // mocked method returns null by default, but just to be explicit in the test: 401 when(mDeps.getNetworkInterfaceByName(eq(TEST_IFACE))).thenReturn(null); 402 403 createAndVerifyProvisionedInterface(TEST_IFACE); 404 triggerOnProvisioningFailure(); 405 406 // the interface disappeared and getNetworkInterfaceByName returns null, we should not retry 407 verify(mIpClient, never()).startProvisioning(any()); 408 verifyNoStopOrStart(); 409 } 410 verifyNoStopOrStart()411 private void verifyNoStopOrStart() { 412 verify(mNetworkAgent, never()).register(); 413 verify(mIpClient, never()).shutdown(); 414 verify(mNetworkAgent, never()).unregister(); 415 verify(mIpClient, never()).startProvisioning(any()); 416 } 417 418 @Test testLinkPropertiesChanged()419 public void testLinkPropertiesChanged() throws Exception { 420 initEthernetNetworkFactory(); 421 createAndVerifyProvisionedInterface(TEST_IFACE); 422 423 LinkProperties lp = new LinkProperties(); 424 mIpClientCallbacks.onLinkPropertiesChange(lp); 425 mLooper.dispatchAll(); 426 verify(mNetworkAgent).sendLinkPropertiesImpl(same(lp)); 427 } 428 429 @Test testNetworkUnwanted()430 public void testNetworkUnwanted() throws Exception { 431 initEthernetNetworkFactory(); 432 createAndVerifyProvisionedInterface(TEST_IFACE); 433 434 mNetworkAgent.getCallbacks().onNetworkUnwanted(); 435 mLooper.dispatchAll(); 436 verifyStop(); 437 } 438 439 @Test testNetworkUnwantedWithStaleNetworkAgent()440 public void testNetworkUnwantedWithStaleNetworkAgent() throws Exception { 441 initEthernetNetworkFactory(); 442 // ensures provisioning is restarted after provisioning loss 443 when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); 444 createAndVerifyProvisionedInterface(TEST_IFACE); 445 446 EthernetNetworkAgent.Callbacks oldCbs = mNetworkAgent.getCallbacks(); 447 // replace network agent in EthernetNetworkFactory 448 // Loss of provisioning will restart the ip client and network agent. 449 triggerOnProvisioningFailure(); 450 verify(mDeps).makeIpClient(any(), any(), any()); 451 452 triggerOnProvisioningSuccess(); 453 verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()); 454 455 // verify that unwanted is ignored 456 clearInvocations(mIpClient); 457 clearInvocations(mNetworkAgent); 458 oldCbs.onNetworkUnwanted(); 459 verify(mIpClient, never()).shutdown(); 460 verify(mNetworkAgent, never()).unregister(); 461 } 462 463 @Test testTransportOverrideIsCorrectlySet()464 public void testTransportOverrideIsCorrectlySet() throws Exception { 465 initEthernetNetworkFactory(); 466 // createProvisionedInterface() has verifications in place for transport override 467 // functionality which for EthernetNetworkFactory is network score and legacy type mappings. 468 createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_ETHERNET, 469 ConnectivityManager.TYPE_ETHERNET); 470 createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_BLUETOOTH, 471 ConnectivityManager.TYPE_BLUETOOTH); 472 createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_WIFI, 473 ConnectivityManager.TYPE_WIFI); 474 createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_CELLULAR, 475 ConnectivityManager.TYPE_MOBILE); 476 createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_LOWPAN, 477 ConnectivityManager.TYPE_NONE); 478 createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_WIFI_AWARE, 479 ConnectivityManager.TYPE_NONE); 480 createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_TEST, 481 ConnectivityManager.TYPE_NONE); 482 } 483 484 @Test testReachabilityLoss()485 public void testReachabilityLoss() throws Exception { 486 initEthernetNetworkFactory(); 487 createAndVerifyProvisionedInterface(TEST_IFACE); 488 489 triggerOnReachabilityLost(); 490 491 // Reachability loss should trigger a stop and start, since the interface is still there 492 verifyRestart(createDefaultIpConfig()); 493 } 494 getStaleIpClientCallbacks()495 private IpClientCallbacks getStaleIpClientCallbacks() throws Exception { 496 createAndVerifyProvisionedInterface(TEST_IFACE); 497 final IpClientCallbacks staleIpClientCallbacks = mIpClientCallbacks; 498 mNetFactory.removeInterface(TEST_IFACE); 499 verifyStop(); 500 assertNotSame(mIpClientCallbacks, staleIpClientCallbacks); 501 return staleIpClientCallbacks; 502 } 503 504 @Test testIgnoreOnIpLayerStartedCallbackForStaleCallback()505 public void testIgnoreOnIpLayerStartedCallbackForStaleCallback() throws Exception { 506 initEthernetNetworkFactory(); 507 final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks(); 508 509 staleIpClientCallbacks.onProvisioningSuccess(new LinkProperties()); 510 mLooper.dispatchAll(); 511 512 verify(mIpClient, never()).startProvisioning(any()); 513 verify(mNetworkAgent, never()).register(); 514 } 515 516 @Test testIgnoreOnIpLayerStoppedCallbackForStaleCallback()517 public void testIgnoreOnIpLayerStoppedCallbackForStaleCallback() throws Exception { 518 initEthernetNetworkFactory(); 519 when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams); 520 final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks(); 521 522 staleIpClientCallbacks.onProvisioningFailure(new LinkProperties()); 523 mLooper.dispatchAll(); 524 525 verify(mIpClient, never()).startProvisioning(any()); 526 } 527 528 @Test testIgnoreLinkPropertiesCallbackForStaleCallback()529 public void testIgnoreLinkPropertiesCallbackForStaleCallback() throws Exception { 530 initEthernetNetworkFactory(); 531 final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks(); 532 final LinkProperties lp = new LinkProperties(); 533 534 staleIpClientCallbacks.onLinkPropertiesChange(lp); 535 mLooper.dispatchAll(); 536 537 verify(mNetworkAgent, never()).sendLinkPropertiesImpl(eq(lp)); 538 } 539 540 @Test testIgnoreNeighborLossCallbackForStaleCallback()541 public void testIgnoreNeighborLossCallbackForStaleCallback() throws Exception { 542 initEthernetNetworkFactory(); 543 final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks(); 544 545 staleIpClientCallbacks.onReachabilityLost("Neighbor Lost"); 546 mLooper.dispatchAll(); 547 548 verify(mIpClient, never()).startProvisioning(any()); 549 verify(mNetworkAgent, never()).register(); 550 } 551 verifyRestart(@onNull final IpConfiguration ipConfig)552 private void verifyRestart(@NonNull final IpConfiguration ipConfig) { 553 verifyStop(); 554 verifyStart(ipConfig); 555 } 556 verifyStart(@onNull final IpConfiguration ipConfig)557 private void verifyStart(@NonNull final IpConfiguration ipConfig) { 558 verify(mDeps).makeIpClient(any(Context.class), anyString(), any()); 559 verify(mIpClient).startProvisioning( 560 argThat(x -> Objects.equals(x.mStaticIpConfig, ipConfig.getStaticIpConfiguration())) 561 ); 562 } 563 verifyStop()564 private void verifyStop() { 565 verify(mIpClient).shutdown(); 566 verify(mNetworkAgent).unregister(); 567 } 568 verifyNetworkAgentRegistersAndConnects()569 private void verifyNetworkAgentRegistersAndConnects() { 570 verify(mNetworkAgent).register(); 571 verify(mNetworkAgent).markConnected(); 572 } 573 574 private static final class TestNetworkManagementListener 575 implements INetworkInterfaceOutcomeReceiver { 576 private final CompletableFuture<String> mResult = new CompletableFuture<>(); 577 578 @Override onResult(@onNull String iface)579 public void onResult(@NonNull String iface) { 580 mResult.complete(iface); 581 } 582 583 @Override onError(@onNull EthernetNetworkManagementException exception)584 public void onError(@NonNull EthernetNetworkManagementException exception) { 585 mResult.completeExceptionally(exception); 586 } 587 expectOnResult()588 String expectOnResult() throws Exception { 589 return mResult.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); 590 } 591 expectOnError()592 void expectOnError() throws Exception { 593 assertThrows(EthernetNetworkManagementException.class, () -> { 594 try { 595 mResult.get(); 596 } catch (ExecutionException e) { 597 throw e.getCause(); 598 } 599 }); 600 } 601 602 @Override asBinder()603 public IBinder asBinder() { 604 return null; 605 } 606 } 607 608 @Test testUpdateInterfaceCallsListenerCorrectlyOnSuccess()609 public void testUpdateInterfaceCallsListenerCorrectlyOnSuccess() throws Exception { 610 initEthernetNetworkFactory(); 611 createAndVerifyProvisionedInterface(TEST_IFACE); 612 final NetworkCapabilities capabilities = createDefaultFilterCaps(); 613 final IpConfiguration ipConfiguration = createStaticIpConfig(); 614 final TestNetworkManagementListener listener = new TestNetworkManagementListener(); 615 616 mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); 617 triggerOnProvisioningSuccess(); 618 619 assertEquals(listener.expectOnResult(), TEST_IFACE); 620 } 621 622 @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available 623 @Test testUpdateInterfaceAbortsOnConcurrentRemoveInterface()624 public void testUpdateInterfaceAbortsOnConcurrentRemoveInterface() throws Exception { 625 initEthernetNetworkFactory(); 626 verifyNetworkManagementCallIsAbortedWhenInterrupted( 627 TEST_IFACE, 628 () -> mNetFactory.removeInterface(TEST_IFACE)); 629 } 630 631 @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available 632 @Test testUpdateInterfaceAbortsOnConcurrentUpdateInterfaceLinkState()633 public void testUpdateInterfaceAbortsOnConcurrentUpdateInterfaceLinkState() throws Exception { 634 initEthernetNetworkFactory(); 635 verifyNetworkManagementCallIsAbortedWhenInterrupted( 636 TEST_IFACE, 637 () -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER)); 638 } 639 640 @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available 641 @Test testUpdateInterfaceAbortsOnNetworkUneededRemovesAllRequests()642 public void testUpdateInterfaceAbortsOnNetworkUneededRemovesAllRequests() throws Exception { 643 initEthernetNetworkFactory(); 644 verifyNetworkManagementCallIsAbortedWhenInterrupted( 645 TEST_IFACE, 646 () -> mNetworkOfferCallback.onNetworkUnneeded(mRequestToKeepNetworkUp)); 647 } 648 649 @Test testUpdateInterfaceCallsListenerCorrectlyOnConcurrentRequests()650 public void testUpdateInterfaceCallsListenerCorrectlyOnConcurrentRequests() throws Exception { 651 initEthernetNetworkFactory(); 652 final NetworkCapabilities capabilities = createDefaultFilterCaps(); 653 final IpConfiguration ipConfiguration = createStaticIpConfig(); 654 final TestNetworkManagementListener successfulListener = 655 new TestNetworkManagementListener(); 656 657 // If two calls come in before the first one completes, the first listener will be aborted 658 // and the second one will be successful. 659 verifyNetworkManagementCallIsAbortedWhenInterrupted( 660 TEST_IFACE, 661 () -> { 662 mNetFactory.updateInterface( 663 TEST_IFACE, ipConfiguration, capabilities, successfulListener); 664 triggerOnProvisioningSuccess(); 665 }); 666 667 assertEquals(successfulListener.expectOnResult(), TEST_IFACE); 668 } 669 verifyNetworkManagementCallIsAbortedWhenInterrupted( @onNull final String iface, @NonNull final Runnable interruptingRunnable)670 private void verifyNetworkManagementCallIsAbortedWhenInterrupted( 671 @NonNull final String iface, 672 @NonNull final Runnable interruptingRunnable) throws Exception { 673 createAndVerifyProvisionedInterface(iface); 674 final NetworkCapabilities capabilities = createDefaultFilterCaps(); 675 final IpConfiguration ipConfiguration = createStaticIpConfig(); 676 final TestNetworkManagementListener failedListener = new TestNetworkManagementListener(); 677 678 // An active update request will be aborted on interrupt prior to provisioning completion. 679 mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener); 680 interruptingRunnable.run(); 681 682 failedListener.expectOnError(); 683 } 684 685 @Test testUpdateInterfaceRestartsAgentCorrectly()686 public void testUpdateInterfaceRestartsAgentCorrectly() throws Exception { 687 initEthernetNetworkFactory(); 688 createAndVerifyProvisionedInterface(TEST_IFACE); 689 final NetworkCapabilities capabilities = createDefaultFilterCaps(); 690 final IpConfiguration ipConfiguration = createStaticIpConfig(); 691 final TestNetworkManagementListener listener = new TestNetworkManagementListener(); 692 693 mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); 694 triggerOnProvisioningSuccess(); 695 696 assertEquals(listener.expectOnResult(), TEST_IFACE); 697 verify(mDeps).makeEthernetNetworkAgent(any(), any(), 698 eq(capabilities), any(), any(), any(), any()); 699 verifyRestart(ipConfiguration); 700 } 701 702 @Test testUpdateInterfaceForNonExistingInterface()703 public void testUpdateInterfaceForNonExistingInterface() throws Exception { 704 initEthernetNetworkFactory(); 705 // No interface exists due to not calling createAndVerifyProvisionedInterface(...). 706 final NetworkCapabilities capabilities = createDefaultFilterCaps(); 707 final IpConfiguration ipConfiguration = createStaticIpConfig(); 708 final TestNetworkManagementListener listener = new TestNetworkManagementListener(); 709 710 mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener); 711 712 verifyNoStopOrStart(); 713 listener.expectOnError(); 714 } 715 716 @Test testUpdateInterfaceWithNullIpConfiguration()717 public void testUpdateInterfaceWithNullIpConfiguration() throws Exception { 718 initEthernetNetworkFactory(); 719 createAndVerifyProvisionedInterface(TEST_IFACE); 720 721 final IpConfiguration initialIpConfig = createStaticIpConfig(); 722 mNetFactory.updateInterface(TEST_IFACE, initialIpConfig, null /*capabilities*/, 723 null /*listener*/); 724 triggerOnProvisioningSuccess(); 725 verifyRestart(initialIpConfig); 726 727 // TODO: have verifyXyz functions clear invocations. 728 clearInvocations(mDeps); 729 clearInvocations(mIpClient); 730 clearInvocations(mNetworkAgent); 731 732 733 // verify that sending a null ipConfig does not update the current ipConfig. 734 mNetFactory.updateInterface(TEST_IFACE, null /*ipConfig*/, null /*capabilities*/, 735 null /*listener*/); 736 triggerOnProvisioningSuccess(); 737 verifyRestart(initialIpConfig); 738 } 739 } 740