1 /* 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 17 package com.android.testutils 18 19 import android.net.DnsResolver 20 import android.net.InetAddresses 21 import android.os.Looper 22 import android.os.Handler 23 import com.android.internal.annotations.GuardedBy 24 import java.net.InetAddress 25 import java.util.concurrent.Executor 26 import org.mockito.invocation.InvocationOnMock 27 import org.mockito.Mockito.any 28 import org.mockito.Mockito.anyInt 29 import org.mockito.Mockito.doAnswer 30 31 const val TYPE_UNSPECIFIED = -1 32 // TODO: Integrate with NetworkMonitorTest. 33 class FakeDns(val mockResolver: DnsResolver) { 34 class DnsEntry(val hostname: String, val type: Int, val addresses: List<InetAddress>) { matchnull35 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 <lambda>null45 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 generateAnswernull54 private fun generateAnswer(answer: Array<String>) = 55 answer.filterNotNull().map { InetAddresses.parseNumericAddress(it) } 56 startMockingnull57 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 mockAnswernull71 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. */ <lambda>null91 fun clearAll() = synchronized(answers) { 92 answers.clear() 93 } 94 } 95