Create proxy NetworkAgent for testing

This change adds a proxy NetworkAgent to facilitate testing, adding the
ability to test final methods such as sendNetworkCapabilities() and
sendLinkProperties(), which would otherwise call a real implementation,
and throw a null pointer while trying to access internal fields.

Bug: 184579891
Bug: 184697651
Test: atest FrameworksVcnTests
Change-Id: I8f13159bd266bf488f095a13d6ffe444bec65f38
This commit is contained in:
Benedict Wong
2021-04-06 18:08:13 -07:00
parent a4f28edac3
commit 7087a4ac87
3 changed files with 98 additions and 36 deletions

View File

@@ -575,7 +575,7 @@ public class VcnGatewayConnection extends StateMachine {
* <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
* otherwise.
*/
private NetworkAgent mNetworkAgent;
private VcnNetworkAgent mNetworkAgent;
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
@Nullable private WakeupMessage mDisconnectRequestAlarm;
@@ -1441,7 +1441,7 @@ public class VcnGatewayConnection extends StateMachine {
private abstract class ConnectedStateBase extends ActiveBaseState {
protected void updateNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull NetworkAgent agent,
@NonNull VcnNetworkAgent agent,
@NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
@@ -1452,7 +1452,7 @@ public class VcnGatewayConnection extends StateMachine {
agent.sendLinkProperties(lp);
}
protected NetworkAgent buildNetworkAgent(
protected VcnNetworkAgent buildNetworkAgent(
@NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig) {
final NetworkCapabilities caps =
@@ -1464,7 +1464,7 @@ public class VcnGatewayConnection extends StateMachine {
.setLegacyType(ConnectivityManager.TYPE_MOBILE)
.build();
final NetworkAgent agent =
final VcnNetworkAgent agent =
mDeps.newNetworkAgent(
mVcnContext,
TAG,
@@ -1993,12 +1993,12 @@ public class VcnGatewayConnection extends StateMachine {
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
NetworkAgent getNetworkAgent() {
VcnNetworkAgent getNetworkAgent() {
return mNetworkAgent;
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
void setNetworkAgent(@Nullable NetworkAgent networkAgent) {
void setNetworkAgent(@Nullable VcnNetworkAgent networkAgent) {
mNetworkAgent = networkAgent;
}
@@ -2086,8 +2086,8 @@ public class VcnGatewayConnection extends StateMachine {
return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
}
/** Builds a new NetworkAgent. */
public NetworkAgent newNetworkAgent(
/** Builds a new VcnNetworkAgent. */
public VcnNetworkAgent newNetworkAgent(
@NonNull VcnContext vcnContext,
@NonNull String tag,
@NonNull NetworkCapabilities caps,
@@ -2095,27 +2095,18 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull int score,
@NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider,
@NonNull Consumer<NetworkAgent> networkUnwantedCallback,
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
@NonNull Consumer<Integer> validationStatusCallback) {
return new NetworkAgent(
vcnContext.getContext(),
vcnContext.getLooper(),
return new VcnNetworkAgent(
vcnContext,
tag,
caps,
lp,
score,
nac,
provider) {
@Override
public void onNetworkUnwanted() {
networkUnwantedCallback.accept(this);
}
@Override
public void onValidationStatus(int status, @Nullable Uri redirectUri) {
validationStatusCallback.accept(status);
}
};
provider,
networkUnwantedCallback,
validationStatusCallback);
}
/** Gets the elapsed real time since boot, in millis. */
@@ -2231,4 +2222,73 @@ public class VcnGatewayConnection extends StateMachine {
mImpl.release();
}
}
/** Proxy Implementation of NetworkAgent, used for testing. */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class VcnNetworkAgent {
private final NetworkAgent mImpl;
public VcnNetworkAgent(
@NonNull VcnContext vcnContext,
@NonNull String tag,
@NonNull NetworkCapabilities caps,
@NonNull LinkProperties lp,
@NonNull int score,
@NonNull NetworkAgentConfig nac,
@NonNull NetworkProvider provider,
@NonNull Consumer<VcnNetworkAgent> networkUnwantedCallback,
@NonNull Consumer<Integer> validationStatusCallback) {
mImpl =
new NetworkAgent(
vcnContext.getContext(),
vcnContext.getLooper(),
tag,
caps,
lp,
score,
nac,
provider) {
@Override
public void onNetworkUnwanted() {
networkUnwantedCallback.accept(VcnNetworkAgent.this);
}
@Override
public void onValidationStatus(int status, @Nullable Uri redirectUri) {
validationStatusCallback.accept(status);
}
};
}
/** Registers the underlying NetworkAgent */
public void register() {
mImpl.register();
}
/** Marks the underlying NetworkAgent as connected */
public void markConnected() {
mImpl.markConnected();
}
/** Unregisters the underlying NetworkAgent */
public void unregister() {
mImpl.unregister();
}
/** Sends new NetworkCapabilities for the underlying NetworkAgent */
public void sendNetworkCapabilities(@NonNull NetworkCapabilities caps) {
mImpl.sendNetworkCapabilities(caps);
}
/** Sends new LinkProperties for the underlying NetworkAgent */
public void sendLinkProperties(@NonNull LinkProperties lp) {
mImpl.sendLinkProperties(lp);
}
/** Retrieves the Network for the underlying NetworkAgent */
@Nullable
public Network getNetwork() {
return mImpl.getNetwork();
}
}
}

View File

@@ -26,6 +26,7 @@ import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -73,13 +74,13 @@ import java.util.function.Consumer;
@SmallTest
public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
private VcnIkeSession mIkeSession;
private NetworkAgent mNetworkAgent;
private VcnNetworkAgent mNetworkAgent;
@Before
public void setUp() throws Exception {
super.setUp();
mNetworkAgent = mock(NetworkAgent.class);
mNetworkAgent = mock(VcnNetworkAgent.class);
doReturn(mNetworkAgent)
.when(mDeps)
.newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
@@ -299,8 +300,9 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
.removeAddressFromTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
// TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties
// is mockable
verify(mNetworkAgent).sendLinkProperties(argThat(
lp -> newInternalAddrs.equals(lp.getLinkAddresses())
&& Collections.singletonList(TEST_DNS_ADDR_2).equals(lp.getDnsServers())));
// Verify that IpSecTunnelInterface only created once
verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
@@ -323,11 +325,11 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
assertFalse(mGatewayConnection.isInSafeMode());
}
private Consumer<NetworkAgent> setupNetworkAndGetUnwantedCallback() {
private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() {
triggerChildOpened();
mTestLooper.dispatchAll();
final ArgumentCaptor<Consumer<NetworkAgent>> unwantedCallbackCaptor =
final ArgumentCaptor<Consumer<VcnNetworkAgent>> unwantedCallbackCaptor =
ArgumentCaptor.forClass(Consumer.class);
verify(mDeps)
.newNetworkAgent(
@@ -346,7 +348,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
@Test
public void testUnwantedNetworkAgentTriggersTeardown() throws Exception {
final Consumer<NetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
unwantedCallback.accept(mNetworkAgent);
mTestLooper.dispatchAll();
@@ -357,7 +359,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
@Test
public void testUnwantedNetworkAgentWithDisconnectedNetworkAgent() throws Exception {
final Consumer<NetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
mGatewayConnection.setNetworkAgent(null);
unwantedCallback.accept(mNetworkAgent);
@@ -371,8 +373,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
@Test
public void testUnwantedNetworkAgentWithNewNetworkAgent() throws Exception {
final Consumer<NetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
final NetworkAgent testAgent = mock(NetworkAgent.class);
final Consumer<VcnNetworkAgent> unwantedCallback = setupNetworkAndGetUnwantedCallback();
final VcnNetworkAgent testAgent = mock(VcnNetworkAgent.class);
mGatewayConnection.setNetworkAgent(testAgent);
unwantedCallback.accept(mNetworkAgent);

View File

@@ -18,6 +18,7 @@ package com.android.server.vcn;
import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
import static org.junit.Assert.assertEquals;
@@ -44,7 +45,6 @@ import android.net.IpSecTunnelInterfaceResponse;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.IkeSessionCallback;
@@ -278,8 +278,8 @@ public class VcnGatewayConnectionTestBase {
protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
@NonNull State expectedState) {
// Set a NetworkAgent, and expect it to be unregistered and cleared
final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class);
// Set a VcnNetworkAgent, and expect it to be unregistered and cleared
final VcnNetworkAgent mockNetworkAgent = mock(VcnNetworkAgent.class);
mGatewayConnection.setNetworkAgent(mockNetworkAgent);
// SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial