Merge EthernetServiceTests into FrameworksNetTests
As per the TODO, merge EthernetServiceTests into the larger FrameworksNetTests suite. Similarly to NetworkStats, NSD or IpSec tests, the tests are also marked as "non-connectivity-module-test", where "module" actually refers to modules being built for release (from an S-based branch) today. This is necessary as the tests and associated code cannot build without T APIs. Also add FrameworksNetTests to presubmit as non-connectivity-module tests are not run in presubmit without this. Test: TH Merged-In: Id533cdb4ac184b963f570af299dea04754ba88e9 Change-Id: I9950fcb49fdc2217134a59e993941cbe5da0b556
This commit is contained in:
@@ -0,0 +1,783 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.ethernet;
|
||||
|
||||
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.same;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.test.MockAnswerUtil.AnswerWithArguments;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.EthernetNetworkSpecifier;
|
||||
import android.net.EthernetNetworkManagementException;
|
||||
import android.net.INetworkInterfaceOutcomeReceiver;
|
||||
import android.net.IpConfiguration;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkAgentConfig;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkProvider;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.StaticIpConfiguration;
|
||||
import android.net.ip.IpClientCallbacks;
|
||||
import android.net.ip.IpClientManager;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.test.TestLooper;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.connectivity.resources.R;
|
||||
import com.android.net.module.util.InterfaceParams;
|
||||
|
||||
import com.android.testutils.DevSdkIgnoreRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class EthernetNetworkFactoryTest {
|
||||
private static final int TIMEOUT_MS = 2_000;
|
||||
private static final String TEST_IFACE = "test123";
|
||||
private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
|
||||
private static final String IP_ADDR = "192.0.2.2/25";
|
||||
private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR);
|
||||
private static final String HW_ADDR = "01:02:03:04:05:06";
|
||||
private TestLooper mLooper;
|
||||
private Handler mHandler;
|
||||
private EthernetNetworkFactory mNetFactory = null;
|
||||
private IpClientCallbacks mIpClientCallbacks;
|
||||
@Mock private Context mContext;
|
||||
@Mock private Resources mResources;
|
||||
@Mock private EthernetNetworkFactory.Dependencies mDeps;
|
||||
@Mock private IpClientManager mIpClient;
|
||||
@Mock private EthernetNetworkAgent mNetworkAgent;
|
||||
@Mock private InterfaceParams mInterfaceParams;
|
||||
@Mock private Network mMockNetwork;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
setupNetworkAgentMock();
|
||||
setupIpClientMock();
|
||||
setupContext();
|
||||
}
|
||||
|
||||
//TODO: Move away from usage of TestLooper in order to move this logic back into @Before.
|
||||
private void initEthernetNetworkFactory() {
|
||||
mLooper = new TestLooper();
|
||||
mHandler = new Handler(mLooper.getLooper());
|
||||
mNetFactory = new EthernetNetworkFactory(mHandler, mContext, mDeps);
|
||||
}
|
||||
|
||||
private void setupNetworkAgentMock() {
|
||||
when(mDeps.makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()))
|
||||
.thenAnswer(new AnswerWithArguments() {
|
||||
public EthernetNetworkAgent answer(
|
||||
Context context,
|
||||
Looper looper,
|
||||
NetworkCapabilities nc,
|
||||
LinkProperties lp,
|
||||
NetworkAgentConfig config,
|
||||
NetworkProvider provider,
|
||||
EthernetNetworkAgent.Callbacks cb) {
|
||||
when(mNetworkAgent.getCallbacks()).thenReturn(cb);
|
||||
when(mNetworkAgent.getNetwork())
|
||||
.thenReturn(mMockNetwork);
|
||||
return mNetworkAgent;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void setupIpClientMock() throws Exception {
|
||||
doAnswer(inv -> {
|
||||
// these tests only support one concurrent IpClient, so make sure we do not accidentally
|
||||
// create a mess.
|
||||
assertNull("An IpClient has already been created.", mIpClientCallbacks);
|
||||
|
||||
mIpClientCallbacks = inv.getArgument(2);
|
||||
mIpClientCallbacks.onIpClientCreated(null);
|
||||
mLooper.dispatchAll();
|
||||
return null;
|
||||
}).when(mDeps).makeIpClient(any(Context.class), anyString(), any());
|
||||
|
||||
doAnswer(inv -> {
|
||||
mIpClientCallbacks.onQuit();
|
||||
mLooper.dispatchAll();
|
||||
mIpClientCallbacks = null;
|
||||
return null;
|
||||
}).when(mIpClient).shutdown();
|
||||
|
||||
when(mDeps.makeIpClientManager(any())).thenReturn(mIpClient);
|
||||
}
|
||||
|
||||
private void triggerOnProvisioningSuccess() {
|
||||
mIpClientCallbacks.onProvisioningSuccess(new LinkProperties());
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
private void triggerOnProvisioningFailure() {
|
||||
mIpClientCallbacks.onProvisioningFailure(new LinkProperties());
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
private void triggerOnReachabilityLost() {
|
||||
mIpClientCallbacks.onReachabilityLost("ReachabilityLost");
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
private void setupContext() {
|
||||
when(mDeps.getTcpBufferSizesFromResource(eq(mContext))).thenReturn("");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
// looper is shared with the network agents, so there may still be messages to dispatch on
|
||||
// tear down.
|
||||
mLooper.dispatchAll();
|
||||
}
|
||||
|
||||
private NetworkCapabilities createDefaultFilterCaps() {
|
||||
return NetworkCapabilities.Builder.withoutDefaultCapabilities()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.build();
|
||||
}
|
||||
|
||||
private NetworkCapabilities.Builder createInterfaceCapsBuilder(final int transportType) {
|
||||
return new NetworkCapabilities.Builder()
|
||||
.addTransportType(transportType)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
|
||||
}
|
||||
|
||||
private NetworkRequest.Builder createDefaultRequestBuilder() {
|
||||
return new NetworkRequest.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
|
||||
}
|
||||
|
||||
private NetworkRequest createDefaultRequest() {
|
||||
return createDefaultRequestBuilder().build();
|
||||
}
|
||||
|
||||
private IpConfiguration createDefaultIpConfig() {
|
||||
IpConfiguration ipConfig = new IpConfiguration();
|
||||
ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
|
||||
ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE);
|
||||
return ipConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link IpConfiguration} with an associated {@link StaticIpConfiguration}.
|
||||
*
|
||||
* @return {@link IpConfiguration} with its {@link StaticIpConfiguration} set.
|
||||
*/
|
||||
private IpConfiguration createStaticIpConfig() {
|
||||
final IpConfiguration ipConfig = new IpConfiguration();
|
||||
ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC);
|
||||
ipConfig.setStaticIpConfiguration(
|
||||
new StaticIpConfiguration.Builder().setIpAddress(LINK_ADDR).build());
|
||||
return ipConfig;
|
||||
}
|
||||
|
||||
// creates an interface with provisioning in progress (since updating the interface link state
|
||||
// automatically starts the provisioning process)
|
||||
private void createInterfaceUndergoingProvisioning(String iface) {
|
||||
// Default to the ethernet transport type.
|
||||
createInterfaceUndergoingProvisioning(iface, NetworkCapabilities.TRANSPORT_ETHERNET);
|
||||
}
|
||||
|
||||
private void createInterfaceUndergoingProvisioning(
|
||||
@NonNull final String iface, final int transportType) {
|
||||
final IpConfiguration ipConfig = createDefaultIpConfig();
|
||||
mNetFactory.addInterface(iface, HW_ADDR, ipConfig,
|
||||
createInterfaceCapsBuilder(transportType).build());
|
||||
assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER));
|
||||
verifyStart(ipConfig);
|
||||
clearInvocations(mDeps);
|
||||
clearInvocations(mIpClient);
|
||||
}
|
||||
|
||||
// creates a provisioned interface
|
||||
private void createAndVerifyProvisionedInterface(String iface) throws Exception {
|
||||
// Default to the ethernet transport type.
|
||||
createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_ETHERNET,
|
||||
ConnectivityManager.TYPE_ETHERNET);
|
||||
}
|
||||
|
||||
private void createVerifyAndRemoveProvisionedInterface(final int transportType,
|
||||
final int expectedLegacyType) throws Exception {
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE, transportType,
|
||||
expectedLegacyType);
|
||||
mNetFactory.removeInterface(TEST_IFACE);
|
||||
}
|
||||
|
||||
private void createAndVerifyProvisionedInterface(
|
||||
@NonNull final String iface, final int transportType, final int expectedLegacyType)
|
||||
throws Exception {
|
||||
createInterfaceUndergoingProvisioning(iface, transportType);
|
||||
triggerOnProvisioningSuccess();
|
||||
// provisioning succeeded, verify that the network agent is created, registered, marked
|
||||
// as connected and legacy type are correctly set.
|
||||
final ArgumentCaptor<NetworkCapabilities> ncCaptor = ArgumentCaptor.forClass(
|
||||
NetworkCapabilities.class);
|
||||
verify(mDeps).makeEthernetNetworkAgent(any(), any(), ncCaptor.capture(), any(),
|
||||
argThat(x -> x.getLegacyType() == expectedLegacyType), any(), any());
|
||||
assertEquals(
|
||||
new EthernetNetworkSpecifier(iface), ncCaptor.getValue().getNetworkSpecifier());
|
||||
verifyNetworkAgentRegistersAndConnects();
|
||||
clearInvocations(mDeps);
|
||||
clearInvocations(mNetworkAgent);
|
||||
}
|
||||
|
||||
// creates an unprovisioned interface
|
||||
private void createUnprovisionedInterface(String iface) throws Exception {
|
||||
// To create an unprovisioned interface, provision and then "stop" it, i.e. stop its
|
||||
// NetworkAgent and IpClient. One way this can be done is by provisioning an interface and
|
||||
// then calling onNetworkUnwanted.
|
||||
createAndVerifyProvisionedInterface(iface);
|
||||
|
||||
mNetworkAgent.getCallbacks().onNetworkUnwanted();
|
||||
mLooper.dispatchAll();
|
||||
verifyStop();
|
||||
|
||||
clearInvocations(mIpClient);
|
||||
clearInvocations(mNetworkAgent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptRequest() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createInterfaceUndergoingProvisioning(TEST_IFACE);
|
||||
assertTrue(mNetFactory.acceptRequest(createDefaultRequest()));
|
||||
|
||||
NetworkRequest wifiRequest = createDefaultRequestBuilder()
|
||||
.removeTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
|
||||
assertFalse(mNetFactory.acceptRequest(wifiRequest));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createInterfaceUndergoingProvisioning(TEST_IFACE);
|
||||
final TestNetworkManagementListener listener = new TestNetworkManagementListener();
|
||||
|
||||
// verify that the IpClient gets shut down when interface state changes to down.
|
||||
final boolean ret =
|
||||
mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener);
|
||||
|
||||
assertTrue(ret);
|
||||
verify(mIpClient).shutdown();
|
||||
assertEquals(listener.expectOnResult(), TEST_IFACE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
final TestNetworkManagementListener listener = new TestNetworkManagementListener();
|
||||
|
||||
final boolean ret =
|
||||
mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener);
|
||||
|
||||
assertTrue(ret);
|
||||
verifyStop();
|
||||
assertEquals(listener.expectOnResult(), TEST_IFACE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceLinkStateForUnprovisionedInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createUnprovisionedInterface(TEST_IFACE);
|
||||
final TestNetworkManagementListener listener = new TestNetworkManagementListener();
|
||||
|
||||
final boolean ret =
|
||||
mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener);
|
||||
|
||||
assertTrue(ret);
|
||||
// There should not be an active IPClient or NetworkAgent.
|
||||
verify(mDeps, never()).makeIpClient(any(), any(), any());
|
||||
verify(mDeps, never())
|
||||
.makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any());
|
||||
assertEquals(listener.expectOnResult(), TEST_IFACE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceLinkStateForNonExistingInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
final TestNetworkManagementListener listener = new TestNetworkManagementListener();
|
||||
|
||||
// if interface was never added, link state cannot be updated.
|
||||
final boolean ret =
|
||||
mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener);
|
||||
|
||||
assertFalse(ret);
|
||||
verifyNoStopOrStart();
|
||||
listener.expectOnErrorWithMessage("can't be updated as it is not available");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceLinkStateWithNoChanges() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
final TestNetworkManagementListener listener = new TestNetworkManagementListener();
|
||||
|
||||
final boolean ret =
|
||||
mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener);
|
||||
|
||||
assertFalse(ret);
|
||||
verifyNoStopOrStart();
|
||||
listener.expectOnErrorWithMessage("No changes");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeedNetworkForOnProvisionedInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
mNetFactory.needNetworkFor(createDefaultRequest());
|
||||
verify(mIpClient, never()).startProvisioning(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeedNetworkForOnUnprovisionedInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createUnprovisionedInterface(TEST_IFACE);
|
||||
mNetFactory.needNetworkFor(createDefaultRequest());
|
||||
verify(mIpClient).startProvisioning(any());
|
||||
|
||||
triggerOnProvisioningSuccess();
|
||||
verifyNetworkAgentRegistersAndConnects();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNeedNetworkForOnInterfaceUndergoingProvisioning() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createInterfaceUndergoingProvisioning(TEST_IFACE);
|
||||
mNetFactory.needNetworkFor(createDefaultRequest());
|
||||
verify(mIpClient, never()).startProvisioning(any());
|
||||
|
||||
triggerOnProvisioningSuccess();
|
||||
verifyNetworkAgentRegistersAndConnects();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningLoss() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams);
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
|
||||
triggerOnProvisioningFailure();
|
||||
verifyStop();
|
||||
// provisioning loss should trigger a retry, since the interface is still there
|
||||
verify(mIpClient).startProvisioning(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProvisioningLossForDisappearedInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
// mocked method returns null by default, but just to be explicit in the test:
|
||||
when(mDeps.getNetworkInterfaceByName(eq(TEST_IFACE))).thenReturn(null);
|
||||
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
triggerOnProvisioningFailure();
|
||||
|
||||
// the interface disappeared and getNetworkInterfaceByName returns null, we should not retry
|
||||
verify(mIpClient, never()).startProvisioning(any());
|
||||
verifyNoStopOrStart();
|
||||
}
|
||||
|
||||
private void verifyNoStopOrStart() {
|
||||
verify(mNetworkAgent, never()).register();
|
||||
verify(mIpClient, never()).shutdown();
|
||||
verify(mNetworkAgent, never()).unregister();
|
||||
verify(mIpClient, never()).startProvisioning(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIpClientIsNotStartedWhenLinkIsDown() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createUnprovisionedInterface(TEST_IFACE);
|
||||
mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER);
|
||||
|
||||
mNetFactory.needNetworkFor(createDefaultRequest());
|
||||
|
||||
verify(mDeps, never()).makeIpClient(any(), any(), any());
|
||||
|
||||
// BUG(b/191854824): requesting a network with a specifier (Android Auto use case) should
|
||||
// not start an IpClient when the link is down, but fixing this may make matters worse by
|
||||
// tiggering b/197548738.
|
||||
NetworkRequest specificNetRequest = new NetworkRequest.Builder()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE))
|
||||
.build();
|
||||
mNetFactory.needNetworkFor(specificNetRequest);
|
||||
mNetFactory.releaseNetworkFor(specificNetRequest);
|
||||
|
||||
mNetFactory.updateInterfaceLinkState(TEST_IFACE, true, NULL_LISTENER);
|
||||
// TODO: change to once when b/191854824 is fixed.
|
||||
verify(mDeps, times(2)).makeIpClient(any(), eq(TEST_IFACE), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinkPropertiesChanged() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
|
||||
LinkProperties lp = new LinkProperties();
|
||||
mIpClientCallbacks.onLinkPropertiesChange(lp);
|
||||
mLooper.dispatchAll();
|
||||
verify(mNetworkAgent).sendLinkPropertiesImpl(same(lp));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkUnwanted() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
|
||||
mNetworkAgent.getCallbacks().onNetworkUnwanted();
|
||||
mLooper.dispatchAll();
|
||||
verifyStop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkUnwantedWithStaleNetworkAgent() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
// ensures provisioning is restarted after provisioning loss
|
||||
when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams);
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
|
||||
EthernetNetworkAgent.Callbacks oldCbs = mNetworkAgent.getCallbacks();
|
||||
// replace network agent in EthernetNetworkFactory
|
||||
// Loss of provisioning will restart the ip client and network agent.
|
||||
triggerOnProvisioningFailure();
|
||||
verify(mDeps).makeIpClient(any(), any(), any());
|
||||
|
||||
triggerOnProvisioningSuccess();
|
||||
verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any());
|
||||
|
||||
// verify that unwanted is ignored
|
||||
clearInvocations(mIpClient);
|
||||
clearInvocations(mNetworkAgent);
|
||||
oldCbs.onNetworkUnwanted();
|
||||
verify(mIpClient, never()).shutdown();
|
||||
verify(mNetworkAgent, never()).unregister();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransportOverrideIsCorrectlySet() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
// createProvisionedInterface() has verifications in place for transport override
|
||||
// functionality which for EthernetNetworkFactory is network score and legacy type mappings.
|
||||
createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_ETHERNET,
|
||||
ConnectivityManager.TYPE_ETHERNET);
|
||||
createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_BLUETOOTH,
|
||||
ConnectivityManager.TYPE_BLUETOOTH);
|
||||
createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_WIFI,
|
||||
ConnectivityManager.TYPE_WIFI);
|
||||
createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_CELLULAR,
|
||||
ConnectivityManager.TYPE_MOBILE);
|
||||
createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_LOWPAN,
|
||||
ConnectivityManager.TYPE_NONE);
|
||||
createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_WIFI_AWARE,
|
||||
ConnectivityManager.TYPE_NONE);
|
||||
createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_TEST,
|
||||
ConnectivityManager.TYPE_NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReachabilityLoss() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
|
||||
triggerOnReachabilityLost();
|
||||
|
||||
// Reachability loss should trigger a stop and start, since the interface is still there
|
||||
verifyRestart(createDefaultIpConfig());
|
||||
}
|
||||
|
||||
private IpClientCallbacks getStaleIpClientCallbacks() throws Exception {
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
final IpClientCallbacks staleIpClientCallbacks = mIpClientCallbacks;
|
||||
mNetFactory.removeInterface(TEST_IFACE);
|
||||
verifyStop();
|
||||
assertNotSame(mIpClientCallbacks, staleIpClientCallbacks);
|
||||
return staleIpClientCallbacks;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreOnIpLayerStartedCallbackForStaleCallback() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks();
|
||||
|
||||
staleIpClientCallbacks.onProvisioningSuccess(new LinkProperties());
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mIpClient, never()).startProvisioning(any());
|
||||
verify(mNetworkAgent, never()).register();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreOnIpLayerStoppedCallbackForStaleCallback() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams);
|
||||
final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks();
|
||||
|
||||
staleIpClientCallbacks.onProvisioningFailure(new LinkProperties());
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mIpClient, never()).startProvisioning(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreLinkPropertiesCallbackForStaleCallback() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks();
|
||||
final LinkProperties lp = new LinkProperties();
|
||||
|
||||
staleIpClientCallbacks.onLinkPropertiesChange(lp);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mNetworkAgent, never()).sendLinkPropertiesImpl(eq(lp));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoreNeighborLossCallbackForStaleCallback() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks();
|
||||
|
||||
staleIpClientCallbacks.onReachabilityLost("Neighbor Lost");
|
||||
mLooper.dispatchAll();
|
||||
|
||||
verify(mIpClient, never()).startProvisioning(any());
|
||||
verify(mNetworkAgent, never()).register();
|
||||
}
|
||||
|
||||
private void verifyRestart(@NonNull final IpConfiguration ipConfig) {
|
||||
verifyStop();
|
||||
verifyStart(ipConfig);
|
||||
}
|
||||
|
||||
private void verifyStart(@NonNull final IpConfiguration ipConfig) {
|
||||
verify(mDeps).makeIpClient(any(Context.class), anyString(), any());
|
||||
verify(mIpClient).startProvisioning(
|
||||
argThat(x -> Objects.equals(x.mStaticIpConfig, ipConfig.getStaticIpConfiguration()))
|
||||
);
|
||||
}
|
||||
|
||||
private void verifyStop() {
|
||||
verify(mIpClient).shutdown();
|
||||
verify(mNetworkAgent).unregister();
|
||||
}
|
||||
|
||||
private void verifyNetworkAgentRegistersAndConnects() {
|
||||
verify(mNetworkAgent).register();
|
||||
verify(mNetworkAgent).markConnected();
|
||||
}
|
||||
|
||||
private static final class TestNetworkManagementListener
|
||||
implements INetworkInterfaceOutcomeReceiver {
|
||||
private final CompletableFuture<String> mResult = new CompletableFuture<>();
|
||||
private final CompletableFuture<EthernetNetworkManagementException> mError =
|
||||
new CompletableFuture<>();
|
||||
|
||||
@Override
|
||||
public void onResult(@NonNull String iface) {
|
||||
mResult.complete(iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull EthernetNetworkManagementException exception) {
|
||||
mError.complete(exception);
|
||||
}
|
||||
|
||||
String expectOnResult() throws Exception {
|
||||
return mResult.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
EthernetNetworkManagementException expectOnError() throws Exception {
|
||||
return mError.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
void expectOnErrorWithMessage(String msg) throws Exception {
|
||||
assertTrue(expectOnError().getMessage().contains(msg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceCallsListenerCorrectlyOnSuccess() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
final NetworkCapabilities capabilities = createDefaultFilterCaps();
|
||||
final IpConfiguration ipConfiguration = createStaticIpConfig();
|
||||
final TestNetworkManagementListener listener = new TestNetworkManagementListener();
|
||||
|
||||
mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
|
||||
triggerOnProvisioningSuccess();
|
||||
|
||||
assertEquals(listener.expectOnResult(), TEST_IFACE);
|
||||
}
|
||||
|
||||
@DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
|
||||
@Test
|
||||
public void testUpdateInterfaceAbortsOnConcurrentRemoveInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
verifyNetworkManagementCallIsAbortedWhenInterrupted(
|
||||
TEST_IFACE,
|
||||
() -> mNetFactory.removeInterface(TEST_IFACE));
|
||||
}
|
||||
|
||||
@DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
|
||||
@Test
|
||||
public void testUpdateInterfaceAbortsOnConcurrentUpdateInterfaceLinkState() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
verifyNetworkManagementCallIsAbortedWhenInterrupted(
|
||||
TEST_IFACE,
|
||||
() -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER));
|
||||
}
|
||||
|
||||
@DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
|
||||
@Test
|
||||
public void testUpdateInterfaceCallsListenerCorrectlyOnConcurrentRequests() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
final NetworkCapabilities capabilities = createDefaultFilterCaps();
|
||||
final IpConfiguration ipConfiguration = createStaticIpConfig();
|
||||
final TestNetworkManagementListener successfulListener =
|
||||
new TestNetworkManagementListener();
|
||||
|
||||
// If two calls come in before the first one completes, the first listener will be aborted
|
||||
// and the second one will be successful.
|
||||
verifyNetworkManagementCallIsAbortedWhenInterrupted(
|
||||
TEST_IFACE,
|
||||
() -> {
|
||||
mNetFactory.updateInterface(
|
||||
TEST_IFACE, ipConfiguration, capabilities, successfulListener);
|
||||
triggerOnProvisioningSuccess();
|
||||
});
|
||||
|
||||
assertEquals(successfulListener.expectOnResult(), TEST_IFACE);
|
||||
}
|
||||
|
||||
private void verifyNetworkManagementCallIsAbortedWhenInterrupted(
|
||||
@NonNull final String iface,
|
||||
@NonNull final Runnable interruptingRunnable) throws Exception {
|
||||
createAndVerifyProvisionedInterface(iface);
|
||||
final NetworkCapabilities capabilities = createDefaultFilterCaps();
|
||||
final IpConfiguration ipConfiguration = createStaticIpConfig();
|
||||
final TestNetworkManagementListener failedListener = new TestNetworkManagementListener();
|
||||
|
||||
// An active update request will be aborted on interrupt prior to provisioning completion.
|
||||
mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener);
|
||||
interruptingRunnable.run();
|
||||
|
||||
failedListener.expectOnErrorWithMessage("aborted");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceRestartsAgentCorrectly() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
final NetworkCapabilities capabilities = createDefaultFilterCaps();
|
||||
final IpConfiguration ipConfiguration = createStaticIpConfig();
|
||||
final TestNetworkManagementListener listener = new TestNetworkManagementListener();
|
||||
|
||||
mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
|
||||
triggerOnProvisioningSuccess();
|
||||
|
||||
assertEquals(listener.expectOnResult(), TEST_IFACE);
|
||||
verify(mDeps).makeEthernetNetworkAgent(any(), any(),
|
||||
eq(capabilities), any(), any(), any(), any());
|
||||
verifyRestart(ipConfiguration);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceForNonExistingInterface() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
// No interface exists due to not calling createAndVerifyProvisionedInterface(...).
|
||||
final NetworkCapabilities capabilities = createDefaultFilterCaps();
|
||||
final IpConfiguration ipConfiguration = createStaticIpConfig();
|
||||
final TestNetworkManagementListener listener = new TestNetworkManagementListener();
|
||||
|
||||
mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
|
||||
|
||||
verifyNoStopOrStart();
|
||||
listener.expectOnErrorWithMessage("can't be updated as it is not available");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateInterfaceWithNullIpConfiguration() throws Exception {
|
||||
initEthernetNetworkFactory();
|
||||
createAndVerifyProvisionedInterface(TEST_IFACE);
|
||||
|
||||
final IpConfiguration initialIpConfig = createStaticIpConfig();
|
||||
mNetFactory.updateInterface(TEST_IFACE, initialIpConfig, null /*capabilities*/,
|
||||
null /*listener*/);
|
||||
triggerOnProvisioningSuccess();
|
||||
verifyRestart(initialIpConfig);
|
||||
|
||||
// TODO: have verifyXyz functions clear invocations.
|
||||
clearInvocations(mDeps);
|
||||
clearInvocations(mIpClient);
|
||||
clearInvocations(mNetworkAgent);
|
||||
|
||||
|
||||
// verify that sending a null ipConfig does not update the current ipConfig.
|
||||
mNetFactory.updateInterface(TEST_IFACE, null /*ipConfig*/, null /*capabilities*/,
|
||||
null /*listener*/);
|
||||
triggerOnProvisioningSuccess();
|
||||
verifyRestart(initialIpConfig);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.ethernet;
|
||||
|
||||
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
|
||||
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.INetworkInterfaceOutcomeReceiver;
|
||||
import android.net.EthernetNetworkUpdateRequest;
|
||||
import android.net.IpConfiguration;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.os.Handler;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class EthernetServiceImplTest {
|
||||
private static final String TEST_IFACE = "test123";
|
||||
private static final EthernetNetworkUpdateRequest UPDATE_REQUEST =
|
||||
new EthernetNetworkUpdateRequest.Builder()
|
||||
.setIpConfiguration(new IpConfiguration())
|
||||
.setNetworkCapabilities(new NetworkCapabilities.Builder().build())
|
||||
.build();
|
||||
private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_CAPABILITIES =
|
||||
new EthernetNetworkUpdateRequest.Builder()
|
||||
.setIpConfiguration(new IpConfiguration())
|
||||
.build();
|
||||
private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_IP_CONFIG =
|
||||
new EthernetNetworkUpdateRequest.Builder()
|
||||
.setNetworkCapabilities(new NetworkCapabilities.Builder().build())
|
||||
.build();
|
||||
private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
|
||||
private EthernetServiceImpl mEthernetServiceImpl;
|
||||
@Mock private Context mContext;
|
||||
@Mock private Handler mHandler;
|
||||
@Mock private EthernetTracker mEthernetTracker;
|
||||
@Mock private PackageManager mPackageManager;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||
mEthernetServiceImpl = new EthernetServiceImpl(mContext, mHandler, mEthernetTracker);
|
||||
mEthernetServiceImpl.mStarted.set(true);
|
||||
toggleAutomotiveFeature(true);
|
||||
shouldTrackIface(TEST_IFACE, true);
|
||||
}
|
||||
|
||||
private void toggleAutomotiveFeature(final boolean isEnabled) {
|
||||
doReturn(isEnabled)
|
||||
.when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
|
||||
}
|
||||
|
||||
private void shouldTrackIface(@NonNull final String iface, final boolean shouldTrack) {
|
||||
doReturn(shouldTrack).when(mEthernetTracker).isTrackingInterface(iface);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetConfigurationRejectsWhenEthNotStarted() {
|
||||
mEthernetServiceImpl.mStarted.set(false);
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
mEthernetServiceImpl.setConfiguration("" /* iface */, new IpConfiguration());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationRejectsWhenEthNotStarted() {
|
||||
mEthernetServiceImpl.mStarted.set(false);
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
mEthernetServiceImpl.updateConfiguration(
|
||||
"" /* iface */, UPDATE_REQUEST, null /* listener */);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectNetworkRejectsWhenEthNotStarted() {
|
||||
mEthernetServiceImpl.mStarted.set(false);
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
mEthernetServiceImpl.connectNetwork("" /* iface */, null /* listener */);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNetworkRejectsWhenEthNotStarted() {
|
||||
mEthernetServiceImpl.mStarted.set(false);
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
mEthernetServiceImpl.disconnectNetwork("" /* iface */, null /* listener */);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationRejectsNullIface() {
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
mEthernetServiceImpl.updateConfiguration(null, UPDATE_REQUEST, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectNetworkRejectsNullIface() {
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
mEthernetServiceImpl.connectNetwork(null /* iface */, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNetworkRejectsNullIface() {
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
mEthernetServiceImpl.disconnectNetwork(null /* iface */, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationWithCapabilitiesRejectsWithoutAutomotiveFeature() {
|
||||
toggleAutomotiveFeature(false);
|
||||
assertThrows(UnsupportedOperationException.class, () -> {
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationWithCapabilitiesWithAutomotiveFeature() {
|
||||
toggleAutomotiveFeature(false);
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_CAPABILITIES,
|
||||
NULL_LISTENER);
|
||||
verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
|
||||
eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getIpConfiguration()),
|
||||
eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getNetworkCapabilities()), isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectNetworkRejectsWithoutAutomotiveFeature() {
|
||||
toggleAutomotiveFeature(false);
|
||||
assertThrows(UnsupportedOperationException.class, () -> {
|
||||
mEthernetServiceImpl.connectNetwork("" /* iface */, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNetworkRejectsWithoutAutomotiveFeature() {
|
||||
toggleAutomotiveFeature(false);
|
||||
assertThrows(UnsupportedOperationException.class, () -> {
|
||||
mEthernetServiceImpl.disconnectNetwork("" /* iface */, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
private void denyManageEthPermission() {
|
||||
doThrow(new SecurityException("")).when(mContext)
|
||||
.enforceCallingOrSelfPermission(
|
||||
eq(Manifest.permission.MANAGE_ETHERNET_NETWORKS), anyString());
|
||||
}
|
||||
|
||||
private void denyManageTestNetworksPermission() {
|
||||
doThrow(new SecurityException("")).when(mContext)
|
||||
.enforceCallingOrSelfPermission(
|
||||
eq(Manifest.permission.MANAGE_TEST_NETWORKS), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationRejectsWithoutManageEthPermission() {
|
||||
denyManageEthPermission();
|
||||
assertThrows(SecurityException.class, () -> {
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectNetworkRejectsWithoutManageEthPermission() {
|
||||
denyManageEthPermission();
|
||||
assertThrows(SecurityException.class, () -> {
|
||||
mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNetworkRejectsWithoutManageEthPermission() {
|
||||
denyManageEthPermission();
|
||||
assertThrows(SecurityException.class, () -> {
|
||||
mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
private void enableTestInterface() {
|
||||
when(mEthernetTracker.isValidTestInterface(eq(TEST_IFACE))).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationRejectsTestRequestWithoutTestPermission() {
|
||||
enableTestInterface();
|
||||
denyManageTestNetworksPermission();
|
||||
assertThrows(SecurityException.class, () -> {
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectNetworkRejectsTestRequestWithoutTestPermission() {
|
||||
enableTestInterface();
|
||||
denyManageTestNetworksPermission();
|
||||
assertThrows(SecurityException.class, () -> {
|
||||
mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNetworkRejectsTestRequestWithoutTestPermission() {
|
||||
enableTestInterface();
|
||||
denyManageTestNetworksPermission();
|
||||
assertThrows(SecurityException.class, () -> {
|
||||
mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfiguration() {
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
|
||||
verify(mEthernetTracker).updateConfiguration(
|
||||
eq(TEST_IFACE),
|
||||
eq(UPDATE_REQUEST.getIpConfiguration()),
|
||||
eq(UPDATE_REQUEST.getNetworkCapabilities()), eq(NULL_LISTENER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectNetwork() {
|
||||
mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
verify(mEthernetTracker).connectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNetwork() {
|
||||
mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationAcceptsTestRequestWithNullCapabilities() {
|
||||
enableTestInterface();
|
||||
final EthernetNetworkUpdateRequest request =
|
||||
new EthernetNetworkUpdateRequest
|
||||
.Builder()
|
||||
.setIpConfiguration(new IpConfiguration()).build();
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER);
|
||||
verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
|
||||
eq(request.getIpConfiguration()),
|
||||
eq(request.getNetworkCapabilities()), isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationAcceptsRequestWithNullIpConfiguration() {
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_IP_CONFIG,
|
||||
NULL_LISTENER);
|
||||
verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
|
||||
eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getIpConfiguration()),
|
||||
eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getNetworkCapabilities()), isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationRejectsInvalidTestRequest() {
|
||||
enableTestInterface();
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
|
||||
});
|
||||
}
|
||||
|
||||
private EthernetNetworkUpdateRequest createTestNetworkUpdateRequest() {
|
||||
final NetworkCapabilities nc = new NetworkCapabilities
|
||||
.Builder(UPDATE_REQUEST.getNetworkCapabilities())
|
||||
.addTransportType(TRANSPORT_TEST).build();
|
||||
|
||||
return new EthernetNetworkUpdateRequest
|
||||
.Builder(UPDATE_REQUEST)
|
||||
.setNetworkCapabilities(nc).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfigurationForTestRequestDoesNotRequireAutoOrEthernetPermission() {
|
||||
enableTestInterface();
|
||||
toggleAutomotiveFeature(false);
|
||||
denyManageEthPermission();
|
||||
final EthernetNetworkUpdateRequest request = createTestNetworkUpdateRequest();
|
||||
|
||||
mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER);
|
||||
verify(mEthernetTracker).updateConfiguration(
|
||||
eq(TEST_IFACE),
|
||||
eq(request.getIpConfiguration()),
|
||||
eq(request.getNetworkCapabilities()), eq(NULL_LISTENER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectNetworkForTestRequestDoesNotRequireAutoOrNetPermission() {
|
||||
enableTestInterface();
|
||||
toggleAutomotiveFeature(false);
|
||||
denyManageEthPermission();
|
||||
|
||||
mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
verify(mEthernetTracker).connectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNetworkForTestRequestDoesNotRequireAutoOrNetPermission() {
|
||||
enableTestInterface();
|
||||
toggleAutomotiveFeature(false);
|
||||
denyManageEthPermission();
|
||||
|
||||
mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER));
|
||||
}
|
||||
|
||||
private void denyPermissions(String... permissions) {
|
||||
for (String permission: permissions) {
|
||||
doReturn(PackageManager.PERMISSION_DENIED).when(mContext)
|
||||
.checkCallingOrSelfPermission(eq(permission));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetEthernetEnabled() {
|
||||
denyPermissions(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
|
||||
mEthernetServiceImpl.setEthernetEnabled(true);
|
||||
verify(mEthernetTracker).setEthernetEnabled(true);
|
||||
reset(mEthernetTracker);
|
||||
|
||||
denyPermissions(Manifest.permission.NETWORK_STACK);
|
||||
mEthernetServiceImpl.setEthernetEnabled(false);
|
||||
verify(mEthernetTracker).setEthernetEnabled(false);
|
||||
reset(mEthernetTracker);
|
||||
|
||||
denyPermissions(Manifest.permission.NETWORK_SETTINGS);
|
||||
try {
|
||||
mEthernetServiceImpl.setEthernetEnabled(true);
|
||||
fail("Should get SecurityException");
|
||||
} catch (SecurityException e) { }
|
||||
verify(mEthernetTracker, never()).setEthernetEnabled(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.ethernet;
|
||||
|
||||
import static android.net.TestNetworkManager.TEST_TAP_PREFIX;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.EthernetManager;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.INetworkInterfaceOutcomeReceiver;
|
||||
import android.net.IEthernetServiceListener;
|
||||
import android.net.INetd;
|
||||
import android.net.IpConfiguration;
|
||||
import android.net.IpConfiguration.IpAssignment;
|
||||
import android.net.IpConfiguration.ProxySettings;
|
||||
import android.net.InterfaceConfigurationParcel;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.StaticIpConfiguration;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.connectivity.resources.R;
|
||||
import com.android.testutils.HandlerUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class EthernetTrackerTest {
|
||||
private static final String TEST_IFACE = "test123";
|
||||
private static final int TIMEOUT_MS = 1_000;
|
||||
private static final String THREAD_NAME = "EthernetServiceThread";
|
||||
private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
|
||||
private EthernetTracker tracker;
|
||||
private HandlerThread mHandlerThread;
|
||||
@Mock private Context mContext;
|
||||
@Mock private EthernetNetworkFactory mFactory;
|
||||
@Mock private INetd mNetd;
|
||||
@Mock private EthernetTracker.Dependencies mDeps;
|
||||
|
||||
@Before
|
||||
public void setUp() throws RemoteException {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
initMockResources();
|
||||
when(mFactory.updateInterfaceLinkState(anyString(), anyBoolean(), any())).thenReturn(false);
|
||||
when(mNetd.interfaceGetList()).thenReturn(new String[0]);
|
||||
mHandlerThread = new HandlerThread(THREAD_NAME);
|
||||
mHandlerThread.start();
|
||||
tracker = new EthernetTracker(mContext, mHandlerThread.getThreadHandler(), mFactory, mNetd,
|
||||
mDeps);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
mHandlerThread.quitSafely();
|
||||
}
|
||||
|
||||
private void initMockResources() {
|
||||
when(mDeps.getInterfaceRegexFromResource(eq(mContext))).thenReturn("");
|
||||
when(mDeps.getInterfaceConfigFromResource(eq(mContext))).thenReturn(new String[0]);
|
||||
}
|
||||
|
||||
private void waitForIdle() {
|
||||
HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test: Creation of various valid static IP configurations
|
||||
*/
|
||||
@Test
|
||||
public void createStaticIpConfiguration() {
|
||||
// Empty gives default StaticIPConfiguration object
|
||||
assertStaticConfiguration(new StaticIpConfiguration(), "");
|
||||
|
||||
// Setting only the IP address properly cascades and assumes defaults
|
||||
assertStaticConfiguration(new StaticIpConfiguration.Builder()
|
||||
.setIpAddress(new LinkAddress("192.0.2.10/24")).build(), "ip=192.0.2.10/24");
|
||||
|
||||
final ArrayList<InetAddress> dnsAddresses = new ArrayList<>();
|
||||
dnsAddresses.add(InetAddresses.parseNumericAddress("4.4.4.4"));
|
||||
dnsAddresses.add(InetAddresses.parseNumericAddress("8.8.8.8"));
|
||||
// Setting other fields properly cascades them
|
||||
assertStaticConfiguration(new StaticIpConfiguration.Builder()
|
||||
.setIpAddress(new LinkAddress("192.0.2.10/24"))
|
||||
.setDnsServers(dnsAddresses)
|
||||
.setGateway(InetAddresses.parseNumericAddress("192.0.2.1"))
|
||||
.setDomains("android").build(),
|
||||
"ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android");
|
||||
|
||||
// Verify order doesn't matter
|
||||
assertStaticConfiguration(new StaticIpConfiguration.Builder()
|
||||
.setIpAddress(new LinkAddress("192.0.2.10/24"))
|
||||
.setDnsServers(dnsAddresses)
|
||||
.setGateway(InetAddresses.parseNumericAddress("192.0.2.1"))
|
||||
.setDomains("android").build(),
|
||||
"domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test: Attempt creation of various bad static IP configurations
|
||||
*/
|
||||
@Test
|
||||
public void createStaticIpConfiguration_Bad() {
|
||||
assertStaticConfigurationFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key
|
||||
assertStaticConfigurationFails("ip=192.0.2.1"); // mask is missing
|
||||
assertStaticConfigurationFails("ip=a.b.c"); // not a valid ip address
|
||||
assertStaticConfigurationFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns
|
||||
assertStaticConfigurationFails("="); // Key and value is empty
|
||||
assertStaticConfigurationFails("ip="); // Value is empty
|
||||
assertStaticConfigurationFails("ip=192.0.2.1/24 gateway="); // Gateway is empty
|
||||
}
|
||||
|
||||
private void assertStaticConfigurationFails(String config) {
|
||||
try {
|
||||
EthernetTracker.parseStaticIpConfiguration(config);
|
||||
fail("Expected to fail: " + config);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
private void assertStaticConfiguration(StaticIpConfiguration expectedStaticIpConfig,
|
||||
String configAsString) {
|
||||
final IpConfiguration expectedIpConfiguration = new IpConfiguration();
|
||||
expectedIpConfiguration.setIpAssignment(IpAssignment.STATIC);
|
||||
expectedIpConfiguration.setProxySettings(ProxySettings.NONE);
|
||||
expectedIpConfiguration.setStaticIpConfiguration(expectedStaticIpConfig);
|
||||
|
||||
assertEquals(expectedIpConfiguration,
|
||||
EthernetTracker.parseStaticIpConfiguration(configAsString));
|
||||
}
|
||||
|
||||
private NetworkCapabilities.Builder makeEthernetCapabilitiesBuilder(boolean clearAll) {
|
||||
final NetworkCapabilities.Builder builder =
|
||||
clearAll ? NetworkCapabilities.Builder.withoutDefaultCapabilities()
|
||||
: new NetworkCapabilities.Builder();
|
||||
return builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test: Attempt to create a capabilties with various valid sets of capabilities/transports
|
||||
*/
|
||||
@Test
|
||||
public void createNetworkCapabilities() {
|
||||
|
||||
// Particularly common expected results
|
||||
NetworkCapabilities defaultEthernetCleared =
|
||||
makeEthernetCapabilitiesBuilder(true /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.build();
|
||||
|
||||
NetworkCapabilities ethernetClearedWithCommonCaps =
|
||||
makeEthernetCapabilitiesBuilder(true /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.addCapability(12)
|
||||
.addCapability(13)
|
||||
.addCapability(14)
|
||||
.addCapability(15)
|
||||
.build();
|
||||
|
||||
// Empty capabilities and transports lists with a "please clear defaults" should
|
||||
// yield an empty capabilities set with TRANPORT_ETHERNET
|
||||
assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "");
|
||||
|
||||
// Empty capabilities and transports without the clear defaults flag should return the
|
||||
// default capabilities set with TRANSPORT_ETHERNET
|
||||
assertParsedNetworkCapabilities(
|
||||
makeEthernetCapabilitiesBuilder(false /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.build(),
|
||||
false, "", "");
|
||||
|
||||
// A list of capabilities without the clear defaults flag should return the default
|
||||
// capabilities, mixed with the desired capabilities, and TRANSPORT_ETHERNET
|
||||
assertParsedNetworkCapabilities(
|
||||
makeEthernetCapabilitiesBuilder(false /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
.addCapability(11)
|
||||
.addCapability(12)
|
||||
.build(),
|
||||
false, "11,12", "");
|
||||
|
||||
// Adding a list of capabilities with a clear defaults will leave exactly those capabilities
|
||||
// with a default TRANSPORT_ETHERNET since no overrides are specified
|
||||
assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15", "");
|
||||
|
||||
// Adding any invalid capabilities to the list will cause them to be ignored
|
||||
assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,65,73", "");
|
||||
assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,abcdefg", "");
|
||||
|
||||
// Adding a valid override transport will remove the default TRANSPORT_ETHERNET transport
|
||||
// and apply only the override to the capabiltities object
|
||||
assertParsedNetworkCapabilities(
|
||||
makeEthernetCapabilitiesBuilder(true /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addTransportType(0)
|
||||
.build(),
|
||||
true, "", "0");
|
||||
assertParsedNetworkCapabilities(
|
||||
makeEthernetCapabilitiesBuilder(true /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addTransportType(1)
|
||||
.build(),
|
||||
true, "", "1");
|
||||
assertParsedNetworkCapabilities(
|
||||
makeEthernetCapabilitiesBuilder(true /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addTransportType(2)
|
||||
.build(),
|
||||
true, "", "2");
|
||||
assertParsedNetworkCapabilities(
|
||||
makeEthernetCapabilitiesBuilder(true /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addTransportType(3)
|
||||
.build(),
|
||||
true, "", "3");
|
||||
|
||||
// "4" is TRANSPORT_VPN, which is unsupported. Should default back to TRANPORT_ETHERNET
|
||||
assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "4");
|
||||
|
||||
// "5" is TRANSPORT_WIFI_AWARE, which is currently supported due to no legacy TYPE_NONE
|
||||
// conversion. When that becomes available, this test must be updated
|
||||
assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "5");
|
||||
|
||||
// "6" is TRANSPORT_LOWPAN, which is currently supported due to no legacy TYPE_NONE
|
||||
// conversion. When that becomes available, this test must be updated
|
||||
assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "6");
|
||||
|
||||
// Adding an invalid override transport will leave the transport as TRANSPORT_ETHERNET
|
||||
assertParsedNetworkCapabilities(defaultEthernetCleared,true, "", "100");
|
||||
assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "abcdefg");
|
||||
|
||||
// Ensure the adding of both capabilities and transports work
|
||||
assertParsedNetworkCapabilities(
|
||||
makeEthernetCapabilitiesBuilder(true /* clearAll */)
|
||||
.setLinkUpstreamBandwidthKbps(100000)
|
||||
.setLinkDownstreamBandwidthKbps(100000)
|
||||
.addCapability(12)
|
||||
.addCapability(13)
|
||||
.addCapability(14)
|
||||
.addCapability(15)
|
||||
.addTransportType(3)
|
||||
.build(),
|
||||
true, "12,13,14,15", "3");
|
||||
|
||||
// Ensure order does not matter for capability list
|
||||
assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "13,12,15,14", "");
|
||||
}
|
||||
|
||||
private void assertParsedNetworkCapabilities(NetworkCapabilities expectedNetworkCapabilities,
|
||||
boolean clearCapabilties, String configCapabiltiies,String configTransports) {
|
||||
assertEquals(expectedNetworkCapabilities,
|
||||
EthernetTracker.createNetworkCapabilities(clearCapabilties, configCapabiltiies,
|
||||
configTransports).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEthernetTrackerConfigReturnsCorrectValue() {
|
||||
final String capabilities = "2";
|
||||
final String ipConfig = "3";
|
||||
final String transport = "4";
|
||||
final String configString = String.join(";", TEST_IFACE, capabilities, ipConfig, transport);
|
||||
|
||||
final EthernetTracker.EthernetTrackerConfig config =
|
||||
EthernetTracker.createEthernetTrackerConfig(configString);
|
||||
|
||||
assertEquals(TEST_IFACE, config.mIface);
|
||||
assertEquals(capabilities, config.mCapabilities);
|
||||
assertEquals(ipConfig, config.mIpConfig);
|
||||
assertEquals(transport, config.mTransport);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEthernetTrackerConfigThrowsNpeWithNullInput() {
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> EthernetTracker.createEthernetTrackerConfig(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConfiguration() {
|
||||
final NetworkCapabilities capabilities = new NetworkCapabilities.Builder().build();
|
||||
final LinkAddress linkAddr = new LinkAddress("192.0.2.2/25");
|
||||
final StaticIpConfiguration staticIpConfig =
|
||||
new StaticIpConfiguration.Builder().setIpAddress(linkAddr).build();
|
||||
final IpConfiguration ipConfig =
|
||||
new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build();
|
||||
final INetworkInterfaceOutcomeReceiver listener = null;
|
||||
|
||||
tracker.updateConfiguration(TEST_IFACE, ipConfig, capabilities, listener);
|
||||
waitForIdle();
|
||||
|
||||
verify(mFactory).updateInterface(
|
||||
eq(TEST_IFACE), eq(ipConfig), eq(capabilities), eq(listener));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectNetworkCorrectlyCallsFactory() {
|
||||
tracker.connectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
waitForIdle();
|
||||
|
||||
verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(true /* up */),
|
||||
eq(NULL_LISTENER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnectNetworkCorrectlyCallsFactory() {
|
||||
tracker.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
|
||||
waitForIdle();
|
||||
|
||||
verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(false /* up */),
|
||||
eq(NULL_LISTENER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidTestInterfaceIsFalseWhenTestInterfacesAreNotIncluded() {
|
||||
final String validIfaceName = TEST_TAP_PREFIX + "123";
|
||||
tracker.setIncludeTestInterfaces(false);
|
||||
waitForIdle();
|
||||
|
||||
final boolean isValidTestInterface = tracker.isValidTestInterface(validIfaceName);
|
||||
|
||||
assertFalse(isValidTestInterface);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidTestInterfaceIsFalseWhenTestInterfaceNameIsInvalid() {
|
||||
final String invalidIfaceName = "123" + TEST_TAP_PREFIX;
|
||||
tracker.setIncludeTestInterfaces(true);
|
||||
waitForIdle();
|
||||
|
||||
final boolean isValidTestInterface = tracker.isValidTestInterface(invalidIfaceName);
|
||||
|
||||
assertFalse(isValidTestInterface);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValidTestInterfaceIsTrueWhenTestInterfacesIncludedAndValidName() {
|
||||
final String validIfaceName = TEST_TAP_PREFIX + "123";
|
||||
tracker.setIncludeTestInterfaces(true);
|
||||
waitForIdle();
|
||||
|
||||
final boolean isValidTestInterface = tracker.isValidTestInterface(validIfaceName);
|
||||
|
||||
assertTrue(isValidTestInterface);
|
||||
}
|
||||
|
||||
public static class EthernetStateListener extends IEthernetServiceListener.Stub {
|
||||
@Override
|
||||
public void onEthernetStateChanged(int state) { }
|
||||
|
||||
@Override
|
||||
public void onInterfaceStateChanged(String iface, int state, int role,
|
||||
IpConfiguration configuration) { }
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListenEthernetStateChange() throws Exception {
|
||||
final String testIface = "testtap123";
|
||||
final String testHwAddr = "11:22:33:44:55:66";
|
||||
final InterfaceConfigurationParcel ifaceParcel = new InterfaceConfigurationParcel();
|
||||
ifaceParcel.ifName = testIface;
|
||||
ifaceParcel.hwAddr = testHwAddr;
|
||||
ifaceParcel.flags = new String[] {INetd.IF_STATE_UP};
|
||||
|
||||
tracker.setIncludeTestInterfaces(true);
|
||||
waitForIdle();
|
||||
|
||||
when(mNetd.interfaceGetList()).thenReturn(new String[] {testIface});
|
||||
when(mNetd.interfaceGetCfg(eq(testIface))).thenReturn(ifaceParcel);
|
||||
doReturn(new String[] {testIface}).when(mFactory).getAvailableInterfaces(anyBoolean());
|
||||
doReturn(EthernetManager.STATE_LINK_UP).when(mFactory).getInterfaceState(eq(testIface));
|
||||
|
||||
final EthernetStateListener listener = spy(new EthernetStateListener());
|
||||
tracker.addListener(listener, true /* canUseRestrictedNetworks */);
|
||||
// Check default state.
|
||||
waitForIdle();
|
||||
verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_LINK_UP),
|
||||
anyInt(), any());
|
||||
verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_ENABLED));
|
||||
reset(listener);
|
||||
|
||||
doReturn(EthernetManager.STATE_ABSENT).when(mFactory).getInterfaceState(eq(testIface));
|
||||
tracker.setEthernetEnabled(false);
|
||||
waitForIdle();
|
||||
verify(mFactory).removeInterface(eq(testIface));
|
||||
verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_DISABLED));
|
||||
verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_ABSENT),
|
||||
anyInt(), any());
|
||||
reset(listener);
|
||||
|
||||
doReturn(EthernetManager.STATE_LINK_UP).when(mFactory).getInterfaceState(eq(testIface));
|
||||
tracker.setEthernetEnabled(true);
|
||||
waitForIdle();
|
||||
verify(mFactory).addInterface(eq(testIface), eq(testHwAddr), any(), any());
|
||||
verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_ENABLED));
|
||||
verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_LINK_UP),
|
||||
anyInt(), any());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user