Use case-insensitive matching in discovery/advertising

mDNS is supposed to be case-insensitive (like DNS). Both advertising and
discovery logic should use case-insensitive matching instead of
case-sensitive matching.

The case sensitive matching can be found by grepping the String.equals()
and Arrays.equals() check across the whole code base. Each occurrence is
analyzed carefully to list up all necessary fixes.

Bug: 272194544
Test: atest FrameworksNetTests
Change-Id: I7c10878129663549c9171c1420b6f399930df2cb
This commit is contained in:
Yuyang Huang
2023-05-01 13:43:12 +09:00
parent 94a4149a8f
commit 73772f325d
21 changed files with 442 additions and 54 deletions

View File

@@ -51,6 +51,7 @@ private const val SERVICE_ID_1 = 1
private const val SERVICE_ID_2 = 2
private const val LONG_SERVICE_ID_1 = 3
private const val LONG_SERVICE_ID_2 = 4
private const val CASE_INSENSITIVE_TEST_SERVICE_ID = 5
private const val TIMEOUT_MS = 10_000L
private val TEST_ADDR = parseNumericAddress("2001:db8::123")
private val TEST_LINKADDR = LinkAddress(TEST_ADDR, 64 /* prefixLength */)
@@ -78,6 +79,13 @@ private val ALL_NETWORKS_SERVICE = NsdServiceInfo("TestServiceName", "_advertise
network = null
}
private val ALL_NETWORKS_SERVICE_2 =
NsdServiceInfo("TESTSERVICENAME", "_ADVERTISERTEST._tcp").apply {
port = 12345
hostAddresses = listOf(TEST_ADDR)
network = null
}
private val LONG_ALL_NETWORKS_SERVICE =
NsdServiceInfo("a".repeat(48) + "TestServiceName", "_longadvertisertest._tcp").apply {
port = 12345
@@ -228,6 +236,9 @@ class MdnsAdvertiserTest {
postSync { advertiser.addService(LONG_SERVICE_ID_2, LONG_ALL_NETWORKS_SERVICE,
null /* subtype */) }
postSync { advertiser.addService(CASE_INSENSITIVE_TEST_SERVICE_ID, ALL_NETWORKS_SERVICE_2,
null /* subtype */) }
// Callbacks for matching network and all networks both get the socket
postSync {
oneNetSocketCb.onSocketCreated(TEST_NETWORK_1, mockSocket1, listOf(TEST_LINKADDR))
@@ -249,6 +260,14 @@ class MdnsAdvertiserTest {
network = LONG_ALL_NETWORKS_SERVICE.network
}
val expectedCaseInsensitiveRenamed = NsdServiceInfo(
"${ALL_NETWORKS_SERVICE_2.serviceName} (3)", ALL_NETWORKS_SERVICE_2.serviceType
).apply {
port = ALL_NETWORKS_SERVICE_2.port
hostAddresses = ALL_NETWORKS_SERVICE_2.hostAddresses
network = ALL_NETWORKS_SERVICE_2.network
}
val intAdvCbCaptor = ArgumentCaptor.forClass(MdnsInterfaceAdvertiser.Callback::class.java)
verify(mockDeps).makeAdvertiser(eq(mockSocket1), eq(listOf(TEST_LINKADDR)),
eq(thread.looper), any(), intAdvCbCaptor.capture(), eq(TEST_HOSTNAME), any()
@@ -261,6 +280,8 @@ class MdnsAdvertiserTest {
argThat { it.matches(LONG_SERVICE_1) }, eq(null))
verify(mockInterfaceAdvertiser1).addService(eq(LONG_SERVICE_ID_2),
argThat { it.matches(expectedLongRenamed) }, eq(null))
verify(mockInterfaceAdvertiser1).addService(eq(CASE_INSENSITIVE_TEST_SERVICE_ID),
argThat { it.matches(expectedCaseInsensitiveRenamed) }, eq(null))
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(

View File

@@ -31,7 +31,7 @@ class MdnsPacketWriterTest {
@Test
fun testNameCompression() {
val writer = MdnsPacketWriter(ByteArray(1000))
writer.writeLabels(arrayOf("my", "first", "name"))
writer.writeLabels(arrayOf("my", "FIRST", "name"))
writer.writeLabels(arrayOf("my", "second", "name"))
writer.writeLabels(arrayOf("other", "first", "name"))
writer.writeLabels(arrayOf("my", "second", "name"))
@@ -41,7 +41,7 @@ class MdnsPacketWriterTest {
InetSocketAddress(InetAddresses.parseNumericAddress("2001:db8::123"), 123))
// Each label takes length + 1. So "first.name" offset = 3, "name" offset = 9
val expected = "my".label() + "first".label() + "name".label() + 0x00.toByte() +
val expected = "my".label() + "FIRST".label() + "name".label() + 0x00.toByte() +
// "my.second.name" offset = 15
"my".label() + "second".label() + byteArrayOf(0xC0.toByte(), 9) +
"other".label() + byteArrayOf(0xC0.toByte(), 3) +

View File

@@ -48,6 +48,7 @@ private const val SHORT_TIMEOUT_MS = 200L
private val TEST_SERVICE_NAME_1 = arrayOf("testservice", "_nmt", "_tcp", "local")
private val TEST_SERVICE_NAME_2 = arrayOf("testservice2", "_nmt", "_tcp", "local")
private val TEST_SERVICE_NAME_3 = arrayOf("Testservice", "_nmt", "_tcp", "local")
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
@@ -128,6 +129,15 @@ class MdnsProberTest {
assertProbesSent(probeInfo, expected)
}
@Test
fun testCreateProberCaseInsensitive() {
val probeInfo = TestProbeInfo(
listOf(makeServiceRecord(TEST_SERVICE_NAME_1, 37890),
makeServiceRecord(TEST_SERVICE_NAME_2, 37890),
makeServiceRecord(TEST_SERVICE_NAME_3, 37890)))
assertEquals(2, probeInfo.getPacket(0).questions.size)
}
@Test
fun testProbeMultipleRecords() {
val replySender = MdnsReplySender("testiface", thread.looper, socket, buffer)

View File

@@ -43,6 +43,7 @@ import org.junit.runner.RunWith
private const val TEST_SERVICE_ID_1 = 42
private const val TEST_SERVICE_ID_2 = 43
private const val TEST_SERVICE_ID_3 = 44
private const val TEST_PORT = 12345
private const val TEST_SUBTYPE = "_subtype"
private val TEST_HOSTNAME = arrayOf("Android_000102030405060708090A0B0C0D0E0F", "local")
@@ -63,6 +64,12 @@ private val TEST_SERVICE_2 = NsdServiceInfo().apply {
port = TEST_PORT
}
private val TEST_SERVICE_3 = NsdServiceInfo().apply {
serviceType = "_TESTSERVICE._tcp"
serviceName = "MyTESTSERVICE"
port = TEST_PORT
}
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
class MdnsRecordRepositoryTest {
@@ -124,6 +131,9 @@ class MdnsRecordRepositoryTest {
assertFailsWith(NameConflictException::class) {
repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_1, null /* subtype */)
}
assertFailsWith(NameConflictException::class) {
repository.addService(TEST_SERVICE_ID_3, TEST_SERVICE_3, null /* subtype */)
}
}
@Test
@@ -364,6 +374,27 @@ class MdnsRecordRepositoryTest {
assertContentEquals(expectedV4, getReverseDnsAddress(parseNumericAddress("192.0.2.123")))
}
@Test
fun testGetReplyCaseInsensitive() {
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
repository.initWithService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
val questionsCaseInSensitive =
listOf(MdnsPointerRecord(arrayOf("_TESTSERVICE", "_TCP", "local"),
0L /* receiptTimeMillis */,
false /* cacheFlush */,
// TTL and data is empty for a question
0L /* ttlMillis */,
null /* pointer */))
val queryCaseInsensitive = MdnsPacket(0 /* flags */, questionsCaseInSensitive,
listOf() /* answers */, listOf() /* authorityRecords */,
listOf() /* additionalRecords */)
val src = InetSocketAddress(parseNumericAddress("192.0.2.123"), 5353)
val replyCaseInsensitive = repository.getReply(queryCaseInsensitive, src)
assertNotNull(replyCaseInsensitive)
assertEquals(1, replyCaseInsensitive.answers.size)
assertEquals(7, replyCaseInsensitive.additionalAnswers.size)
}
@Test
fun testGetReply() {
doGetReplyTest(subtype = null)
@@ -489,6 +520,34 @@ class MdnsRecordRepositoryTest {
repository.getConflictingServices(packet))
}
@Test
fun testGetConflictingServicesCaseInsensitive() {
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */)
repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */)
val packet = MdnsPacket(
0 /* flags */,
emptyList() /* questions */,
listOf(
MdnsServiceRecord(
arrayOf("MYTESTSERVICE", "_TESTSERVICE", "_tcp", "local"),
0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */,
0 /* servicePriority */, 0 /* serviceWeight */,
TEST_SERVICE_1.port + 1,
TEST_HOSTNAME),
MdnsTextRecord(
arrayOf("MYOTHERTESTSERVICE", "_TESTSERVICE", "_tcp", "local"),
0L /* receiptTimeMillis */, true /* cacheFlush */, 0L /* ttlMillis */,
listOf(TextEntry.fromString("somedifferent=entry"))),
) /* answers */,
emptyList() /* authorityRecords */,
emptyList() /* additionalRecords */)
assertEquals(setOf(TEST_SERVICE_ID_1, TEST_SERVICE_ID_2),
repository.getConflictingServices(packet))
}
@Test
fun testGetConflictingServices_IdenticalService() {
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
@@ -505,7 +564,7 @@ class MdnsRecordRepositoryTest {
0L /* receiptTimeMillis */, true /* cacheFlush */,
otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */,
TEST_SERVICE_1.port,
TEST_HOSTNAME),
arrayOf("ANDROID_000102030405060708090A0B0C0D0E0F", "local")),
MdnsTextRecord(
arrayOf("MyOtherTestService", "_testservice", "_tcp", "local"),
0L /* receiptTimeMillis */, true /* cacheFlush */,
@@ -517,6 +576,35 @@ class MdnsRecordRepositoryTest {
// Above records are identical to the actual registrations: no conflict
assertEquals(emptySet(), repository.getConflictingServices(packet))
}
@Test
fun testGetConflictingServicesCaseInsensitive_IdenticalService() {
val repository = MdnsRecordRepository(thread.looper, deps, TEST_HOSTNAME)
repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1, null /* subtype */)
repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_2, null /* subtype */)
val otherTtlMillis = 1234L
val packet = MdnsPacket(
0 /* flags */,
emptyList() /* questions */,
listOf(
MdnsServiceRecord(
arrayOf("MYTESTSERVICE", "_TESTSERVICE", "_tcp", "local"),
0L /* receiptTimeMillis */, true /* cacheFlush */,
otherTtlMillis, 0 /* servicePriority */, 0 /* serviceWeight */,
TEST_SERVICE_1.port,
TEST_HOSTNAME),
MdnsTextRecord(
arrayOf("MyOtherTestService", "_TESTSERVICE", "_tcp", "local"),
0L /* receiptTimeMillis */, true /* cacheFlush */,
otherTtlMillis, emptyList()),
) /* answers */,
emptyList() /* authorityRecords */,
emptyList() /* additionalRecords */)
// Above records are identical to the actual registrations: no conflict
assertEquals(emptySet(), repository.getConflictingServices(packet))
}
}
private fun MdnsRecordRepository.initWithService(

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.connectivity.mdns
import android.os.Build
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
class MdnsRecordTest {
@Test
fun testPointerRecordHasSubType() {
val ptrRecord1 = MdnsPointerRecord(
arrayOf("_testtype", "_sub", "_tcp", "local"),
0L /* receiptTimeMillis */,
false /* cacheFlush */,
4500000 /* ttlMillis */,
arrayOf("testservice", "_testtype", "_tcp", "local")
)
val ptrRecord2 = MdnsPointerRecord(
arrayOf("_testtype", "_SUB", "_tcp", "local"),
0L /* receiptTimeMillis */,
false /* cacheFlush */,
4500000 /* ttlMillis */,
arrayOf("testservice", "_testtype", "_tcp", "local")
)
assertTrue(ptrRecord1.hasSubtype())
assertTrue(ptrRecord2.hasSubtype())
}
@Test
fun testEqualsCaseInsensitive() {
val ptrRecord1 = MdnsPointerRecord(
arrayOf("_testtype", "_tcp", "local"),
0L /* receiptTimeMillis */,
false /* cacheFlush */,
4500000 /* ttlMillis */,
arrayOf("testservice", "_testtype", "_tcp", "local")
)
val ptrRecord2 = MdnsPointerRecord(
arrayOf("_testType", "_tcp", "local"),
0L /* receiptTimeMillis */,
false /* cacheFlush */,
4500000 /* ttlMillis */,
arrayOf("testsErvice", "_testtype", "_Tcp", "local")
)
assertEquals(ptrRecord1, ptrRecord2)
assertEquals(ptrRecord1.hashCode(), ptrRecord2.hashCode())
val srvRecord1 = MdnsServiceRecord(
arrayOf("testservice", "_testtype", "_tcp", "local"),
123 /* receiptTimeMillis */,
false /* cacheFlush */,
2000 /* ttlMillis */,
0 /* servicePriority */,
0 /* serviceWeight */,
80 /* port */,
arrayOf("hostname")
)
val srvRecord2 = MdnsServiceRecord(
arrayOf("Testservice", "_testtype", "_tcp", "local"),
123 /* receiptTimeMillis */,
false /* cacheFlush */,
2000 /* ttlMillis */,
0 /* servicePriority */,
0 /* serviceWeight */,
80 /* port */,
arrayOf("Hostname")
)
assertEquals(srvRecord1, srvRecord2)
assertEquals(srvRecord1.hashCode(), srvRecord2.hashCode())
val nsecRecord1 = MdnsNsecRecord(
arrayOf("hostname"),
0L /* receiptTimeMillis */,
true /* cacheFlush */,
2000L, /* ttlMillis */
arrayOf("hostname"),
intArrayOf(1, 2, 3) /* types */
)
val nsecRecord2 = MdnsNsecRecord(
arrayOf("HOSTNAME"),
0L /* receiptTimeMillis */,
true /* cacheFlush */,
2000L, /* ttlMillis */
arrayOf("HOSTNAME"),
intArrayOf(1, 2, 3) /* types */
)
assertEquals(nsecRecord1, nsecRecord2)
assertEquals(nsecRecord1.hashCode(), nsecRecord2.hashCode())
}
@Test
fun testLabelsAreSuffix() {
val labels1 = arrayOf("a", "b", "c")
val labels2 = arrayOf("B", "C")
val labels3 = arrayOf("b", "c")
val labels4 = arrayOf("b", "d")
assertTrue(MdnsRecord.labelsAreSuffix(labels2, labels1))
assertTrue(MdnsRecord.labelsAreSuffix(labels3, labels1))
assertFalse(MdnsRecord.labelsAreSuffix(labels4, labels1))
}
}

View File

@@ -269,14 +269,9 @@ public class MdnsResponseDecoderTests {
assertEquals("st=0", textStrings.get(6));
}
@Test
public void testDecodeIPv6AnswerPacket() throws IOException {
MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE);
assertNotNull(data6);
responses = decode(decoder, data6);
assertEquals(1, responses.size());
MdnsResponse response = responses.valueAt(0);
private void verifyResponse(ArraySet<MdnsResponse> responseArraySet) {
assertEquals(1, responseArraySet.size());
MdnsResponse response = responseArraySet.valueAt(0);
assertTrue(response.isComplete());
MdnsInetAddressRecord inet6AddressRecord = response.getInet6AddressRecord();
@@ -289,6 +284,22 @@ public class MdnsResponseDecoderTests {
assertEquals(inet6Addr.getHostAddress(), "2000:3333::da6c:63ff:fe7c:7483");
}
@Test
public void testDecodeIPv6AnswerPacket() throws IOException {
MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, CAST_SERVICE_TYPE);
assertNotNull(data6);
verifyResponse(decode(decoder, data6));
}
@Test
public void testDecodeCaseInsensitiveMatch() throws IOException {
final String[] castServiceTypeUpperCase =
new String[] {"_GOOGLECAST", "_TCP", "LOCAL"};
MdnsResponseDecoder decoder = new MdnsResponseDecoder(mClock, castServiceTypeUpperCase);
assertNotNull(data6);
verifyResponse(decode(decoder, data6));
}
@Test
public void testIsComplete() {
MdnsResponse response = new MdnsResponse(responses.valueAt(0));

View File

@@ -228,6 +228,12 @@ public class MdnsResponseTests {
final MdnsResponse response = makeCompleteResponse(TEST_TTL_MS);
assertFalse(response.addPointerRecord(response.getPointerRecords().get(0)));
final String[] serviceName = new String[] { "MYSERVICE", "_TYPE", "_tcp", "local" };
final String[] serviceType = new String[] { "_TYPE", "_tcp", "local" };
MdnsPointerRecord pointerRecordCaseInsensitive =
new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */,
false /* cacheFlush */, TEST_TTL_MS, serviceName);
assertFalse(response.addPointerRecord(pointerRecordCaseInsensitive));
assertFalse(response.addInet6AddressRecord(response.getInet6AddressRecord()));
assertFalse(response.addInet4AddressRecord(response.getInet4AddressRecord()));
assertFalse(response.setServiceRecord(response.getServiceRecord()));
@@ -270,4 +276,30 @@ public class MdnsResponseTests {
// All records were replaced, not added
assertEquals(ttlZeroResponse.getRecords().size(), response.getRecords().size());
}
@Test
public void dropUnmatchedAddressRecords_caseInsensitive() {
final String[] hostname = new String[] { "MyHostname" };
final String[] upperCaseHostName = new String[] { "MYHOSTNAME" };
final String[] serviceName = new String[] { "MyService", "_type", "_tcp", "local" };
final String[] serviceType = new String[] { "_type", "_tcp", "local" };
final MdnsResponse response = new MdnsResponse(/* now= */ 0, serviceName, INTERFACE_INDEX,
mNetwork);
response.addPointerRecord(new MdnsPointerRecord(serviceType, 0L /* receiptTimeMillis */,
false /* cacheFlush */, TEST_TTL_MS, serviceName));
response.setServiceRecord(new MdnsServiceRecord(serviceName, 0L /* receiptTimeMillis */,
true /* cacheFlush */, TEST_TTL_MS, 0 /* servicePriority */,
0 /* serviceWeight */, 0 /* servicePort */, hostname));
response.setTextRecord(new MdnsTextRecord(serviceName, 0L /* receiptTimeMillis */,
true /* cacheFlush */, TEST_TTL_MS, emptyList() /* entries */));
response.addInet4AddressRecord(new MdnsInetAddressRecord(
upperCaseHostName , 0L /* receiptTimeMillis */, true /* cacheFlush */,
TEST_TTL_MS, parseNumericAddress("192.0.2.123")));
response.addInet6AddressRecord(new MdnsInetAddressRecord(
upperCaseHostName, 0L /* receiptTimeMillis */, true /* cacheFlush */,
TEST_TTL_MS, parseNumericAddress("2001:db8::123")));
assertFalse(response.dropUnmatchedAddressRecords());
}
}

View File

@@ -1006,10 +1006,11 @@ public class MdnsServiceTypeClientTests {
final String otherInstance = "instance2";
final String ipV4Address = "192.0.2.0";
final String ipV6Address = "2001:db8::";
final String capitalizedRequestInstance = "Instance1";
final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
// Use different case in the options
.setResolveInstanceName("Instance1").build();
.setResolveInstanceName(capitalizedRequestInstance).build();
client.startSendAndReceive(mockListenerOne, resolveOptions);
client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
@@ -1037,8 +1038,9 @@ public class MdnsServiceTypeClientTests {
Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork);
// mockListenerOne gets notified for the requested instance
verify(mockListenerOne).onServiceNameDiscovered(matchServiceName(requestedInstance));
verify(mockListenerOne).onServiceFound(matchServiceName(requestedInstance));
verify(mockListenerOne).onServiceNameDiscovered(
matchServiceName(capitalizedRequestInstance));
verify(mockListenerOne).onServiceFound(matchServiceName(capitalizedRequestInstance));
// ...but does not get any callback for the other instance
verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance));
@@ -1049,8 +1051,9 @@ public class MdnsServiceTypeClientTests {
// mockListenerTwo gets notified for both though
final InOrder inOrder = inOrder(mockListenerTwo);
inOrder.verify(mockListenerTwo).onServiceNameDiscovered(
matchServiceName(requestedInstance));
inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(requestedInstance));
matchServiceName(capitalizedRequestInstance));
inOrder.verify(mockListenerTwo).onServiceFound(
matchServiceName(capitalizedRequestInstance));
inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance));
inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance));
@@ -1149,8 +1152,7 @@ public class MdnsServiceTypeClientTests {
final String ipV4Address = "192.0.2.0";
final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
// Use different case in the options
.setResolveInstanceName("Instance1").build();
.setResolveInstanceName("instance1").build();
client.startSendAndReceive(mockListenerOne, resolveOptions);
client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());

View File

@@ -17,11 +17,14 @@
package com.android.server.connectivity.mdns.util
import android.os.Build
import com.android.server.connectivity.mdns.util.MdnsUtils.equalsDnsLabelIgnoreDnsCase
import com.android.server.connectivity.mdns.util.MdnsUtils.equalsIgnoreDnsCase
import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLabelsLowerCase
import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLowerCase
import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -49,6 +52,12 @@ class MdnsUtilsTest {
"\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<"))
}
@Test
fun testToDnsLabelsLowerCase() {
assertArrayEquals(arrayOf("test", "tÉst", "ţést"),
toDnsLabelsLowerCase(arrayOf("TeSt", "TÉST", "ţést")))
}
@Test
fun testEqualsIgnoreDnsCase() {
assertTrue(equalsIgnoreDnsCase("TEST", "Test"))
@@ -72,4 +81,25 @@ class MdnsUtilsTest {
assertEquals(truncateServiceName("测试abcde", 7), "测试a")
assertEquals(truncateServiceName("测试abcde", 100), "测试abcde")
}
@Test
fun testEqualsLabelIgnoreDnsCase() {
assertTrue(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test", "test")))
assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test")))
assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("Test"), arrayOf("test", "test")))
assertFalse(equalsDnsLabelIgnoreDnsCase(arrayOf("TEST", "Test"), arrayOf("test", "tést")))
}
@Test
fun testTypeEqualsOrIsSubtype() {
assertTrue(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_type", "_tcp", "local"),
arrayOf("_type", "_TCP", "local")))
assertTrue(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_type", "_tcp", "local"),
arrayOf("a", "_SUB", "_type", "_TCP", "local")))
assertFalse(MdnsUtils.typeEqualsOrIsSubtype(arrayOf("_sub", "_type", "_tcp", "local"),
arrayOf("_type", "_TCP", "local")))
assertFalse(MdnsUtils.typeEqualsOrIsSubtype(
arrayOf("a", "_other", "_type", "_tcp", "local"),
arrayOf("a", "_SUB", "_type", "_TCP", "local")))
}
}