Use a CountDownLatch instead of sleep() in NetworkFactory tests.
This makes testNetworkFactoryRequests 2-3 times faster. Bug: 22606153 Change-Id: I9657b6929e77f23ec811d0ab57b2ba974f0b6a69
This commit is contained in:
@@ -61,7 +61,8 @@ import com.android.server.connectivity.NetworkAgentInfo;
|
|||||||
import com.android.server.connectivity.NetworkMonitor;
|
import com.android.server.connectivity.NetworkMonitor;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,6 +74,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
public class ConnectivityServiceTest extends AndroidTestCase {
|
public class ConnectivityServiceTest extends AndroidTestCase {
|
||||||
private static final String TAG = "ConnectivityServiceTest";
|
private static final String TAG = "ConnectivityServiceTest";
|
||||||
|
|
||||||
|
private static final int TIMEOUT_MS = 500;
|
||||||
|
|
||||||
private BroadcastInterceptingContext mServiceContext;
|
private BroadcastInterceptingContext mServiceContext;
|
||||||
private WrappedConnectivityService mService;
|
private WrappedConnectivityService mService;
|
||||||
private ConnectivityManager mCm;
|
private ConnectivityManager mCm;
|
||||||
@@ -311,13 +314,28 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
|
||||||
|
* operations have been processed. Before ConnectivityService can add or remove any requests,
|
||||||
|
* the factory must be told to expect those operations by calling expectAddRequests or
|
||||||
|
* expectRemoveRequests.
|
||||||
|
*/
|
||||||
private static class MockNetworkFactory extends NetworkFactory {
|
private static class MockNetworkFactory extends NetworkFactory {
|
||||||
private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
|
private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
|
||||||
private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
|
private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
|
||||||
private final ConditionVariable mNetworkRequestedCV = new ConditionVariable();
|
|
||||||
private final ConditionVariable mNetworkReleasedCV = new ConditionVariable();
|
|
||||||
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
|
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
// Used to expect that requests be removed or added on a separate thread, without sleeping.
|
||||||
|
// Callers can call either expectAddRequests() or expectRemoveRequests() exactly once, then
|
||||||
|
// cause some other thread to add or remove requests, then call waitForRequests(). We can
|
||||||
|
// either expect requests to be added or removed, but not both, because CountDownLatch can
|
||||||
|
// only count in one direction.
|
||||||
|
private CountDownLatch mExpectations;
|
||||||
|
|
||||||
|
// Whether we are currently expecting requests to be added or removed. Valid only if
|
||||||
|
// mExpectations is non-null.
|
||||||
|
private boolean mExpectingAdditions;
|
||||||
|
|
||||||
public MockNetworkFactory(Looper looper, Context context, String logTag,
|
public MockNetworkFactory(Looper looper, Context context, String logTag,
|
||||||
NetworkCapabilities filter) {
|
NetworkCapabilities filter) {
|
||||||
super(looper, context, logTag, filter);
|
super(looper, context, logTag, filter);
|
||||||
@@ -351,28 +369,75 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
return mNetworkStoppedCV;
|
return mNetworkStoppedCV;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void needNetworkFor(NetworkRequest networkRequest, int score) {
|
@Override
|
||||||
super.needNetworkFor(networkRequest, score);
|
protected void handleAddRequest(NetworkRequest request, int score) {
|
||||||
mNetworkRequestedCV.open();
|
// If we're expecting anything, we must be expecting additions.
|
||||||
|
if (mExpectations != null && !mExpectingAdditions) {
|
||||||
|
fail("Can't add requests while expecting requests to be removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void releaseNetworkFor(NetworkRequest networkRequest) {
|
// Add the request.
|
||||||
super.releaseNetworkFor(networkRequest);
|
super.handleAddRequest(request, score);
|
||||||
mNetworkReleasedCV.open();
|
|
||||||
|
// Reduce the number of request additions we're waiting for.
|
||||||
|
if (mExpectingAdditions) {
|
||||||
|
assertTrue("Added more requests than expected", mExpectations.getCount() > 0);
|
||||||
|
mExpectations.countDown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConditionVariable getNetworkRequestedCV() {
|
@Override
|
||||||
mNetworkRequestedCV.close();
|
protected void handleRemoveRequest(NetworkRequest request) {
|
||||||
return mNetworkRequestedCV;
|
// If we're expecting anything, we must be expecting removals.
|
||||||
|
if (mExpectations != null && mExpectingAdditions) {
|
||||||
|
fail("Can't remove requests while expecting requests to be added");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConditionVariable getNetworkReleasedCV() {
|
// Remove the request.
|
||||||
mNetworkReleasedCV.close();
|
super.handleRemoveRequest(request);
|
||||||
return mNetworkReleasedCV;
|
|
||||||
|
// Reduce the number of request removals we're waiting for.
|
||||||
|
if (!mExpectingAdditions) {
|
||||||
|
assertTrue("Removed more requests than expected", mExpectations.getCount() > 0);
|
||||||
|
mExpectations.countDown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForNetworkRequests(final int count) {
|
private void assertNoExpectations() {
|
||||||
waitFor(new Criteria() { public boolean get() { return count == getRequestCount(); } });
|
if (mExpectations != null) {
|
||||||
|
fail("Can't add expectation, " + mExpectations.getCount() + " already pending");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expects that count requests will be added.
|
||||||
|
public void expectAddRequests(final int count) {
|
||||||
|
assertNoExpectations();
|
||||||
|
mExpectingAdditions = true;
|
||||||
|
mExpectations = new CountDownLatch(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expects that count requests will be removed.
|
||||||
|
public void expectRemoveRequests(final int count) {
|
||||||
|
assertNoExpectations();
|
||||||
|
mExpectingAdditions = false;
|
||||||
|
mExpectations = new CountDownLatch(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Waits for the expected request additions or removals to happen within a timeout.
|
||||||
|
public void waitForRequests() throws InterruptedException {
|
||||||
|
assertNotNull("Nothing to wait for", mExpectations);
|
||||||
|
mExpectations.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
|
final long count = mExpectations.getCount();
|
||||||
|
final String msg = count + " requests still not " +
|
||||||
|
(mExpectingAdditions ? "added" : "removed") +
|
||||||
|
" after " + TIMEOUT_MS + " ms";
|
||||||
|
assertEquals(msg, 0, count);
|
||||||
|
mExpectations = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void waitForNetworkRequests(final int count) throws InterruptedException {
|
||||||
|
waitForRequests();
|
||||||
|
assertEquals(count, getMyRequestCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +515,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void waitForIdle() {
|
public void waitForIdle() {
|
||||||
waitForIdle(500);
|
waitForIdle(TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -475,11 +540,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait up to 500ms for {@code conditionVariable} to open.
|
* Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
|
||||||
* Fails if 500ms goes by before {@code conditionVariable} opens.
|
* Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
|
||||||
*/
|
*/
|
||||||
static private void waitFor(ConditionVariable conditionVariable) {
|
static private void waitFor(ConditionVariable conditionVariable) {
|
||||||
assertTrue(conditionVariable.block(500));
|
assertTrue(conditionVariable.block(TIMEOUT_MS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -963,18 +1028,21 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
mServiceContext, "testFactory", filter);
|
mServiceContext, "testFactory", filter);
|
||||||
testFactory.setScoreFilter(40);
|
testFactory.setScoreFilter(40);
|
||||||
ConditionVariable cv = testFactory.getNetworkStartedCV();
|
ConditionVariable cv = testFactory.getNetworkStartedCV();
|
||||||
|
testFactory.expectAddRequests(1);
|
||||||
testFactory.register();
|
testFactory.register();
|
||||||
|
testFactory.waitForNetworkRequests(1);
|
||||||
int expectedRequestCount = 1;
|
int expectedRequestCount = 1;
|
||||||
NetworkCallback networkCallback = null;
|
NetworkCallback networkCallback = null;
|
||||||
// For non-INTERNET capabilities we cannot rely on the default request being present, so
|
// For non-INTERNET capabilities we cannot rely on the default request being present, so
|
||||||
// add one.
|
// add one.
|
||||||
if (capability != NET_CAPABILITY_INTERNET) {
|
if (capability != NET_CAPABILITY_INTERNET) {
|
||||||
testFactory.waitForNetworkRequests(1);
|
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
|
NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
|
||||||
networkCallback = new NetworkCallback();
|
networkCallback = new NetworkCallback();
|
||||||
|
testFactory.expectAddRequests(1);
|
||||||
mCm.requestNetwork(request, networkCallback);
|
mCm.requestNetwork(request, networkCallback);
|
||||||
expectedRequestCount++;
|
expectedRequestCount++;
|
||||||
|
testFactory.waitForNetworkRequests(expectedRequestCount);
|
||||||
}
|
}
|
||||||
waitFor(cv);
|
waitFor(cv);
|
||||||
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
|
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
|
||||||
@@ -987,13 +1055,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
// unvalidated penalty.
|
// unvalidated penalty.
|
||||||
testAgent.adjustScore(40);
|
testAgent.adjustScore(40);
|
||||||
cv = testFactory.getNetworkStoppedCV();
|
cv = testFactory.getNetworkStoppedCV();
|
||||||
|
|
||||||
|
// When testAgent connects, ConnectivityService will re-send us all current requests with
|
||||||
|
// the new score. There are expectedRequestCount such requests, and we must wait for all of
|
||||||
|
// them.
|
||||||
|
testFactory.expectAddRequests(expectedRequestCount);
|
||||||
testAgent.connect(false);
|
testAgent.connect(false);
|
||||||
testAgent.addCapability(capability);
|
testAgent.addCapability(capability);
|
||||||
waitFor(cv);
|
waitFor(cv);
|
||||||
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
|
testFactory.waitForNetworkRequests(expectedRequestCount);
|
||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Bring in a bunch of requests.
|
// Bring in a bunch of requests.
|
||||||
|
testFactory.expectAddRequests(10);
|
||||||
|
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
|
||||||
ConnectivityManager.NetworkCallback[] networkCallbacks =
|
ConnectivityManager.NetworkCallback[] networkCallbacks =
|
||||||
new ConnectivityManager.NetworkCallback[10];
|
new ConnectivityManager.NetworkCallback[10];
|
||||||
for (int i = 0; i< networkCallbacks.length; i++) {
|
for (int i = 0; i< networkCallbacks.length; i++) {
|
||||||
@@ -1006,6 +1081,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
assertFalse(testFactory.getMyStartRequested());
|
assertFalse(testFactory.getMyStartRequested());
|
||||||
|
|
||||||
// Remove the requests.
|
// Remove the requests.
|
||||||
|
testFactory.expectRemoveRequests(10);
|
||||||
for (int i = 0; i < networkCallbacks.length; i++) {
|
for (int i = 0; i < networkCallbacks.length; i++) {
|
||||||
mCm.unregisterNetworkCallback(networkCallbacks[i]);
|
mCm.unregisterNetworkCallback(networkCallbacks[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user