blob: b67ec05fe71689ddb47f38bf0b07500f4d888ca1 [file]
/*
* Copyright (C) 2024 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.net.apf
import android.net.apf.ApfCounterTracker.Counter
import android.net.apf.ApfCounterTracker.Counter.APF_PROGRAM_ID
import android.net.apf.ApfCounterTracker.Counter.APF_VERSION
import android.net.apf.ApfCounterTracker.Counter.TOTAL_PACKETS
import android.net.apf.ApfTestUtils.DROP
import android.net.apf.ApfTestUtils.PASS
import android.net.apf.ApfTestUtils.assertVerdict
import android.net.apf.BaseApfGenerator.APF_VERSION_6
import android.net.ip.IpClient
import com.android.net.module.util.HexDump
import kotlin.test.assertEquals
import org.mockito.ArgumentCaptor
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.timeout
import org.mockito.Mockito.verify
class ApfTestHelpers private constructor() {
companion object {
const val TIMEOUT_MS: Long = 1000
fun verifyProgramRun(
version: Int,
program: ByteArray,
pkt: ByteArray,
targetCnt: Counter,
cntMap: MutableMap<Counter, Long> = mutableMapOf(),
dataRegion: ByteArray = ByteArray(Counter.totalSize()) { 0 },
incTotal: Boolean = true,
result: Int = if (targetCnt.name.startsWith("PASSED")) PASS else DROP
) {
assertVerdict(version, result, program, pkt, dataRegion)
cntMap[targetCnt] = cntMap.getOrDefault(targetCnt, 0) + 1
if (incTotal) {
cntMap[TOTAL_PACKETS] = cntMap.getOrDefault(TOTAL_PACKETS, 0) + 1
}
val errMsg = "Counter is not increased properly. To debug: \n" +
" apf_run --program ${HexDump.toHexString(program)} " +
"--packet ${HexDump.toHexString(pkt)} " +
"--data ${HexDump.toHexString(dataRegion)} --age 0 " +
"${if (version == APF_VERSION_6) "--v6" else "" } --trace | less \n"
assertEquals(cntMap, decodeCountersIntoMap(dataRegion), errMsg)
}
fun decodeCountersIntoMap(counterBytes: ByteArray): Map<Counter, Long> {
val counters = Counter::class.java.enumConstants
val ret = HashMap<Counter, Long>()
val skippedCounters = setOf(APF_PROGRAM_ID, APF_VERSION)
// starting from index 2 to skip the endianness mark
if (counters != null) {
for (c in listOf(*counters).subList(2, counters.size)) {
if (c in skippedCounters) continue
val value = ApfCounterTracker.getCounterValue(counterBytes, c)
if (value != 0L) {
ret[c] = value
}
}
}
return ret
}
fun consumeInstalledProgram(
ipClientCb: IpClient.IpClientCallbacksWrapper,
installCnt: Int
): ByteArray {
val programCaptor = ArgumentCaptor.forClass(
ByteArray::class.java
)
verify(ipClientCb, timeout(TIMEOUT_MS).times(installCnt)).installPacketFilter(
programCaptor.capture()
)
clearInvocations<Any>(ipClientCb)
return programCaptor.value
}
}
}