1 /* <lambda>null2 * 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.server.net.integrationtests 18 19 import android.app.Service 20 import android.content.Intent 21 import androidx.annotation.GuardedBy 22 import com.android.testutils.quitExecutorServices 23 import com.android.testutils.quitThreads 24 import java.net.URL 25 import java.util.Collections 26 import java.util.concurrent.ConcurrentHashMap 27 import java.util.concurrent.ConcurrentLinkedQueue 28 import java.util.concurrent.ExecutorService 29 import kotlin.collections.ArrayList 30 import kotlin.test.fail 31 32 /** 33 * An instrumentation interface for the NetworkStack that allows controlling behavior to 34 * facilitate integration tests. 35 */ 36 class NetworkStackInstrumentationService : Service() { 37 override fun onBind(intent: Intent) = InstrumentationConnector.asBinder() 38 39 object InstrumentationConnector : INetworkStackInstrumentation.Stub() { 40 private val httpResponses = ConcurrentHashMap<String, ConcurrentLinkedQueue<HttpResponse>>() 41 .run { 42 withDefault { key -> getOrPut(key) { ConcurrentLinkedQueue() } } 43 } 44 private val httpRequestUrls = Collections.synchronizedList(mutableListOf<String>()) 45 46 @GuardedBy("networkMonitorThreads") 47 private val networkMonitorThreads = mutableListOf<Thread>() 48 @GuardedBy("networkMonitorExecutorServices") 49 private val networkMonitorExecutorServices = mutableListOf<ExecutorService>() 50 51 /** 52 * Called when an HTTP request is being processed by NetworkMonitor. Returns the response 53 * that should be simulated. 54 */ 55 fun processRequest(url: URL): HttpResponse { 56 val strUrl = url.toString() 57 httpRequestUrls.add(strUrl) 58 return httpResponses[strUrl]?.poll() 59 ?: fail("No mocked response for request: $strUrl. " + 60 "Mocked URL keys are: ${httpResponses.keys}") 61 } 62 63 /** 64 * Called when NetworkMonitor creates a new Thread. 65 */ 66 fun onNetworkMonitorThreadCreated(thread: Thread) { 67 synchronized(networkMonitorThreads) { 68 networkMonitorThreads.add(thread) 69 } 70 } 71 72 /** 73 * Called when NetworkMonitor creates a new ExecutorService. 74 */ 75 fun onNetworkMonitorExecutorServiceCreated(executorService: ExecutorService) { 76 synchronized(networkMonitorExecutorServices) { 77 networkMonitorExecutorServices.add(executorService) 78 } 79 } 80 81 /** 82 * Clear all state of this connector. This is intended for use between two tests, so all 83 * state should be reset as if the connector was just created. 84 */ 85 override fun clearAllState() { 86 quitThreads( 87 maxRetryCount = 3, 88 interrupt = true) { 89 synchronized(networkMonitorThreads) { 90 networkMonitorThreads.toList().also { networkMonitorThreads.clear() } 91 } 92 } 93 quitExecutorServices( 94 maxRetryCount = 3, 95 // NetworkMonitor is expected to have interrupted its executors when probing 96 // finishes, otherwise it's a thread pool leak that should be caught, so they should 97 // not need to be interrupted (the test only needs to wait for them to finish). 98 interrupt = false) { 99 synchronized(networkMonitorExecutorServices) { 100 networkMonitorExecutorServices.toList().also { 101 networkMonitorExecutorServices.clear() 102 } 103 } 104 } 105 httpResponses.clear() 106 httpRequestUrls.clear() 107 } 108 109 /** 110 * Add a response to a future HTTP request. 111 * 112 * <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be 113 * used to mock the query response. 114 * 115 * <p>All requests that are expected to be sent must have a mock response: if an unexpected 116 * request is seen, the test will fail. 117 */ 118 override fun addHttpResponse(response: HttpResponse) { 119 httpResponses.getValue(checkNotNull(response.requestUrl)).add(response) 120 } 121 122 /** 123 * Get the ordered list of request URLs that have been sent by NetworkMonitor, and were 124 * answered based on mock responses. 125 */ 126 override fun getRequestUrls(): List<String> { 127 return ArrayList(httpRequestUrls) 128 } 129 } 130 } 131