1 /* 2 * Copyright (C) 2021 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.pm.test.install 18 19 import com.android.server.pm.utils.RequestThrottle 20 import com.android.server.testutils.TestHandler 21 import com.google.common.collect.Range 22 import com.google.common.truth.LongSubject 23 import com.google.common.truth.Truth.assertThat 24 import org.junit.Before 25 import org.junit.Test 26 import java.util.concurrent.CountDownLatch 27 import java.util.concurrent.CyclicBarrier 28 import java.util.concurrent.TimeUnit 29 import java.util.concurrent.atomic.AtomicBoolean 30 import java.util.concurrent.atomic.AtomicInteger 31 import java.util.concurrent.atomic.AtomicLong 32 33 class RequestThrottleTest { 34 35 private val counter = AtomicInteger(0) 36 37 private val handler = TestHandler(null) 38 39 @Before resetValuesnull40 fun resetValues() { 41 handler.flush() 42 counter.set(0) 43 assertThat(counter.get()).isEqualTo(0) 44 } 45 46 @Test simpleThrottlenull47 fun simpleThrottle() { 48 val request = RequestThrottle(handler) { 49 counter.incrementAndGet() 50 true 51 } 52 53 fun sendRequests() { 54 request.schedule() 55 val thread = startThread { request.schedule() } 56 request.schedule() 57 thread.joinForTest() 58 } 59 60 sendRequests() 61 handler.flush() 62 assertThat(counter.get()).isEqualTo(1) 63 64 sendRequests() 65 handler.flush() 66 assertThat(counter.get()).isEqualTo(2) 67 } 68 69 @Test exceptionInRequestnull70 fun exceptionInRequest() { 71 val shouldThrow = AtomicBoolean(true) 72 val request = RequestThrottle(handler) { 73 if (shouldThrow.get()) { 74 throw RuntimeException() 75 } 76 counter.incrementAndGet() 77 true 78 } 79 80 fun sendRequests() { 81 request.schedule() 82 val thread = startThread { request.schedule() } 83 request.schedule() 84 thread.joinForTest() 85 } 86 87 sendRequests() 88 try { 89 handler.flush() 90 } catch (ignored: Exception) { 91 } 92 assertThat(counter.get()).isEqualTo(0) 93 94 shouldThrow.set(false) 95 96 sendRequests() 97 handler.flush() 98 assertThat(counter.get()).isEqualTo(1) 99 } 100 101 @Test scheduleWhileRunningnull102 fun scheduleWhileRunning() { 103 val latchForStartRequest = CountDownLatch(1) 104 val latchForEndRequest = CountDownLatch(1) 105 val request = RequestThrottle(handler) { 106 latchForStartRequest.countDown() 107 counter.incrementAndGet() 108 latchForEndRequest.awaitForTest() 109 true 110 } 111 112 // Schedule and block a request 113 request.schedule() 114 val handlerThread = startThread { handler.timeAdvance() } 115 latchForStartRequest.awaitForTest() 116 117 // Hit it with other requests 118 request.schedule() 119 (0..5).map { startThread { request.schedule() } } 120 .forEach { it.joinForTest() } 121 122 // Release everything 123 latchForEndRequest.countDown() 124 handlerThread.join() 125 handler.flush() 126 127 // Ensure another request was run after initial blocking request ends 128 assertThat(counter.get()).isEqualTo(2) 129 } 130 131 @Test backoffRetrynull132 fun backoffRetry() { 133 val time = AtomicLong(0) 134 val handler = TestHandler(null) { time.get() } 135 val returnValue = AtomicBoolean(false) 136 val request = RequestThrottle(handler, 3, 1000, 2) { 137 counter.incrementAndGet() 138 returnValue.get() 139 } 140 141 request.schedule() 142 143 handler.timeAdvance() 144 handler.pendingMessages.apply { 145 assertThat(size).isEqualTo(1) 146 assertThat(single().sendTime).isAround(1000) 147 } 148 149 time.set(1000) 150 handler.timeAdvance() 151 handler.pendingMessages.apply { 152 assertThat(size).isEqualTo(1) 153 assertThat(single().sendTime).isAround(3000) 154 } 155 156 time.set(3000) 157 handler.timeAdvance() 158 handler.pendingMessages.apply { 159 assertThat(size).isEqualTo(1) 160 assertThat(single().sendTime).isAround(7000) 161 } 162 163 returnValue.set(true) 164 time.set(7000) 165 handler.timeAdvance() 166 assertThat(handler.pendingMessages).isEmpty() 167 168 // Ensure another request was run after initial blocking request ends 169 assertThat(counter.get()).isEqualTo(4) 170 } 171 172 @Test forceWriteMultiplenull173 fun forceWriteMultiple() { 174 val request = RequestThrottle(handler) { 175 counter.incrementAndGet() 176 true 177 } 178 179 request.runNow() 180 request.runNow() 181 request.runNow() 182 183 assertThat(counter.get()).isEqualTo(3) 184 } 185 186 @Test forceWriteNowWithoutSyncnull187 fun forceWriteNowWithoutSync() { 188 // When forcing a write without synchronizing the request block, 2 instances will be run. 189 // There is no test for "with sync" because any logic to avoid multiple runs is left 190 // entirely up to the caller. 191 192 val barrierForEndRequest = CyclicBarrier(2) 193 val request = RequestThrottle(handler) { 194 counter.incrementAndGet() 195 barrierForEndRequest.awaitForTest() 196 true 197 } 198 199 // Schedule and block a request 200 request.schedule() 201 val thread = startThread { handler.timeAdvance() } 202 203 request.runNow() 204 205 thread.joinForTest() 206 207 assertThat(counter.get()).isEqualTo(2) 208 } 209 CountDownLatchnull210 private fun CountDownLatch.awaitForTest() = assertThat(await(5, TimeUnit.SECONDS)).isTrue() 211 private fun CyclicBarrier.awaitForTest() = await(5, TimeUnit.SECONDS) 212 private fun Thread.joinForTest() = join(5000) 213 214 private fun startThread(block: () -> Unit) = Thread { block() }.apply { start() } 215 216 // Float math means time calculations are not exact, so use a loose range LongSubjectnull217 private fun LongSubject.isAround(value: Long, threshold: Long = 10) = 218 isIn(Range.closed(value - threshold, value + threshold)) 219 } 220