mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-21 07:56:07 +08:00
Add property recoverable
to HeartbeatFailedException
, to control recoverability.
Fix `SelectorRecoveryTest`
This commit is contained in:
parent
8799d653e6
commit
b90f86258c
@ -10,11 +10,15 @@
|
||||
package net.mamoe.mirai.internal.network.impl.netty
|
||||
|
||||
import net.mamoe.mirai.internal.network.handler.selector.NetworkException
|
||||
import net.mamoe.mirai.utils.unwrap
|
||||
import net.mamoe.mirai.utils.unwrapCancellationException
|
||||
import java.io.IOException
|
||||
|
||||
internal class HeartbeatFailedException(
|
||||
private val name: String, // kind of HB
|
||||
override val cause: Throwable? = null,
|
||||
) : NetworkException(true) {
|
||||
override val cause: Throwable,
|
||||
recoverable: Boolean = cause.unwrapCancellationException() is IOException || cause is NetworkException && cause.recoverable,
|
||||
) : NetworkException(recoverable) {
|
||||
override val message: String = "Exception in $name job"
|
||||
override fun toString(): String = "HeartbeatFailedException: $name, cause=$cause"
|
||||
override fun toString(): String = "HeartbeatFailedException: $name, recoverable=$recoverable, cause=$cause"
|
||||
}
|
@ -146,6 +146,13 @@ internal sealed class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abstr
|
||||
assertEquals(state, network.state)
|
||||
}
|
||||
|
||||
fun assertState(vararg accepted: State) {
|
||||
val s = network.state
|
||||
if (s !in accepted) {
|
||||
throw AssertionError("Expected: ${accepted.joinToString()}, actual: $s")
|
||||
}
|
||||
}
|
||||
|
||||
fun NetworkHandler.assertState(state: State) {
|
||||
assertEquals(state, this.state)
|
||||
}
|
||||
|
@ -16,8 +16,10 @@ import net.mamoe.mirai.internal.network.components.HeartbeatFailureHandler
|
||||
import net.mamoe.mirai.internal.network.components.HeartbeatScheduler
|
||||
import net.mamoe.mirai.internal.network.framework.AbstractNettyNHTestWithSelector
|
||||
import net.mamoe.mirai.internal.network.impl.netty.HeartbeatFailedException
|
||||
import net.mamoe.mirai.internal.network.impl.netty.NettyChannelException
|
||||
import net.mamoe.mirai.internal.test.runBlockingUnit
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.io.IOException
|
||||
import kotlin.test.assertFails
|
||||
|
||||
internal class SelectorRecoveryTest : AbstractNettyNHTestWithSelector() {
|
||||
@ -33,16 +35,36 @@ internal class SelectorRecoveryTest : AbstractNettyNHTestWithSelector() {
|
||||
* @see HeartbeatFailedException
|
||||
*/
|
||||
@Test
|
||||
fun `can recover on heartbeat failure`() = runBlockingUnit {
|
||||
testRecover { HeartbeatFailedException("test", null) } // NetworkException
|
||||
fun `can recover on heartbeat failure with IOException`() = runBlockingUnit {
|
||||
// We allow IOException to cause a reconnect.
|
||||
testRecoverWhenHeartbeatFailWith { IOException("test IO ex") }
|
||||
|
||||
// BotOfflineMonitor immediately launches a recovery which is UNDISPATCHED, so connection is immediately recovered.
|
||||
assertState(NetworkHandler.State.CONNECTING, NetworkHandler.State.OK)
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulates system hibernation and network failure.
|
||||
* @see HeartbeatFailedException
|
||||
*/
|
||||
@Test
|
||||
fun `can recover on heartbeat failure with NettyChannelException`() = runBlockingUnit {
|
||||
// We allow IOException to cause a reconnect.
|
||||
testRecoverWhenHeartbeatFailWith { NettyChannelException("test IO ex") }
|
||||
|
||||
// BotOfflineMonitor immediately launches a recovery which is UNDISPATCHED, so connection is immediately recovered.
|
||||
assertState(NetworkHandler.State.CONNECTING, NetworkHandler.State.OK)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `cannot recover on other failures`() = runBlockingUnit {
|
||||
testRecover { IllegalStateException() }
|
||||
// ISE is considered as an internal error (bug).
|
||||
testRecoverWhenHeartbeatFailWith { IllegalStateException() }
|
||||
|
||||
assertState(NetworkHandler.State.CLOSED)
|
||||
}
|
||||
|
||||
private suspend fun testRecover(exception: () -> Exception) {
|
||||
private suspend fun testRecoverWhenHeartbeatFailWith(exception: () -> Exception) {
|
||||
val heartbeatScheduler = object : HeartbeatScheduler {
|
||||
lateinit var onHeartFailure: HeartbeatFailureHandler
|
||||
override fun launchJobsIn(
|
||||
@ -61,9 +83,5 @@ internal class SelectorRecoveryTest : AbstractNettyNHTestWithSelector() {
|
||||
assertState(NetworkHandler.State.OK)
|
||||
|
||||
heartbeatScheduler.onHeartFailure("Test", exception())
|
||||
assertState(NetworkHandler.State.CLOSED)
|
||||
|
||||
bot.network.resumeConnection() // in real, this is called by BotOnlineWatchdog in SelectorNetworkHandler
|
||||
assertState(NetworkHandler.State.OK)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user