Merge "Remove the ServiceTypeClient after socket destroyed"

This commit is contained in:
Paul Hu
2023-05-11 11:50:57 +00:00
committed by Gerrit Code Review
7 changed files with 181 additions and 12 deletions

View File

@@ -20,6 +20,7 @@ import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -193,6 +194,60 @@ public class MdnsDiscoveryManagerTests {
verify(mockServiceTypeClientTwo2).processResponse(responseForSubtype, ifIndex, NETWORK_2);
}
@Test
public void testSocketCreatedAndDestroyed() throws IOException {
// Create a ServiceTypeClient for SERVICE_TYPE_1 and NETWORK_1
final MdnsSearchOptions options1 =
MdnsSearchOptions.newBuilder().setNetwork(NETWORK_1).build();
final SocketCreationCallback callback = expectSocketCreationCallback(
SERVICE_TYPE_1, mockListenerOne, options1);
callback.onSocketCreated(NETWORK_1);
verify(mockServiceTypeClientOne1).startSendAndReceive(mockListenerOne, options1);
// Create a ServiceTypeClient for SERVICE_TYPE_2 and NETWORK_2
final MdnsSearchOptions options2 =
MdnsSearchOptions.newBuilder().setNetwork(NETWORK_2).build();
final SocketCreationCallback callback2 = expectSocketCreationCallback(
SERVICE_TYPE_2, mockListenerTwo, options2);
callback2.onSocketCreated(NETWORK_2);
verify(mockServiceTypeClientTwo2).startSendAndReceive(mockListenerTwo, options2);
// Receive a response, it should be processed on both clients.
final MdnsPacket response = createMdnsPacket(SERVICE_TYPE_1);
final int ifIndex = 1;
discoveryManager.onResponseReceived(response, ifIndex, null /* network */);
verify(mockServiceTypeClientOne1).processResponse(response, ifIndex, null /* network */);
verify(mockServiceTypeClientTwo2).processResponse(response, ifIndex, null /* network */);
// The client for NETWORK_1 receives the callback that the NETWORK_1 has been destroyed,
// mockServiceTypeClientOne1 should send service removed notifications and remove from the
// list of clients.
callback.onSocketDestroyed(NETWORK_1);
verify(mockServiceTypeClientOne1).notifyAllServicesRemoved();
// Receive a response again, it should be processed only on mockServiceTypeClientTwo2.
// Because the mockServiceTypeClientOne1 is removed from the list of clients, it is no
// longer able to process responses.
discoveryManager.onResponseReceived(response, ifIndex, null /* network */);
verify(mockServiceTypeClientOne1, times(1))
.processResponse(response, ifIndex, null /* network */);
verify(mockServiceTypeClientTwo2, times(2))
.processResponse(response, ifIndex, null /* network */);
// The client for NETWORK_2 receives the callback that the NETWORK_1 has been destroyed,
// mockServiceTypeClientTwo2 shouldn't send any notifications.
callback2.onSocketDestroyed(NETWORK_1);
verify(mockServiceTypeClientTwo2, never()).notifyAllServicesRemoved();
// Receive a response again, mockServiceTypeClientTwo2 is still in the list of clients, it's
// still able to process responses.
discoveryManager.onResponseReceived(response, ifIndex, null /* network */);
verify(mockServiceTypeClientOne1, times(1))
.processResponse(response, ifIndex, null /* network */);
verify(mockServiceTypeClientTwo2, times(3))
.processResponse(response, ifIndex, null /* network */);
}
private MdnsPacket createMdnsPacket(String serviceType) {
final String[] type = TextUtils.split(serviceType, "\\.");
final ArrayList<String> name = new ArrayList<>(type.length + 1);

View File

@@ -1056,6 +1056,61 @@ public class MdnsServiceTypeClientTests {
inOrder.verify(mockListenerTwo).onServiceRemoved(matchServiceName(otherInstance));
}
@Test
public void testNotifyAllServicesRemoved() {
client = new MdnsServiceTypeClient(
SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork, mockSharedLog);
final String requestedInstance = "instance1";
final String otherInstance = "instance2";
final String ipV4Address = "192.0.2.0";
final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
// Use different case in the options
.setResolveInstanceName("Instance1").build();
client.startSendAndReceive(mockListenerOne, resolveOptions);
client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
// Complete response from instanceName
client.processResponse(createResponse(
requestedInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS,
Collections.emptyMap() /* textAttributes */, TEST_TTL),
INTERFACE_INDEX, mockNetwork);
// Complete response from otherInstanceName
client.processResponse(createResponse(
otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS,
Collections.emptyMap() /* textAttributes */, TEST_TTL),
INTERFACE_INDEX, mockNetwork);
client.notifyAllServicesRemoved();
// mockListenerOne gets notified for the requested instance
final InOrder inOrder1 = inOrder(mockListenerOne);
inOrder1.verify(mockListenerOne).onServiceNameDiscovered(
matchServiceName(requestedInstance));
inOrder1.verify(mockListenerOne).onServiceFound(matchServiceName(requestedInstance));
inOrder1.verify(mockListenerOne).onServiceRemoved(matchServiceName(requestedInstance));
inOrder1.verify(mockListenerOne).onServiceNameRemoved(matchServiceName(requestedInstance));
verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance));
verify(mockListenerOne, never()).onServiceNameDiscovered(matchServiceName(otherInstance));
verify(mockListenerOne, never()).onServiceRemoved(matchServiceName(otherInstance));
verify(mockListenerOne, never()).onServiceNameRemoved(matchServiceName(otherInstance));
// mockListenerTwo gets notified for both though
final InOrder inOrder2 = inOrder(mockListenerTwo);
inOrder2.verify(mockListenerTwo).onServiceNameDiscovered(
matchServiceName(requestedInstance));
inOrder2.verify(mockListenerTwo).onServiceFound(matchServiceName(requestedInstance));
inOrder2.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance));
inOrder2.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance));
inOrder2.verify(mockListenerTwo).onServiceRemoved(matchServiceName(otherInstance));
inOrder2.verify(mockListenerTwo).onServiceNameRemoved(matchServiceName(otherInstance));
inOrder2.verify(mockListenerTwo).onServiceRemoved(matchServiceName(requestedInstance));
inOrder2.verify(mockListenerTwo).onServiceNameRemoved(matchServiceName(requestedInstance));
}
private static MdnsServiceInfo matchServiceName(String name) {
return argThat(info -> info.getServiceInstanceName().equals(name));
}