From 300882ea18def1be55e9b7ec327d516610476132 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Tue, 8 Jun 2021 17:13:15 +0800 Subject: [PATCH] Redesign `ComponentStorage` initialization for clearer tests --- .../src/commonMain/kotlin/QQAndroidBot.kt | 13 ++--- .../component/ComponentStorageDelegate.kt | 20 +++++++ .../component/MutableComponentStorage.kt | 11 ++++ mirai-core/src/commonTest/kotlin/MockBot.kt | 19 ++++--- .../AbstractMockNetworkHandlerTest.kt | 2 +- .../AbstractRealNetworkHandlerTest.kt | 53 +++++-------------- .../handler/SelectorNetworkHandlerTest.kt | 2 +- .../network/impl/netty/AbstractNettyNHTest.kt | 2 +- 8 files changed, 66 insertions(+), 56 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/network/component/ComponentStorageDelegate.kt diff --git a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt index a9534522d..ef10cd6e8 100644 --- a/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt +++ b/mirai-core/src/commonMain/kotlin/QQAndroidBot.kt @@ -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()) } } diff --git a/mirai-core/src/commonMain/kotlin/network/component/ComponentStorageDelegate.kt b/mirai-core/src/commonMain/kotlin/network/component/ComponentStorageDelegate.kt new file mode 100644 index 000000000..8617a13b6 --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/network/component/ComponentStorageDelegate.kt @@ -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() +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/network/component/MutableComponentStorage.kt b/mirai-core/src/commonMain/kotlin/network/component/MutableComponentStorage.kt index 8e8b51614..0c600d763 100644 --- a/mirai-core/src/commonMain/kotlin/network/component/MutableComponentStorage.kt +++ b/mirai-core/src/commonMain/kotlin/network/component/MutableComponentStorage.kt @@ -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?) { diff --git a/mirai-core/src/commonTest/kotlin/MockBot.kt b/mirai-core/src/commonTest/kotlin/MockBot.kt index 7a918d43a..41650bc29 100644 --- a/mirai-core/src/commonTest/kotlin/MockBot.kt +++ b/mirai-core/src/commonTest/kotlin/MockBot.kt @@ -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() +} \ No newline at end of file diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractMockNetworkHandlerTest.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractMockNetworkHandlerTest.kt index 7a9dc9b59..998a71846 100644 --- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractMockNetworkHandlerTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractMockNetworkHandlerTest.kt @@ -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 { diff --git a/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt b/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt index 1c1d4367d..78eea477e 100644 --- a/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt @@ -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 diff --git a/mirai-core/src/commonTest/kotlin/network/handler/SelectorNetworkHandlerTest.kt b/mirai-core/src/commonTest/kotlin/network/handler/SelectorNetworkHandlerTest.kt index a0c399fb7..69bc148e9 100644 --- a/mirai-core/src/commonTest/kotlin/network/handler/SelectorNetworkHandlerTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/handler/SelectorNetworkHandlerTest.kt @@ -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() diff --git a/mirai-core/src/commonTest/kotlin/network/impl/netty/AbstractNettyNHTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/netty/AbstractNettyNHTest.kt index 4ecd8ff5b..3d468b40c 100644 --- a/mirai-core/src/commonTest/kotlin/network/impl/netty/AbstractNettyNHTest.kt +++ b/mirai-core/src/commonTest/kotlin/network/impl/netty/AbstractNettyNHTest.kt @@ -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) } } \ No newline at end of file