Merge "Use a delayed message to schedule the query task" into main
This commit is contained in:
@@ -54,10 +54,6 @@ public class MdnsConfigs {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldCancelScanTaskWhenFutureIsNull() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long sleepTimeForSocketThreadMs() {
|
public static long sleepTimeForSocketThreadMs() {
|
||||||
return 20_000L;
|
return 20_000L;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,11 @@ package com.android.server.connectivity.mdns;
|
|||||||
|
|
||||||
import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
|
import static com.android.server.connectivity.mdns.util.MdnsUtils.ensureRunningOnHandlerThread;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
@@ -45,7 +44,6 @@ import java.util.HashMap;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,6 +54,8 @@ public class MdnsServiceTypeClient {
|
|||||||
|
|
||||||
private static final String TAG = MdnsServiceTypeClient.class.getSimpleName();
|
private static final String TAG = MdnsServiceTypeClient.class.getSimpleName();
|
||||||
private static final int DEFAULT_MTU = 1500;
|
private static final int DEFAULT_MTU = 1500;
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int EVENT_START_QUERYTASK = 1;
|
||||||
|
|
||||||
private final String serviceType;
|
private final String serviceType;
|
||||||
private final String[] serviceTypeLabels;
|
private final String[] serviceTypeLabels;
|
||||||
@@ -65,6 +65,7 @@ public class MdnsServiceTypeClient {
|
|||||||
@NonNull private final SocketKey socketKey;
|
@NonNull private final SocketKey socketKey;
|
||||||
@NonNull private final SharedLog sharedLog;
|
@NonNull private final SharedLog sharedLog;
|
||||||
@NonNull private final Handler handler;
|
@NonNull private final Handler handler;
|
||||||
|
@NonNull private final Dependencies dependencies;
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
private final ArrayMap<MdnsServiceBrowserListener, MdnsSearchOptions> listeners =
|
private final ArrayMap<MdnsServiceBrowserListener, MdnsSearchOptions> listeners =
|
||||||
new ArrayMap<>();
|
new ArrayMap<>();
|
||||||
@@ -82,10 +83,6 @@ public class MdnsServiceTypeClient {
|
|||||||
// new subtypes. It stays the same between packets for same subtypes.
|
// new subtypes. It stays the same between packets for same subtypes.
|
||||||
private long currentSessionId = 0;
|
private long currentSessionId = 0;
|
||||||
|
|
||||||
@GuardedBy("lock")
|
|
||||||
@Nullable
|
|
||||||
private Future<?> nextQueryTaskFuture;
|
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private QueryTask lastScheduledTask;
|
private QueryTask lastScheduledTask;
|
||||||
@@ -93,6 +90,52 @@ public class MdnsServiceTypeClient {
|
|||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private long lastSentTime;
|
private long lastSentTime;
|
||||||
|
|
||||||
|
private class QueryTaskHandler extends Handler {
|
||||||
|
QueryTaskHandler(Looper looper) {
|
||||||
|
super(looper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case EVENT_START_QUERYTASK:
|
||||||
|
handleStartQueryTask((QueryTask) msg.obj);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sharedLog.e("Unrecognized event " + msg.what);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependencies of MdnsServiceTypeClient, for injection in tests.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public static class Dependencies {
|
||||||
|
/**
|
||||||
|
* @see Handler#sendMessageDelayed(Message, long)
|
||||||
|
*/
|
||||||
|
public void sendMessageDelayed(@NonNull Handler handler, @NonNull Message message,
|
||||||
|
long delayMillis) {
|
||||||
|
handler.sendMessageDelayed(message, delayMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Handler#removeMessages(int)
|
||||||
|
*/
|
||||||
|
public void removeMessages(@NonNull Handler handler, int what) {
|
||||||
|
handler.removeMessages(what);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Handler#hasMessages(int)
|
||||||
|
*/
|
||||||
|
public boolean hasMessages(@NonNull Handler handler, int what) {
|
||||||
|
return handler.hasMessages(what);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor of {@link MdnsServiceTypeClient}.
|
* Constructor of {@link MdnsServiceTypeClient}.
|
||||||
*
|
*
|
||||||
@@ -107,7 +150,7 @@ public class MdnsServiceTypeClient {
|
|||||||
@NonNull SharedLog sharedLog,
|
@NonNull SharedLog sharedLog,
|
||||||
@NonNull Looper looper) {
|
@NonNull Looper looper) {
|
||||||
this(serviceType, socketClient, executor, new MdnsResponseDecoder.Clock(), socketKey,
|
this(serviceType, socketClient, executor, new MdnsResponseDecoder.Clock(), socketKey,
|
||||||
sharedLog, looper);
|
sharedLog, looper, new Dependencies());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -118,7 +161,8 @@ public class MdnsServiceTypeClient {
|
|||||||
@NonNull MdnsResponseDecoder.Clock clock,
|
@NonNull MdnsResponseDecoder.Clock clock,
|
||||||
@NonNull SocketKey socketKey,
|
@NonNull SocketKey socketKey,
|
||||||
@NonNull SharedLog sharedLog,
|
@NonNull SharedLog sharedLog,
|
||||||
@NonNull Looper looper) {
|
@NonNull Looper looper,
|
||||||
|
@NonNull Dependencies dependencies) {
|
||||||
this.serviceType = serviceType;
|
this.serviceType = serviceType;
|
||||||
this.socketClient = socketClient;
|
this.socketClient = socketClient;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
@@ -127,7 +171,8 @@ public class MdnsServiceTypeClient {
|
|||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.socketKey = socketKey;
|
this.socketKey = socketKey;
|
||||||
this.sharedLog = sharedLog;
|
this.sharedLog = sharedLog;
|
||||||
this.handler = new Handler(looper);
|
this.handler = new QueryTaskHandler(looper);
|
||||||
|
this.dependencies = dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MdnsServiceInfo buildMdnsServiceInfoFromResponse(
|
private static MdnsServiceInfo buildMdnsServiceInfoFromResponse(
|
||||||
@@ -206,10 +251,8 @@ public class MdnsServiceTypeClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Cancel the next scheduled periodical task.
|
// Remove the next scheduled periodical task.
|
||||||
if (nextQueryTaskFuture != null) {
|
removeScheduledTaskLock();
|
||||||
cancelRequestTaskLocked();
|
|
||||||
}
|
|
||||||
// Keep tracking the ScheduledFuture for the task so we can cancel it if caller is not
|
// Keep tracking the ScheduledFuture for the task so we can cancel it if caller is not
|
||||||
// interested anymore.
|
// interested anymore.
|
||||||
final QueryTaskConfig taskConfig = new QueryTaskConfig(
|
final QueryTaskConfig taskConfig = new QueryTaskConfig(
|
||||||
@@ -226,30 +269,29 @@ public class MdnsServiceTypeClient {
|
|||||||
final QueryTaskConfig queryTaskConfig = taskConfig.getConfigForNextRun();
|
final QueryTaskConfig queryTaskConfig = taskConfig.getConfigForNextRun();
|
||||||
final long minRemainingTtl = getMinRemainingTtlLocked(now);
|
final long minRemainingTtl = getMinRemainingTtlLocked(now);
|
||||||
final long timeToRun = now + queryTaskConfig.delayUntilNextTaskWithoutBackoffMs;
|
final long timeToRun = now + queryTaskConfig.delayUntilNextTaskWithoutBackoffMs;
|
||||||
nextQueryTaskFuture = scheduleNextRunLocked(queryTaskConfig,
|
scheduleNextRunLocked(
|
||||||
minRemainingTtl, now, timeToRun, currentSessionId);
|
queryTaskConfig, minRemainingTtl, now, timeToRun, currentSessionId);
|
||||||
} else {
|
} else {
|
||||||
lastScheduledTask = new QueryTask(taskConfig,
|
lastScheduledTask = new QueryTask(taskConfig,
|
||||||
now /* timeToRun */,
|
now /* timeToRun */,
|
||||||
now + getMinRemainingTtlLocked(now)/* minTtlExpirationTimeWhenScheduled */,
|
now + getMinRemainingTtlLocked(now)/* minTtlExpirationTimeWhenScheduled */,
|
||||||
currentSessionId);
|
currentSessionId);
|
||||||
nextQueryTaskFuture = executor.submit(lastScheduledTask);
|
handleStartQueryTask(lastScheduledTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private void cancelRequestTaskLocked() {
|
private void removeScheduledTaskLock() {
|
||||||
final boolean canceled = nextQueryTaskFuture.cancel(true);
|
dependencies.removeMessages(handler, EVENT_START_QUERYTASK);
|
||||||
sharedLog.log("task canceled:" + canceled + ", current session: " + currentSessionId
|
sharedLog.log("Remove EVENT_START_QUERYTASK"
|
||||||
+ " task hashcode: " + getHexString(nextQueryTaskFuture));
|
+ ", current session: " + currentSessionId);
|
||||||
++currentSessionId;
|
++currentSessionId;
|
||||||
nextQueryTaskFuture = null;
|
|
||||||
lastScheduledTask = null;
|
lastScheduledTask = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getHexString(Object o) {
|
private void handleStartQueryTask(@NonNull QueryTask task) {
|
||||||
return Integer.toHexString(System.identityHashCode(o));
|
executor.submit(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean responseMatchesOptions(@NonNull MdnsResponse response,
|
private boolean responseMatchesOptions(@NonNull MdnsResponse response,
|
||||||
@@ -285,8 +327,8 @@ public class MdnsServiceTypeClient {
|
|||||||
if (listeners.remove(listener) == null) {
|
if (listeners.remove(listener) == null) {
|
||||||
return listeners.isEmpty();
|
return listeners.isEmpty();
|
||||||
}
|
}
|
||||||
if (listeners.isEmpty() && nextQueryTaskFuture != null) {
|
if (listeners.isEmpty()) {
|
||||||
cancelRequestTaskLocked();
|
removeScheduledTaskLock();
|
||||||
}
|
}
|
||||||
return listeners.isEmpty();
|
return listeners.isEmpty();
|
||||||
}
|
}
|
||||||
@@ -329,7 +371,8 @@ public class MdnsServiceTypeClient {
|
|||||||
instanceNameToResponse.put(response.getServiceInstanceName(), response);
|
instanceNameToResponse.put(response.getServiceInstanceName(), response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nextQueryTaskFuture != null && lastScheduledTask != null
|
if (dependencies.hasMessages(handler, EVENT_START_QUERYTASK)
|
||||||
|
&& lastScheduledTask != null
|
||||||
&& lastScheduledTask.config.shouldUseQueryBackoff()) {
|
&& lastScheduledTask.config.shouldUseQueryBackoff()) {
|
||||||
final long now = clock.elapsedRealtime();
|
final long now = clock.elapsedRealtime();
|
||||||
final long minRemainingTtl = getMinRemainingTtlLocked(now);
|
final long minRemainingTtl = getMinRemainingTtlLocked(now);
|
||||||
@@ -338,9 +381,9 @@ public class MdnsServiceTypeClient {
|
|||||||
minRemainingTtl, lastSentTime);
|
minRemainingTtl, lastSentTime);
|
||||||
if (timeToRun > lastScheduledTask.timeToRun) {
|
if (timeToRun > lastScheduledTask.timeToRun) {
|
||||||
QueryTaskConfig lastTaskConfig = lastScheduledTask.config;
|
QueryTaskConfig lastTaskConfig = lastScheduledTask.config;
|
||||||
cancelRequestTaskLocked();
|
removeScheduledTaskLock();
|
||||||
nextQueryTaskFuture = scheduleNextRunLocked(lastTaskConfig, minRemainingTtl,
|
scheduleNextRunLocked(
|
||||||
now, timeToRun, currentSessionId);
|
lastTaskConfig, minRemainingTtl, now, timeToRun, currentSessionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,10 +416,7 @@ public class MdnsServiceTypeClient {
|
|||||||
listener.onServiceNameRemoved(serviceInfo);
|
listener.onServiceNameRemoved(serviceInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
removeScheduledTaskLock();
|
||||||
if (nextQueryTaskFuture != null) {
|
|
||||||
cancelRequestTaskLocked();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,14 +718,6 @@ public class MdnsServiceTypeClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MdnsConfigs.shouldCancelScanTaskWhenFutureIsNull()) {
|
|
||||||
if (nextQueryTaskFuture == null) {
|
|
||||||
// If requestTaskFuture is set to null, the task is cancelled. We can't use
|
|
||||||
// isCancelled() here because this QueryTask is different from the future
|
|
||||||
// that is returned from executor.schedule(). See b/71646910.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((result != null)) {
|
if ((result != null)) {
|
||||||
for (int i = 0; i < listeners.size(); i++) {
|
for (int i = 0; i < listeners.size(); i++) {
|
||||||
listeners.keyAt(i).onDiscoveryQuerySent(result.second, result.first);
|
listeners.keyAt(i).onDiscoveryQuerySent(result.second, result.first);
|
||||||
@@ -730,8 +762,8 @@ public class MdnsServiceTypeClient {
|
|||||||
final long minRemainingTtl = getMinRemainingTtlLocked(now);
|
final long minRemainingTtl = getMinRemainingTtlLocked(now);
|
||||||
final long timeToRun = calculateTimeToRun(this, nextRunConfig, now,
|
final long timeToRun = calculateTimeToRun(this, nextRunConfig, now,
|
||||||
minRemainingTtl, lastSentTime);
|
minRemainingTtl, lastSentTime);
|
||||||
nextQueryTaskFuture = scheduleNextRunLocked(nextRunConfig,
|
scheduleNextRunLocked(nextRunConfig, minRemainingTtl, now, timeToRun,
|
||||||
minRemainingTtl, now, timeToRun, lastScheduledTask.sessionId);
|
lastScheduledTask.sessionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -779,7 +811,7 @@ public class MdnsServiceTypeClient {
|
|||||||
|
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
@NonNull
|
@NonNull
|
||||||
private Future<?> scheduleNextRunLocked(@NonNull QueryTaskConfig nextRunConfig,
|
private void scheduleNextRunLocked(@NonNull QueryTaskConfig nextRunConfig,
|
||||||
long minRemainingTtl,
|
long minRemainingTtl,
|
||||||
long timeWhenScheduled, long timeToRun, long sessionId) {
|
long timeWhenScheduled, long timeToRun, long sessionId) {
|
||||||
lastScheduledTask = new QueryTask(nextRunConfig, timeToRun,
|
lastScheduledTask = new QueryTask(nextRunConfig, timeToRun,
|
||||||
@@ -789,7 +821,9 @@ public class MdnsServiceTypeClient {
|
|||||||
sharedLog.log(
|
sharedLog.log(
|
||||||
String.format("Next run: sessionId: %d, in %d ms", lastScheduledTask.sessionId,
|
String.format("Next run: sessionId: %d, in %d ms", lastScheduledTask.sessionId,
|
||||||
timeToNextTasksWithBackoffInMs));
|
timeToNextTasksWithBackoffInMs));
|
||||||
return executor.schedule(lastScheduledTask, timeToNextTasksWithBackoffInMs,
|
dependencies.sendMessageDelayed(
|
||||||
MILLISECONDS);
|
handler,
|
||||||
|
handler.obtainMessage(EVENT_START_QUERYTASK, lastScheduledTask),
|
||||||
|
timeToNextTasksWithBackoffInMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.connectivity.mdns;
|
package com.android.server.connectivity.mdns;
|
||||||
|
|
||||||
|
import static com.android.server.connectivity.mdns.MdnsServiceTypeClient.EVENT_START_QUERYTASK;
|
||||||
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
|
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
@@ -26,8 +27,10 @@ import static org.junit.Assert.assertNull;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@@ -43,6 +46,7 @@ import android.net.InetAddresses;
|
|||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
|
import android.os.Message;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.android.net.module.util.CollectionUtils;
|
import com.android.net.module.util.CollectionUtils;
|
||||||
@@ -112,6 +116,8 @@ public class MdnsServiceTypeClientTests {
|
|||||||
private MdnsResponseDecoder.Clock mockDecoderClock;
|
private MdnsResponseDecoder.Clock mockDecoderClock;
|
||||||
@Mock
|
@Mock
|
||||||
private SharedLog mockSharedLog;
|
private SharedLog mockSharedLog;
|
||||||
|
@Mock
|
||||||
|
private MdnsServiceTypeClient.Dependencies mockDeps;
|
||||||
@Captor
|
@Captor
|
||||||
private ArgumentCaptor<MdnsServiceInfo> serviceInfoCaptor;
|
private ArgumentCaptor<MdnsServiceInfo> serviceInfoCaptor;
|
||||||
|
|
||||||
@@ -119,13 +125,15 @@ public class MdnsServiceTypeClientTests {
|
|||||||
|
|
||||||
private DatagramPacket[] expectedIPv4Packets;
|
private DatagramPacket[] expectedIPv4Packets;
|
||||||
private DatagramPacket[] expectedIPv6Packets;
|
private DatagramPacket[] expectedIPv6Packets;
|
||||||
private ScheduledFuture<?>[] expectedSendFutures;
|
|
||||||
private FakeExecutor currentThreadExecutor = new FakeExecutor();
|
private FakeExecutor currentThreadExecutor = new FakeExecutor();
|
||||||
|
|
||||||
private MdnsServiceTypeClient client;
|
private MdnsServiceTypeClient client;
|
||||||
private SocketKey socketKey;
|
private SocketKey socketKey;
|
||||||
private HandlerThread thread;
|
private HandlerThread thread;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
private long latestDelayMs = 0;
|
||||||
|
private Message delayMessage = null;
|
||||||
|
private Handler realHandler = null;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@SuppressWarnings("DoNotMock")
|
@SuppressWarnings("DoNotMock")
|
||||||
@@ -135,15 +143,13 @@ public class MdnsServiceTypeClientTests {
|
|||||||
|
|
||||||
expectedIPv4Packets = new DatagramPacket[16];
|
expectedIPv4Packets = new DatagramPacket[16];
|
||||||
expectedIPv6Packets = new DatagramPacket[16];
|
expectedIPv6Packets = new DatagramPacket[16];
|
||||||
expectedSendFutures = new ScheduledFuture<?>[16];
|
|
||||||
socketKey = new SocketKey(mockNetwork, INTERFACE_INDEX);
|
socketKey = new SocketKey(mockNetwork, INTERFACE_INDEX);
|
||||||
|
|
||||||
for (int i = 0; i < expectedSendFutures.length; ++i) {
|
for (int i = 0; i < expectedIPv4Packets.length; ++i) {
|
||||||
expectedIPv4Packets[i] = new DatagramPacket(buf, 0 /* offset */, 5 /* length */,
|
expectedIPv4Packets[i] = new DatagramPacket(buf, 0 /* offset */, 5 /* length */,
|
||||||
MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT);
|
MdnsConstants.getMdnsIPv4Address(), MdnsConstants.MDNS_PORT);
|
||||||
expectedIPv6Packets[i] = new DatagramPacket(buf, 0 /* offset */, 5 /* length */,
|
expectedIPv6Packets[i] = new DatagramPacket(buf, 0 /* offset */, 5 /* length */,
|
||||||
MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT);
|
MdnsConstants.getMdnsIPv6Address(), MdnsConstants.MDNS_PORT);
|
||||||
expectedSendFutures[i] = Mockito.mock(ScheduledFuture.class);
|
|
||||||
}
|
}
|
||||||
when(mockPacketWriter.getPacket(IPV4_ADDRESS))
|
when(mockPacketWriter.getPacket(IPV4_ADDRESS))
|
||||||
.thenReturn(expectedIPv4Packets[0])
|
.thenReturn(expectedIPv4Packets[0])
|
||||||
@@ -184,9 +190,23 @@ public class MdnsServiceTypeClientTests {
|
|||||||
thread = new HandlerThread("MdnsServiceTypeClientTests");
|
thread = new HandlerThread("MdnsServiceTypeClientTests");
|
||||||
thread.start();
|
thread.start();
|
||||||
handler = new Handler(thread.getLooper());
|
handler = new Handler(thread.getLooper());
|
||||||
|
|
||||||
|
doAnswer(inv -> {
|
||||||
|
latestDelayMs = 0;
|
||||||
|
delayMessage = null;
|
||||||
|
return true;
|
||||||
|
}).when(mockDeps).removeMessages(any(Handler.class), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
|
doAnswer(inv -> {
|
||||||
|
realHandler = (Handler) inv.getArguments()[0];
|
||||||
|
delayMessage = (Message) inv.getArguments()[1];
|
||||||
|
latestDelayMs = (long) inv.getArguments()[2];
|
||||||
|
return true;
|
||||||
|
}).when(mockDeps).sendMessageDelayed(any(Handler.class), any(Message.class), anyLong());
|
||||||
|
|
||||||
client =
|
client =
|
||||||
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()) {
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps) {
|
||||||
@Override
|
@Override
|
||||||
MdnsPacketWriter createMdnsPacketWriter() {
|
MdnsPacketWriter createMdnsPacketWriter() {
|
||||||
return mockPacketWriter;
|
return mockPacketWriter;
|
||||||
@@ -223,11 +243,18 @@ public class MdnsServiceTypeClientTests {
|
|||||||
runOnHandler(() -> client.notifySocketDestroyed());
|
runOnHandler(() -> client.notifySocketDestroyed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void dispatchMessage() {
|
||||||
|
runOnHandler(() -> realHandler.dispatchMessage(delayMessage));
|
||||||
|
delayMessage = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendQueries_activeScanMode() {
|
public void sendQueries_activeScanMode() {
|
||||||
MdnsSearchOptions searchOptions =
|
MdnsSearchOptions searchOptions =
|
||||||
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build();
|
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build();
|
||||||
startSendAndReceive(mockListenerOne, searchOptions);
|
startSendAndReceive(mockListenerOne, searchOptions);
|
||||||
|
// Always try to remove the task.
|
||||||
|
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// First burst, 3 queries.
|
// First burst, 3 queries.
|
||||||
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
||||||
@@ -265,10 +292,12 @@ public class MdnsServiceTypeClientTests {
|
|||||||
13, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false);
|
13, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false);
|
||||||
verifyAndSendQuery(
|
verifyAndSendQuery(
|
||||||
14, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false);
|
14, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false);
|
||||||
|
// Verify that Task is not removed before stopSendAndReceive was called.
|
||||||
|
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// Stop sending packets.
|
// Stop sending packets.
|
||||||
stopSendAndReceive(mockListenerOne);
|
stopSendAndReceive(mockListenerOne);
|
||||||
verify(expectedSendFutures[15]).cancel(true);
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -276,6 +305,8 @@ public class MdnsServiceTypeClientTests {
|
|||||||
MdnsSearchOptions searchOptions =
|
MdnsSearchOptions searchOptions =
|
||||||
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build();
|
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(false).build();
|
||||||
startSendAndReceive(mockListenerOne, searchOptions);
|
startSendAndReceive(mockListenerOne, searchOptions);
|
||||||
|
// Always try to remove the task.
|
||||||
|
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// First burst, first query is sent.
|
// First burst, first query is sent.
|
||||||
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
||||||
@@ -289,7 +320,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
.build();
|
.build();
|
||||||
startSendAndReceive(mockListenerOne, searchOptions);
|
startSendAndReceive(mockListenerOne, searchOptions);
|
||||||
// The previous scheduled task should be canceled.
|
// The previous scheduled task should be canceled.
|
||||||
verify(expectedSendFutures[1]).cancel(true);
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// Queries should continue to be sent.
|
// Queries should continue to be sent.
|
||||||
verifyAndSendQuery(1, 0, /* expectsUnicastResponse= */ true);
|
verifyAndSendQuery(1, 0, /* expectsUnicastResponse= */ true);
|
||||||
@@ -300,7 +331,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
|
|
||||||
// Stop sending packets.
|
// Stop sending packets.
|
||||||
stopSendAndReceive(mockListenerOne);
|
stopSendAndReceive(mockListenerOne);
|
||||||
verify(expectedSendFutures[5]).cancel(true);
|
verify(mockDeps, times(3)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -308,6 +339,8 @@ public class MdnsServiceTypeClientTests {
|
|||||||
MdnsSearchOptions searchOptions =
|
MdnsSearchOptions searchOptions =
|
||||||
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(true).build();
|
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(true).build();
|
||||||
startSendAndReceive(mockListenerOne, searchOptions);
|
startSendAndReceive(mockListenerOne, searchOptions);
|
||||||
|
// Always try to remove the task.
|
||||||
|
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// First burst, 3 query.
|
// First burst, 3 query.
|
||||||
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
||||||
@@ -324,7 +357,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
|
|
||||||
// Stop sending packets.
|
// Stop sending packets.
|
||||||
stopSendAndReceive(mockListenerOne);
|
stopSendAndReceive(mockListenerOne);
|
||||||
verify(expectedSendFutures[5]).cancel(true);
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -333,6 +366,8 @@ public class MdnsServiceTypeClientTests {
|
|||||||
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(
|
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(
|
||||||
false).setNumOfQueriesBeforeBackoff(11).build();
|
false).setNumOfQueriesBeforeBackoff(11).build();
|
||||||
startSendAndReceive(mockListenerOne, searchOptions);
|
startSendAndReceive(mockListenerOne, searchOptions);
|
||||||
|
// Always try to remove the task.
|
||||||
|
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// First burst, 3 queries.
|
// First burst, 3 queries.
|
||||||
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
||||||
@@ -367,16 +402,21 @@ public class MdnsServiceTypeClientTests {
|
|||||||
// 0.8 * smallestRemainingTtl is larger than time to next run.
|
// 0.8 * smallestRemainingTtl is larger than time to next run.
|
||||||
long currentTime = TEST_TTL / 2 + TEST_ELAPSED_REALTIME;
|
long currentTime = TEST_TTL / 2 + TEST_ELAPSED_REALTIME;
|
||||||
doReturn(currentTime).when(mockDecoderClock).elapsedRealtime();
|
doReturn(currentTime).when(mockDecoderClock).elapsedRealtime();
|
||||||
|
doReturn(true).when(mockDeps).hasMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
processResponse(createResponse(
|
processResponse(createResponse(
|
||||||
"service-instance-1", "192.0.2.123", 5353,
|
"service-instance-1", "192.0.2.123", 5353,
|
||||||
SERVICE_TYPE_LABELS,
|
SERVICE_TYPE_LABELS,
|
||||||
Collections.emptyMap(), TEST_TTL), socketKey);
|
Collections.emptyMap(), TEST_TTL), socketKey);
|
||||||
verifyAndSendQuery(12, (long) (TEST_TTL / 2 * 0.8), /* expectsUnicastResponse= */
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
false);
|
assertNotNull(delayMessage);
|
||||||
|
verifyAndSendQuery(12 /* index */, (long) (TEST_TTL / 2 * 0.8) /* timeInMs */,
|
||||||
|
false /* expectsUnicastResponse */, true /* multipleSocketDiscovery */,
|
||||||
|
14 /* scheduledCount */);
|
||||||
currentTime += (long) (TEST_TTL / 2 * 0.8);
|
currentTime += (long) (TEST_TTL / 2 * 0.8);
|
||||||
doReturn(currentTime).when(mockDecoderClock).elapsedRealtime();
|
doReturn(currentTime).when(mockDecoderClock).elapsedRealtime();
|
||||||
verifyAndSendQuery(
|
verifyAndSendQuery(13 /* index */, MdnsConfigs.timeBetweenQueriesInBurstMs(),
|
||||||
13, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false);
|
false /* expectsUnicastResponse */, true /* multipleSocketDiscovery */,
|
||||||
|
15 /* scheduledCount */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -385,29 +425,36 @@ public class MdnsServiceTypeClientTests {
|
|||||||
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(
|
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(
|
||||||
true).setNumOfQueriesBeforeBackoff(3).build();
|
true).setNumOfQueriesBeforeBackoff(3).build();
|
||||||
startSendAndReceive(mockListenerOne, searchOptions);
|
startSendAndReceive(mockListenerOne, searchOptions);
|
||||||
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
// Always try to remove the task.
|
||||||
verifyAndSendQuery(
|
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
1, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false);
|
|
||||||
verifyAndSendQuery(
|
verifyAndSendQuery(0 /* index */, 0 /* timeInMs */, true /* expectsUnicastResponse */,
|
||||||
2, MdnsConfigs.timeBetweenQueriesInBurstMs(), /* expectsUnicastResponse= */ false);
|
true /* multipleSocketDiscovery */, 1 /* scheduledCount */);
|
||||||
verifyAndSendQuery(3, MdnsConfigs.timeBetweenBurstsMs(), /* expectsUnicastResponse= */
|
verifyAndSendQuery(1 /* index */, MdnsConfigs.timeBetweenQueriesInBurstMs(),
|
||||||
false);
|
false /* expectsUnicastResponse */, true /* multipleSocketDiscovery */,
|
||||||
assertEquals(4, currentThreadExecutor.getNumOfScheduledFuture());
|
2 /* scheduledCount */);
|
||||||
|
verifyAndSendQuery(2 /* index */, MdnsConfigs.timeBetweenQueriesInBurstMs(),
|
||||||
|
false /* expectsUnicastResponse */, true /* multipleSocketDiscovery */,
|
||||||
|
3 /* scheduledCount */);
|
||||||
|
verifyAndSendQuery(3 /* index */, MdnsConfigs.timeBetweenBurstsMs(),
|
||||||
|
false /* expectsUnicastResponse */, true /* multipleSocketDiscovery */,
|
||||||
|
4 /* scheduledCount */);
|
||||||
|
|
||||||
// In backoff mode, the current scheduled task will be canceled and reschedule if the
|
// In backoff mode, the current scheduled task will be canceled and reschedule if the
|
||||||
// 0.8 * smallestRemainingTtl is larger than time to next run.
|
// 0.8 * smallestRemainingTtl is larger than time to next run.
|
||||||
doReturn(TEST_ELAPSED_REALTIME + 20000).when(mockDecoderClock).elapsedRealtime();
|
doReturn(TEST_ELAPSED_REALTIME + 20000).when(mockDecoderClock).elapsedRealtime();
|
||||||
|
doReturn(true).when(mockDeps).hasMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
processResponse(createResponse(
|
processResponse(createResponse(
|
||||||
"service-instance-1", "192.0.2.123", 5353,
|
"service-instance-1", "192.0.2.123", 5353,
|
||||||
SERVICE_TYPE_LABELS,
|
SERVICE_TYPE_LABELS,
|
||||||
Collections.emptyMap(), TEST_TTL), socketKey);
|
Collections.emptyMap(), TEST_TTL), socketKey);
|
||||||
verify(expectedSendFutures[4]).cancel(true);
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
assertEquals(5, currentThreadExecutor.getNumOfScheduledFuture());
|
assertNotNull(delayMessage);
|
||||||
verifyAndSendQuery(4, 80000 /* timeInMs */, false /* expectsUnicastResponse */);
|
verifyAndSendQuery(4 /* index */, 80000 /* timeInMs */, false /* expectsUnicastResponse */,
|
||||||
assertEquals(6, currentThreadExecutor.getNumOfScheduledFuture());
|
true /* multipleSocketDiscovery */, 6 /* scheduledCount */);
|
||||||
// Next run should also be scheduled in 0.8 * smallestRemainingTtl
|
// Next run should also be scheduled in 0.8 * smallestRemainingTtl
|
||||||
verifyAndSendQuery(5, 80000 /* timeInMs */, false /* expectsUnicastResponse */);
|
verifyAndSendQuery(5 /* index */, 80000 /* timeInMs */, false /* expectsUnicastResponse */,
|
||||||
assertEquals(7, currentThreadExecutor.getNumOfScheduledFuture());
|
true /* multipleSocketDiscovery */, 7 /* scheduledCount */);
|
||||||
|
|
||||||
// If the records is not refreshed, the current scheduled task will not be canceled.
|
// If the records is not refreshed, the current scheduled task will not be canceled.
|
||||||
doReturn(TEST_ELAPSED_REALTIME + 20001).when(mockDecoderClock).elapsedRealtime();
|
doReturn(TEST_ELAPSED_REALTIME + 20001).when(mockDecoderClock).elapsedRealtime();
|
||||||
@@ -416,7 +463,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
SERVICE_TYPE_LABELS,
|
SERVICE_TYPE_LABELS,
|
||||||
Collections.emptyMap(), TEST_TTL,
|
Collections.emptyMap(), TEST_TTL,
|
||||||
TEST_ELAPSED_REALTIME - 1), socketKey);
|
TEST_ELAPSED_REALTIME - 1), socketKey);
|
||||||
verify(expectedSendFutures[7], never()).cancel(true);
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// In backoff mode, the current scheduled task will not be canceled if the
|
// In backoff mode, the current scheduled task will not be canceled if the
|
||||||
// 0.8 * smallestRemainingTtl is smaller than time to next run.
|
// 0.8 * smallestRemainingTtl is smaller than time to next run.
|
||||||
@@ -425,10 +472,10 @@ public class MdnsServiceTypeClientTests {
|
|||||||
"service-instance-1", "192.0.2.123", 5353,
|
"service-instance-1", "192.0.2.123", 5353,
|
||||||
SERVICE_TYPE_LABELS,
|
SERVICE_TYPE_LABELS,
|
||||||
Collections.emptyMap(), TEST_TTL), socketKey);
|
Collections.emptyMap(), TEST_TTL), socketKey);
|
||||||
verify(expectedSendFutures[7], never()).cancel(true);
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
stopSendAndReceive(mockListenerOne);
|
stopSendAndReceive(mockListenerOne);
|
||||||
verify(expectedSendFutures[7]).cancel(true);
|
verify(mockDeps, times(3)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -436,6 +483,8 @@ public class MdnsServiceTypeClientTests {
|
|||||||
MdnsSearchOptions searchOptions =
|
MdnsSearchOptions searchOptions =
|
||||||
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(true).build();
|
MdnsSearchOptions.newBuilder().addSubtype("12345").setIsPassiveMode(true).build();
|
||||||
startSendAndReceive(mockListenerOne, searchOptions);
|
startSendAndReceive(mockListenerOne, searchOptions);
|
||||||
|
// Always try to remove the task.
|
||||||
|
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// First burst, first query is sent.
|
// First burst, first query is sent.
|
||||||
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
verifyAndSendQuery(0, 0, /* expectsUnicastResponse= */ true);
|
||||||
@@ -449,7 +498,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
.build();
|
.build();
|
||||||
startSendAndReceive(mockListenerOne, searchOptions);
|
startSendAndReceive(mockListenerOne, searchOptions);
|
||||||
// The previous scheduled task should be canceled.
|
// The previous scheduled task should be canceled.
|
||||||
verify(expectedSendFutures[1]).cancel(true);
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// Queries should continue to be sent.
|
// Queries should continue to be sent.
|
||||||
verifyAndSendQuery(1, 0, /* expectsUnicastResponse= */ true);
|
verifyAndSendQuery(1, 0, /* expectsUnicastResponse= */ true);
|
||||||
@@ -460,7 +509,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
|
|
||||||
// Stop sending packets.
|
// Stop sending packets.
|
||||||
stopSendAndReceive(mockListenerOne);
|
stopSendAndReceive(mockListenerOne);
|
||||||
verify(expectedSendFutures[5]).cancel(true);
|
verify(mockDeps, times(3)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -596,10 +645,9 @@ public class MdnsServiceTypeClientTests {
|
|||||||
|
|
||||||
// This time no query is submitted, only scheduled
|
// This time no query is submitted, only scheduled
|
||||||
assertNull(currentThreadExecutor.getAndClearSubmittedRunnable());
|
assertNull(currentThreadExecutor.getAndClearSubmittedRunnable());
|
||||||
assertNotNull(currentThreadExecutor.getAndClearLastScheduledRunnable());
|
|
||||||
// This just skips the first query of the first burst
|
// This just skips the first query of the first burst
|
||||||
assertEquals(MdnsConfigs.timeBetweenQueriesInBurstMs(),
|
verify(mockDeps).sendMessageDelayed(
|
||||||
currentThreadExecutor.getAndClearLastScheduledDelayInMs());
|
any(), any(), eq(MdnsConfigs.timeBetweenQueriesInBurstMs()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyServiceInfo(MdnsServiceInfo serviceInfo, String serviceName,
|
private static void verifyServiceInfo(MdnsServiceInfo serviceInfo, String serviceName,
|
||||||
@@ -853,7 +901,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
final String serviceInstanceName = "service-instance-1";
|
final String serviceInstanceName = "service-instance-1";
|
||||||
client =
|
client =
|
||||||
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()) {
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps) {
|
||||||
@Override
|
@Override
|
||||||
MdnsPacketWriter createMdnsPacketWriter() {
|
MdnsPacketWriter createMdnsPacketWriter() {
|
||||||
return mockPacketWriter;
|
return mockPacketWriter;
|
||||||
@@ -896,7 +944,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
final String serviceInstanceName = "service-instance-1";
|
final String serviceInstanceName = "service-instance-1";
|
||||||
client =
|
client =
|
||||||
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()) {
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps) {
|
||||||
@Override
|
@Override
|
||||||
MdnsPacketWriter createMdnsPacketWriter() {
|
MdnsPacketWriter createMdnsPacketWriter() {
|
||||||
return mockPacketWriter;
|
return mockPacketWriter;
|
||||||
@@ -929,7 +977,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
final String serviceInstanceName = "service-instance-1";
|
final String serviceInstanceName = "service-instance-1";
|
||||||
client =
|
client =
|
||||||
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper()) {
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps) {
|
||||||
@Override
|
@Override
|
||||||
MdnsPacketWriter createMdnsPacketWriter() {
|
MdnsPacketWriter createMdnsPacketWriter() {
|
||||||
return mockPacketWriter;
|
return mockPacketWriter;
|
||||||
@@ -1049,7 +1097,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testProcessResponse_Resolve() throws Exception {
|
public void testProcessResponse_Resolve() throws Exception {
|
||||||
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
socketKey, mockSharedLog, thread.getLooper());
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps);
|
||||||
|
|
||||||
final String instanceName = "service-instance";
|
final String instanceName = "service-instance";
|
||||||
final String[] hostname = new String[] { "testhost "};
|
final String[] hostname = new String[] { "testhost "};
|
||||||
@@ -1070,6 +1118,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
inOrder.verify(mockSocketClient, times(2)).sendPacketRequestingUnicastResponse(
|
inOrder.verify(mockSocketClient, times(2)).sendPacketRequestingUnicastResponse(
|
||||||
srvTxtQueryCaptor.capture(),
|
srvTxtQueryCaptor.capture(),
|
||||||
eq(socketKey), eq(false));
|
eq(socketKey), eq(false));
|
||||||
|
assertNotNull(delayMessage);
|
||||||
|
|
||||||
final MdnsPacket srvTxtQueryPacket = MdnsPacket.parse(
|
final MdnsPacket srvTxtQueryPacket = MdnsPacket.parse(
|
||||||
new MdnsPacketReader(srvTxtQueryCaptor.getValue()));
|
new MdnsPacketReader(srvTxtQueryCaptor.getValue()));
|
||||||
@@ -1095,6 +1144,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
processResponse(srvTxtResponse, socketKey);
|
processResponse(srvTxtResponse, socketKey);
|
||||||
|
|
||||||
// Expect a query for A/AAAA
|
// Expect a query for A/AAAA
|
||||||
|
dispatchMessage();
|
||||||
final ArgumentCaptor<DatagramPacket> addressQueryCaptor =
|
final ArgumentCaptor<DatagramPacket> addressQueryCaptor =
|
||||||
ArgumentCaptor.forClass(DatagramPacket.class);
|
ArgumentCaptor.forClass(DatagramPacket.class);
|
||||||
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
|
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
|
||||||
@@ -1139,7 +1189,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testRenewTxtSrvInResolve() throws Exception {
|
public void testRenewTxtSrvInResolve() throws Exception {
|
||||||
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper());
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps);
|
||||||
|
|
||||||
final String instanceName = "service-instance";
|
final String instanceName = "service-instance";
|
||||||
final String[] hostname = new String[] { "testhost "};
|
final String[] hostname = new String[] { "testhost "};
|
||||||
@@ -1160,6 +1210,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
inOrder.verify(mockSocketClient, times(2)).sendPacketRequestingUnicastResponse(
|
inOrder.verify(mockSocketClient, times(2)).sendPacketRequestingUnicastResponse(
|
||||||
srvTxtQueryCaptor.capture(),
|
srvTxtQueryCaptor.capture(),
|
||||||
eq(socketKey), eq(false));
|
eq(socketKey), eq(false));
|
||||||
|
assertNotNull(delayMessage);
|
||||||
|
|
||||||
final MdnsPacket srvTxtQueryPacket = MdnsPacket.parse(
|
final MdnsPacket srvTxtQueryPacket = MdnsPacket.parse(
|
||||||
new MdnsPacketReader(srvTxtQueryCaptor.getValue()));
|
new MdnsPacketReader(srvTxtQueryCaptor.getValue()));
|
||||||
@@ -1187,6 +1238,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
Collections.emptyList() /* authorityRecords */,
|
Collections.emptyList() /* authorityRecords */,
|
||||||
Collections.emptyList() /* additionalRecords */);
|
Collections.emptyList() /* additionalRecords */);
|
||||||
processResponse(srvTxtResponse, socketKey);
|
processResponse(srvTxtResponse, socketKey);
|
||||||
|
dispatchMessage();
|
||||||
inOrder.verify(mockListenerOne).onServiceNameDiscovered(any());
|
inOrder.verify(mockListenerOne).onServiceNameDiscovered(any());
|
||||||
inOrder.verify(mockListenerOne).onServiceFound(any());
|
inOrder.verify(mockListenerOne).onServiceFound(any());
|
||||||
|
|
||||||
@@ -1197,6 +1249,8 @@ public class MdnsServiceTypeClientTests {
|
|||||||
// Advance time so 75% of TTL passes and re-execute
|
// Advance time so 75% of TTL passes and re-execute
|
||||||
doReturn(TEST_ELAPSED_REALTIME + (long) (TEST_TTL * 0.75))
|
doReturn(TEST_ELAPSED_REALTIME + (long) (TEST_TTL * 0.75))
|
||||||
.when(mockDecoderClock).elapsedRealtime();
|
.when(mockDecoderClock).elapsedRealtime();
|
||||||
|
assertNotNull(delayMessage);
|
||||||
|
dispatchMessage();
|
||||||
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
|
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
|
||||||
|
|
||||||
// Expect a renewal query
|
// Expect a renewal query
|
||||||
@@ -1211,6 +1265,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
new MdnsPacketReader(renewalQueryCaptor.getValue()));
|
new MdnsPacketReader(renewalQueryCaptor.getValue()));
|
||||||
assertTrue(hasQuestion(renewalPacket, MdnsRecord.TYPE_ANY, serviceName));
|
assertTrue(hasQuestion(renewalPacket, MdnsRecord.TYPE_ANY, serviceName));
|
||||||
inOrder.verifyNoMoreInteractions();
|
inOrder.verifyNoMoreInteractions();
|
||||||
|
assertNotNull(delayMessage);
|
||||||
|
|
||||||
long updatedReceiptTime = TEST_ELAPSED_REALTIME + TEST_TTL;
|
long updatedReceiptTime = TEST_ELAPSED_REALTIME + TEST_TTL;
|
||||||
final MdnsPacket refreshedSrvTxtResponse = new MdnsPacket(
|
final MdnsPacket refreshedSrvTxtResponse = new MdnsPacket(
|
||||||
@@ -1232,6 +1287,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
Collections.emptyList() /* authorityRecords */,
|
Collections.emptyList() /* authorityRecords */,
|
||||||
Collections.emptyList() /* additionalRecords */);
|
Collections.emptyList() /* additionalRecords */);
|
||||||
processResponse(refreshedSrvTxtResponse, socketKey);
|
processResponse(refreshedSrvTxtResponse, socketKey);
|
||||||
|
dispatchMessage();
|
||||||
|
|
||||||
// Advance time to updatedReceiptTime + 1, expected no refresh query because the cache
|
// Advance time to updatedReceiptTime + 1, expected no refresh query because the cache
|
||||||
// should contain the record that have update last receipt time.
|
// should contain the record that have update last receipt time.
|
||||||
@@ -1243,7 +1299,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testProcessResponse_ResolveExcludesOtherServices() {
|
public void testProcessResponse_ResolveExcludesOtherServices() {
|
||||||
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
socketKey, mockSharedLog, thread.getLooper());
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps);
|
||||||
|
|
||||||
final String requestedInstance = "instance1";
|
final String requestedInstance = "instance1";
|
||||||
final String otherInstance = "instance2";
|
final String otherInstance = "instance2";
|
||||||
@@ -1307,7 +1363,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testProcessResponse_SubtypeDiscoveryLimitedToSubtype() {
|
public void testProcessResponse_SubtypeDiscoveryLimitedToSubtype() {
|
||||||
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
socketKey, mockSharedLog, thread.getLooper());
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps);
|
||||||
|
|
||||||
final String matchingInstance = "instance1";
|
final String matchingInstance = "instance1";
|
||||||
final String subtype = "_subtype";
|
final String subtype = "_subtype";
|
||||||
@@ -1388,7 +1444,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testNotifySocketDestroyed() throws Exception {
|
public void testNotifySocketDestroyed() throws Exception {
|
||||||
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
client = new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
|
||||||
socketKey, mockSharedLog, thread.getLooper());
|
mockDecoderClock, socketKey, mockSharedLog, thread.getLooper(), mockDeps);
|
||||||
|
|
||||||
final String requestedInstance = "instance1";
|
final String requestedInstance = "instance1";
|
||||||
final String otherInstance = "instance2";
|
final String otherInstance = "instance2";
|
||||||
@@ -1399,6 +1455,8 @@ public class MdnsServiceTypeClientTests {
|
|||||||
.setResolveInstanceName("instance1").build();
|
.setResolveInstanceName("instance1").build();
|
||||||
|
|
||||||
startSendAndReceive(mockListenerOne, resolveOptions);
|
startSendAndReceive(mockListenerOne, resolveOptions);
|
||||||
|
// Always try to remove the task.
|
||||||
|
verify(mockDeps, times(1)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
// Ensure the first task is executed so it schedules a future task
|
// Ensure the first task is executed so it schedules a future task
|
||||||
currentThreadExecutor.getAndClearSubmittedFuture().get(
|
currentThreadExecutor.getAndClearSubmittedFuture().get(
|
||||||
TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||||
@@ -1407,7 +1465,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
Integer.MAX_VALUE).build());
|
Integer.MAX_VALUE).build());
|
||||||
|
|
||||||
// Filing the second request cancels the first future
|
// Filing the second request cancels the first future
|
||||||
verify(expectedSendFutures[0]).cancel(true);
|
verify(mockDeps, times(2)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// Ensure it gets executed too
|
// Ensure it gets executed too
|
||||||
currentThreadExecutor.getAndClearSubmittedFuture().get(
|
currentThreadExecutor.getAndClearSubmittedFuture().get(
|
||||||
@@ -1425,9 +1483,8 @@ public class MdnsServiceTypeClientTests {
|
|||||||
Collections.emptyMap() /* textAttributes */, TEST_TTL),
|
Collections.emptyMap() /* textAttributes */, TEST_TTL),
|
||||||
socketKey);
|
socketKey);
|
||||||
|
|
||||||
verify(expectedSendFutures[1], never()).cancel(true);
|
|
||||||
notifySocketDestroyed();
|
notifySocketDestroyed();
|
||||||
verify(expectedSendFutures[1]).cancel(true);
|
verify(mockDeps, times(3)).removeMessages(any(), eq(EVENT_START_QUERYTASK));
|
||||||
|
|
||||||
// mockListenerOne gets notified for the requested instance
|
// mockListenerOne gets notified for the requested instance
|
||||||
final InOrder inOrder1 = inOrder(mockListenerOne);
|
final InOrder inOrder1 = inOrder(mockListenerOne);
|
||||||
@@ -1461,13 +1518,17 @@ public class MdnsServiceTypeClientTests {
|
|||||||
// verifies that the right query was enqueued with the right delay, and send query by executing
|
// verifies that the right query was enqueued with the right delay, and send query by executing
|
||||||
// the runnable.
|
// the runnable.
|
||||||
private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse) {
|
private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse) {
|
||||||
verifyAndSendQuery(
|
verifyAndSendQuery(index, timeInMs, expectsUnicastResponse,
|
||||||
index, timeInMs, expectsUnicastResponse, true /* multipleSocketDiscovery */);
|
true /* multipleSocketDiscovery */, index + 1 /* scheduledCount */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse,
|
private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse,
|
||||||
boolean multipleSocketDiscovery) {
|
boolean multipleSocketDiscovery, int scheduledCount) {
|
||||||
assertEquals(timeInMs, currentThreadExecutor.getAndClearLastScheduledDelayInMs());
|
// Dispatch the message
|
||||||
|
if (delayMessage != null && realHandler != null) {
|
||||||
|
dispatchMessage();
|
||||||
|
}
|
||||||
|
assertEquals(timeInMs, latestDelayMs);
|
||||||
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
|
currentThreadExecutor.getAndClearLastScheduledRunnable().run();
|
||||||
if (expectsUnicastResponse) {
|
if (expectsUnicastResponse) {
|
||||||
verify(mockSocketClient).sendPacketRequestingUnicastResponse(
|
verify(mockSocketClient).sendPacketRequestingUnicastResponse(
|
||||||
@@ -1484,6 +1545,9 @@ public class MdnsServiceTypeClientTests {
|
|||||||
expectedIPv6Packets[index], socketKey, false);
|
expectedIPv6Packets[index], socketKey, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Verify the task has been scheduled.
|
||||||
|
verify(mockDeps, times(scheduledCount))
|
||||||
|
.sendMessageDelayed(any(Handler.class), any(Message.class), anyLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] getTestServiceName(String instanceName) {
|
private static String[] getTestServiceName(String instanceName) {
|
||||||
@@ -1528,7 +1592,7 @@ public class MdnsServiceTypeClientTests {
|
|||||||
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
|
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
|
||||||
lastScheduledDelayInMs = delay;
|
lastScheduledDelayInMs = delay;
|
||||||
lastScheduledRunnable = command;
|
lastScheduledRunnable = command;
|
||||||
return expectedSendFutures[futureIndex++];
|
return Mockito.mock(ScheduledFuture.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the delay of the last scheduled task, and clear it.
|
// Returns the delay of the last scheduled task, and clear it.
|
||||||
@@ -1556,10 +1620,6 @@ public class MdnsServiceTypeClientTests {
|
|||||||
lastSubmittedFuture = null;
|
lastSubmittedFuture = null;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumOfScheduledFuture() {
|
|
||||||
return futureIndex - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MdnsPacket createResponse(
|
private MdnsPacket createResponse(
|
||||||
|
|||||||
Reference in New Issue
Block a user