bump kutil (1.21), make timing testing even more robust, fix tests

This commit is contained in:
Bixilon 2023-03-20 09:04:53 +01:00
parent b4ef596dc6
commit f670908a4d
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
16 changed files with 106 additions and 61 deletions

View File

@ -59,7 +59,7 @@ repositories {
buildscript {
dependencies {
classpath("de.bixilon", "kutil", "1.20.1")
classpath("de.bixilon", "kutil", "1.21")
}
}

View File

@ -17,4 +17,4 @@ lwjgl.version=3.3.2-SNAPSHOT
ikonli.version=12.3.1
netty.version=4.1.90.Final
jackson.version=2.14.2
kutil.version=1.20.1
kutil.version=1.21

View File

@ -0,0 +1,50 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.input.interaction
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.concurrent.schedule.RepeatedTask
import de.bixilon.kutil.time.TimeUtil.millis
import org.testng.SkipException
object KeyHandlerUtil {
private val FIELD = KeyHandler::class.java.getDeclaredField("task")
init {
FIELD.isAccessible = true
}
private fun KeyHandler.getTask(): RepeatedTask {
return FIELD.get(this).unsafeCast() ?: throw IllegalStateException("Not pressed!")
}
fun KeyHandler.awaitTicks(count: Int) {
val start = millis()
val task = getTask()
val executions = task.executions
while (true) {
val time = millis()
if (time - start > (count + 1) * 50 - 1) throw SkipException("busy") // wait max one tick longer
if (time - start < count * 50) {
Thread.sleep(10)
continue
}
if (task.executions - executions == count) break
if (task.executions - executions > count) throw IllegalStateException("Ran too often!")
Thread.sleep(10)
}
}
}

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.input.interaction.breaking
import de.bixilon.minosoft.data.physics.PhysicsTestUtil.createPlayer
import de.bixilon.minosoft.data.registries.blocks.types.stone.RockBlock
import de.bixilon.minosoft.input.interaction.KeyHandlerUtil.awaitTicks
import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil.createConnection
import de.bixilon.minosoft.protocol.network.connection.play.PacketTestUtil.assertNoPacket
import de.bixilon.minosoft.protocol.network.connection.play.PacketTestUtil.assertPacket
@ -53,7 +54,7 @@ class BreakHandlerInputTest {
connection.assertPacket(SwingArmC2SP::class.java)
handler.release() // key not down anymore
connection.assertPacket(PlayerActionC2SP::class.java)
if (measureTimeMillis { Thread.sleep(55) } > 60) throw SkipException("system busy")
Thread.sleep(100)
connection.assertNoPacket()
}
@ -73,10 +74,10 @@ class BreakHandlerInputTest {
if (measureTimeMillis { Thread.sleep(20) } > 30) throw SkipException("system busy")
connection.assertNoPacket()
if (measureTimeMillis { Thread.sleep(35) } > 45) throw SkipException("system busy")
handler.awaitTicks(1)
connection.assertPacket(SwingArmC2SP::class.java)
connection.assertNoPacket()
if (measureTimeMillis { Thread.sleep(50) } > 55) throw SkipException("system busy")
handler.awaitTicks(1)
connection.assertPacket(SwingArmC2SP::class.java)
connection.assertNoPacket()
handler.release()

View File

@ -18,6 +18,7 @@ import de.bixilon.minosoft.data.container.stack.ItemStack
import de.bixilon.minosoft.data.physics.PhysicsTestUtil
import de.bixilon.minosoft.data.registries.item.items.weapon.defend.ShieldItem
import de.bixilon.minosoft.data.registries.items.EggTest0
import de.bixilon.minosoft.input.interaction.KeyHandlerUtil.awaitTicks
import de.bixilon.minosoft.protocol.network.connection.play.ConnectionTestUtil
import de.bixilon.minosoft.protocol.network.connection.play.PacketTestUtil.assertNoPacket
import de.bixilon.minosoft.protocol.network.connection.play.PacketTestUtil.assertPacket
@ -25,9 +26,7 @@ import de.bixilon.minosoft.protocol.packets.c2s.play.PlayerActionC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.item.UseItemC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.move.PositionRotationC2SP
import de.bixilon.minosoft.protocol.packets.c2s.play.move.SwingArmC2SP
import org.testng.SkipException
import org.testng.annotations.Test
import kotlin.system.measureTimeMillis
@Test(groups = ["interaction"], dependsOnGroups = ["item"])
class UseHandlerInputTest {
@ -57,7 +56,7 @@ class UseHandlerInputTest {
connection.assertPacket(UseItemC2SP::class.java)
connection.assertPacket(SwingArmC2SP::class.java)
connection.assertNoPacket()
if (measureTimeMillis { Thread.sleep(4 * 50 + 20) } !in (205..235)) throw SkipException("busy")
handler.awaitTicks(4)
connection.assertPacket(PositionRotationC2SP::class.java)
connection.assertPacket(UseItemC2SP::class.java)
connection.assertPacket(SwingArmC2SP::class.java)
@ -74,7 +73,7 @@ class UseHandlerInputTest {
handler.press()
connection.assertPacket(PositionRotationC2SP::class.java)
connection.assertPacket(UseItemC2SP::class.java)
if (measureTimeMillis { Thread.sleep(55) } > 80) throw SkipException("busy")
handler.awaitTicks(1)
connection.assertNoPacket()
handler.release()
connection.assertPacket(PlayerActionC2SP::class.java)

View File

@ -18,8 +18,8 @@ import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.collections.CollectionUtil.lockMapOf
import de.bixilon.kutil.collections.map.LockMap
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.kutil.concurrent.time.TimeWorker
import de.bixilon.kutil.concurrent.time.TimeWorkerTask
import de.bixilon.kutil.concurrent.schedule.RepeatedTask
import de.bixilon.kutil.concurrent.schedule.TaskScheduler
import de.bixilon.kutil.file.FileUtil
import de.bixilon.kutil.file.FileUtil.read
import de.bixilon.kutil.latch.CountUpAndDownLatch
@ -135,7 +135,7 @@ object GlobalProfileManager {
if (selectedProfilesChanges) {
saveSelectedProfiles()
}
TimeWorker += TimeWorkerTask(1000) {
TaskScheduler += RepeatedTask(1000) {
for (manager in DEFAULT_MANAGERS.values) {
for (profile in manager.profiles.values) {
if (profile.saved) {

View File

@ -14,7 +14,7 @@
package de.bixilon.minosoft.data.entities.entities.player.local
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
import de.bixilon.kutil.concurrent.time.TimeWorker
import de.bixilon.kutil.concurrent.schedule.TaskScheduler.runLater
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.data.accounts.Account
@ -45,7 +45,7 @@ class SignatureKeyManagement(
}
private fun registerRefresh(millis: Int) {
TimeWorker.runLater(millis) {
runLater(millis) {
if (connection.error != null || (connection.wasConnected && !connection.network.connected) || (connection.network.connected && !connection.network.encrypted)) {
// connection is dead
return@runLater

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.language.placeholder
import de.bixilon.kutil.array.ArrayUtil.isIndex
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.EmptyComponent
import de.bixilon.minosoft.data.text.TextComponent
@ -43,7 +44,7 @@ object PlaceholderUtil {
}
private fun PlaceholderIteratorOptions.appendArgument(index: Int) {
val value = if (index >= 0 && index < data.size) data[index] else "<null>" // TODO (kutil 1.21): replace with ArrayUtil::isIndex
val value = if (data.isIndex(index)) data[index] else "<null>"
component += ChatComponent.of(value, parent = previous ?: parent, restricted = restricted)
}

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.data.world.container
import de.bixilon.kotlinglm.vec3.Vec3i
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.kutil.collections.EmptyIterator
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
import de.bixilon.minosoft.data.world.chunk.ChunkSection
import de.bixilon.minosoft.gui.rendering.util.vec.vec3.Vec3iUtil.EMPTY
@ -55,13 +56,11 @@ open class SectionDataProvider<T>(
return get(ChunkSection.getIndex(x, y, z))
}
@Suppress("UNCHECKED_CAST")
@Deprecated("no locking", ReplaceWith("this[index]"))
fun unsafeGet(index: Int): T {
return this[index]
}
@Suppress("UNCHECKED_CAST")
@Deprecated("no locking", ReplaceWith("this[x, y, z]"))
fun unsafeGet(x: Int, y: Int, z: Int): T {
return this[x, y, z]
@ -227,11 +226,6 @@ open class SectionDataProvider<T>(
@Suppress("UNCHECKED_CAST")
override fun iterator(): Iterator<T> {
return (data?.iterator() ?: EMPTY_ITERATOR) as Iterator<T>
}
companion object {
private val EMPTY_ITERATOR = emptyArray<Any>().iterator() // TODO: kutil 1.20.2
return (data?.iterator() ?: EmptyIterator) as Iterator<T>
}
}

View File

@ -15,8 +15,8 @@ package de.bixilon.minosoft.gui.rendering.particle
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
import de.bixilon.kutil.concurrent.time.TimeWorker
import de.bixilon.kutil.concurrent.time.TimeWorkerTask
import de.bixilon.kutil.concurrent.schedule.RepeatedTask
import de.bixilon.kutil.concurrent.schedule.TaskScheduler
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.kutil.time.TimeUtil.millis
@ -60,7 +60,7 @@ class ParticleRenderer(
private var matrixUpdate = true
private lateinit var particleTask: TimeWorkerTask
private lateinit var particleTask: RepeatedTask
override val skipAll: Boolean
get() = !enabled
@ -124,9 +124,9 @@ class ParticleRenderer(
connection.world.particleRenderer = this
particleTask = TimeWorkerTask(ProtocolDefinition.TICK_TIME, maxDelayTime = ProtocolDefinition.TICK_TIME / 2) {
particleTask = RepeatedTask(ProtocolDefinition.TICK_TIME, maxDelay = ProtocolDefinition.TICK_TIME / 2) {
if (!context.state.running || !enabled || connection.state != PlayConnectionStates.PLAYING) {
return@TimeWorkerTask
return@RepeatedTask
}
val cameraPosition = connection.player.physics.positionInfo.chunkPosition
val particleViewDistance = connection.world.view.particleViewDistance
@ -155,13 +155,13 @@ class ParticleRenderer(
particlesLock.unlock()
}
}
TimeWorker += particleTask
TaskScheduler += particleTask
connection::state.observe(this) {
if (!it.disconnected) {
return@observe
}
TimeWorker.removeTask(particleTask)
TaskScheduler -= particleTask
}
}

View File

@ -14,22 +14,20 @@
package de.bixilon.minosoft.input.interaction
import de.bixilon.kutil.concurrent.pool.ThreadPool
import de.bixilon.kutil.concurrent.time.TimeWorker
import de.bixilon.kutil.concurrent.time.TimeWorkerTask
import de.bixilon.kutil.concurrent.schedule.RepeatedTask
import de.bixilon.kutil.concurrent.schedule.TaskScheduler
import de.bixilon.kutil.exception.Broken
import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
abstract class KeyHandler {
private var task: TimeWorkerTask? = null
private var task: RepeatedTask? = null
var isPressed: Boolean = false
private set
private fun queueTick() {
val task = TimeWorkerTask(ProtocolDefinition.TICK_TIME, maxDelayTime = ProtocolDefinition.TICK_TIME, runOnce = false, executionPriority = ThreadPool.HIGH) { onTick() }
task.lastExecution = millis() // TODO: remove this workaround, kutil 1.21
val task = RepeatedTask(ProtocolDefinition.TICK_TIME, maxDelay = ProtocolDefinition.TICK_TIME, priority = ThreadPool.HIGH) { onTick() }
this.task = task
TimeWorker += task
TaskScheduler += task
}
fun press() {
@ -42,7 +40,7 @@ abstract class KeyHandler {
fun release() {
if (!isPressed) return
val task = this.task ?: Broken()
TimeWorker -= task
TaskScheduler -= task
this.task = null
this.isPressed = false
this.onRelease()

View File

@ -14,9 +14,9 @@
package de.bixilon.minosoft.protocol.network.connection.play.tick
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
import de.bixilon.kutil.concurrent.time.TimeWorker
import de.bixilon.kutil.concurrent.time.TimeWorker.runLater
import de.bixilon.kutil.concurrent.time.TimeWorkerTask
import de.bixilon.kutil.concurrent.schedule.RepeatedTask
import de.bixilon.kutil.concurrent.schedule.TaskScheduler
import de.bixilon.kutil.concurrent.schedule.TaskScheduler.runLater
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.minosoft.config.DebugOptions
import de.bixilon.minosoft.data.container.stack.ItemStack
@ -26,7 +26,7 @@ import de.bixilon.minosoft.protocol.network.connection.play.PlayConnectionStates
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
class ConnectionTicker(private val connection: PlayConnection) {
private val tasks: MutableSet<TimeWorkerTask> = mutableSetOf()
private val tasks: MutableSet<RepeatedTask> = mutableSetOf()
private val lock = SimpleLock()
private var registered = false
@ -53,21 +53,21 @@ class ConnectionTicker(private val connection: PlayConnection) {
lock.unlock()
return
}
tasks += TimeWorkerTask(INTERVAL, maxDelayTime = MAX_DELAY) {
tasks += RepeatedTask(INTERVAL, maxDelay = MAX_DELAY) {
connection.world.entities.tick()
}
tasks += TimeWorkerTask(INTERVAL, maxDelayTime = MAX_DELAY) {
tasks += RepeatedTask(INTERVAL, maxDelay = MAX_DELAY) {
connection.world.tick()
}
tasks += TimeWorkerTask(INTERVAL, maxDelayTime = MAX_DELAY) {
tasks += RepeatedTask(INTERVAL, maxDelay = MAX_DELAY) {
connection.world.randomTick()
}
if (DebugOptions.LIGHT_DEBUG_MODE || DebugOptions.INFINITE_TORCHES) {
tasks += TimeWorkerTask(INTERVAL, maxDelayTime = MAX_DELAY) { connection.player.items.inventory[44] = ItemStack(connection.registries.item["minecraft:torch"]!!, Int.MAX_VALUE) }
tasks += RepeatedTask(INTERVAL, maxDelay = MAX_DELAY) { connection.player.items.inventory[44] = ItemStack(connection.registries.item["minecraft:torch"]!!, Int.MAX_VALUE) }
}
if (DebugOptions.SIMULATE_TIME) {
tasks += TimeWorkerTask(INTERVAL, maxDelayTime = MAX_DELAY) {
tasks += RepeatedTask(INTERVAL, maxDelay = MAX_DELAY) {
val time = connection.world.time.time
val offset = if (time in 11800..13300 || (time < 300 || time > 22800)) {
20
@ -79,7 +79,7 @@ class ConnectionTicker(private val connection: PlayConnection) {
}
for (task in tasks) {
TimeWorker += task
TaskScheduler += task
}
registered = true
lock.unlock()
@ -92,7 +92,7 @@ class ConnectionTicker(private val connection: PlayConnection) {
lock.lock()
for (task in tasks) {
TimeWorker -= task
TaskScheduler -= task
}
tasks.clear()
registered = false

View File

@ -13,8 +13,9 @@
package de.bixilon.minosoft.protocol.network.connection.status
import de.bixilon.kutil.concurrent.time.TimeWorker
import de.bixilon.kutil.concurrent.time.TimeWorkerTask
import de.bixilon.kutil.concurrent.schedule.QueuedTask
import de.bixilon.kutil.concurrent.schedule.TaskScheduler
import de.bixilon.kutil.concurrent.schedule.TaskScheduler.runLater
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.kutil.observer.DataObserver.Companion.observed
import de.bixilon.minosoft.modding.event.events.connection.status.StatusConnectionCreateEvent
@ -51,7 +52,7 @@ class StatusConnection(
var state by observed(StatusConnectionStates.WAITING)
private var timeoutTask: TimeWorkerTask? = null
private var timeoutTask: QueuedTask? = null
init {
@ -89,7 +90,7 @@ class StatusConnection(
if (it == StatusConnectionStates.PING_DONE || it == StatusConnectionStates.ERROR) {
val timeoutTask = timeoutTask ?: return@observe
timeoutTask.interrupt()
TimeWorker -= timeoutTask
TaskScheduler -= timeoutTask
this.timeoutTask = null
}
}
@ -137,7 +138,7 @@ class StatusConnection(
error("Already connecting!")
}
// timeout task
timeoutTask = TimeWorker.runLater(30000) {
timeoutTask = runLater(30000) {
if (state == StatusConnectionStates.ERROR) {
return@runLater
}

View File

@ -26,7 +26,7 @@ import de.bixilon.kutil.collections.CollectionUtil.synchronizedMapOf
import de.bixilon.kutil.collections.CollectionUtil.synchronizedSetOf
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedSet
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.kutil.concurrent.time.TimeWorker
import de.bixilon.kutil.concurrent.schedule.TaskScheduler
import de.bixilon.kutil.primitive.BooleanUtil.decide
import de.bixilon.kutil.primitive.DoubleUtil
import de.bixilon.kutil.primitive.DoubleUtil.matches
@ -270,7 +270,7 @@ object KUtil {
DefaultThreadPool += { Jackson::class.java.forceInit() }
DefaultThreadPool += { URLProtocolStreamHandlers::class.java.forceInit() }
DefaultThreadPool += { MicrosoftOAuthUtils::class.java.forceInit() }
DefaultThreadPool += { TimeWorker::class.java.forceInit() }
DefaultThreadPool += { TaskScheduler::class.java.forceInit() }
DefaultThreadPool += { SystemInformation::class.java.forceInit() }
DefaultThreadPool += { StatusConnection::class.java.forceInit() }
DefaultThreadPool += { PlayConnection::class.java.forceInit() }

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@ -14,9 +14,10 @@
package de.bixilon.minosoft.util.account.microsoft
import de.bixilon.kutil.concurrent.pool.DefaultThreadPool
import de.bixilon.kutil.concurrent.time.TimeWorker.runLater
import de.bixilon.kutil.concurrent.schedule.TaskScheduler.runLater
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.kutil.time.TimeUtil
import de.bixilon.kutil.time.TimeUtil.millis
import de.bixilon.minosoft.data.accounts.AccountStates
import de.bixilon.minosoft.data.accounts.types.microsoft.MicrosoftAccount
import de.bixilon.minosoft.data.accounts.types.microsoft.MicrosoftTokens
@ -57,12 +58,12 @@ object MicrosoftOAuthUtils {
val deviceCode = obtainDeviceCode()
Log.log(LogMessageType.AUTHENTICATION, LogLevels.INFO) { "Obtained device code: ${deviceCode.userCode}" }
deviceCodeCallback(deviceCode)
val start = TimeUtil.millis / 1000
val start = millis() / 1000
fun checkToken() {
try {
val response = checkDeviceCode(deviceCode)
val time = TimeUtil.millis / 1000
val time = millis() / 1000
if (time > start + MAX_CHECK_TIME || time > deviceCode.expires) {
throw TimeoutException("Could not obtain access for device code: ${deviceCode.userCode}")
}

View File

@ -84,7 +84,7 @@ internal class ColorParserTest {
fun darkSuggestion() {
val reader = CommandReader("dark")
val parser = ColorParser()
assertEquals(parser.getSuggestions(reader), listOf(
assertEquals(parser.getSuggestions(reader).toSet(), setOf(
Suggestion(0, "dark_blue", TextComponent("dark_blue").color(ChatColors.DARK_BLUE)),
Suggestion(0, "dark_green", TextComponent("dark_green").color(ChatColors.DARK_GREEN)),
Suggestion(0, "dark_aqua", TextComponent("dark_aqua").color(ChatColors.DARK_AQUA)),