mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-25 04:50:26 +08:00
Fix jvmBase bugs caused by migration to common
This commit is contained in:
parent
72c108bc54
commit
c9d343db89
mirai-core-api/src
commonMain/kotlin/message/data
jvmBaseMain/kotlin/utils
jvmBaseTest/kotlin/message/data
jvmTest/kotlin/message/data
nativeMain/kotlin/utils
mirai-core-utils/src
commonTest/kotlin/net/mamoe/mirai/utils
jvmBaseTest/kotlin
mirai-core/src
commonMain/kotlin
commonTest/kotlin
message
network
AwaitStateTest.kt
framework
AbstractCommonNHTest.ktAbstractCommonNHTestWithSelector.ktAbstractMockNetworkHandlerTest.ktAbstractRealNetworkHandlerTest.kt
components
handler
impl/common
notice/processors
jvmBaseTest/kotlin
test
testFramework/codegen
@ -19,8 +19,8 @@ import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_1
|
||||
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
|
||||
import net.mamoe.mirai.message.data.visitor.MessageVisitor
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
import net.mamoe.mirai.utils.asImmutable
|
||||
import net.mamoe.mirai.utils.castOrNull
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import net.mamoe.mirai.utils.replaceAllKotlin
|
||||
import kotlin.jvm.JvmField
|
||||
import kotlin.jvm.JvmMultifileClass
|
||||
@ -131,6 +131,9 @@ internal annotation class MessageChainConstructor
|
||||
@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
|
||||
@Serializable(MessageChain.Serializer::class)
|
||||
internal class LinearMessageChainImpl @MessageChainConstructor private constructor(
|
||||
/**
|
||||
* Must be guaranteed to be immutable
|
||||
*/
|
||||
@JvmField
|
||||
internal val delegate: List<SingleMessage>,
|
||||
override val hasConstrainSingle: Boolean
|
||||
@ -212,7 +215,7 @@ internal class LinearMessageChainImpl @MessageChainConstructor private construct
|
||||
return if (delegate.isEmpty()) {
|
||||
emptyMessageChain()
|
||||
} else {
|
||||
LinearMessageChainImpl(delegate, hasConstrainSingle)
|
||||
LinearMessageChainImpl(delegate.asImmutable(), hasConstrainSingle)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import kotlinx.serialization.json.Json
|
||||
@ -50,13 +49,12 @@ public actual class DeviceInfo actual constructor(
|
||||
@MiraiInternalApi
|
||||
public actual val guid: ByteArray = generateGuid(androidId, macAddress)
|
||||
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") // serializable
|
||||
@Serializable
|
||||
public actual class Version actual constructor(
|
||||
public actual val incremental: ByteArray = "5891938".toByteArray(),
|
||||
public actual val release: ByteArray = "10".toByteArray(),
|
||||
public actual val codename: ByteArray = "REL".toByteArray(),
|
||||
public actual val sdk: Int = 29
|
||||
public actual val incremental: ByteArray,
|
||||
public actual val release: ByteArray,
|
||||
public actual val codename: ByteArray,
|
||||
public actual val sdk: Int
|
||||
) {
|
||||
/**
|
||||
* @since 2.9
|
||||
|
@ -13,30 +13,30 @@ package net.mamoe.mirai.message.data
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFails
|
||||
import java.util.List as JdkList
|
||||
|
||||
internal open class MessageChainImmutableTest {
|
||||
private fun msg0(): MessageChain = messageChainOf(
|
||||
AtAll, PlainText("Hello!"), At(114514),
|
||||
)
|
||||
|
||||
fun msgAsJdk(): JdkList<SingleMessage> {
|
||||
return msg0() as java.util.List<SingleMessage>
|
||||
@Test
|
||||
fun `LinearMessageChainImpl is immutable`() {
|
||||
runCheck(
|
||||
messageChainOf(
|
||||
AtAll, PlainText("Hello!"), At(114514),
|
||||
) as java.util.List<SingleMessage>
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `direct access`() {
|
||||
val chain = msgAsJdk()
|
||||
fun `CombinedMessage is immutable`() {
|
||||
runCheck(
|
||||
(AtAll + PlainText("Hello!")) as java.util.List<SingleMessage>,
|
||||
)
|
||||
}
|
||||
|
||||
private fun runCheck(chain: java.util.List<SingleMessage>) {
|
||||
assertFails { chain.set(0, AtAll) }
|
||||
assertFails { chain.remove(0) }
|
||||
assertFails { chain.clear() }
|
||||
assertFails { chain.add(PlainText("Hey Hey!")) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterator access`() {
|
||||
val chain = msgAsJdk()
|
||||
assertFails { chain.iterator().remove() }
|
||||
assertFails { chain.iterator().also { it.next() }.remove() }
|
||||
assertFails { chain.listIterator().remove() }
|
||||
|
@ -14,10 +14,10 @@ package net.mamoe.mirai.message.data
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFails
|
||||
|
||||
internal class MessageChainImmutableTest_JDK8 : MessageChainImmutableTest() {
|
||||
internal class MessageChainImmutableTestJdk8 : MessageChainImmutableTest() {
|
||||
@Test
|
||||
fun `access with JDK8 lambda`() {
|
||||
val chain = msgAsJdk()
|
||||
val chain = messageChainOf(AtAll, PlainText("Hello!"), At(114514)) as java.util.List<SingleMessage>
|
||||
assertFails { chain.removeIf { true } }
|
||||
assertFails { chain.replaceAll { AtAll } }
|
||||
assertFails { chain.sort { o1, o2 -> o1.javaClass.name.compareTo(o2.javaClass.name) } }
|
@ -9,7 +9,6 @@
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import kotlin.random.Random
|
||||
@ -48,13 +47,12 @@ public actual class DeviceInfo actual constructor(
|
||||
@MiraiInternalApi
|
||||
public actual val guid: ByteArray = generateGuid(androidId, macAddress)
|
||||
|
||||
@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") // serializable
|
||||
@Serializable
|
||||
public actual class Version actual constructor(
|
||||
public actual val incremental: ByteArray = "5891938".toByteArray(),
|
||||
public actual val release: ByteArray = "10".toByteArray(),
|
||||
public actual val codename: ByteArray = "REL".toByteArray(),
|
||||
public actual val sdk: Int = 29
|
||||
public actual val incremental: ByteArray,
|
||||
public actual val release: ByteArray,
|
||||
public actual val codename: ByteArray,
|
||||
public actual val sdk: Int
|
||||
) {
|
||||
/**
|
||||
* @since 2.9
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@ -50,38 +49,6 @@ internal class LateinitMutablePropertyTest {
|
||||
assertEquals(1, counter)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initializerCalledOnceConcurrent() = runBlocking {
|
||||
val value = Symbol("expected")
|
||||
val counter = atomic(0)
|
||||
|
||||
val verySlowInitializer = CompletableDeferred<Unit>()
|
||||
|
||||
|
||||
val prop by lateinitMutableProperty {
|
||||
counter.incrementAndGet()
|
||||
runBlocking { yield(); verySlowInitializer.await() }
|
||||
value
|
||||
}
|
||||
|
||||
|
||||
val lock = CompletableDeferred<Unit>()
|
||||
repeat(10) {
|
||||
launch {
|
||||
lock.join()
|
||||
@Suppress("UNUSED_EXPRESSION")
|
||||
prop
|
||||
}
|
||||
}
|
||||
lock.complete(Unit) // resume callers
|
||||
|
||||
|
||||
verySlowInitializer.complete(Unit)
|
||||
|
||||
assertSame(value, prop)
|
||||
assertEquals(1, counter.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setValuePrevailsOnCompetitionWithInitializer() = runBlocking {
|
||||
val verySlowInitializer = CompletableDeferred<Unit>()
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2019-2022 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/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.yield
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertSame
|
||||
|
||||
internal class LateinitMutablePropertyTestJvm {
|
||||
@Test
|
||||
fun `initializer called once if requested by multiple threads`() = runBlocking {
|
||||
val value = Symbol("expected")
|
||||
var counter = 0
|
||||
|
||||
val verySlowInitializer = CompletableDeferred<Unit>()
|
||||
|
||||
|
||||
val prop by lateinitMutableProperty {
|
||||
counter++
|
||||
runBlocking { yield(); verySlowInitializer.await() }
|
||||
value
|
||||
}
|
||||
|
||||
|
||||
// requested by 10 threads
|
||||
val lock = CompletableFuture<Unit>()
|
||||
repeat(10) {
|
||||
thread {
|
||||
lock.join()
|
||||
@Suppress("UNUSED_EXPRESSION")
|
||||
prop
|
||||
}
|
||||
}
|
||||
lock.complete(Unit) // resume callers
|
||||
|
||||
|
||||
verySlowInitializer.complete(Unit)
|
||||
|
||||
assertSame(value, prop)
|
||||
assertEquals(1, counter)
|
||||
}
|
||||
|
||||
}
|
@ -145,6 +145,8 @@ internal abstract class CommonNetworkHandler<Conn>(
|
||||
this.setState { StateConnecting(ExceptionCollector()) }
|
||||
?.resumeConnection()
|
||||
?: this@CommonNetworkHandler.resumeConnection() // concurrently closed by other thread.
|
||||
|
||||
println("INITIALIZED RETURN")
|
||||
}
|
||||
|
||||
override fun toString(): String = "StateInitialized"
|
||||
@ -212,6 +214,9 @@ internal abstract class CommonNetworkHandler<Conn>(
|
||||
connectResult.await() // propagates exceptions
|
||||
val connection = connection.await()
|
||||
this.setState { StateLoading(connection) }
|
||||
.also {
|
||||
println(" this.setState { StateLoading(connection) }: " + it)
|
||||
}
|
||||
?.resumeConnection()
|
||||
?: this@CommonNetworkHandler.resumeConnection() // concurrently closed by other thread.
|
||||
}
|
||||
|
@ -9,24 +9,21 @@
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlinx.atomicfu.AtomicRef
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.atomicfu.locks.SynchronizedObject
|
||||
import kotlinx.atomicfu.locks.synchronized
|
||||
import kotlin.jvm.Volatile
|
||||
|
||||
|
||||
internal class SingleEntrantLock {
|
||||
@Volatile
|
||||
@PublishedApi
|
||||
internal var locker: Any? = null
|
||||
|
||||
private val lock = SynchronizedObject()
|
||||
internal class SingleEntrantLock : SynchronizedObject() {
|
||||
private val locker: AtomicRef<Any?> = atomic(null)
|
||||
|
||||
inline fun <R> withLock(locker: Any, crossinline block: () -> R): R? {
|
||||
return synchronized(lock) {
|
||||
if (this.locker === locker) return null
|
||||
this.locker = locker
|
||||
return synchronized(this) {
|
||||
if (this.locker.value === locker) return@synchronized null
|
||||
this.locker.value = locker
|
||||
block().also {
|
||||
this.locker = null
|
||||
this.locker.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ internal class ImageReadingTest : AbstractTest() {
|
||||
ImageType.JPG
|
||||
)
|
||||
}
|
||||
assertFailsWith(IOException::class) {
|
||||
assertFailsWith(IllegalStateException::class) {
|
||||
"FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 78 00 78 00 00 FF E1 00 5A".testMatch(
|
||||
ImageType.JPG
|
||||
)
|
||||
|
@ -41,7 +41,6 @@ internal class AwaitStateTest : AbstractMockNetworkHandlerTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun `test whileSelect onStateChanged on demand`() = runBlockingUnit(singleThreadDispatcher + Job()) {
|
||||
createNetworkHandler().run {
|
||||
@ -81,7 +80,6 @@ internal class AwaitStateTest : AbstractMockNetworkHandlerTest() {
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun `test whileSelect onStateChanged drop if not listening`() = runBlockingUnit(singleThreadDispatcher + Job()) {
|
||||
createNetworkHandler().run {
|
||||
|
@ -11,7 +11,9 @@ package net.mamoe.mirai.internal.network.framework
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.handler.*
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.utils.ExceptionCollector
|
||||
|
||||
@ -28,6 +30,23 @@ internal abstract class TestCommonNetworkHandler(
|
||||
}
|
||||
|
||||
override fun PlatformConn.writeAndFlushOrCloseAsync(packet: OutgoingPacket) {
|
||||
for (packetReplier in packetRepliers) {
|
||||
packetReplier.run {
|
||||
object : PacketReplierContext {
|
||||
override fun reply(incoming: IncomingPacket) {
|
||||
collectReceived(incoming)
|
||||
}
|
||||
|
||||
override fun reply(incoming: Packet) {
|
||||
reply(IncomingPacket(packet.commandName, packet.sequenceId, incoming))
|
||||
}
|
||||
|
||||
override fun reply(incoming: Throwable) {
|
||||
reply(IncomingPacket(packet.commandName, packet.sequenceId, incoming))
|
||||
}
|
||||
}.onSend(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||
@ -51,6 +70,24 @@ internal abstract class TestCommonNetworkHandler(
|
||||
return setState { StateLoading(conn) }
|
||||
}
|
||||
|
||||
private val packetRepliers = mutableListOf<PacketReplier>()
|
||||
|
||||
fun addPacketReplier(packetReplier: PacketReplier) {
|
||||
packetRepliers.add(packetReplier)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 应答器, 模拟服务器返回.
|
||||
*/
|
||||
internal fun interface PacketReplier {
|
||||
fun PacketReplierContext.onSend(packet: OutgoingPacket)
|
||||
}
|
||||
|
||||
internal interface PacketReplierContext {
|
||||
fun reply(incoming: IncomingPacket)
|
||||
fun reply(incoming: Packet)
|
||||
fun reply(incoming: Throwable)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,6 @@ import net.mamoe.mirai.internal.network.handler.NetworkHandlerSupport
|
||||
import net.mamoe.mirai.internal.network.handler.TestSelector
|
||||
import net.mamoe.mirai.internal.network.handler.selector.NetworkHandlerSelector
|
||||
import net.mamoe.mirai.internal.network.handler.selector.SelectorNetworkHandler
|
||||
import net.mamoe.mirai.utils.cast
|
||||
|
||||
/**
|
||||
* When network is closed, it will reconnect, so that you test for real environment,
|
||||
@ -45,7 +44,6 @@ internal abstract class AbstractCommonNHTestWithSelector :
|
||||
override val factory: NetworkHandlerFactory<TestSelectorNetworkHandler> =
|
||||
NetworkHandlerFactory { _, _ -> TestSelectorNetworkHandler(selector, bot) }
|
||||
|
||||
override val network: TestSelectorNetworkHandler get() = bot.network.cast()
|
||||
}
|
||||
|
||||
internal class TestSelectorNetworkHandler(
|
||||
|
@ -17,10 +17,7 @@ import net.mamoe.mirai.internal.BotAccount
|
||||
import net.mamoe.mirai.internal.MockBot
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
||||
import net.mamoe.mirai.internal.network.components.EventDispatcher
|
||||
import net.mamoe.mirai.internal.network.components.PacketLoggingStrategy
|
||||
import net.mamoe.mirai.internal.network.components.PacketLoggingStrategyImpl
|
||||
import net.mamoe.mirai.internal.network.components.SsoProcessor
|
||||
import net.mamoe.mirai.internal.network.components.*
|
||||
import net.mamoe.mirai.internal.network.framework.components.TestImagePatcher
|
||||
import net.mamoe.mirai.internal.network.framework.components.TestSsoProcessor
|
||||
import net.mamoe.mirai.internal.network.handler.NetworkHandler
|
||||
@ -69,9 +66,10 @@ internal abstract class AbstractMockNetworkHandlerTest : AbstractNetworkHandlerT
|
||||
)
|
||||
set(ImagePatcher, TestImagePatcher())
|
||||
set(PacketLoggingStrategy, PacketLoggingStrategyImpl(bot))
|
||||
set(AccountSecretsManager, MemoryAccountSecretsManager())
|
||||
}
|
||||
|
||||
fun NetworkHandler.assertState(state: NetworkHandler.State) {
|
||||
assertEquals(state, state)
|
||||
assertEquals(this.state, state)
|
||||
}
|
||||
}
|
@ -14,6 +14,11 @@ package net.mamoe.mirai.internal.network.framework
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import net.mamoe.mirai.internal.*
|
||||
import net.mamoe.mirai.internal.contact.uin
|
||||
import net.mamoe.mirai.internal.network.KeyWithCreationTime
|
||||
import net.mamoe.mirai.internal.network.KeyWithExpiry
|
||||
import net.mamoe.mirai.internal.network.WLoginSigInfo
|
||||
import net.mamoe.mirai.internal.network.WLoginSimpleInfo
|
||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
||||
import net.mamoe.mirai.internal.network.component.setAll
|
||||
@ -29,6 +34,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.internal.utils.subLogger
|
||||
import net.mamoe.mirai.utils.*
|
||||
import network.framework.components.TestEventDispatcherImpl
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.AfterTest
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -39,10 +45,19 @@ import kotlin.test.assertEquals
|
||||
*/
|
||||
internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : AbstractNetworkHandlerTest() {
|
||||
abstract val factory: NetworkHandlerFactory<H>
|
||||
abstract val network: H
|
||||
|
||||
/**
|
||||
* This is shared for all [createBot] by default. `network === bot.network`, unless you change it.
|
||||
*/
|
||||
open val network: H by lateinitMutableProperty {
|
||||
factory.create(createContext(), createAddress())
|
||||
}
|
||||
|
||||
private var botInit = false
|
||||
var bot: QQAndroidBot by lateinitMutableProperty { botInit = true; createBot() }
|
||||
var bot: QQAndroidBot by lateinitMutableProperty {
|
||||
botInit = true
|
||||
createBot()
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
fun afterEach() {
|
||||
@ -52,10 +67,16 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
|
||||
protected open fun createBot(account: BotAccount = MockAccount): QQAndroidBot {
|
||||
return object : QQAndroidBot(account, MockConfiguration.copy()) {
|
||||
override fun createBotLevelComponents(): ConcurrentComponentStorage =
|
||||
super.createBotLevelComponents().apply { setAll(overrideComponents) }
|
||||
super.createBotLevelComponents().apply {
|
||||
setAll(overrideComponents)
|
||||
get(AccountSecretsManager).getSecretsOrCreate(
|
||||
account,
|
||||
DeviceInfo.random(Random(1))
|
||||
).wLoginSigInfo = createWLoginSigInfo(uin)
|
||||
}
|
||||
|
||||
override fun createNetworkHandler(): NetworkHandler =
|
||||
this@AbstractRealNetworkHandlerTest.createHandler()
|
||||
this@AbstractRealNetworkHandlerTest.network
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +170,6 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
|
||||
return instance
|
||||
}
|
||||
|
||||
open fun createHandler(): NetworkHandler = factory.create(createContext(), createAddress())
|
||||
open fun createContext(): NetworkHandlerContextImpl =
|
||||
NetworkHandlerContextImpl(bot, networkLogger, bot.createNetworkLevelComponents())
|
||||
|
||||
@ -185,3 +205,83 @@ internal fun AbstractRealNetworkHandlerTest<*>.setSsoProcessor(action: suspend S
|
||||
override suspend fun login(handler: NetworkHandler) = action(handler)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWLoginSigInfo(
|
||||
uin: Long,
|
||||
creationTime: Long = currentTimeSeconds(),
|
||||
random: Random = Random(1)
|
||||
): WLoginSigInfo {
|
||||
return WLoginSigInfo(
|
||||
uin = uin,
|
||||
encryptA1 = null,
|
||||
noPicSig = null,
|
||||
simpleInfo = WLoginSimpleInfo(
|
||||
uin = uin,
|
||||
imgType = EMPTY_BYTE_ARRAY,
|
||||
imgFormat = EMPTY_BYTE_ARRAY,
|
||||
imgUrl = EMPTY_BYTE_ARRAY,
|
||||
mainDisplayName = EMPTY_BYTE_ARRAY
|
||||
), // defaults {}, from asyncContext._G
|
||||
appPri = 4294967295L, // defaults {}, from asyncContext._G
|
||||
a2ExpiryTime = creationTime + 2160000L, // or from asyncContext._t403.get_body_data()
|
||||
loginBitmap = 0,
|
||||
tgt = getRandomByteArray(16, random),
|
||||
a2CreationTime = creationTime,
|
||||
tgtKey = getRandomByteArray(16, random), // from asyncContext._login_bitmap
|
||||
userStSig = KeyWithCreationTime(getRandomByteArray(16, random), creationTime),
|
||||
userStKey = EMPTY_BYTE_ARRAY,
|
||||
userStWebSig = KeyWithExpiry(
|
||||
EMPTY_BYTE_ARRAY,
|
||||
creationTime,
|
||||
creationTime + 6000
|
||||
),
|
||||
userA5 = KeyWithCreationTime(getRandomByteArray(16, random), creationTime),
|
||||
userA8 = KeyWithExpiry(
|
||||
EMPTY_BYTE_ARRAY,
|
||||
creationTime,
|
||||
creationTime + 72000L
|
||||
),
|
||||
lsKey = KeyWithExpiry(
|
||||
EMPTY_BYTE_ARRAY,
|
||||
creationTime,
|
||||
creationTime + 1641600L
|
||||
),
|
||||
sKey = KeyWithExpiry(
|
||||
EMPTY_BYTE_ARRAY,
|
||||
creationTime,
|
||||
creationTime + 86400L
|
||||
),
|
||||
userSig64 = KeyWithCreationTime(EMPTY_BYTE_ARRAY, creationTime),
|
||||
openId = EMPTY_BYTE_ARRAY,
|
||||
openKey = KeyWithCreationTime(EMPTY_BYTE_ARRAY, creationTime),
|
||||
vKey = KeyWithExpiry(
|
||||
EMPTY_BYTE_ARRAY,
|
||||
creationTime,
|
||||
creationTime + 1728000L
|
||||
),
|
||||
accessToken = KeyWithCreationTime(EMPTY_BYTE_ARRAY, creationTime),
|
||||
d2 = KeyWithExpiry(
|
||||
getRandomByteArray(16, random),
|
||||
creationTime,
|
||||
creationTime + 1728000L
|
||||
),
|
||||
d2Key = getRandomByteArray(16, random),
|
||||
sid = KeyWithExpiry(
|
||||
EMPTY_BYTE_ARRAY,
|
||||
creationTime,
|
||||
creationTime + 1728000L
|
||||
),
|
||||
aqSig = KeyWithCreationTime(EMPTY_BYTE_ARRAY, creationTime),
|
||||
psKeyMap = mutableMapOf(),
|
||||
pt4TokenMap = mutableMapOf(),
|
||||
superKey = EMPTY_BYTE_ARRAY,
|
||||
payToken = EMPTY_BYTE_ARRAY,
|
||||
pf = EMPTY_BYTE_ARRAY,
|
||||
pfKey = EMPTY_BYTE_ARRAY,
|
||||
da2 = EMPTY_BYTE_ARRAY,
|
||||
wtSessionTicket = KeyWithCreationTime(EMPTY_BYTE_ARRAY, creationTime),
|
||||
wtSessionTicketKey = EMPTY_BYTE_ARRAY,
|
||||
deviceToken = EMPTY_BYTE_ARRAY,
|
||||
encryptedDownloadSession = null
|
||||
)
|
||||
}
|
||||
|
@ -18,13 +18,22 @@ import net.mamoe.mirai.internal.network.handler.NetworkHandler
|
||||
import net.mamoe.mirai.internal.network.handler.logger
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.SvcRespRegister
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.utils.DeviceInfo
|
||||
import net.mamoe.mirai.utils.debug
|
||||
import net.mamoe.mirai.utils.lateinitMutableProperty
|
||||
import kotlin.random.Random
|
||||
|
||||
internal open class TestSsoProcessor(private val bot: QQAndroidBot) : SsoProcessor {
|
||||
val deviceInfo = bot.configuration.createDeviceInfo(bot)
|
||||
override var client: QQAndroidClient by lateinitMutableProperty {
|
||||
QQAndroidClient(bot.account, device = deviceInfo, accountSecrets = AccountSecretsImpl(deviceInfo, bot.account))
|
||||
QQAndroidClient(
|
||||
bot.account,
|
||||
device = deviceInfo,
|
||||
accountSecrets = bot.components[AccountSecretsManager].getSecretsOrCreate(
|
||||
bot.account,
|
||||
DeviceInfo.random(Random(1))
|
||||
)
|
||||
)
|
||||
}
|
||||
override val ssoSession: SsoSession get() = bot.client
|
||||
override val firstLoginResult: AtomicRef<FirstLoginResult?> = atomic(null)
|
||||
|
@ -45,7 +45,7 @@ internal class KeepAliveNetworkHandlerSelectorRealTest : AbstractCommonNHTest()
|
||||
throw MyException()
|
||||
}
|
||||
|
||||
val selector = TestSelector(3) { createHandler() }
|
||||
val selector = TestSelector(3) { factory.create(createContext(), createAddress()) }
|
||||
assertFailsWith<Throwable> { selector.awaitResumeInstance() }
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ internal class KeepAliveNetworkHandlerSelectorRealTest : AbstractCommonNHTest()
|
||||
throw object : NetworkException(true) {}
|
||||
}
|
||||
|
||||
val selector = TestSelector(3) { createHandler() }
|
||||
val selector = TestSelector(3) { factory.create(createContext(), createAddress()) }
|
||||
assertFailsWith<MaxAttemptsReachedException> { selector.awaitResumeInstance() }.let {
|
||||
assertIs<NetworkException>(it.cause)
|
||||
}
|
||||
@ -74,7 +74,7 @@ internal class KeepAliveNetworkHandlerSelectorRealTest : AbstractCommonNHTest()
|
||||
throwException = {
|
||||
throw MyException()
|
||||
}
|
||||
val selector = TestSelector(3) { createHandler() }
|
||||
val selector = TestSelector(3) { factory.create(createContext(), createAddress()) }
|
||||
assertFailsWith<MaxAttemptsReachedException> { selector.awaitResumeInstance() }.let {
|
||||
assertIs<MyException>(it.cause)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ package net.mamoe.mirai.internal.network.impl.common
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.job
|
||||
import net.mamoe.mirai.internal.MockBot
|
||||
import net.mamoe.mirai.internal.network.components.EventDispatcher
|
||||
import net.mamoe.mirai.internal.network.components.SsoProcessor
|
||||
@ -84,7 +85,7 @@ internal class BotLifecycleTest : AbstractCommonNHTest() {
|
||||
conf {
|
||||
parentCoroutineContext = CoroutineName("Overrode")
|
||||
}
|
||||
networkHandlerProvider { createHandler() }
|
||||
networkHandlerProvider { factory.create(createContext(), createAddress()) }
|
||||
}
|
||||
assertEquals("Overrode", bot.coroutineContext[CoroutineName]!!.name)
|
||||
}
|
||||
@ -96,7 +97,7 @@ internal class BotLifecycleTest : AbstractCommonNHTest() {
|
||||
conf {
|
||||
parentCoroutineContext = parentJob
|
||||
}
|
||||
networkHandlerProvider { createHandler() }
|
||||
networkHandlerProvider { factory.create(createContext(), createAddress()) }
|
||||
}
|
||||
assertEquals(1, parentJob.children.count())
|
||||
assertEquals(bot.supervisorJob, parentJob.children.first())
|
||||
@ -121,8 +122,9 @@ internal class BotLifecycleTest : AbstractCommonNHTest() {
|
||||
data = StatSvc.SimpleGet.Response.Error(1, "test error"),
|
||||
)
|
||||
)
|
||||
assertFalse { network.isActive }
|
||||
network.coroutineContext.job.join()
|
||||
network.assertState(CLOSED) // we do not use selector in this test so it will be CLOSED. It will recover (reconnect) instead in real.
|
||||
assertFalse { network.isActive }
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,6 +14,11 @@ package net.mamoe.mirai.internal.network.impl.common
|
||||
import io.ktor.utils.io.errors.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import net.mamoe.mirai.internal.BotAccount
|
||||
import net.mamoe.mirai.internal.MockConfiguration
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.component.ConcurrentComponentStorage
|
||||
import net.mamoe.mirai.internal.network.component.setAll
|
||||
import net.mamoe.mirai.internal.network.components.BotOfflineEventMonitor
|
||||
import net.mamoe.mirai.internal.network.components.BotOfflineEventMonitorImpl
|
||||
import net.mamoe.mirai.internal.network.components.FirstLoginResult
|
||||
@ -38,16 +43,23 @@ internal class CommonNHBotNormalLoginTest : AbstractCommonNHTest() {
|
||||
}
|
||||
|
||||
val selector = KeepAliveNetworkHandlerSelector(selectorLogger) {
|
||||
super.factory.create(createContext(), createAddress())
|
||||
factory.create(createContext(), createAddress())
|
||||
}
|
||||
|
||||
override val network: TestCommonNetworkHandler
|
||||
get() = bot.network.cast<SelectorNetworkHandler<*>>().selector.getCurrentInstanceOrCreate().cast()
|
||||
get() = selector.getCurrentInstanceOrCreate().cast()
|
||||
|
||||
override fun createHandler(): NetworkHandler {
|
||||
return SelectorNetworkHandler(selector)
|
||||
override fun createBot(account: BotAccount): QQAndroidBot {
|
||||
return object : QQAndroidBot(account, MockConfiguration.copy()) {
|
||||
override fun createBotLevelComponents(): ConcurrentComponentStorage =
|
||||
super.createBotLevelComponents().apply { setAll(overrideComponents) }
|
||||
|
||||
override fun createNetworkHandler(): NetworkHandler =
|
||||
SelectorNetworkHandler(selector)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CusLoginException(message: String?) : CustomLoginFailedException(true, message)
|
||||
|
||||
@AfterTest
|
||||
|
@ -7,6 +7,8 @@
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
@file:OptIn(TestOnly::class)
|
||||
|
||||
package net.mamoe.mirai.internal.notice.processors
|
||||
|
||||
import kotlinx.serialization.SerializationStrategy
|
||||
@ -84,7 +86,7 @@ internal abstract class AbstractNoticeProcessorTest : AbstractCommonNHTest(), Gr
|
||||
createContext(this, attributes)
|
||||
}, block)
|
||||
|
||||
fun setBot(id: Long): QQAndroidBot {
|
||||
open fun setBot(id: Long): QQAndroidBot {
|
||||
bot = createBot(BotAccount(id, "a"))
|
||||
return bot
|
||||
}
|
||||
|
@ -14,13 +14,16 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.contact.PermissionDeniedException
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.message.source.OnlineMessageSourceFromGroupImpl
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.PbMessageSvc
|
||||
import net.mamoe.mirai.internal.test.runBlockingUnit
|
||||
import net.mamoe.mirai.message.data.OnlineMessageSource
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
internal class RecallTest : AbstractNoticeProcessorTest() {
|
||||
@ -92,6 +95,16 @@ internal class RecallTest : AbstractNoticeProcessorTest() {
|
||||
)
|
||||
)
|
||||
|
||||
override fun setBot(id: Long): QQAndroidBot {
|
||||
return super.setBot(id).also { bot ->
|
||||
runBlockingUnit { bot.login() }
|
||||
network.addPacketReplier {
|
||||
assertEquals("PbMessageSvc.PbMsgWithDraw", it.commandName)
|
||||
reply(PbMessageSvc.PbMsgWithDraw.Response.Success)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `recall member message without permission`() = runBlockingUnit {
|
||||
val bot = setBot(2)
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
package net.mamoe.mirai.internal.test
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.debug.DebugProbes
|
||||
import net.mamoe.mirai.IMirai
|
||||
import net.mamoe.mirai.internal.network.framework.SynchronizedStdoutLogger
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
@ -18,10 +20,13 @@ import java.util.concurrent.TimeUnit
|
||||
|
||||
@Timeout(value = 7, unit = TimeUnit.MINUTES)
|
||||
internal actual abstract class AbstractTest actual constructor() : CommonAbstractTest() {
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
actual companion object {
|
||||
init {
|
||||
initPlatform()
|
||||
|
||||
DebugProbes.install()
|
||||
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
MiraiLogger.setDefaultLoggerCreator {
|
||||
SynchronizedStdoutLogger(it)
|
||||
|
@ -83,7 +83,6 @@ object ValueDescAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
inline fun <reified T> ValueDescAnalyzer.analyze(value: T): ValueDesc {
|
||||
return analyze(value, typeOf<T>())
|
||||
}
|
@ -43,7 +43,7 @@ internal class OptimizeByteArrayAsHexStringTransformerTest : AbstractTest() {
|
||||
fun `can optimize as hex`() {
|
||||
assertEquals(
|
||||
"""
|
||||
"O".toByteArray() /* 4F 02 */
|
||||
"4F 02".hexToBytes()
|
||||
""".trimIndent(), analyzeTransformAndRender(byteArrayOf(0x4f, 0x02))
|
||||
)
|
||||
}
|
||||
|
@ -126,14 +126,15 @@ internal class ValueDescToStringRendererTest {
|
||||
val self: MyClass?,
|
||||
)
|
||||
|
||||
@Suppress("ClassName")
|
||||
data class `MyClass$3`(
|
||||
val str: String,
|
||||
val int: Int,
|
||||
val self: `MyClass$3`?,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `class value`() {
|
||||
data class MyClass2(
|
||||
val str: String,
|
||||
val int: Int,
|
||||
val self: MyClass2?,
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
${MyClass::class.qualifiedName}(
|
||||
@ -144,10 +145,19 @@ internal class ValueDescToStringRendererTest {
|
||||
""".trimIndent(),
|
||||
ValueDescAnalyzer.analyze(MyClass("str", 1, null)).renderToString(renderer)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `local class`() {
|
||||
data class MyClass2(
|
||||
val str: String,
|
||||
val int: Int,
|
||||
val self: MyClass2?,
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
`${MyClass2::class.java.name}`(
|
||||
${MyClass2::class.simpleName}(
|
||||
str = "str",
|
||||
int = 1,
|
||||
self = null,
|
||||
@ -157,6 +167,21 @@ internal class ValueDescToStringRendererTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `class with special name`() {
|
||||
assertEquals(
|
||||
"""
|
||||
`${`MyClass$3`::class.qualifiedName}`(
|
||||
str = "str",
|
||||
int = 1,
|
||||
self = null,
|
||||
)
|
||||
""".trimIndent(),
|
||||
ValueDescAnalyzer.analyze(`MyClass$3`("str", 1, null)).renderToString(renderer)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `class value nested`() {
|
||||
data class MyClass2(
|
||||
@ -182,10 +207,10 @@ internal class ValueDescToStringRendererTest {
|
||||
|
||||
assertEquals(
|
||||
"""
|
||||
`${MyClass2::class.java.name}`(
|
||||
${MyClass2::class.simpleName}(
|
||||
str = "str",
|
||||
int = 1,
|
||||
self = `${MyClass2::class.java.name}`(
|
||||
self = ${MyClass2::class.simpleName}(
|
||||
str = "str",
|
||||
int = 1,
|
||||
self = null,
|
||||
|
Loading…
Reference in New Issue
Block a user