Merge "Verify VPN can handle network loss"
This commit is contained in:
@@ -41,6 +41,7 @@ import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
@@ -177,6 +178,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
@@ -279,6 +281,8 @@ public class VpnTest {
|
||||
@Mock private ConnectivityManager mConnectivityManager;
|
||||
@Mock private IpSecService mIpSecService;
|
||||
@Mock private VpnProfileStore mVpnProfileStore;
|
||||
@Mock private ScheduledThreadPoolExecutor mExecutor;
|
||||
@Mock private ScheduledFuture mScheduledFuture;
|
||||
@Mock DeviceIdleInternal mDeviceIdleInternal;
|
||||
private final VpnProfile mVpnProfile;
|
||||
|
||||
@@ -342,7 +346,9 @@ public class VpnTest {
|
||||
// PERMISSION_DENIED.
|
||||
doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any());
|
||||
|
||||
// Set up mIkev2SessionCreator and mExecutor
|
||||
resetIkev2SessionCreator(mIkeSessionWrapper);
|
||||
resetExecutor(mScheduledFuture);
|
||||
}
|
||||
|
||||
private void resetIkev2SessionCreator(Vpn.IkeSessionWrapper ikeSession) {
|
||||
@@ -351,6 +357,18 @@ public class VpnTest {
|
||||
.thenReturn(ikeSession);
|
||||
}
|
||||
|
||||
private void resetExecutor(ScheduledFuture scheduledFuture) {
|
||||
doAnswer(
|
||||
(invocation) -> {
|
||||
((Runnable) invocation.getArgument(0)).run();
|
||||
return null;
|
||||
})
|
||||
.when(mExecutor)
|
||||
.execute(any());
|
||||
when(mExecutor.schedule(
|
||||
any(Runnable.class), anyLong(), any())).thenReturn(mScheduledFuture);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
|
||||
@@ -1372,10 +1390,6 @@ public class VpnTest {
|
||||
final ArgumentCaptor<IkeSessionCallback> captor =
|
||||
ArgumentCaptor.forClass(IkeSessionCallback.class);
|
||||
|
||||
// This test depends on a real ScheduledThreadPoolExecutor
|
||||
doReturn(new ScheduledThreadPoolExecutor(1)).when(mTestDeps)
|
||||
.newScheduledThreadPoolExecutor();
|
||||
|
||||
final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
|
||||
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
|
||||
.thenReturn(mVpnProfile.encode());
|
||||
@@ -1400,25 +1414,38 @@ public class VpnTest {
|
||||
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
|
||||
.unregisterNetworkCallback(eq(cb));
|
||||
} else if (errorType == VpnManager.ERROR_CLASS_RECOVERABLE) {
|
||||
// To prevent spending much time to test the retry function, only retry 2 times here.
|
||||
int retryIndex = 0;
|
||||
verify(mIkev2SessionCreator,
|
||||
timeout(((TestDeps) vpn.mDeps).getNextRetryDelaySeconds(retryIndex++) * 1000
|
||||
+ TEST_TIMEOUT_MS))
|
||||
.createIkeSession(any(), any(), any(), any(), captor.capture(), any());
|
||||
final IkeSessionCallback ikeCb2 = verifyRetryAndGetNewIkeCb(retryIndex++);
|
||||
|
||||
// Capture a new IkeSessionCallback to get the latest token.
|
||||
reset(mIkev2SessionCreator);
|
||||
final IkeSessionCallback ikeCb2 = captor.getValue();
|
||||
ikeCb2.onClosedWithException(exception);
|
||||
verify(mIkev2SessionCreator,
|
||||
timeout(((TestDeps) vpn.mDeps).getNextRetryDelaySeconds(retryIndex++) * 1000
|
||||
+ TEST_TIMEOUT_MS))
|
||||
.createIkeSession(any(), any(), any(), any(), captor.capture(), any());
|
||||
reset(mIkev2SessionCreator);
|
||||
verifyRetryAndGetNewIkeCb(retryIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
private IkeSessionCallback verifyRetryAndGetNewIkeCb(int retryIndex) {
|
||||
final ArgumentCaptor<Runnable> runnableCaptor =
|
||||
ArgumentCaptor.forClass(Runnable.class);
|
||||
final ArgumentCaptor<IkeSessionCallback> ikeCbCaptor =
|
||||
ArgumentCaptor.forClass(IkeSessionCallback.class);
|
||||
|
||||
// Verify retry is scheduled
|
||||
final long expectedDelay = mTestDeps.getNextRetryDelaySeconds(retryIndex);
|
||||
verify(mExecutor).schedule(runnableCaptor.capture(), eq(expectedDelay), any());
|
||||
|
||||
// Mock the event of firing the retry task
|
||||
runnableCaptor.getValue().run();
|
||||
|
||||
verify(mIkev2SessionCreator)
|
||||
.createIkeSession(any(), any(), any(), any(), ikeCbCaptor.capture(), any());
|
||||
|
||||
// Forget the mIkev2SessionCreator#createIkeSession call and mExecutor#schedule call
|
||||
// for the next retry verification
|
||||
resetIkev2SessionCreator(mIkeSessionWrapper);
|
||||
resetExecutor(mScheduledFuture);
|
||||
|
||||
return ikeCbCaptor.getValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartPlatformVpnAuthenticationFailed() throws Exception {
|
||||
final IkeProtocolException exception = mock(IkeProtocolException.class);
|
||||
@@ -1685,9 +1712,13 @@ public class VpnTest {
|
||||
final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
|
||||
createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
|
||||
|
||||
// Mock network switch
|
||||
// Mock network loss and verify a cleanup task is scheduled
|
||||
vpnSnapShot.nwCb.onLost(TEST_NETWORK);
|
||||
verify(mExecutor).schedule(any(Runnable.class), anyLong(), any());
|
||||
|
||||
// Mock new network comes up and the cleanup task is cancelled
|
||||
vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
|
||||
verify(mScheduledFuture).cancel(anyBoolean());
|
||||
|
||||
// Verify MOBIKE is triggered
|
||||
verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2);
|
||||
@@ -1755,7 +1786,55 @@ public class VpnTest {
|
||||
vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
|
||||
}
|
||||
|
||||
// TODO: Add a test for network loss without mobility
|
||||
private void verifyHandlingNetworkLoss() throws Exception {
|
||||
final ArgumentCaptor<LinkProperties> lpCaptor =
|
||||
ArgumentCaptor.forClass(LinkProperties.class);
|
||||
verify(mMockNetworkAgent).sendLinkProperties(lpCaptor.capture());
|
||||
final LinkProperties lp = lpCaptor.getValue();
|
||||
|
||||
assertNull(lp.getInterfaceName());
|
||||
final List<RouteInfo> expectedRoutes = Arrays.asList(
|
||||
new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/,
|
||||
null /*iface*/, RTN_UNREACHABLE),
|
||||
new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
|
||||
null /*iface*/, RTN_UNREACHABLE));
|
||||
assertEquals(expectedRoutes, lp.getRoutes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartPlatformVpnHandlesNetworkLoss_mobikeEnabled() throws Exception {
|
||||
final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
|
||||
createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
|
||||
|
||||
// Forget the #sendLinkProperties during first setup.
|
||||
reset(mMockNetworkAgent);
|
||||
|
||||
final ArgumentCaptor<Runnable> runnableCaptor =
|
||||
ArgumentCaptor.forClass(Runnable.class);
|
||||
|
||||
// Mock network loss
|
||||
vpnSnapShot.nwCb.onLost(TEST_NETWORK);
|
||||
|
||||
// Mock the grace period expires
|
||||
verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any());
|
||||
runnableCaptor.getValue().run();
|
||||
|
||||
verifyHandlingNetworkLoss();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartPlatformVpnHandlesNetworkLoss_mobikeDisabled() throws Exception {
|
||||
final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
|
||||
createIkeConfig(createIkeConnectInfo(), false /* isMobikeEnabled */));
|
||||
|
||||
// Forget the #sendLinkProperties during first setup.
|
||||
reset(mMockNetworkAgent);
|
||||
|
||||
// Mock network loss
|
||||
vpnSnapShot.nwCb.onLost(TEST_NETWORK);
|
||||
|
||||
verifyHandlingNetworkLoss();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartRacoonNumericAddress() throws Exception {
|
||||
@@ -1981,16 +2060,7 @@ public class VpnTest {
|
||||
|
||||
@Override
|
||||
public ScheduledThreadPoolExecutor newScheduledThreadPoolExecutor() {
|
||||
final ScheduledThreadPoolExecutor mockExecutor =
|
||||
mock(ScheduledThreadPoolExecutor.class);
|
||||
doAnswer(
|
||||
(invocation) -> {
|
||||
((Runnable) invocation.getArgument(0)).run();
|
||||
return null;
|
||||
})
|
||||
.when(mockExecutor)
|
||||
.execute(any());
|
||||
return mockExecutor;
|
||||
return mExecutor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user