blob: 825d74878e7406a0d89cd9ff48f1f656063b1639 [file] [log] [blame]
Chalard Jean48c6c7d2020-06-25 23:39:15 +09001/*
2 * Copyright (C) 2019 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
17package com.android.testutils
18
19import android.net.DnsResolver
20import android.net.InetAddresses
21import android.os.Looper
22import android.os.Handler
23import com.android.internal.annotations.GuardedBy
24import java.net.InetAddress
25import java.util.concurrent.Executor
26import org.mockito.invocation.InvocationOnMock
27import org.mockito.Mockito.any
28import org.mockito.Mockito.anyInt
29import org.mockito.Mockito.doAnswer
30
31const val TYPE_UNSPECIFIED = -1
32// TODO: Integrate with NetworkMonitorTest.
33class FakeDns(val mockResolver: DnsResolver) {
34 class DnsEntry(val hostname: String, val type: Int, val addresses: List<InetAddress>) {
35 fun match(host: String, type: Int) = hostname.equals(host) && type == type
36 }
37
38 @GuardedBy("answers")
39 val answers = ArrayList<DnsEntry>()
40
41 fun getAnswer(hostname: String, type: Int): DnsEntry? = synchronized(answers) {
42 return answers.firstOrNull { it.match(hostname, type) }
43 }
44
45 fun setAnswer(hostname: String, answer: Array<String>, type: Int) = synchronized(answers) {
46 val ans = DnsEntry(hostname, type, generateAnswer(answer))
47 // Replace or remove the existing one.
48 when (val index = answers.indexOfFirst { it.match(hostname, type) }) {
49 -1 -> answers.add(ans)
50 else -> answers[index] = ans
51 }
52 }
53
54 private fun generateAnswer(answer: Array<String>) =
55 answer.filterNotNull().map { InetAddresses.parseNumericAddress(it) }
56
57 fun startMocking() {
58 // Mock DnsResolver.query() w/o type
59 doAnswer {
60 mockAnswer(it, 1, -1, 3, 5)
61 }.`when`(mockResolver).query(any() /* network */, any() /* domain */, anyInt() /* flags */,
62 any() /* executor */, any() /* cancellationSignal */, any() /*callback*/)
63 // Mock DnsResolver.query() w/ type
64 doAnswer {
65 mockAnswer(it, 1, 2, 4, 6)
66 }.`when`(mockResolver).query(any() /* network */, any() /* domain */, anyInt() /* nsType */,
67 anyInt() /* flags */, any() /* executor */, any() /* cancellationSignal */,
68 any() /*callback*/)
69 }
70
71 private fun mockAnswer(
72 it: InvocationOnMock,
73 posHos: Int,
74 posType: Int,
75 posExecutor: Int,
76 posCallback: Int
77 ) {
78 val hostname = it.arguments[posHos] as String
79 val executor = it.arguments[posExecutor] as Executor
80 val callback = it.arguments[posCallback] as DnsResolver.Callback<List<InetAddress>>
81 var type = if (posType != -1) it.arguments[posType] as Int else TYPE_UNSPECIFIED
82 val answer = getAnswer(hostname, type)
83
84 if (!answer?.addresses.isNullOrEmpty()) {
85 Handler(Looper.getMainLooper()).post({ executor.execute({
86 callback.onAnswer(answer?.addresses, 0); }) })
87 }
88 }
89
90 /** Clears all entries. */
91 fun clearAll() = synchronized(answers) {
92 answers.clear()
93 }
94}