From 062492c5464e3ebf505940296b610bd37a626406 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sun, 25 Apr 2021 13:58:13 +0800 Subject: [PATCH] Test: NettyEndlessReconnectionTest --- .../src/commonMain/kotlin/StandardUtils.kt | 4 ++ .../network/impl/netty/NettyNetworkHandler.kt | 13 ++++- .../netty/NettyEndlessReconnectionTest.kt | 55 +++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 mirai-core/src/commonTest/kotlin/network/impl/netty/NettyEndlessReconnectionTest.kt diff --git a/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt b/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt index cd73547b7..f99ba6ff6 100644 --- a/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt +++ b/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt @@ -169,6 +169,10 @@ public fun systemProp(name: String, default: Boolean): Boolean = System.getProperty(name, default.toString())?.toBoolean() ?: default +public fun systemProp(name: String, default: Long): Long = + System.getProperty(name, default.toString())?.toLongOrNull() ?: default + + public fun Throwable.getRootCause(maxDepth: Int = 20): Throwable { var depth = 0 var rootCause: Throwable? = this diff --git a/mirai-core/src/commonMain/kotlin/network/impl/netty/NettyNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/network/impl/netty/NettyNetworkHandler.kt index bef60b1ce..9c59d2b5e 100644 --- a/mirai-core/src/commonMain/kotlin/network/impl/netty/NettyNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/network/impl/netty/NettyNetworkHandler.kt @@ -32,6 +32,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.utils.ExceptionCollector import net.mamoe.mirai.utils.childScope import net.mamoe.mirai.utils.debug +import net.mamoe.mirai.utils.systemProp import java.net.SocketAddress import kotlin.coroutines.CoroutineContext import io.netty.channel.Channel as NettyChannel @@ -206,9 +207,7 @@ internal open class NettyNetworkHandler( wait: Boolean = false ) : NettyState(State.CONNECTING) { private val connection = async { - if (wait) { - delay(5000) - } + if (wait) delay(RECONNECT_DELAY) createConnection(decodePipeline) } @@ -346,4 +345,12 @@ internal open class NettyNetworkHandler( } override fun initialState(): BaseStateImpl = StateInitialized() + + companion object { + /** + * millis + */ + @JvmField + var RECONNECT_DELAY = systemProp("mirai.network.reconnect.delay", 5000) + } } diff --git a/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyEndlessReconnectionTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyEndlessReconnectionTest.kt new file mode 100644 index 000000000..31d9d6860 --- /dev/null +++ b/mirai-core/src/commonTest/kotlin/network/impl/netty/NettyEndlessReconnectionTest.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2019-2021 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.internal.network.impl.netty + +import io.netty.channel.Channel +import kotlinx.coroutines.delay +import net.mamoe.mirai.internal.network.handler.NetworkHandlerContext +import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory +import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport +import net.mamoe.mirai.internal.test.runBlockingUnit +import java.net.SocketAddress +import kotlin.reflect.jvm.javaGetter +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * When offline, handler will try endlessly to re-establish a connection. Exceptions are preserved as suppressed exceptions however, duplicates must be dropped to save memory. + */ +internal class NettyEndlessReconnectionTest : AbstractNettyNHTest() { + + override val factory: NetworkHandlerFactory = object : NetworkHandlerFactory { + override fun create(context: NetworkHandlerContext, address: SocketAddress): TestNettyNH { + return object : TestNettyNH(context, address) { + override suspend fun createConnection(decodePipeline: PacketDecodePipeline): Channel = + error("fail") + } + } + } + + @Test + fun `massive reconnection`() = runBlockingUnit { + val r = NettyNetworkHandler.Companion.RECONNECT_DELAY + NettyNetworkHandler.Companion.RECONNECT_DELAY = 0 + network.setStateConnecting() // will connect endlessly and create a massive amount of exceptions + delay(10000) // if exceptions are ignored by ExceptionCollector, memory usage will not exceed limitation. + + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + val state = network::_state.javaGetter!!.apply { isAccessible = true } + .invoke(network) as NetworkHandlerSupport.BaseStateImpl + + assertTrue { state.getCause()!!.suppressed.size <= 1 } // might be zero if just created since at this time network is still running. + // size <= 1 means duplicates are dropped. + + + network.close(null) + NettyNetworkHandler.Companion.RECONNECT_DELAY = r + } +} \ No newline at end of file