Redesign ComponentStorage initialization for clearer tests

This commit is contained in:
Him188 2021-06-08 17:13:15 +08:00
parent f9da72c136
commit 300882ea18
8 changed files with 66 additions and 56 deletions

View File

@ -20,6 +20,7 @@ import net.mamoe.mirai.event.events.BotOnlineEvent
import net.mamoe.mirai.event.events.BotReloginEvent
import net.mamoe.mirai.internal.contact.checkIsGroupImpl
import net.mamoe.mirai.internal.network.component.ComponentStorage
import net.mamoe.mirai.internal.network.component.ComponentStorageDelegate
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
import net.mamoe.mirai.internal.network.components.*
import net.mamoe.mirai.internal.network.context.SsoProcessorContext
@ -109,13 +110,15 @@ internal open class QQAndroidBot constructor(
private val networkLogger: MiraiLogger by lazy { configuration.networkLoggerSupplier(this) }
override val components: ComponentStorage by lazy {
createDefaultComponents()
final override val components: ComponentStorage by lazy {
createDefaultComponents().apply {
set(StateObserver, stateObserverChain())
}
}
fun createDefaultComponents(): ConcurrentComponentStorage {
open fun createDefaultComponents(): ConcurrentComponentStorage {
return ConcurrentComponentStorage().apply {
val components = this // avoid mistakes
val components = ComponentStorageDelegate { this@QQAndroidBot.components }
// There's no need to interrupt a broadcasting event when network handler closed.
set(EventDispatcher, EventDispatcherImpl(bot.coroutineContext, logger.subLogger("EventDispatcher")))
@ -154,8 +157,6 @@ internal open class QQAndroidBot constructor(
OtherClientUpdaterImpl(bot, components, networkLogger.subLogger("OtherClientUpdater"))
)
set(ConfigPushSyncer, ConfigPushSyncerImpl())
set(StateObserver, stateObserverChain())
}
}

View File

@ -0,0 +1,20 @@
/*
* 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.component
internal class ComponentStorageDelegate(
private val instance: () -> ComponentStorage
) : ComponentStorage {
override val size: Int get() = instance().size
override fun <T : Any> get(key: ComponentKey<T>): T = instance()[key]
override fun <T : Any> getOrNull(key: ComponentKey<T>): T? = instance().getOrNull(key)
override val keys: Set<ComponentKey<*>> get() = instance().keys
override fun toString(): String = instance().toString()
}

View File

@ -9,10 +9,21 @@
package net.mamoe.mirai.internal.network.component
import net.mamoe.mirai.utils.TestOnly
import net.mamoe.mirai.utils.cast
internal interface MutableComponentStorage : ComponentStorage {
override operator fun <T : Any> get(key: ComponentKey<T>): T
operator fun <T : Any> set(key: ComponentKey<T>, value: T)
fun <T : Any> remove(key: ComponentKey<T>): T?
}
@TestOnly
internal fun MutableComponentStorage.setAll(other: ComponentStorage) {
for (key in other.keys) {
set(key.cast(), other[key])
}
}
internal operator fun <T : Any> MutableComponentStorage.set(key: ComponentKey<T>, value: T?) {

View File

@ -14,6 +14,7 @@ package net.mamoe.mirai.internal
import net.mamoe.mirai.internal.network.component.ComponentStorage
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
import net.mamoe.mirai.internal.network.component.setAll
import net.mamoe.mirai.internal.network.handler.NetworkHandler
import net.mamoe.mirai.utils.BotConfiguration
import kotlin.contracts.InvocationKind
@ -29,7 +30,7 @@ internal class MockBotBuilder(
val conf: BotConfiguration = BotConfiguration(),
) {
var nhProvider: (QQAndroidBot.(bot: QQAndroidBot) -> NetworkHandler)? = null
var componentsProvider: (QQAndroidBot.(bot: QQAndroidBot) -> ComponentStorage)? = null
var additionalComponentsProvider: (QQAndroidBot.(bot: QQAndroidBot) -> ComponentStorage)? = null
fun conf(action: BotConfiguration.() -> Unit): MockBotBuilder {
contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) }
@ -44,16 +45,20 @@ internal class MockBotBuilder(
}
@Suppress("TestFunctionName")
internal fun MockBot(conf: MockBotBuilder.() -> Unit = {}) =
MockBotBuilder(MockConfiguration.copy()).apply(conf).run {
internal fun MockBot(conf: MockBotBuilder.() -> Unit = {}): QQAndroidBot {
return MockBotBuilder(MockConfiguration.copy()).apply(conf).run {
object : QQAndroidBot(MockAccount, this.conf) {
override val components: ComponentStorage by lazy {
componentsProvider?.invoke(this, this) ?: EMPTY_COMPONENT_STORAGE
override fun createDefaultComponents(): ConcurrentComponentStorage {
return super.createDefaultComponents().apply {
val componentsProvider = additionalComponentsProvider
if (componentsProvider != null) {
setAll(componentsProvider(bot, bot))
}
}
}
override fun createNetworkHandler(): NetworkHandler =
nhProvider?.invoke(this, this) ?: super.createNetworkHandler()
}
}
private val EMPTY_COMPONENT_STORAGE = ConcurrentComponentStorage()
}

View File

@ -35,7 +35,7 @@ internal abstract class AbstractMockNetworkHandlerTest : AbstractTest() {
protected val bot: QQAndroidBot = MockBot {
nhProvider = { createNetworkHandler() }
componentsProvider = { this@AbstractMockNetworkHandlerTest.components }
additionalComponentsProvider = { this@AbstractMockNetworkHandlerTest.components }
}
protected val logger = MiraiLogger.create("test")
protected val components = ConcurrentComponentStorage().apply {

View File

@ -11,11 +11,11 @@ package net.mamoe.mirai.internal.network.framework
import kotlinx.coroutines.CoroutineScope
import net.mamoe.mirai.internal.AbstractBot
import net.mamoe.mirai.internal.MockBot
import net.mamoe.mirai.internal.MockAccount
import net.mamoe.mirai.internal.MockConfiguration
import net.mamoe.mirai.internal.QQAndroidBot
import net.mamoe.mirai.internal.network.component.ComponentStorage
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
import net.mamoe.mirai.internal.network.component.withFallback
import net.mamoe.mirai.internal.network.component.setAll
import net.mamoe.mirai.internal.network.components.*
import net.mamoe.mirai.internal.network.context.SsoProcessorContext
import net.mamoe.mirai.internal.network.context.SsoProcessorContextImpl
@ -24,7 +24,6 @@ import net.mamoe.mirai.internal.network.handler.NetworkHandler
import net.mamoe.mirai.internal.network.handler.NetworkHandler.State
import net.mamoe.mirai.internal.network.handler.NetworkHandlerContextImpl
import net.mamoe.mirai.internal.network.handler.NetworkHandlerFactory
import net.mamoe.mirai.internal.network.handler.state.StateObserver
import net.mamoe.mirai.internal.test.AbstractTest
import net.mamoe.mirai.internal.utils.subLogger
import net.mamoe.mirai.utils.MiraiLogger
@ -45,9 +44,12 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
abstract val network: NetworkHandler
var bot: QQAndroidBot by lateinitMutableProperty {
MockBot {
networkHandlerProvider { createHandler() }
componentsProvider = { network.context } // initialized in [createHandler]
object : QQAndroidBot(MockAccount, MockConfiguration.copy()) {
override fun createDefaultComponents(): ConcurrentComponentStorage =
super.createDefaultComponents().apply { setAll(overrideComponents) }
override fun createNetworkHandler(): NetworkHandler =
this@AbstractRealNetworkHandlerTest.createHandler()
}
}
@ -65,7 +67,7 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
/**
* This overrides [QQAndroidBot.components]
*/
open val defaultComponents = ConcurrentComponentStorage().apply {
open val overrideComponents = ConcurrentComponentStorage().apply {
set(SsoProcessorContext, SsoProcessorContextImpl(bot))
set(SsoProcessor, object : TestSsoProcessor(bot) {
override suspend fun login(handler: NetworkHandler) {
@ -117,38 +119,9 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
// set(StateObserver, bot.run { stateObserverChain() })
}
/**
* [additionalComponents] overrides [defaultComponents] and [QQAndroidBot.components]
*/
open fun createHandler(additionalComponents: ComponentStorage? = null): H {
return factory.create(
createContext(additionalComponents),
address
)
}
val address = InetSocketAddress.createUnresolved("localhost", 123)
open fun createContext(additionalComponents: ComponentStorage? = null): NetworkHandlerContextImpl {
// StateObserver
val components =
additionalComponents.withFallback(defaultComponents).withFallback(bot.createDefaultComponents())
val observerComponents = if (
additionalComponents?.getOrNull(StateObserver)
?: defaultComponents.getOrNull(StateObserver)
== null
) {
ConcurrentComponentStorage().apply {
set(StateObserver, bot.run { components.stateObserverChain() })
}
} else null
return NetworkHandlerContextImpl(
bot,
networkLogger,
observerComponents.withFallback(components)
)
}
open fun createHandler(): H = factory.create(createContext(), address)
open fun createContext(): NetworkHandlerContextImpl = NetworkHandlerContextImpl(bot, networkLogger, bot.components)
val address: InetSocketAddress = InetSocketAddress.createUnresolved("localhost", 123)
///////////////////////////////////////////////////////////////////////////
// Assertions

View File

@ -80,7 +80,7 @@ internal class SelectorNetworkHandlerTest : AbstractRealNetworkHandlerTest<Selec
return listOf(Job())
}
}
defaultComponents[HeartbeatScheduler] = heartbeatScheduler
overrideComponents[HeartbeatScheduler] = heartbeatScheduler
bot.login()
bot.network.context[EventDispatcher].joinBroadcast()

View File

@ -95,7 +95,7 @@ internal abstract class AbstractNettyNHTest : AbstractRealNetworkHandlerTest<Tes
}
internal fun AbstractNettyNHTest.setSsoProcessor(action: suspend SsoProcessor.(handler: NetworkHandler) -> Unit) {
defaultComponents[SsoProcessor] = object : SsoProcessor by defaultComponents[SsoProcessor] {
overrideComponents[SsoProcessor] = object : SsoProcessor by overrideComponents[SsoProcessor] {
override suspend fun login(handler: NetworkHandler) = action(handler)
}
}