Skip to content

Commit

Permalink
Unit test for actions
Browse files Browse the repository at this point in the history
  • Loading branch information
ryoii committed Oct 5, 2023
1 parent 390665d commit c5d501a
Show file tree
Hide file tree
Showing 11 changed files with 1,337 additions and 3 deletions.
31 changes: 30 additions & 1 deletion mirai-api-http/src/test/kotlin/framework/TestMahApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ import io.ktor.server.testing.*
import io.ktor.util.*
import io.ktor.util.pipeline.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import net.mamoe.mirai.api.http.adapter.MahAdapter
import net.mamoe.mirai.api.http.adapter.MahAdapterFactory
import net.mamoe.mirai.api.http.adapter.http.router.httpModule
import net.mamoe.mirai.api.http.adapter.internal.dto.BotEventDTO
import net.mamoe.mirai.api.http.adapter.internal.dto.EventDTO
import net.mamoe.mirai.api.http.adapter.internal.dto.MessagePacketDTO
import net.mamoe.mirai.api.http.adapter.internal.serializer.BuiltinJsonSerializer
import net.mamoe.mirai.api.http.adapter.webhook.WebhookAdapter
import net.mamoe.mirai.api.http.adapter.ws.router.websocketRouteModule
import net.mamoe.mirai.api.http.context.MahContextHolder
Expand Down Expand Up @@ -70,7 +75,7 @@ class MahApplicationTestBuilder(private val builder: ApplicationTestBuilder): Cl
contentConverter = KotlinxWebsocketSerializationConverter(Json)
}
install(ContentNegotiation) {
json()
json(json = buildPolyJson())
}
}}

Expand All @@ -84,6 +89,30 @@ class MahApplicationTestBuilder(private val builder: ApplicationTestBuilder): Cl
}.body<T>()
}

@KtorDsl
fun testHttpApplication(
verifyKey: String = "verifyKey",
enableVerify: Boolean = false,
singleMode: Boolean = true,
debug: Boolean = false,
block: suspend MahApplicationTestBuilder.() -> Unit
) = testMahApplication(verifyKey, enableVerify, singleMode, debug) {
installHttpAdapter()
block.invoke(this)
}

@KtorDsl
fun testWebsocketApplication(
verifyKey: String = "verifyKey",
enableVerify: Boolean = false,
singleMode: Boolean = true,
debug: Boolean = false,
block: suspend MahApplicationTestBuilder.() -> Unit
) = testMahApplication(verifyKey, enableVerify, singleMode, debug) {
installWsAdapter()
block.invoke(this)
}

@KtorDsl
fun testMahApplication(
verifyKey: String = "verifyKey",
Expand Down
28 changes: 26 additions & 2 deletions mirai-api-http/src/test/kotlin/framework/extend.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

package framework

import net.mamoe.mirai.Bot
import net.mamoe.mirai.mock.MockBot
import net.mamoe.mirai.mock.MockBotFactory
import org.junit.jupiter.api.extension.BeforeAllCallback
import org.junit.jupiter.api.extension.ExtensionContext
Expand All @@ -23,11 +25,33 @@ class SetupMockBot : BeforeAllCallback {
.id(ID)
.create()

bot.addFriend(FRIEND_ID, "friend")
bot.addFriend(BEST_FRIEND_ID, "best_friend")
bot.addFriend(WORST_FRIEND_ID, "worst_friend")
bot.addGroup(BEST_GROUP_ID, "best_group").apply {
addMember(BEST_MEMBER_ID, "best_member")
addMember(GOOD_MEMBER_ID, "good_member")
}
bot.addGroup(WORST_GROUP_ID, "worst_group").apply {
addMember(WORST_MEMBER_ID, "worst_member")
addMember(BAD_MEMBER_ID, "bad_member")
}
}

companion object {
const val ID = 1L
const val FRIEND_ID = 11L
const val BEST_FRIEND_ID = 11L
const val WORST_FRIEND_ID = 99L

const val BEST_GROUP_ID = 111L
const val BEST_MEMBER_ID = 11111L
const val GOOD_MEMBER_ID = 11122L

const val WORST_GROUP_ID = 999L
const val WORST_MEMBER_ID = 99999L
const val BAD_MEMBER_ID = 99988L

fun instance(): MockBot {
return Bot.getInstance(ID) as MockBot
}
}
}
34 changes: 34 additions & 0 deletions mirai-api-http/src/test/kotlin/framework/json.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package framework

import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.SerializersModuleBuilder
import kotlinx.serialization.serializer
import net.mamoe.mirai.api.http.adapter.internal.dto.BotEventDTO
import net.mamoe.mirai.api.http.adapter.internal.dto.EventDTO
import net.mamoe.mirai.api.http.adapter.internal.dto.MessagePacketDTO
import kotlin.reflect.KClass


fun buildPolyJson() = Json {
serializersModule = SerializersModule {
polymorphicSealedClass(EventDTO::class, MessagePacketDTO::class)
polymorphicSealedClass(EventDTO::class, BotEventDTO::class)
}
}

/**
* 从 sealed class 里注册到多态序列化
*/
@OptIn(InternalSerializationApi::class)
@Suppress("UNCHECKED_CAST")
private fun <B : Any, S : B> SerializersModuleBuilder.polymorphicSealedClass(
baseClass: KClass<B>,
sealedClass: KClass<S>
) {
sealedClass.sealedSubclasses.forEach {
val c = it as KClass<S>
polymorphic(baseClass, c, c.serializer())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package integration.action

import framework.SetupMockBot
import framework.testMahApplication
import integration.withSession
import io.ktor.client.call.*
import io.ktor.client.request.*
import net.mamoe.mirai.api.http.adapter.common.StateCode
import net.mamoe.mirai.api.http.adapter.internal.consts.Paths
import net.mamoe.mirai.api.http.adapter.internal.dto.*
import net.mamoe.mirai.api.http.adapter.internal.serializer.jsonElementParseOrNull
import org.junit.jupiter.api.extension.ExtendWith
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull


@ExtendWith(SetupMockBot::class)
class AboutActionTest {

private val pathsVerify = Paths.httpPath("verify")
private val pathsBind = Paths.httpPath("bind")

@Test
fun testOnGetSessionInfo() = testMahApplication(
enableVerify = true,
singleMode = false,
) {
installHttpAdapter()

val verifyRet = postJsonData<VerifyRetDTO>(pathsVerify, VerifyDTO("verifyKey")).also {
assertEquals(StateCode.Success.code, it.code)
assertNotNull(it.session)
}

// bind
postJsonData<StateCode>(pathsBind, BindDTO(SetupMockBot.ID).withSession(verifyRet.session)).also {
assertEquals(StateCode.Success.code, it.code)
}

client.get(Paths.sessionInfo){ parameter("sessionKey", verifyRet.session) }.body<ElementResult>().also {
val session = it.data.jsonElementParseOrNull<SessionDTO>()
assertNotNull(session)
assertEquals(verifyRet.session, session.sessionKey)
}
}

@Test
fun testOnGetBotList() = testMahApplication {
installHttpAdapter()

client.get(Paths.botList).body<LongListRestfulResult>().also {
assertEquals(1, it.data.size)
assertEquals(SetupMockBot.ID, it.data[0])
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package integration.action

import framework.ExtendWith
import framework.SetupMockBot
import framework.testMahApplication
import io.ktor.client.call.*
import io.ktor.client.request.*
import kotlinx.coroutines.flow.first
import net.mamoe.mirai.Bot
import net.mamoe.mirai.api.http.adapter.common.StateCode
import net.mamoe.mirai.api.http.adapter.internal.consts.Paths
import net.mamoe.mirai.api.http.adapter.internal.dto.AnnouncementDTO
import net.mamoe.mirai.api.http.adapter.internal.dto.ElementResult
import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.AnnouncementDeleteDTO
import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.AnnouncementList
import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.PublishAnnouncementDTO
import net.mamoe.mirai.api.http.adapter.internal.serializer.jsonElementParseOrNull
import net.mamoe.mirai.console.util.cast
import net.mamoe.mirai.contact.announcement.AnnouncementParameters
import net.mamoe.mirai.contact.getMemberOrFail
import net.mamoe.mirai.mock.MockBot
import net.mamoe.mirai.mock.contact.announcement.MockOnlineAnnouncement
import net.mamoe.mirai.utils.MiraiInternalApi
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.MethodOrderer
import org.junit.jupiter.api.Order
import org.junit.jupiter.api.TestMethodOrder
import kotlin.test.*

@ExtendWith(SetupMockBot::class)
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
class AnnouncementActionTest {

@Test
@Order(1)
fun testOnListAnnouncement() = testMahApplication {
installHttpAdapter()

client.get(Paths.httpPath(Paths.announcementList)) {
parameter("id", SetupMockBot.BEST_GROUP_ID)
}.body<AnnouncementList>().also {
assertEquals(1, it.data.size)

val announcement = it.data[0]
assertEquals("announcement content", announcement.content)
assertEquals(SetupMockBot.BEST_MEMBER_ID, announcement.senderId)
assertEquals(SetupMockBot.BEST_GROUP_ID, announcement.group.id)
}
}

@Test
@Order(2)
fun testOnPublishAnnouncement() = testMahApplication {
installHttpAdapter()

postJsonData<ElementResult>(
Paths.httpPath(Paths.announcementPublish), PublishAnnouncementDTO(
SetupMockBot.BEST_GROUP_ID,
"new announcement content",
)
).also {
assertEquals(StateCode.Success.code, it.code)
val announcement = it.data.jsonElementParseOrNull<AnnouncementDTO>()

assertNotNull(announcement)
assertEquals("new announcement content", announcement.content)
assertEquals(SetupMockBot.ID, announcement.senderId)
assertEquals(SetupMockBot.BEST_GROUP_ID, announcement.group.id)

Bot.getInstance(SetupMockBot.ID).groups[SetupMockBot.BEST_GROUP_ID]!!.announcements.get(announcement.fid)
.also { groupAnnouncement ->
assertNotNull(groupAnnouncement)
assertEquals("new announcement content", groupAnnouncement.content)
assertEquals(SetupMockBot.ID, announcement.senderId)
assertEquals(SetupMockBot.BEST_GROUP_ID, groupAnnouncement.group.id)
}
}
}

@Test
@Order(3)
fun testOnDeleteAnnouncement() = testMahApplication {
installHttpAdapter()

val fid = Bot.getInstance(SetupMockBot.ID).groups[SetupMockBot.BEST_GROUP_ID]!!.announcements.asFlow().first().fid

postJsonData<StateCode>(
Paths.httpPath(Paths.announcementDelete),
AnnouncementDeleteDTO(
SetupMockBot.BEST_GROUP_ID,
fid,
)
).also {
assertEquals(StateCode.Success.code, it.code)

Bot.getInstance(SetupMockBot.ID).groups[SetupMockBot.BEST_GROUP_ID]!!.announcements.get(fid)
.also(::assertNull)
}

postJsonData<StateCode>(
Paths.httpPath(Paths.announcementDelete),
AnnouncementDeleteDTO(
SetupMockBot.BEST_GROUP_ID,
fid,
)
).also {
assertEquals(StateCode.NoElement.code, it.code)
}
}

companion object {
@JvmStatic
@OptIn(MiraiInternalApi::class)
@BeforeAll
fun setUpAnnouncement() {
val bot: MockBot = Bot.getInstance(SetupMockBot.ID).cast()
bot.groups[SetupMockBot.BEST_GROUP_ID]!!.announcements
.mockPublish(
MockOnlineAnnouncement(
"announcement content",
AnnouncementParameters.DEFAULT,
SetupMockBot.BEST_MEMBER_ID,
"mock announcement fid",
false,
0,
1,
),
bot.getGroupOrFail(SetupMockBot.BEST_GROUP_ID).getMemberOrFail(SetupMockBot.BEST_MEMBER_ID),
false
)
}
}
}
Loading

0 comments on commit c5d501a

Please sign in to comment.