Merge "Add unit tests for IKEv2 VPN setup and MOBIKE" am: e934e484c7

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2113906

Change-Id: I9afde149a585c369c60439835045cffcce12a50d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Yan Yan
2022-06-13 18:01:50 +00:00
committed by Automerger Merge Worker
2 changed files with 287 additions and 10 deletions

View File

@@ -1477,7 +1477,7 @@ public class ConnectivityServiceTest {
!mMockNetworkAgent.isBypassableVpn(), mVpnType)); !mMockNetworkAgent.isBypassableVpn(), mVpnType));
updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent"); updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities()); mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
mNetworkAgent = mMockNetworkAgent.getNetworkAgent(); mNetworkAgent = new Vpn.VpnNetworkAgentWrapper(mMockNetworkAgent.getNetworkAgent());
} }
private void registerAgent(Set<UidRange> uids) throws Exception { private void registerAgent(Set<UidRange> uids) throws Exception {

View File

@@ -27,11 +27,14 @@ import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static android.net.ConnectivityManager.NetworkCallback; import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_DOWN;
import static android.net.INetd.IF_STATE_UP; import static android.net.INetd.IF_STATE_UP;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.TYPE_VPN_PLATFORM; import static android.net.VpnManager.TYPE_VPN_PLATFORM;
import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE;
import static android.os.Build.VERSION_CODES.S_V2; import static android.os.Build.VERSION_CODES.S_V2;
import static android.os.UserHandle.PER_USER_RANGE; import static android.os.UserHandle.PER_USER_RANGE;
import static com.android.modules.utils.build.SdkLevel.isAtLeastT; import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.server.connectivity.Vpn.VpnNetworkAgentWrapper;
import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import static com.android.testutils.MiscAsserts.assertThrows; import static com.android.testutils.MiscAsserts.assertThrows;
@@ -59,6 +62,7 @@ import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -83,7 +87,9 @@ import android.net.Ikev2VpnProfile;
import android.net.InetAddresses; import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel; import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix; import android.net.IpPrefix;
import android.net.IpSecConfig;
import android.net.IpSecManager; import android.net.IpSecManager;
import android.net.IpSecTransform;
import android.net.IpSecTunnelInterfaceResponse; import android.net.IpSecTunnelInterfaceResponse;
import android.net.LinkAddress; import android.net.LinkAddress;
import android.net.LinkProperties; import android.net.LinkProperties;
@@ -100,7 +106,12 @@ import android.net.VpnManager;
import android.net.VpnProfileState; import android.net.VpnProfileState;
import android.net.VpnService; import android.net.VpnService;
import android.net.VpnTransportInfo; import android.net.VpnTransportInfo;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.IkeSessionCallback; import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionConfiguration;
import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.exceptions.IkeException; import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeNetworkLostException; import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
import android.net.ipsec.ike.exceptions.IkeNonProtocolException; import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
@@ -121,6 +132,7 @@ import android.provider.Settings;
import android.security.Credentials; import android.security.Credentials;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Pair;
import android.util.Range; import android.util.Range;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -155,6 +167,7 @@ import java.io.FileDescriptor;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -165,6 +178,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -198,11 +212,37 @@ public class VpnTest {
static final Network EGRESS_NETWORK = new Network(101); static final Network EGRESS_NETWORK = new Network(101);
static final String EGRESS_IFACE = "wlan0"; static final String EGRESS_IFACE = "wlan0";
static final String TEST_VPN_PKG = "com.testvpn.vpn"; static final String TEST_VPN_PKG = "com.testvpn.vpn";
private static final String TEST_VPN_CLIENT = "2.4.6.8";
private static final String TEST_VPN_SERVER = "1.2.3.4"; private static final String TEST_VPN_SERVER = "1.2.3.4";
private static final String TEST_VPN_IDENTITY = "identity"; private static final String TEST_VPN_IDENTITY = "identity";
private static final byte[] TEST_VPN_PSK = "psk".getBytes(); private static final byte[] TEST_VPN_PSK = "psk".getBytes();
private static final int IP4_PREFIX_LEN = 32;
private static final int MIN_PORT = 0;
private static final int MAX_PORT = 65535;
private static final InetAddress TEST_VPN_CLIENT_IP =
InetAddresses.parseNumericAddress(TEST_VPN_CLIENT);
private static final InetAddress TEST_VPN_SERVER_IP =
InetAddresses.parseNumericAddress(TEST_VPN_SERVER);
private static final InetAddress TEST_VPN_CLIENT_IP_2 =
InetAddresses.parseNumericAddress("192.0.2.200");
private static final InetAddress TEST_VPN_SERVER_IP_2 =
InetAddresses.parseNumericAddress("192.0.2.201");
private static final InetAddress TEST_VPN_INTERNAL_IP =
InetAddresses.parseNumericAddress("198.51.100.10");
private static final InetAddress TEST_VPN_INTERNAL_DNS =
InetAddresses.parseNumericAddress("8.8.8.8");
private static final IkeTrafficSelector IN_TS =
new IkeTrafficSelector(MIN_PORT, MAX_PORT, TEST_VPN_INTERNAL_IP, TEST_VPN_INTERNAL_IP);
private static final IkeTrafficSelector OUT_TS =
new IkeTrafficSelector(MIN_PORT, MAX_PORT,
InetAddresses.parseNumericAddress("0.0.0.0"),
InetAddresses.parseNumericAddress("255.255.255.255"));
private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE); private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE);
private static final Network TEST_NETWORK_2 = new Network(Integer.MAX_VALUE - 1);
private static final String TEST_IFACE_NAME = "TEST_IFACE"; private static final String TEST_IFACE_NAME = "TEST_IFACE";
private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345; private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345;
private static final long TEST_TIMEOUT_MS = 500L; private static final long TEST_TIMEOUT_MS = 500L;
@@ -234,7 +274,9 @@ public class VpnTest {
@Mock private AppOpsManager mAppOps; @Mock private AppOpsManager mAppOps;
@Mock private NotificationManager mNotificationManager; @Mock private NotificationManager mNotificationManager;
@Mock private Vpn.SystemServices mSystemServices; @Mock private Vpn.SystemServices mSystemServices;
@Mock private Vpn.IkeSessionWrapper mIkeSessionWrapper;
@Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator; @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
@Mock private Vpn.VpnNetworkAgentWrapper mVpnNetworkAgentWrapper;
@Mock private ConnectivityManager mConnectivityManager; @Mock private ConnectivityManager mConnectivityManager;
@Mock private IpSecService mIpSecService; @Mock private IpSecService mIpSecService;
@Mock private VpnProfileStore mVpnProfileStore; @Mock private VpnProfileStore mVpnProfileStore;
@@ -243,6 +285,8 @@ public class VpnTest {
private IpSecManager mIpSecManager; private IpSecManager mIpSecManager;
private TestDeps mTestDeps;
public VpnTest() throws Exception { public VpnTest() throws Exception {
// Build an actual VPN profile that is capable of being converted to and from an // Build an actual VPN profile that is capable of being converted to and from an
// Ikev2VpnProfile // Ikev2VpnProfile
@@ -257,6 +301,7 @@ public class VpnTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mIpSecManager = new IpSecManager(mContext, mIpSecService); mIpSecManager = new IpSecManager(mContext, mIpSecService);
mTestDeps = spy(new TestDeps());
when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getPackageManager()).thenReturn(mPackageManager);
setMockedPackages(mPackages); setMockedPackages(mPackages);
@@ -297,6 +342,14 @@ public class VpnTest {
// itself, so set the default value of Context#checkCallingOrSelfPermission to // itself, so set the default value of Context#checkCallingOrSelfPermission to
// PERMISSION_DENIED. // PERMISSION_DENIED.
doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any()); doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any());
resetIkev2SessionCreator(mIkeSessionWrapper);
}
private void resetIkev2SessionCreator(Vpn.IkeSessionWrapper ikeSession) {
reset(mIkev2SessionCreator);
when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
.thenReturn(ikeSession);
} }
@After @After
@@ -808,10 +861,11 @@ public class VpnTest {
vpn.startVpnProfile(TEST_VPN_PKG); vpn.startVpnProfile(TEST_VPN_PKG);
verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
vpn.mNetworkAgent = new NetworkAgent(mContext, Looper.getMainLooper(), TAG, vpn.mNetworkAgent = new VpnNetworkAgentWrapper(
new NetworkCapabilities.Builder().build(), new LinkProperties(), 10 /* score */, new NetworkAgent(mContext, Looper.getMainLooper(), TAG,
new NetworkAgentConfig.Builder().build(), new NetworkCapabilities.Builder().build(), new LinkProperties(),
new NetworkProvider(mContext, Looper.getMainLooper(), TAG)) {}; 10 /* score */, new NetworkAgentConfig.Builder().build(),
new NetworkProvider(mContext, Looper.getMainLooper(), TAG)) {});
return vpn; return vpn;
} }
@@ -1320,6 +1374,10 @@ public class VpnTest {
final ArgumentCaptor<IkeSessionCallback> captor = final ArgumentCaptor<IkeSessionCallback> captor =
ArgumentCaptor.forClass(IkeSessionCallback.class); ArgumentCaptor.forClass(IkeSessionCallback.class);
// This test depends on a real ScheduledThreadPoolExecutor
doReturn(new ScheduledThreadPoolExecutor(1)).when(mTestDeps)
.getScheduledThreadPoolExecutor();
final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode()); .thenReturn(mVpnProfile.encode());
@@ -1491,13 +1549,216 @@ public class VpnTest {
return vpn; return vpn;
} }
private IkeSessionConnectionInfo createIkeConnectInfo() {
return new IkeSessionConnectionInfo(TEST_VPN_CLIENT_IP, TEST_VPN_SERVER_IP, TEST_NETWORK);
}
private IkeSessionConnectionInfo createNewIkeConnectInfo() {
return new IkeSessionConnectionInfo(
TEST_VPN_CLIENT_IP_2, TEST_VPN_SERVER_IP_2, TEST_NETWORK_2);
}
private IkeSessionConfiguration createIkeConfig(
IkeSessionConnectionInfo ikeConnectInfo, boolean isMobikeEnabled) {
final IkeSessionConfiguration.Builder builder =
new IkeSessionConfiguration.Builder(ikeConnectInfo);
if (isMobikeEnabled) {
builder.addIkeExtension(EXTENSION_TYPE_MOBIKE);
}
return builder.build();
}
private ChildSessionConfiguration createChildConfig() {
return new ChildSessionConfiguration.Builder(Arrays.asList(IN_TS), Arrays.asList(OUT_TS))
.addInternalAddress(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN))
.addInternalDnsServer(TEST_VPN_INTERNAL_DNS)
.build();
}
private IpSecTransform createIpSecTransform() {
return new IpSecTransform(mContext, new IpSecConfig());
}
private void verifyApplyTunnelModeTransforms(int expectedTimes) throws Exception {
verify(mIpSecService, times(expectedTimes)).applyTunnelModeTransform(
eq(TEST_TUNNEL_RESOURCE_ID), eq(IpSecManager.DIRECTION_IN),
anyInt(), anyString());
verify(mIpSecService, times(expectedTimes)).applyTunnelModeTransform(
eq(TEST_TUNNEL_RESOURCE_ID), eq(IpSecManager.DIRECTION_OUT),
anyInt(), anyString());
}
private Pair<IkeSessionCallback, ChildSessionCallback> verifyCreateIkeAndCaptureCbs()
throws Exception {
final ArgumentCaptor<IkeSessionCallback> ikeCbCaptor =
ArgumentCaptor.forClass(IkeSessionCallback.class);
final ArgumentCaptor<ChildSessionCallback> childCbCaptor =
ArgumentCaptor.forClass(ChildSessionCallback.class);
verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS)).createIkeSession(
any(), any(), any(), any(), ikeCbCaptor.capture(), childCbCaptor.capture());
final IkeSessionCallback ikeCb = ikeCbCaptor.getValue();
final ChildSessionCallback childCb = childCbCaptor.getValue();
return new Pair<>(ikeCbCaptor.getValue(), childCbCaptor.getValue());
}
private static class PlatformVpnSnapshot {
public final Vpn vpn;
public final NetworkCallback nwCb;
public final IkeSessionCallback ikeCb;
public final ChildSessionCallback childCb;
PlatformVpnSnapshot(Vpn vpn, NetworkCallback nwCb,
IkeSessionCallback ikeCb, ChildSessionCallback childCb) {
this.vpn = vpn;
this.nwCb = nwCb;
this.ikeCb = ikeCb;
this.childCb = childCb;
}
}
private PlatformVpnSnapshot verifySetupPlatformVpn(IkeSessionConfiguration ikeConfig)
throws Exception {
doReturn(mVpnNetworkAgentWrapper).when(mTestDeps)
.getVpnNetworkAgentWrapper(
any(), any(), anyString(), any(), any(), any(), any(), any());
final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
vpn.startVpnProfile(TEST_VPN_PKG);
final NetworkCallback nwCb = triggerOnAvailableAndGetCallback();
// Mock the setup procedure by firing callbacks
final Pair<IkeSessionCallback, ChildSessionCallback> cbPair =
verifyCreateIkeAndCaptureCbs();
final IkeSessionCallback ikeCb = cbPair.first;
final ChildSessionCallback childCb = cbPair.second;
ikeCb.onOpened(ikeConfig);
childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_IN);
childCb.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_OUT);
childCb.onOpened(createChildConfig());
// Verification VPN setup
verifyApplyTunnelModeTransforms(1);
ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
verify(mTestDeps).getVpnNetworkAgentWrapper(
any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(),
any(), any(), any());
// Check LinkProperties
final LinkProperties lp = lpCaptor.getValue();
final List<RouteInfo> expectedRoutes = Arrays.asList(
new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/,
TEST_IFACE_NAME, RouteInfo.RTN_UNICAST),
new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
TEST_IFACE_NAME, RTN_UNREACHABLE));
assertEquals(expectedRoutes, lp.getRoutes());
// Check internal addresses
final List<LinkAddress> expectedAddresses =
Arrays.asList(new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN));
assertEquals(expectedAddresses, lp.getLinkAddresses());
// Check internal DNS
assertEquals(Arrays.asList(TEST_VPN_INTERNAL_DNS), lp.getDnsServers());
// Check NetworkCapabilities
assertEquals(Arrays.asList(TEST_NETWORK), ncCaptor.getValue().getUnderlyingNetworks());
return new PlatformVpnSnapshot(vpn, nwCb, ikeCb, childCb);
}
@Test @Test
public void testStartPlatformVpn() throws Exception { public void testStartPlatformVpn() throws Exception {
startLegacyVpn(createVpn(primaryUser.id), mVpnProfile); final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
// TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
// a subsequent patch. vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
} }
@Test
public void testStartPlatformVpnMobility_mobikeEnabled() throws Exception {
final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
// Mock network switch
vpnSnapShot.nwCb.onLost(TEST_NETWORK);
vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
// Verify MOBIKE is triggered
verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2);
// Mock the MOBIKE procedure
vpnSnapShot.ikeCb.onIkeSessionConnectionInfoChanged(createNewIkeConnectInfo());
vpnSnapShot.childCb.onIpSecTransformsMigrated(
createIpSecTransform(), createIpSecTransform());
verify(mIpSecService).setNetworkForTunnelInterface(
eq(TEST_TUNNEL_RESOURCE_ID), eq(TEST_NETWORK_2), anyString());
// Expect 2 times: one for initial setup and one for MOBIKE
verifyApplyTunnelModeTransforms(2);
// Verify mNetworkCapabilities and mNetworkAgent are updated
assertEquals(
Collections.singletonList(TEST_NETWORK_2),
vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
verify(mVpnNetworkAgentWrapper)
.setUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
}
@Test
public void testStartPlatformVpnReestablishes_mobikeDisabled() throws Exception {
final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
// Forget the first IKE creation
resetIkev2SessionCreator(mock(Vpn.IkeSessionWrapper.class));
// Mock network switch
vpnSnapShot.nwCb.onLost(TEST_NETWORK);
vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
// Verify the old IKE Session is killed
verify(mIkeSessionWrapper).kill();
final Pair<IkeSessionCallback, ChildSessionCallback> cbPair =
verifyCreateIkeAndCaptureCbs();
final IkeSessionCallback ikeCbNew = cbPair.first;
final ChildSessionCallback childCbNew = cbPair.second;
// Mock the IKE Session setup
ikeCbNew.onOpened(createIkeConfig(createNewIkeConnectInfo(), false /* isMobikeEnabled */));
childCbNew.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_IN);
childCbNew.onIpSecTransformCreated(createIpSecTransform(), IpSecManager.DIRECTION_OUT);
childCbNew.onOpened(createChildConfig());
// Expect 2 times since there have been two Session setups
verifyApplyTunnelModeTransforms(2);
// Verify mNetworkCapabilities and mNetworkAgent are updated
assertEquals(
Collections.singletonList(TEST_NETWORK_2),
vpnSnapShot.vpn.mNetworkCapabilities.getUnderlyingNetworks());
verify(mVpnNetworkAgentWrapper)
.setUnderlyingNetworks(Collections.singletonList(TEST_NETWORK_2));
vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
}
// TODO: Add a test for network loss without mobility
@Test @Test
public void testStartRacoonNumericAddress() throws Exception { public void testStartRacoonNumericAddress() throws Exception {
startRacoon("1.2.3.4", "1.2.3.4"); startRacoon("1.2.3.4", "1.2.3.4");
@@ -1578,7 +1839,8 @@ public class VpnTest {
} }
} }
private final class TestDeps extends Vpn.Dependencies { // Make it public and un-final so as to spy it
public class TestDeps extends Vpn.Dependencies {
public final CompletableFuture<String[]> racoonArgs = new CompletableFuture(); public final CompletableFuture<String[]> racoonArgs = new CompletableFuture();
public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture(); public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture();
public final File mStateFile; public final File mStateFile;
@@ -1713,10 +1975,25 @@ public class VpnTest {
return mDeviceIdleInternal; return mDeviceIdleInternal;
} }
@Override
public long getNextRetryDelaySeconds(int retryCount) { public long getNextRetryDelaySeconds(int retryCount) {
// Simply return retryCount as the delay seconds for retrying. // Simply return retryCount as the delay seconds for retrying.
return retryCount; return retryCount;
} }
@Override
public ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() {
final ScheduledThreadPoolExecutor mockExecutor =
mock(ScheduledThreadPoolExecutor.class);
doAnswer(
(invocation) -> {
((Runnable) invocation.getArgument(0)).run();
return null;
})
.when(mockExecutor)
.execute(any());
return mockExecutor;
}
} }
/** /**
@@ -1728,7 +2005,7 @@ public class VpnTest {
when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt())) when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
.thenReturn(asUserContext); .thenReturn(asUserContext);
final TestLooper testLooper = new TestLooper(); final TestLooper testLooper = new TestLooper();
final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService, final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, mTestDeps, mNetService,
mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator); mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator);
verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat( verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
provider -> provider.getName().contains("VpnNetworkProvider") provider -> provider.getName().contains("VpnNetworkProvider")