Model delayed network callbacks and config workers in host tests
This commit is contained in:
1 parent
7b526ba681
commit
97a899c0c3
3 files changed
+64
-4
No files matched your search
@@ -1,10 +1,20 @@
|
||||
package android.net
|
||||
|
||||
class Network
|
||||
class LinkProperties
|
||||
|
||||
/** Только host-тест: listener принадлежит конкретному manager; старые callbacks тест может доставить после удаления. */
|
||||
class ConnectivityManager {
|
||||
open class NetworkCallback {
|
||||
open fun onAvailable(network: Network) {}
|
||||
open fun onLost(network: Network) {}
|
||||
open fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {}
|
||||
}
|
||||
fun interface OnNetworkActiveListener { fun onNetworkActive() }
|
||||
val listeners = mutableListOf<OnNetworkActiveListener>()
|
||||
val history = mutableListOf<OnNetworkActiveListener>()
|
||||
val callbacks = mutableListOf<NetworkCallback>()
|
||||
val callbackHistory = mutableListOf<NetworkCallback>()
|
||||
var addAttempts = 0
|
||||
var removeAttempts = 0
|
||||
var failAdd = false
|
||||
@@ -32,4 +42,16 @@ class ConnectivityManager {
|
||||
}
|
||||
|
||||
fun deliver(index: Int) { history[index].onNetworkActive() }
|
||||
|
||||
fun registerDefaultNetworkCallback(callback: NetworkCallback) {
|
||||
if (failAdd) throw SecurityException("network callback registration denied")
|
||||
check(callback !in callbacks)
|
||||
callbacks.add(callback)
|
||||
callbackHistory.add(callback)
|
||||
}
|
||||
|
||||
fun unregisterNetworkCallback(callback: NetworkCallback) {
|
||||
if (failRemove) throw IllegalStateException("network callback removal failed")
|
||||
check(callbacks.remove(callback)) { "callback belongs to another manager or was already removed" }
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,20 @@ import java.util.concurrent.ConcurrentLinkedQueue
|
||||
/** Host-модель SDK/главной очереди: callbacks и их доставку тест контролирует явно, без настоящего Android Looper. */
|
||||
object Build { object VERSION { var SDK_INT = 36 }; object VERSION_CODES { const val P = 28; const val S = 31 } }
|
||||
class Looper private constructor() {
|
||||
private val tasks = ConcurrentLinkedQueue<Runnable>()
|
||||
internal fun post(task: Runnable): Boolean { tasks.add(task); return true }
|
||||
private data class Task(val handler: Handler, val runnable: Runnable, val deadline: Long)
|
||||
private val tasks = ConcurrentLinkedQueue<Task>()
|
||||
@Volatile private var time = 0L
|
||||
internal fun post(handler: Handler, task: Runnable, delay: Long): Boolean {
|
||||
tasks.add(Task(handler, task, time + delay)); return true
|
||||
}
|
||||
internal fun remove(handler: Handler, task: Runnable) { tasks.removeIf { it.handler === handler && it.runnable === task } }
|
||||
fun advanceBy(milliseconds: Long) { check(milliseconds >= 0); time += milliseconds; dispatchAll() }
|
||||
fun dispatchAll() {
|
||||
check(myLooper() === this)
|
||||
while (true) (tasks.poll() ?: return).run()
|
||||
while (true) {
|
||||
val next = tasks.filter { it.deadline <= time }.minByOrNull { it.deadline } ?: return
|
||||
if (tasks.remove(next)) next.runnable.run()
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
private val main = Looper()
|
||||
@@ -18,5 +27,9 @@ class Looper private constructor() {
|
||||
fun myLooper(): Looper? = if (Thread.currentThread() === owner) main else null
|
||||
}
|
||||
}
|
||||
class Handler(val looper: Looper) { fun post(task: Runnable): Boolean = looper.post(task) }
|
||||
class Handler(val looper: Looper) {
|
||||
fun post(task: Runnable): Boolean = looper.post(this, task, 0)
|
||||
fun postDelayed(task: Runnable, delay: Long): Boolean = looper.post(this, task, delay)
|
||||
fun removeCallbacks(task: Runnable) = looper.remove(this, task)
|
||||
}
|
||||
object SystemClock { fun elapsedRealtime(): Long = System.nanoTime() / 1_000_000 }
|
||||
+25
@@ -26,5 +26,30 @@ object LogManager {
|
||||
/** Только host-тест: считает уведомления standby, не загружает JNI и не запускает ядро. */
|
||||
object NativeLib {
|
||||
val networkNotifications = AtomicInteger()
|
||||
var ready = true
|
||||
var acceptSocketUpdate = true
|
||||
val socketUpdates = mutableListOf<String>()
|
||||
fun notifyNetworkActive() { networkNotifications.incrementAndGet() }
|
||||
fun isReady(): Boolean = ready
|
||||
fun updateSockets(config: String): Boolean { socketUpdates.add(config); return acceptSocketUpdate }
|
||||
}
|
||||
|
||||
/** Управляемая подготовка конфига: тест удерживает реальный worker, считает перекрытия и затем дожидается его завершения. */
|
||||
class HostConfigProvider {
|
||||
val builds = AtomicInteger()
|
||||
val inBuild = AtomicInteger()
|
||||
val maximumConcurrentBuilds = AtomicInteger()
|
||||
private val workers: MutableSet<Thread> = Collections.synchronizedSet(mutableSetOf<Thread>())
|
||||
@Volatile var interfaces = listOf("wlan0" to "192.0.2.1")
|
||||
@Volatile var onBuild: (Int) -> String = { "config-$it" }
|
||||
|
||||
fun getAvailableInterfaces(): List<Pair<String, String>> { workers.add(Thread.currentThread()); return interfaces }
|
||||
fun buildConfigText(): String {
|
||||
maximumConcurrentBuilds.accumulateAndGet(inBuild.incrementAndGet(), ::maxOf)
|
||||
try { return onBuild(builds.incrementAndGet()) } finally { inBuild.decrementAndGet() }
|
||||
}
|
||||
fun joinWorkers() {
|
||||
val snapshot = synchronized(workers) { workers.toList() }
|
||||
snapshot.forEach { it.join(2_000); check(!it.isAlive) { "config worker did not finish" } }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user