1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.net.apf 17 18 import android.net.apf.ApfMdnsUtils.extractOffloadReplyRule 19 import android.net.nsd.OffloadEngine 20 import android.net.nsd.OffloadServiceInfo 21 import android.net.nsd.OffloadServiceInfo.Key 22 import android.os.Build 23 import androidx.test.filters.SmallTest 24 import com.android.net.module.util.NetworkStackConstants.TYPE_A 25 import com.android.net.module.util.NetworkStackConstants.TYPE_AAAA 26 import com.android.net.module.util.NetworkStackConstants.TYPE_PTR 27 import com.android.net.module.util.NetworkStackConstants.TYPE_SRV 28 import com.android.net.module.util.NetworkStackConstants.TYPE_TXT 29 import com.android.testutils.DevSdkIgnoreRule 30 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo 31 import com.android.testutils.DevSdkIgnoreRunner 32 import java.io.IOException 33 import kotlin.test.assertContentEquals 34 import kotlin.test.assertFailsWith 35 import org.junit.Rule 36 import org.junit.Test 37 import org.junit.runner.RunWith 38 39 /** 40 * Tests for Apf mDNS utility functions. 41 */ 42 @RunWith(DevSdkIgnoreRunner::class) 43 @SmallTest 44 @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 45 class ApfMdnsUtilsTest { 46 @get:Rule 47 val ignoreRule = DevSdkIgnoreRule() 48 49 private val testServiceName1 = "NsdChat" 50 private val testServiceName2 = "NsdCall" 51 private val testServiceType = "_http._tcp" 52 private val testSubType = "tsub" 53 private val testHostName = "Android.local" 54 private val testRawPacket1 = byteArrayOf(1, 2, 3, 4, 5) 55 private val testRawPacket2 = byteArrayOf(6, 7, 8, 9) 56 private val encodedFullServiceName1 = intArrayOf( 57 7, 'N'.code, 'S'.code, 'D'.code, 'C'.code, 'H'.code, 'A'.code, 'T'.code, 58 5, '_'.code, 'H'.code, 'T'.code, 'T'.code, 'P'.code, 59 4, '_'.code, 'T'.code, 'C'.code, 'P'.code, 60 5, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code, <lambda>null61 0, 0).map { it.toByte() }.toByteArray() 62 private val encodedFullServiceName2 = intArrayOf( 63 7, 'N'.code, 'S'.code, 'D'.code, 'C'.code, 'A'.code, 'L'.code, 'L'.code, 64 5, '_'.code, 'H'.code, 'T'.code, 'T'.code, 'P'.code, 65 4, '_'.code, 'T'.code, 'C'.code, 'P'.code, 66 5, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code, <lambda>null67 0, 0).map { it.toByte() }.toByteArray() 68 private val encodedServiceType = intArrayOf( 69 5, '_'.code, 'H'.code, 'T'.code, 'T'.code, 'P'.code, 70 4, '_'.code, 'T'.code, 'C'.code, 'P'.code, 71 5, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code, <lambda>null72 0, 0).map { it.toByte() }.toByteArray() 73 private val encodedServiceTypeWithSub1 = intArrayOf( 74 4, 'T'.code, 'S'.code, 'U'.code, 'B'.code, 75 4, '_'.code, 'S'.code, 'U'.code, 'B'.code, 76 5, '_'.code, 'H'.code, 'T'.code, 'T'.code, 'P'.code, 77 4, '_'.code, 'T'.code, 'C'.code, 'P'.code, 78 5, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code, <lambda>null79 0, 0).map { it.toByte() }.toByteArray() 80 private val encodedServiceTypeWithWildCard = intArrayOf( 81 0xff, 82 4, '_'.code, 'S'.code, 'U'.code, 'B'.code, 83 5, '_'.code, 'H'.code, 'T'.code, 'T'.code, 'P'.code, 84 4, '_'.code, 'T'.code, 'C'.code, 'P'.code, 85 5, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code, <lambda>null86 0, 0).map { it.toByte() }.toByteArray() 87 private val encodedTestHostName = intArrayOf( 88 7, 'A'.code, 'N'.code, 'D'.code, 'R'.code, 'O'.code, 'I'.code, 'D'.code, 89 5, 'L'.code, 'O'.code, 'C'.code, 'A'.code, 'L'.code, <lambda>null90 0, 0).map { it.toByte() }.toByteArray() 91 92 @Test testExtractOffloadReplyRule_extractRulesnull93 fun testExtractOffloadReplyRule_extractRules() { 94 val info1 = createOffloadServiceInfo(10) 95 val info2 = createOffloadServiceInfo( 96 Integer.MAX_VALUE, 97 testServiceName2, 98 listOf("a", "b", "c", "d"), 99 testRawPacket2 100 ) 101 val rules = extractOffloadReplyRule(listOf(info2, info1)) 102 val expectedResult = listOf( 103 MdnsOffloadRule( 104 "${info1.key.serviceName}.${info1.key.serviceType}", 105 listOf( 106 MdnsOffloadRule.Matcher(encodedServiceType, intArrayOf(TYPE_PTR)), 107 MdnsOffloadRule.Matcher( 108 encodedServiceTypeWithSub1, 109 intArrayOf(TYPE_PTR) 110 ), 111 MdnsOffloadRule.Matcher( 112 encodedFullServiceName1, 113 intArrayOf(TYPE_SRV, TYPE_TXT) 114 ), 115 MdnsOffloadRule.Matcher( 116 encodedTestHostName, 117 intArrayOf(TYPE_A, TYPE_AAAA) 118 ), 119 120 ), 121 testRawPacket1, 122 ), 123 MdnsOffloadRule( 124 "${info2.key.serviceName}.${info2.key.serviceType}", 125 listOf( 126 MdnsOffloadRule.Matcher( 127 encodedServiceTypeWithWildCard, 128 intArrayOf(TYPE_PTR) 129 ), 130 MdnsOffloadRule.Matcher( 131 encodedFullServiceName2, 132 intArrayOf(TYPE_SRV, TYPE_TXT) 133 ), 134 135 ), 136 null, 137 ) 138 ) 139 assertContentEquals(expectedResult, rules) 140 } 141 142 @Test testExtractOffloadReplyRule_longLabelThrowsExceptionnull143 fun testExtractOffloadReplyRule_longLabelThrowsException() { 144 val info = createOffloadServiceInfo(10, "a".repeat(256)) 145 assertFailsWith<IOException> { extractOffloadReplyRule(listOf(info)) } 146 } 147 createOffloadServiceInfonull148 private fun createOffloadServiceInfo( 149 priority: Int, 150 serviceName: String = testServiceName1, 151 subTypes: List<String> = listOf(testSubType), 152 rawPacket1: ByteArray = testRawPacket1 153 ): OffloadServiceInfo = OffloadServiceInfo( 154 Key(serviceName, testServiceType), 155 subTypes, 156 testHostName, 157 rawPacket1, 158 priority, 159 OffloadEngine.OFFLOAD_TYPE_REPLY.toLong() 160 ) 161 } 162