diff --git a/mirai-api-http/src/test/kotlin/framework/TestMahApplication.kt b/mirai-api-http/src/test/kotlin/framework/TestMahApplication.kt index ae02ea2f..b37656bb 100644 --- a/mirai-api-http/src/test/kotlin/framework/TestMahApplication.kt +++ b/mirai-api-http/src/test/kotlin/framework/TestMahApplication.kt @@ -70,7 +70,7 @@ class MahApplicationTestBuilder(private val builder: ApplicationTestBuilder): Cl contentConverter = KotlinxWebsocketSerializationConverter(Json) } install(ContentNegotiation) { - json() + json(json = buildPolyJson()) } }} @@ -84,6 +84,30 @@ class MahApplicationTestBuilder(private val builder: ApplicationTestBuilder): Cl }.body() } +@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", diff --git a/mirai-api-http/src/test/kotlin/framework/extend.kt b/mirai-api-http/src/test/kotlin/framework/extend.kt index 4b4eb7fe..10c685c7 100644 --- a/mirai-api-http/src/test/kotlin/framework/extend.kt +++ b/mirai-api-http/src/test/kotlin/framework/extend.kt @@ -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 @@ -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 + } } } \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/framework/json.kt b/mirai-api-http/src/test/kotlin/framework/json.kt new file mode 100644 index 00000000..cb8f43f6 --- /dev/null +++ b/mirai-api-http/src/test/kotlin/framework/json.kt @@ -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 SerializersModuleBuilder.polymorphicSealedClass( + baseClass: KClass, + sealedClass: KClass +) { + sealedClass.sealedSubclasses.forEach { + val c = it as KClass + polymorphic(baseClass, c, c.serializer()) + } +} \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/integration/action/AboutActionTest.kt b/mirai-api-http/src/test/kotlin/integration/action/AboutActionTest.kt new file mode 100644 index 00000000..585a5ef9 --- /dev/null +++ b/mirai-api-http/src/test/kotlin/integration/action/AboutActionTest.kt @@ -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(pathsVerify, VerifyDTO("verifyKey")).also { + assertEquals(StateCode.Success.code, it.code) + assertNotNull(it.session) + } + + // bind + postJsonData(pathsBind, BindDTO(SetupMockBot.ID).withSession(verifyRet.session)).also { + assertEquals(StateCode.Success.code, it.code) + } + + client.get(Paths.sessionInfo){ parameter("sessionKey", verifyRet.session) }.body().also { + val session = it.data.jsonElementParseOrNull() + assertNotNull(session) + assertEquals(verifyRet.session, session.sessionKey) + } + } + + @Test + fun testOnGetBotList() = testMahApplication { + installHttpAdapter() + + client.get(Paths.botList).body().also { + assertEquals(1, it.data.size) + assertEquals(SetupMockBot.ID, it.data[0]) + } + } +} \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/integration/action/AnnouncementActionTest.kt b/mirai-api-http/src/test/kotlin/integration/action/AnnouncementActionTest.kt new file mode 100644 index 00000000..a3180e2f --- /dev/null +++ b/mirai-api-http/src/test/kotlin/integration/action/AnnouncementActionTest.kt @@ -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().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( + Paths.httpPath(Paths.announcementPublish), PublishAnnouncementDTO( + SetupMockBot.BEST_GROUP_ID, + "new announcement content", + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + val announcement = it.data.jsonElementParseOrNull() + + 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( + 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( + 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 + ) + } + } +} \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/integration/action/EventActionTest.kt b/mirai-api-http/src/test/kotlin/integration/action/EventActionTest.kt new file mode 100644 index 00000000..6fc29859 --- /dev/null +++ b/mirai-api-http/src/test/kotlin/integration/action/EventActionTest.kt @@ -0,0 +1,168 @@ +package integration.action + +import framework.ExtendWith +import framework.SetupMockBot +import framework.testHttpApplication +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.parameter.EventRespDTO +import net.mamoe.mirai.event.broadcast +import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent +import net.mamoe.mirai.event.events.MemberJoinRequestEvent +import net.mamoe.mirai.utils.MiraiInternalApi +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@ExtendWith(SetupMockBot::class) +class EventActionTest { + + @Test + fun testNewFriend() = testHttpApplication { + val newFriendId = 11133L + val bot = SetupMockBot.instance() + + bot.broadcastNewFriendRequestEvent( + newFriendId, + "nickname", + SetupMockBot.BEST_GROUP_ID, + "hello" + ).let { event -> + assertNull(bot.getFriend(newFriendId)) + postJsonData(Paths.httpPath(Paths.newFriend), EventRespDTO( + event.eventId, + event.fromId, + event.fromGroupId, + 1, + "" + )).also { + assertEquals(StateCode.Success.code, it.code) + assertNull(bot.getFriend(newFriendId)) + } + } + + // accept + bot.broadcastNewFriendRequestEvent( + newFriendId, + "nickname", + SetupMockBot.BEST_GROUP_ID, + "hello" + ).let { event -> + assertNull(bot.getFriend(newFriendId)) + postJsonData(Paths.httpPath(Paths.newFriend), EventRespDTO( + event.eventId, + event.fromId, + event.fromGroupId, + 0, + "" + )).also { + assertEquals(StateCode.Success.code, it.code) + assertNotNull(bot.getFriend(newFriendId)) + } + } + } + + @Test + @OptIn(MiraiInternalApi::class) + fun testMemberJoin() = testHttpApplication { + val newMemberId = 11133L + val bot = SetupMockBot.instance() + + MemberJoinRequestEvent( + bot, + Random.nextLong(), + "hello", + newMemberId, + SetupMockBot.BEST_GROUP_ID, + "Best Group", + "new member", + invitorId = SetupMockBot.BEST_MEMBER_ID, + ).broadcast().let { event -> + assertNull(bot.getGroupOrFail(SetupMockBot.BEST_GROUP_ID)[newMemberId]) + postJsonData(Paths.httpPath(Paths.memberJoin), EventRespDTO( + event.eventId, + event.fromId, + event.groupId, + 1, + "reject" + )).also { + assertEquals(StateCode.Success.code, it.code) + assertNull(bot.getGroupOrFail(SetupMockBot.BEST_GROUP_ID)[newMemberId]) + } + } + + MemberJoinRequestEvent( + bot, + Random.nextLong(), + "hello", + newMemberId, + SetupMockBot.BEST_GROUP_ID, + "Best Group", + "new member", + invitorId = SetupMockBot.BEST_MEMBER_ID, + ).broadcast().let { event -> + assertNull(bot.getGroupOrFail(SetupMockBot.BEST_GROUP_ID)[newMemberId]) + postJsonData(Paths.httpPath(Paths.memberJoin), EventRespDTO( + event.eventId, + event.fromId, + event.groupId, + 0, + "accept" + )).also { + assertEquals(StateCode.Success.code, it.code) + assertNotNull(bot.getGroupOrFail(SetupMockBot.BEST_GROUP_ID)[newMemberId]) + } + } + } + + @Test + @OptIn(MiraiInternalApi::class) + fun testBotInvited() = testHttpApplication { + val newGroupId = 222L + val bot = SetupMockBot.instance() + + BotInvitedJoinGroupRequestEvent( + bot, + Random.nextLong(), + SetupMockBot.BEST_FRIEND_ID, + newGroupId, + "new group", + "best friend" + ).broadcast().also { event -> + assertNull(bot.getGroup(newGroupId)) + postJsonData(Paths.httpPath(Paths.memberJoin), EventRespDTO( + event.eventId, + event.invitorId, + event.groupId, + 1, + "reject" + )).also { + assertEquals(StateCode.Success.code, it.code) + assertNull(bot.getGroup(newGroupId)) + } + } + + BotInvitedJoinGroupRequestEvent( + bot, + Random.nextLong(), + SetupMockBot.BEST_FRIEND_ID, + newGroupId, + "new group", + "best friend" + ).broadcast().also { event -> + assertNull(bot.getGroup(newGroupId)) + postJsonData(Paths.httpPath(Paths.botInvited), EventRespDTO( + event.eventId, + event.invitorId, + event.groupId, + 0, + "accept" + )).also { + assertEquals(StateCode.Success.code, it.code) + assertNotNull(bot.getGroup(newGroupId)) + } + } + } +} \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/integration/action/FileActionTest.kt b/mirai-api-http/src/test/kotlin/integration/action/FileActionTest.kt new file mode 100644 index 00000000..34812cd2 --- /dev/null +++ b/mirai-api-http/src/test/kotlin/integration/action/FileActionTest.kt @@ -0,0 +1,301 @@ +package integration.action + +import framework.ExtendWith +import framework.SetupMockBot +import framework.testHttpApplication +import io.ktor.client.call.* +import io.ktor.client.request.* +import io.ktor.client.request.forms.* +import io.ktor.http.* +import io.ktor.http.content.* +import io.ktor.utils.io.streams.* +import kotlinx.coroutines.runBlocking +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.ElementResult +import net.mamoe.mirai.api.http.adapter.internal.dto.RemoteFileDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.* +import net.mamoe.mirai.api.http.adapter.internal.serializer.jsonElementParseOrNull +import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource +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 FileActionTest { + + @Test + @Order(1) + fun testListFile() = testHttpApplication { + client.get(Paths.httpPath(Paths.fileList)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/") + }.body().also { + assertEquals(StateCode.Success.code, it.code) + assertEquals(2, it.data.size) + + val (file, folder) = if (it.data[0].isFile) { + it.data[0] to it.data[1] + } else { + it.data[1] to it.data[0] + } + + assertTrue(folder.isDirectory) + assertEquals("/tmpFolder", folder.path) + assertEquals("tmpFolder", folder.name) + assertNotNull(folder.parent) + assertEquals("/", folder.parent.path) + assertNull(folder.parent.parent) + + assertTrue(file.isFile) + assertEquals("/test.txt", file.path) + assertEquals("test.txt", file.name) + assertNotNull(file.parent) + assertEquals("/", file.parent.path) + assertNull(file.parent.parent) + } + } + + @Test + @Order(2) + fun testFileInfo() = testHttpApplication { + client.get(Paths.httpPath(Paths.fileInfo)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/test.txt") + parameter("withDownloadInfo", true) + }.body().also { + assertEquals(StateCode.Success.code, it.code) + + val data = it.data.jsonElementParseOrNull() + assertNotNull(data) + assertEquals("/test.txt", data.path) + assertEquals("test.txt", data.name) + assertNotNull(data.parent) + assertEquals("/", data.parent.path) + assertNull(data.parent.parent) + + val download = data.downloadInfo + assertNotNull(download) + assertNotNull(download.url) + assertNotNull(download.md5) + assertNotNull(download.sha1) + } + + client.get(Paths.httpPath(Paths.fileInfo)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/test.txt") + parameter("withDownloadInfo", false) + }.body().also { + assertEquals(StateCode.Success.code, it.code) + + val data = it.data.jsonElementParseOrNull() + assertNotNull(data) + assertNull(data.downloadInfo) + } + + client.get(Paths.httpPath(Paths.fileInfo)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/tmpFolder") + parameter("withDownloadInfo", true) + }.body().also { + assertEquals(StateCode.NoElement.code, it.code) + } + } + + @Test + @Order(3) + fun testFileMkdir() = testHttpApplication { + client.get(Paths.httpPath(Paths.fileList)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/mkdir") + }.body().also { + assertEquals(StateCode.NoElement.code, it.code) + } + + postJsonData( + Paths.httpPath(Paths.fileMkdir), MkDirDTO( + path = "/", target = SetupMockBot.BEST_GROUP_ID, directoryName = "mkdir" + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + + val data = it.data.jsonElementParseOrNull() + assertNotNull(data) + assertTrue(data.isDirectory) + assertEquals("/mkdir", data.path) + assertEquals("mkdir", data.name) + assertNotNull(data.parent) + assertEquals("/", data.parent.path) + } + + client.get(Paths.httpPath(Paths.fileList)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/mkdir") + }.body().also { + assertEquals(StateCode.Success.code, it.code) + assertTrue(it.data.isEmpty()) + } + } + + @Test + @Order(4) + fun testUploadFile() = testHttpApplication { + client.get(Paths.httpPath(Paths.fileInfo)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/upload.txt") + }.body().also { + assertEquals(StateCode.NoElement.code, it.code) + } + + client.submitFormWithBinaryData(Paths.httpPath(Paths.uploadFile), formData { + append("path", "/") + append("type", "group") + append("target", SetupMockBot.BEST_GROUP_ID) + append("file", "content", Headers.build { + append(HttpHeaders.ContentDisposition, "filename=upload.txt") + }) + }).body().also { + assertEquals(StateCode.Success.code, it.code) + + val data = it.data.jsonElementParseOrNull() + assertNotNull(data) + assertTrue(data.isFile) + assertEquals("/upload.txt", data.path) + assertEquals("upload.txt", data.name) + } + + client.get(Paths.httpPath(Paths.fileInfo)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/upload.txt") + }.body().also { + assertEquals(StateCode.Success.code, it.code) + + val data = it.data.jsonElementParseOrNull() + assertNotNull(data) + } + } + + @Test + @Order(5) + fun testFileMove() = testHttpApplication { + client.submitFormWithBinaryData(Paths.httpPath(Paths.uploadFile), formData { + append("path", "/") + append("type", "group") + append("target", SetupMockBot.BEST_GROUP_ID) + append("file", "content", Headers.build { + append(HttpHeaders.ContentDisposition, "filename=move.txt") + }) + }).body().also { + assertEquals(StateCode.Success.code, it.code) + } + + postJsonData( + Paths.httpPath(Paths.fileMove), MoveFileDTO( + path = "/move.txt", target = SetupMockBot.BEST_GROUP_ID, moveToPath = "/noExist" + ) + ).also { + assertEquals(StateCode.NoElement.code, it.code) + } + + postJsonData( + Paths.httpPath(Paths.fileMove), MoveFileDTO( + path = "/move.txt", target = SetupMockBot.BEST_GROUP_ID, moveToPath = "/tmpFolder" + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + } + + client.get(Paths.httpPath(Paths.fileInfo)) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("path", "/tmpFolder/move.txt") + }.body().also { + assertEquals(StateCode.Success.code, it.code) + + val data = it.data.jsonElementParseOrNull() + assertNotNull(data) + } + } + + @Test + @Order(6) + fun testFileRename() = testHttpApplication { + client.submitFormWithBinaryData(Paths.httpPath(Paths.uploadFile), formData { + append("path", "/") + append("type", "group") + append("target", SetupMockBot.BEST_GROUP_ID) + append("file", "content", Headers.build { + append(HttpHeaders.ContentDisposition, "filename=rename.txt") + }) + }).body().also { + assertEquals(StateCode.Success.code, it.code) + } + + postJsonData( + Paths.httpPath(Paths.fileRename), RenameFileDTO( + path = "/noExist.txt", group = SetupMockBot.BEST_GROUP_ID, renameTo = "newName.txt" + ) + ).also { + assertEquals(StateCode.NoElement.code, it.code) + } + + postJsonData( + Paths.httpPath(Paths.fileRename), RenameFileDTO( + path = "/rename.txt", group = SetupMockBot.BEST_GROUP_ID, renameTo = "newName.txt" + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + } + } + + @Test + @Order(7) + fun testFileDelete() = testHttpApplication { + client.submitFormWithBinaryData(Paths.httpPath(Paths.uploadFile), formData { + append("path", "/") + append("type", "group") + append("target", SetupMockBot.BEST_GROUP_ID) + append("file", "content", Headers.build { + append(HttpHeaders.ContentDisposition, "filename=delete.txt") + }) + }).body().also { + assertEquals(StateCode.Success.code, it.code) + } + + postJsonData( + Paths.httpPath(Paths.fileDelete), FileTargetDTO( + path = "/noExist.txt", + group = SetupMockBot.BEST_GROUP_ID, + ) + ).also { + assertEquals(StateCode.NoElement.code, it.code) + } + + postJsonData( + Paths.httpPath(Paths.fileDelete), FileTargetDTO( + path = "/delete.txt", + group = SetupMockBot.BEST_GROUP_ID, + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + } + } + + companion object { + + @JvmStatic + @BeforeAll + fun setupGroupFile(): Unit = runBlocking { + SetupMockBot.instance().getGroupOrFail(SetupMockBot.BEST_GROUP_ID).files.apply { + "content".byteInputStream().toExternalResource().use { + uploadNewFile("/test.txt", it) + } + + + root.createFolder("tmpFolder") + } + } + } +} \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/integration/action/FriendActionTest.kt b/mirai-api-http/src/test/kotlin/integration/action/FriendActionTest.kt new file mode 100644 index 00000000..e979a525 --- /dev/null +++ b/mirai-api-http/src/test/kotlin/integration/action/FriendActionTest.kt @@ -0,0 +1,54 @@ +package integration.action + +import framework.ExtendWith +import framework.SetupMockBot +import framework.testHttpApplication +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.parameter.FriendList +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.LongTargetDTO +import kotlin.test.Test +import kotlin.test.assertContains +import kotlin.test.assertEquals + +@ExtendWith(SetupMockBot::class) +class FriendActionTest { + + @Test + fun testDeleteFriend() = testHttpApplication { + client.get(Paths.friendList).body().also { + assertEquals(StateCode.Success.code, it.code) + assertEquals(2, it.data.size) + + val ids = it.data.map { q -> q.id }.toList() + assertContains(ids, SetupMockBot.BEST_FRIEND_ID) + assertContains(ids, SetupMockBot.WORST_FRIEND_ID) + } + + postJsonData( + Paths.deleteFriend, LongTargetDTO( + target = 987654321L + ) + ).also { + assertEquals(StateCode.NoElement.code, it.code) + } + + postJsonData( + Paths.deleteFriend, LongTargetDTO( + target = SetupMockBot.WORST_FRIEND_ID + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + } + + client.get(Paths.friendList).body().also { + assertEquals(StateCode.Success.code, it.code) + assertEquals(1, it.data.size) + + val ids = it.data.map { q -> q.id }.toList() + assertContains(ids, SetupMockBot.BEST_FRIEND_ID) + } + } +} \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/integration/action/GroupActionTest.kt b/mirai-api-http/src/test/kotlin/integration/action/GroupActionTest.kt new file mode 100644 index 00000000..7efe79e7 --- /dev/null +++ b/mirai-api-http/src/test/kotlin/integration/action/GroupActionTest.kt @@ -0,0 +1,207 @@ +package integration.action + +import framework.ExtendWith +import framework.SetupMockBot +import framework.testHttpApplication +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.MemberDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.* +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.GroupConfigDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.GroupDetailDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.KickDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.LongTargetDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.MuteDTO +import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.contact.nameCardOrNick +import net.mamoe.mirai.utils.MiraiExperimentalApi +import kotlin.test.* + +@ExtendWith(SetupMockBot::class) +class GroupActionTest { + + @Test + fun testMuteAllAndUnmuteAll() = testHttpApplication { + val bot = SetupMockBot.instance() + val group = bot.getGroupOrFail(SetupMockBot.BEST_GROUP_ID) + + assertFalse(group.settings.isMuteAll) + + postJsonData(Paths.muteAll, MuteDTO(target = 987654321L)).also { + assertEquals(StateCode.NoElement.code, it.code) + } + + postJsonData(Paths.muteAll, MuteDTO(target = SetupMockBot.BEST_GROUP_ID)).also { + assertEquals(StateCode.Success.code, it.code) + assertTrue(group.settings.isMuteAll) + } + + postJsonData(Paths.unmuteAll, MuteDTO(target = SetupMockBot.BEST_GROUP_ID)).also { + assertEquals(StateCode.Success.code, it.code) + assertFalse(group.settings.isMuteAll) + } + } + + @Test + fun testMuteAndUnmute() = testHttpApplication { + val bot = SetupMockBot.instance() + val member = bot.getGroupOrFail(SetupMockBot.BEST_GROUP_ID).getOrFail(SetupMockBot.BEST_MEMBER_ID) + + assertFalse(member.isMuted) + + postJsonData(Paths.mute, MuteDTO(target = 987654321L, memberId = member.id, time = 3000)).also { + assertEquals(StateCode.NoElement.code, it.code) + } + + postJsonData( + Paths.mute, + MuteDTO(target = SetupMockBot.BEST_GROUP_ID, memberId = 123, time = 3000) + ).also { + assertEquals(StateCode.NoElement.code, it.code) + } + + postJsonData( + Paths.mute, + MuteDTO(target = SetupMockBot.BEST_GROUP_ID, memberId = member.id, time = 3000) + ).also { + assertEquals(StateCode.Success.code, it.code) + assertTrue(member.isMuted) + } + + postJsonData( + Paths.unmute, + MuteDTO(target = SetupMockBot.BEST_GROUP_ID, memberId = member.id, time = 3000) + ).also { + assertEquals(StateCode.Success.code, it.code) + assertFalse(member.isMuted) + } + } + + @Test + fun testKick() = testHttpApplication { + val bot = SetupMockBot.instance() + val memberId = 123L + val group = bot.getGroupOrFail(SetupMockBot.BEST_GROUP_ID) + .appendMember(memberId, "kick") + + + postJsonData(Paths.kick, KickDTO(target = SetupMockBot.BEST_GROUP_ID, memberId = memberId)).also { + assertEquals(StateCode.Success.code, it.code) + assertNull(group[memberId]) + } + } + + @Test + fun testQuit() = testHttpApplication { + val bot = SetupMockBot.instance() + val groupId = 987654321L + val group = bot.addGroup(groupId, "to leave") + + postJsonData(Paths.quit, LongTargetDTO(groupId)).also { + assertEquals(MemberPermission.OWNER, group.botPermission) + // FixMe: Mirai-Mock bug + // assertEquals(500, it.code) + assertEquals(StateCode.Success.code, it.code) + assertNull(bot.getGroup(groupId)) + } + } + + // @Test + // fun testSetEssence(): Unit = TODO() + + @Test + @OptIn(MiraiExperimentalApi::class) + fun testGroupConfig() = testHttpApplication { + val bot = SetupMockBot.instance() + val group = bot.addGroup(123, "test group") + + client.get(Paths.groupConfig) { + parameter("target", group.id) + }.body().also { + assertEquals(group.name, it.name) + assertEquals(group.settings.isAnonymousChatEnabled, it.anonymousChat) + assertEquals(group.settings.isMuteAll, it.muteAll) + assertEquals(group.settings.isAllowMemberInvite, it.allowMemberInvite) + assertEquals(group.settings.isAutoApproveEnabled, it.autoApprove) + assertEquals(false, it.confessTalk) + } + + postJsonData( + Paths.groupConfig, GroupConfigDTO( + target = group.id, + config = GroupDetailDTO( + name = "new name", + allowMemberInvite = true, + // TODO: other config + ) + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + } + + client.get(Paths.groupConfig) { + parameter("target", group.id) + }.body().also { + assertEquals("new name", it.name) + assertEquals(true, it.allowMemberInvite) + } + } + + @Test + fun testMemberInfo() = testHttpApplication { + val bot = SetupMockBot.instance() + val group = bot.addGroup(456, "test group") + val member = group.addMember(456, "test member") + + client.get(Paths.memberInfo) { + parameter("target", group.id) + parameter("memberId", member.id) + }.body().also { + assertEquals(member.id, it.id) + assertEquals(member.nameCardOrNick, it.memberName) + assertEquals(member.specialTitle, it.specialTitle) + assertEquals(member.permission, it.permission) + } + + postJsonData( + Paths.memberInfo, MemberInfoDTO( + target = group.id, + memberId = member.id, + info = MemberDetailDTO( + name = "new name", + specialTitle = "new special title", + ) + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + } + + client.get(Paths.memberInfo) { + parameter("target", group.id) + parameter("memberId", member.id) + }.body().also { + assertEquals("new name", it.memberName) + assertEquals("new special title", it.specialTitle) + } + } + + @Test + fun testMemberAdmin() = testHttpApplication { + val bot = SetupMockBot.instance() + val group = bot.addGroup(789, "test group") + val member = group.addMember(789, "test member") + + assertEquals(MemberPermission.MEMBER, member.permission) + + postJsonData(Paths.memberAdmin, ModifyAdminDTO( + target = group.id, + memberId = member.id, + assign = true + )).also { + assertEquals(StateCode.Success.code, it.code) + assertEquals(MemberPermission.ADMINISTRATOR, member.permission) + } + } +} \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/integration/action/InfoActionTest.kt b/mirai-api-http/src/test/kotlin/integration/action/InfoActionTest.kt new file mode 100644 index 00000000..7b83b76c --- /dev/null +++ b/mirai-api-http/src/test/kotlin/integration/action/InfoActionTest.kt @@ -0,0 +1,117 @@ +package integration.action + +import framework.ExtendWith +import framework.SetupMockBot +import framework.testHttpApplication +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.GroupDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.MemberDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.ProfileDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.QQDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.FriendList +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.GroupList +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.MemberList +import net.mamoe.mirai.contact.getMemberOrFail +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +@ExtendWith(SetupMockBot::class) +class InfoActionTest { + + @Test + fun testFriendLest() = testHttpApplication { + client.get(Paths.friendList).body().also { + assertEquals(StateCode.Success.code, it.code) + val data = it.data + assertEquals(2, data.size) + assertTrue(it.data.map(QQDTO::id).containsAll(listOf(SetupMockBot.BEST_FRIEND_ID, SetupMockBot.WORST_FRIEND_ID))) + } + } + + @Test + fun testGroupList() = testHttpApplication { + client.get(Paths.groupList).body().also { + assertEquals(StateCode.Success.code, it.code) + val data = it.data + assertEquals(2, data.size) + assertTrue(it.data.map(GroupDTO::id).containsAll(listOf(SetupMockBot.BEST_GROUP_ID, SetupMockBot.WORST_GROUP_ID))) + } + } + + @Test + fun testMemberList() = testHttpApplication { + client.get(Paths.memberList) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + }.body().also { + assertEquals(StateCode.Success.code, it.code) + val data = it.data + assertEquals(2, data.size) + assertTrue(it.data.map(MemberDTO::id).containsAll(listOf(SetupMockBot.BEST_MEMBER_ID, SetupMockBot.GOOD_MEMBER_ID))) + } + } + + @Test + fun testBotProfile() = testHttpApplication { + client.get(Paths.botProfile).body().also { + val profile = SetupMockBot.instance().asFriend.queryProfile() + assertEquals(profile.age, it.age) + assertEquals(profile.email, it.email) + assertEquals(profile.sex.name, it.sex) + assertEquals(profile.qLevel, it.level) + assertEquals(profile.nickname, it.nickname) + assertEquals(profile.sign, it.sign) + } + } + + @Test + fun testFriendProfile() = testHttpApplication { + client.get(Paths.friendProfile) { + parameter("target", SetupMockBot.BEST_FRIEND_ID) + }.body().also { + val profile = SetupMockBot.instance().getFriendOrFail(SetupMockBot.BEST_FRIEND_ID).queryProfile() + assertEquals(profile.age, it.age) + assertEquals(profile.email, it.email) + assertEquals(profile.sex.name, it.sex) + assertEquals(profile.qLevel, it.level) + assertEquals(profile.nickname, it.nickname) + assertEquals(profile.sign, it.sign) + } + } + + @Test + fun testMemberProfile() = testHttpApplication { + client.get(Paths.memberProfile) { + parameter("target", SetupMockBot.BEST_GROUP_ID) + parameter("memberId", SetupMockBot.BEST_MEMBER_ID) + }.body().also { + val profile = SetupMockBot.instance() + .getGroupOrFail(SetupMockBot.BEST_GROUP_ID) + .getMemberOrFail(SetupMockBot.BEST_MEMBER_ID).queryProfile() + assertEquals(profile.age, it.age) + assertEquals(profile.email, it.email) + assertEquals(profile.sex.name, it.sex) + assertEquals(profile.qLevel, it.level) + assertEquals(profile.nickname, it.nickname) + assertEquals(profile.sign, it.sign) + } + } + + @Test + fun testUserProfile() = testHttpApplication { + client.get(Paths.userProfile) { + parameter("target", SetupMockBot.BEST_FRIEND_ID) + }.body().also { + val profile = SetupMockBot.instance().getFriendOrFail(SetupMockBot.BEST_FRIEND_ID).queryProfile() + assertEquals(profile.age, it.age) + assertEquals(profile.email, it.email) + assertEquals(profile.sex.name, it.sex) + assertEquals(profile.qLevel, it.level) + assertEquals(profile.nickname, it.nickname) + assertEquals(profile.sign, it.sign) + } + } +} \ No newline at end of file diff --git a/mirai-api-http/src/test/kotlin/integration/action/MessageActionTest.kt b/mirai-api-http/src/test/kotlin/integration/action/MessageActionTest.kt new file mode 100644 index 00000000..c385753e --- /dev/null +++ b/mirai-api-http/src/test/kotlin/integration/action/MessageActionTest.kt @@ -0,0 +1,201 @@ +package integration.action + +import framework.ExtendWith +import framework.SetupMockBot +import framework.testHttpApplication +import io.ktor.client.call.* +import io.ktor.client.request.* +import kotlinx.coroutines.* +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.dto.parameter.SendDTO +import net.mamoe.mirai.api.http.adapter.internal.dto.parameter.SendRetDTO +import kotlin.test.* + +@ExtendWith(SetupMockBot::class) +class MessageActionTest { + + @Test + fun testMessageFromId() = testHttpApplication { + val msg = postJsonData( + Paths.sendFriendMessage, SendDTO( + target = SetupMockBot.BEST_FRIEND_ID, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.Success.code, it.code) } + + client.get(Paths.messageFromId) { + parameter("target", SetupMockBot.BEST_FRIEND_ID) + parameter("messageId", msg.messageId) + }.body().also { + assertEquals(StateCode.Success.code, it.code) + assertNotNull(it.data) + val data = assertIs(it.data) + assertEquals(SetupMockBot.ID, data.sender.id) + assertEquals(2, data.messageChain.size) + + val source = assertIs(data.messageChain[0]) + val plain = assertIs(data.messageChain[1]) + + assertEquals(msg.messageId, source.id) + assertEquals("Hello World", plain.text) + } + } + + @Test + fun testSendFriendMessage() = testHttpApplication { + + // 无指定对象 + postJsonData( + Paths.sendFriendMessage, SendDTO( + qq = null, + target = null, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + + // 找不到指定对象 + postJsonData( + Paths.sendFriendMessage, SendDTO( + target = 987654321L, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + + // 正常成功 + postJsonData( + Paths.sendFriendMessage, SendDTO( + qq = SetupMockBot.BEST_FRIEND_ID, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + assertNotEquals(-1, it.messageId) + } + // 正常成功 + postJsonData( + Paths.sendFriendMessage, SendDTO( + target = SetupMockBot.BEST_FRIEND_ID, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + assertNotEquals(-1, it.messageId) + } + + // 处理“陌生人”消息 + SetupMockBot.instance().addStranger(114514, "Stranger") + postJsonData( + Paths.sendFriendMessage, SendDTO( + qq = 114514, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + assertNotEquals(-1, it.messageId) + } + } + + @Test + fun testSendGroupMessage() = testHttpApplication { + // 无指定对象 + postJsonData( + Paths.sendGroupMessage, SendDTO( + group = null, + target = null, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + + // 找不到指定对象 + postJsonData( + Paths.sendGroupMessage, SendDTO( + target = 987654321L, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + + // 正常成功 + postJsonData( + Paths.sendGroupMessage, SendDTO( + group = SetupMockBot.BEST_GROUP_ID, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + assertNotEquals(-1, it.messageId) + } + // 正常成功 + postJsonData( + Paths.sendGroupMessage, SendDTO( + target = SetupMockBot.BEST_GROUP_ID, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + assertNotEquals(-1, it.messageId) + } + } + + @Test + fun testSendTempMessage() = testHttpApplication { + // 无指定对象 + postJsonData( + Paths.sendTempMessage, SendDTO( + group = null, + qq = null, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + + // 找不到指定对象 + postJsonData( + Paths.sendTempMessage, SendDTO( + group = SetupMockBot.BEST_GROUP_ID, + qq = null, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + + // 找不到指定对象 + postJsonData( + Paths.sendTempMessage, SendDTO( + group = null, + qq = SetupMockBot.BEST_MEMBER_ID, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + + // 正常成功 + postJsonData( + Paths.sendTempMessage, SendDTO( + group = SetupMockBot.BEST_GROUP_ID, + qq = SetupMockBot.BEST_MEMBER_ID, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { + assertEquals(StateCode.Success.code, it.code) + assertNotEquals(-1, it.messageId) + } + } + + @Test + fun testSendOtherClientMessage() = testHttpApplication { + // 无指定对象 + postJsonData( + Paths.sendTempMessage, SendDTO( + target = null, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + + // 找不到指定对象 + postJsonData( + Paths.sendTempMessage, SendDTO( + target = 0, + messageChain = listOf(PlainDTO("Hello World")) + ) + ).also { assertEquals(StateCode.NoElement.code, it.code) } + } +} \ No newline at end of file