summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/unit/src/android/networkstack/util/DnsUtilsTest.kt92
-rw-r--r--tests/unit/src/android/networkstack/util/FakeDns.kt94
2 files changed, 186 insertions, 0 deletions
diff --git a/tests/unit/src/android/networkstack/util/DnsUtilsTest.kt b/tests/unit/src/android/networkstack/util/DnsUtilsTest.kt
new file mode 100644
index 0000000..815fc60
--- /dev/null
+++ b/tests/unit/src/android/networkstack/util/DnsUtilsTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 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 android.networkstack.util
+
+import android.net.DnsResolver
+import android.net.DnsResolver.FLAG_EMPTY
+import android.net.DnsResolver.TYPE_A
+import android.net.DnsResolver.TYPE_AAAA
+import android.net.Network
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.networkstack.util.DnsUtils
+import com.android.networkstack.util.DnsUtils.TYPE_ADDRCONFIG
+import com.android.server.connectivity.NetworkMonitor.DnsLogFunc
+import java.net.InetAddress
+import java.net.UnknownHostException
+import kotlin.test.assertFailsWith
+import org.junit.Assert.assertArrayEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+const val DEFAULT_TIMEOUT_MS = 1000
+const val SHORT_TIMEOUT_MS = 200
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class DnsUtilsTest {
+ val fakeNetwork: Network = Network(1234)
+ @Mock
+ lateinit var mockLogger: DnsLogFunc
+ @Mock
+ lateinit var mockResolver: DnsResolver
+ lateinit var fakeDns: FakeDns
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ fakeDns = FakeDns(mockResolver)
+ fakeDns.startMocking()
+ }
+
+ private fun assertIpAddressArrayEquals(expect: Array<String>, actual: Array<InetAddress>) =
+ assertArrayEquals("Array of IP addresses differs", expect,
+ actual.map { it.getHostAddress() }.toTypedArray())
+
+ @Test
+ fun testGetAllByNameWithTypeSuccess() {
+ // Test different query types.
+ verifyGetAllByName("www.google.com", arrayOf("2001:db8::1"), TYPE_AAAA)
+ verifyGetAllByName("www.google.com", arrayOf("192.168.0.1"), TYPE_A)
+ verifyGetAllByName("www.android.com", arrayOf("192.168.0.2", "2001:db8::2"),
+ TYPE_ADDRCONFIG)
+ }
+
+ private fun verifyGetAllByName(name: String, expected: Array<String>, type: Int) {
+ fakeDns.setAnswer(name, expected, type)
+ DnsUtils.getAllByName(mockResolver, fakeNetwork, name, type, FLAG_EMPTY, DEFAULT_TIMEOUT_MS,
+ mockLogger).let { assertIpAddressArrayEquals(expected, it) }
+ }
+
+ @Test
+ fun testGetAllByNameWithTypeNoResult() {
+ verifyGetAllByNameFails("www.android.com", TYPE_A)
+ verifyGetAllByNameFails("www.android.com", TYPE_AAAA)
+ verifyGetAllByNameFails("www.android.com", TYPE_ADDRCONFIG)
+ }
+
+ private fun verifyGetAllByNameFails(name: String, type: Int) {
+ assertFailsWith<UnknownHostException> {
+ DnsUtils.getAllByName(mockResolver, fakeNetwork, name, type,
+ FLAG_EMPTY, SHORT_TIMEOUT_MS, mockLogger)
+ }
+ }
+ // TODO: Add more tests. Verify timeout, logger and error.
+} \ No newline at end of file
diff --git a/tests/unit/src/android/networkstack/util/FakeDns.kt b/tests/unit/src/android/networkstack/util/FakeDns.kt
new file mode 100644
index 0000000..f0d44d0
--- /dev/null
+++ b/tests/unit/src/android/networkstack/util/FakeDns.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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 android.networkstack.util
+
+import android.net.DnsResolver
+import android.net.InetAddresses
+import android.os.Looper
+import android.os.Handler
+import com.android.internal.annotations.GuardedBy
+import com.android.networkstack.util.DnsUtils.TYPE_ADDRCONFIG
+import java.net.InetAddress
+import java.util.concurrent.Executor
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.doAnswer
+
+// TODO: Integrate with NetworkMonitorTest.
+class FakeDns(val mockResolver: DnsResolver) {
+ class DnsEntry(val hostname: String, val type: Int, val addresses: List<InetAddress>) {
+ fun match(host: String, type: Int) = hostname.equals(host) && type == type
+ }
+
+ @GuardedBy("answers")
+ val answers = ArrayList<DnsEntry>()
+
+ fun getAnswer(hostname: String, type: Int): DnsEntry? = synchronized(answers) {
+ return answers.firstOrNull { it.match(hostname, type) }
+ }
+
+ fun setAnswer(hostname: String, answer: Array<String>, type: Int) = synchronized(answers) {
+ val ans = DnsEntry(hostname, type, generateAnswer(answer))
+ // Replace or remove the existing one.
+ when (val index = answers.indexOfFirst { it.match(hostname, type) }) {
+ -1 -> answers.add(ans)
+ else -> answers[index] = ans
+ }
+ }
+
+ private fun generateAnswer(answer: Array<String>) =
+ answer.filterNotNull().map { InetAddresses.parseNumericAddress(it) }
+
+ fun startMocking() {
+ // Mock DnsResolver.query() w/o type
+ doAnswer {
+ mockAnswer(it, 1, -1, 3, 5)
+ }.`when`(mockResolver).query(any() /* network */, any() /* domain */, anyInt() /* flags */,
+ any() /* executor */, any() /* cancellationSignal */, any() /*callback*/)
+ // Mock DnsResolver.query() w/ type
+ doAnswer {
+ mockAnswer(it, 1, 2, 4, 6)
+ }.`when`(mockResolver).query(any() /* network */, any() /* domain */, anyInt() /* nsType */,
+ anyInt() /* flags */, any() /* executor */, any() /* cancellationSignal */,
+ any() /*callback*/)
+ }
+
+ private fun mockAnswer(
+ it: InvocationOnMock,
+ posHos: Int,
+ posType: Int,
+ posExecutor: Int,
+ posCallback: Int
+ ) {
+ val hostname = it.arguments[posHos] as String
+ val executor = it.arguments[posExecutor] as Executor
+ val callback = it.arguments[posCallback] as DnsResolver.Callback<List<InetAddress>>
+ var type = if (posType != -1) it.arguments[posType] as Int else TYPE_ADDRCONFIG
+ val answer = getAnswer(hostname, type)
+
+ if (!answer?.addresses.isNullOrEmpty()) {
+ Handler(Looper.getMainLooper()).post({ executor.execute({
+ callback.onAnswer(answer?.addresses, 0); }) })
+ }
+ }
+
+ /** Clears all entries. */
+ fun clearAll() = synchronized(answers) {
+ answers.clear()
+ }
+} \ No newline at end of file