Test Network startup in ConnectedState
Add additional tests based on proxy implementations of
ChildSessionCallback and ChildSessionConfiguration
Bug: 165827287
Test: atest FrameworksVcnTests
Change-Id: I165716a0212da7c06b9723656ffe35921cf81854
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 9ecdf1b..4d5cf4f 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -75,6 +75,7 @@
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -297,9 +298,9 @@
private static final int EVENT_SETUP_COMPLETED = 6;
private static class EventSetupCompletedInfo implements EventInfo {
- @NonNull public final ChildSessionConfiguration childSessionConfig;
+ @NonNull public final VcnChildSessionConfiguration childSessionConfig;
- EventSetupCompletedInfo(@NonNull ChildSessionConfiguration childSessionConfig) {
+ EventSetupCompletedInfo(@NonNull VcnChildSessionConfiguration childSessionConfig) {
this.childSessionConfig = Objects.requireNonNull(childSessionConfig);
}
@@ -471,7 +472,7 @@
* <p>Set in Connected and Migrating states, always @NonNull in Connected, Migrating
* states, @Nullable otherwise.
*/
- private ChildSessionConfiguration mChildConfig;
+ private VcnChildSessionConfiguration mChildConfig;
/**
* The active network agent.
@@ -659,7 +660,7 @@
new EventTransformCreatedInfo(direction, transform));
}
- private void childOpened(int token, @NonNull ChildSessionConfiguration childConfig) {
+ private void childOpened(int token, @NonNull VcnChildSessionConfiguration childConfig) {
sendMessage(EVENT_SETUP_COMPLETED, token, new EventSetupCompletedInfo(childConfig));
}
@@ -1008,7 +1009,7 @@
protected void updateNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull NetworkAgent agent,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
@@ -1020,7 +1021,7 @@
protected NetworkAgent buildNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
@@ -1068,15 +1069,15 @@
protected void setupInterface(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
setupInterface(token, tunnelIface, childConfig, null);
}
protected void setupInterface(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig,
- @Nullable ChildSessionConfiguration oldChildConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig,
+ @Nullable VcnChildSessionConfiguration oldChildConfig) {
try {
final Set<LinkAddress> newAddrs =
new ArraySet<>(childConfig.getInternalAddresses());
@@ -1189,7 +1190,7 @@
protected void setupInterfaceAndNetworkAgent(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
setupInterface(token, tunnelIface, childConfig);
if (mNetworkAgent == null) {
@@ -1277,7 +1278,7 @@
private static LinkProperties buildConnectedLinkProperties(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull ChildSessionConfiguration childConfig) {
+ @NonNull VcnChildSessionConfiguration childConfig) {
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName(tunnelIface.getInterfaceName());
@@ -1328,17 +1329,25 @@
}
}
- private class ChildSessionCallbackImpl implements ChildSessionCallback {
+ /** Implementation of ChildSessionCallback, exposed for testing. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public class VcnChildSessionCallback implements ChildSessionCallback {
private final int mToken;
- ChildSessionCallbackImpl(int token) {
+ VcnChildSessionCallback(int token) {
mToken = token;
}
+ /** Internal proxy method for injecting of mocked ChildSessionConfiguration */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void onOpened(@NonNull VcnChildSessionConfiguration childConfig) {
+ Slog.v(TAG, "ChildOpened for token " + mToken);
+ childOpened(mToken, childConfig);
+ }
+
@Override
public void onOpened(@NonNull ChildSessionConfiguration childConfig) {
- Slog.v(TAG, "ChildOpened for token " + mToken);
- childOpened(mToken, childConfig);
+ onOpened(new VcnChildSessionConfiguration(childConfig));
}
@Override
@@ -1421,7 +1430,7 @@
buildIkeParams(),
buildChildParams(),
new IkeSessionCallbackImpl(token),
- new ChildSessionCallbackImpl(token));
+ new VcnChildSessionCallback(token));
}
/** External dependencies used by VcnGatewayConnection, for injection in tests */
@@ -1458,6 +1467,35 @@
}
}
+ /**
+ * Proxy implementation of Child Session Configuration, used for testing.
+ *
+ * <p>This wrapper allows mocking of the final, parcelable ChildSessionConfiguration object for
+ * testing purposes. This is the unfortunate result of mockito-inline (for mocking final
+ * classes) not working properly with system services & associated classes.
+ *
+ * <p>This class MUST EXCLUSIVELY be a passthrough, proxying calls directly to the actual
+ * ChildSessionConfiguration.
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class VcnChildSessionConfiguration {
+ private final ChildSessionConfiguration mChildConfig;
+
+ public VcnChildSessionConfiguration(ChildSessionConfiguration childConfig) {
+ mChildConfig = childConfig;
+ }
+
+ /** Retrieves the addresses to be used inside the tunnel. */
+ public List<LinkAddress> getInternalAddresses() {
+ return mChildConfig.getInternalAddresses();
+ }
+
+ /** Retrieves the DNS servers to be used inside the tunnel. */
+ public List<InetAddress> getInternalDnsServers() {
+ return mChildConfig.getInternalDnsServers();
+ }
+ }
+
/** Proxy implementation of IKE session, used for testing. */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class VcnIkeSession {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index e20070e..278d93a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -18,22 +18,35 @@
import static android.net.IpSecManager.DIRECTION_IN;
import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+
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.ArgumentCaptor;
+
+import java.util.Collections;
/** Tests for VcnGatewayConnection.ConnectedState */
@RunWith(AndroidJUnit4.class)
@@ -107,6 +120,51 @@
}
@Test
+ public void testChildOpenedRegistersNetwork() throws Exception {
+ final VcnChildSessionConfiguration mMockChildSessionConfig =
+ mock(VcnChildSessionConfiguration.class);
+ doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
+ .when(mMockChildSessionConfig)
+ .getInternalAddresses();
+ doReturn(Collections.singletonList(TEST_DNS_ADDR))
+ .when(mMockChildSessionConfig)
+ .getInternalDnsServers();
+
+ getChildSessionCallback().onOpened(mMockChildSessionConfig);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+
+ final ArgumentCaptor<LinkProperties> lpCaptor =
+ ArgumentCaptor.forClass(LinkProperties.class);
+ final ArgumentCaptor<NetworkCapabilities> ncCaptor =
+ ArgumentCaptor.forClass(NetworkCapabilities.class);
+ verify(mConnMgr)
+ .registerNetworkAgent(
+ any(),
+ any(),
+ lpCaptor.capture(),
+ ncCaptor.capture(),
+ anyInt(),
+ any(),
+ anyInt());
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+ final LinkProperties lp = lpCaptor.getValue();
+ assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
+ assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
+
+ final NetworkCapabilities nc = ncCaptor.getValue();
+ assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+ for (int cap : mConfig.getAllExposedCapabilities()) {
+ assertTrue(nc.hasCapability(cap));
+ }
+ }
+
+ @Test
public void testChildSessionClosedTriggersDisconnect() throws Exception {
getChildSessionCallback().onClosed();
mTestLooper.dispatchAll();
@@ -122,6 +180,4 @@
assertEquals(mGatewayConnection.mRetryTimeoutState, mGatewayConnection.getCurrentState());
verify(mIkeSession).close();
}
-
- // TODO: Add tests for childOpened() when ChildSessionConfiguration can be mocked or created
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 333b5b9..d449eab 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -27,10 +27,13 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.InetAddresses;
import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecTransform;
import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -44,15 +47,22 @@
import com.android.server.IpSecService;
import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
+import java.net.InetAddress;
import java.util.Collections;
import java.util.UUID;
public class VcnGatewayConnectionTestBase {
protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
+ protected static final InetAddress TEST_DNS_ADDR =
+ InetAddresses.parseNumericAddress("2001:DB8:0:1::");
+ protected static final LinkAddress TEST_INTERNAL_ADDR =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64);
+
protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
protected static final int TEST_IPSEC_TRANSFORM_RESOURCE_ID = 2;
@@ -86,6 +96,7 @@
@NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
@NonNull protected final IpSecService mIpSecSvc;
+ @NonNull protected final ConnectivityManager mConnMgr;
protected VcnIkeSession mMockIkeSession;
protected VcnGatewayConnection mGatewayConnection;
@@ -103,6 +114,10 @@
mIpSecSvc = mock(IpSecService.class);
setupIpSecManager(mContext, mIpSecSvc);
+ mConnMgr = mock(ConnectivityManager.class);
+ VcnTestUtils.setupSystemService(
+ mContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+
doReturn(mContext).when(mVcnContext).getContext();
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
@@ -145,10 +160,10 @@
return captor.getValue();
}
- protected ChildSessionCallback getChildSessionCallback() {
+ protected VcnChildSessionCallback getChildSessionCallback() {
ArgumentCaptor<ChildSessionCallback> captor =
ArgumentCaptor.forClass(ChildSessionCallback.class);
verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
- return captor.getValue();
+ return (VcnChildSessionCallback) captor.getValue();
}
}