diff --git a/build.gradle.kts b/build.gradle.kts index d612d5b..90d72b5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -105,6 +105,7 @@ subprojects { "testImplementation"("org.slf4j:slf4j-simple:2.0.4") "testImplementation"("io.github.artsok:rerunner-jupiter:2.1.6") "implementation"("com.goncalossilva:murmurhash:0.4.0") + "testImplementation"("io.mockk:mockk:1.13.4") } publishing { diff --git a/core/src/main/kotlin/dev/usbharu/multim/api/ApiClient.kt b/core/src/main/kotlin/dev/usbharu/multim/api/ApiClient.kt index e866b3f..8b03fe9 100644 --- a/core/src/main/kotlin/dev/usbharu/multim/api/ApiClient.kt +++ b/core/src/main/kotlin/dev/usbharu/multim/api/ApiClient.kt @@ -90,6 +90,8 @@ abstract class ApiClient(var baseUrl: String, val client: HttpClient) { return Err(HttpClientClientError(e)) } catch (e: ServerResponseException) { return Err(HttpClientServerError(e)) + } catch (e: Exception) { + return Err(ThrowableError(e)) } return Ok(Unit) @@ -100,15 +102,16 @@ abstract class ApiClient(var baseUrl: String, val client: HttpClient) { block: HttpRequestBuilder.() -> Unit ): Result { Logger.trace("Api Client", "Get $baseUrl$path") - return runCatching { - client.get( - baseUrl + path, - block - ) - }.fold(onSuccess = { Ok(it) }, onFailure = { + return try { + Ok(client.get(baseUrl + path, block)) + } catch (e: ClientRequestException) { + Err(HttpClientClientError(e)) + } catch (e: ServerResponseException) { + Err(HttpClientServerError(e)) + } catch (e: Exception) { Logger.warn("Api Client", "FAILURE Get $baseUrl$path") - Err(ThrowableError(it)) - }) + Err(ThrowableError(e)) + } } } diff --git a/core/src/test/kotlin/dev/usbharu/multim/TestUtil.kt b/core/src/test/kotlin/dev/usbharu/multim/TestUtil.kt index 65cf419..f939222 100644 --- a/core/src/test/kotlin/dev/usbharu/multim/TestUtil.kt +++ b/core/src/test/kotlin/dev/usbharu/multim/TestUtil.kt @@ -1,6 +1,7 @@ package dev.usbharu.multim import com.github.michaelbull.result.* +import dev.usbharu.multim.error.Error import dev.usbharu.multim.error.ErrorType import dev.usbharu.multim.error.MultiMResult import io.ktor.client.* @@ -72,11 +73,14 @@ object TestUtil { } - fun assertIsOk(result: Result<*, *>) { + fun assertIsOk(result: Result<*, Error>) { + result.getError()?.let { + Logger.warn("Test Util", "エラーが発生しました", it) + } assertInstanceOf(Ok::class.java, result, "resultの型がOkではない") } - inline fun assertIsErr(result: Result<*, T>) { + inline fun assertIsErr(result: Result<*, T>) { assertInstanceOf(Err::class.java, result, "resultの型がErrではない") assertInstanceOf(R::class.java, result.getError(), "Errorの型が違う") } diff --git a/core/src/test/kotlin/dev/usbharu/multim/api/ApiClientTest.kt b/core/src/test/kotlin/dev/usbharu/multim/api/ApiClientTest.kt index b2b8b4a..0dfecf7 100644 --- a/core/src/test/kotlin/dev/usbharu/multim/api/ApiClientTest.kt +++ b/core/src/test/kotlin/dev/usbharu/multim/api/ApiClientTest.kt @@ -18,33 +18,40 @@ import org.junit.jupiter.api.Test @OptIn(ExperimentalCoroutinesApi::class) abstract class ApiClientTest { - abstract var apiClient: ApiClient + abstract val apiClient: ApiClient + val postEmpty_emptyRequest_returnOk = "postEmpty/emptyRequest/returnOk" @Test - open fun postEmpty_emptyRequest_returnOk() = runTest { - val postEmpty = apiClient.postEmpty("postEmpty/emptyRequest/returnOk") - assertIsOk(postEmpty) + open fun postEmpty_emptyRequest_returnOk() { + runTest { + val postEmpty = apiClient.postEmpty(postEmpty_emptyRequest_returnOk) + assertIsOk(postEmpty) + } } + val postEmpty_illegalRequest_returnErr = "postEmpty/illegalRequest/returnErr" @Test - open fun postEmpty_illegalRequest_returnErr() = runTest { - val postEmpty = apiClient.postEmpty("postEmpty/illegalRequest/returnErr") - assertInstanceOf(Err::class.java, postEmpty, "返り値がErr型ではない") - assertInstanceOf( - HttpClientClientError::class.java, - (postEmpty as Err).error, - "ErrorがHttpClientClientError型ではない" - ) - assertInstanceOf( - ClientRequestException::class.java, - postEmpty.error.throwable, - "throwableがClientRequestException型ではない" - ) + open fun postEmpty_illegalRequest_returnErr() { + runTest { + val postEmpty = apiClient.postEmpty(postEmpty_illegalRequest_returnErr) + assertInstanceOf(Err::class.java, postEmpty, "返り値がErr型ではない") + assertInstanceOf( + HttpClientClientError::class.java, + (postEmpty as Err).error, + "ErrorがHttpClientClientError型ではない" + ) + assertInstanceOf( + ClientRequestException::class.java, + postEmpty.error.throwable, + "throwableがClientRequestException型ではない" + ) + } } + val postEmpty_serverError_returnErr = "postEmpty/serverError/returnErr" @Test fun postEmpty_serverError_returnErr() = runTest { - val postEmpty = apiClient.postEmpty("postEmpty/serverError/returnErr") + val postEmpty = apiClient.postEmpty(postEmpty_serverError_returnErr) assertInstanceOf(Err::class.java, postEmpty, "返り値がErr型ではない") assertInstanceOf( HttpClientServerError::class.java, @@ -58,79 +65,105 @@ abstract class ApiClientTest { ) } + val post_request_returnOkWithEchoBody = "post/request/returnOkWithEchoBody" @Test - fun post_request_returnOkWithEchoBody() = runTest { - val expectBody = PostEmptyData("957a29f2-03bc-4856-b880-3ef42fbc4c77") - val actual = apiClient.post( - expectBody, - "post/request/returnOkWithEchoBody" - ) - assertIsOk(actual) - assertEquals(expectBody, actual.get()) + fun post_request_returnOkWithEchoBody() { + runTest { + val expectBody = PostEmptyData("957a29f2-03bc-4856-b880-3ef42fbc4c77") + val actual = apiClient.post( + expectBody, + post_request_returnOkWithEchoBody + ) + assertIsOk(actual) + assertEquals(expectBody, actual.get()) + } } + val post_IllegalRequest_returnErr = "post/illegalRequest/returnErr" @Test - fun post_illegalRequest_returnErr() = runTest { - val body = PostEmptyData("1974d2a0-552e-442d-a60c-07ab410d4e44") - val actual = apiClient.post( - body, - "post/illegalRequest/returnErr" - ) - assertIsErr(actual) + fun post_illegalRequest_returnErr() { + runTest { + val body = PostEmptyData("1974d2a0-552e-442d-a60c-07ab410d4e44") + val actual = apiClient.post( + body, + post_IllegalRequest_returnErr + ) + assertIsErr(actual) + } } + val post_serverError_returnErr = "post/serverError/returnErr" @Test - fun post_serverError_returnErr() = runTest { - val body = PostEmptyData("3a84e1a1-5323-4158-824d-ccf9efee0bf7") - val actual = apiClient.post( - body, - "post/serverError/returnErr" - ) - assertIsErr(actual) + fun post_serverError_returnErr() { + runTest { + val body = PostEmptyData("3a84e1a1-5323-4158-824d-ccf9efee0bf7") + val actual = apiClient.post( + body, + post_serverError_returnErr + ) + assertIsErr(actual) + } } - + val postWithoutResponse_request_returnOk = "postWithoutResponse/request/returnOk" @Test - fun postWithoutResponse_request_returnOk() = runTest { - val body = PostEmptyData("497676e7-731b-42cb-bc44-dee573858e66") - val actual = - apiClient.postWithoutResponse(body, "postWithoutResponse/request/returnOk") - assertIsOk(actual) + fun postWithoutResponse_request_returnOk() { + runTest { + val body = PostEmptyData("497676e7-731b-42cb-bc44-dee573858e66") + val actual = + apiClient.postWithoutResponse(body, postWithoutResponse_request_returnOk) + assertIsOk(actual) + } } + val postWithoutResponse_IllegalRequest_returnErr = "postWithoutResponse/illegalRequest/returnErr" @Test - fun postWithoutResponse_illegalRequest_returnErr() = runTest { - val body = PostEmptyData("20b04325-1386-4076-8068-fb6370ba6150") - val actual = - apiClient.postWithoutResponse(body, "postWithoutResponse/illegalRequest/returnErr") - assertIsErr(actual) + fun postWithoutResponse_illegalRequest_returnErr() { + runTest { + val body = PostEmptyData("20b04325-1386-4076-8068-fb6370ba6150") + val actual = + apiClient.postWithoutResponse(body, postWithoutResponse_IllegalRequest_returnErr) + assertIsErr(actual) + } } + val postWithoutResponse_serverError_returnErr = "postWithoutResponse/serverError/returnErr" @Test - fun postWithoutResponse_serverError_returnErr() = runTest { - val body = PostEmptyData("5ef770aa-b228-4b02-90dd-1c1866933f16") - val actual = - apiClient.postWithoutResponse(body, "postWithoutResponse/serverError/returnErr") - assertIsErr(actual) + fun postWithoutResponse_serverError_returnErr() { + runTest { + val body = PostEmptyData("5ef770aa-b228-4b02-90dd-1c1866933f16") + val actual = + apiClient.postWithoutResponse(body, postWithoutResponse_serverError_returnErr) + assertIsErr(actual) + } } + val get_request_returnOk = "get/request/returnOk" @Test - fun get_request_returnOk() = runTest { - val expectBody = PostEmptyData("43c56ee1-ad7a-418e-9411-2fcb61b34cf9") - val actual = apiClient.get("get/request/returnOk") {} - assertIsOk(actual) - assertEquals(expectBody, actual.get()?.body()) + fun get_request_returnOk() { + runTest { + val expectBody = PostEmptyData("43c56ee1-ad7a-418e-9411-2fcb61b34cf9") + val actual = apiClient.get(get_request_returnOk) {} + assertIsOk(actual) + assertEquals(expectBody, actual.get()?.body()) + } } + val get_IllegalRequest_returnErr = "get/illegalRequest/returnErr" @Test - fun get_illegalRequest_returnErr() = runTest { - val actual = apiClient.get("get/illegalRequest/returnErr") {} - assertIsErr(actual) + fun get_illegalRequest_returnErr() { + runTest { + val actual = apiClient.get(get_IllegalRequest_returnErr) {} + assertIsErr(actual) + } } + val get_serverError_returnErr = "get/serverError/returnErr" @Test - fun get_serverError_returnErr() = runTest { - val actual = apiClient.get("get/serverError/returnErr") {} - assertIsErr(actual) + fun get_serverError_returnErr() { + runTest { + val actual = apiClient.get(get_serverError_returnErr) {} + assertIsErr(actual) + } } @Serializable diff --git a/impl/misskey/src/main/kotlin/dev/usbharu/multim/misskey/v12/common/api/MisskeyApiClient.kt b/impl/misskey/src/main/kotlin/dev/usbharu/multim/misskey/v12/common/api/MisskeyApiClient.kt index 6eb0edd..3b10d33 100644 --- a/impl/misskey/src/main/kotlin/dev/usbharu/multim/misskey/v12/common/api/MisskeyApiClient.kt +++ b/impl/misskey/src/main/kotlin/dev/usbharu/multim/misskey/v12/common/api/MisskeyApiClient.kt @@ -22,6 +22,7 @@ import kotlinx.serialization.encodeToString class MisskeyApiClient(var auth: SingleTokenAuth, baseUrl: String, client: HttpClient) : ApiClient(baseUrl, client.config { + expectSuccess = true install(WebSockets) { pingInterval = 20_000 contentConverter = KotlinxWebsocketSerializationConverter(json) diff --git a/impl/misskey/src/main/kotlin/dev/usbharu/multim/misskey/v12/model/UsersNotes.kt b/impl/misskey/src/main/kotlin/dev/usbharu/multim/misskey/v12/model/UsersNotes.kt index fd4dc8c..c703d0a 100644 --- a/impl/misskey/src/main/kotlin/dev/usbharu/multim/misskey/v12/model/UsersNotes.kt +++ b/impl/misskey/src/main/kotlin/dev/usbharu/multim/misskey/v12/model/UsersNotes.kt @@ -1,5 +1,6 @@ package dev.usbharu.multim.misskey.v12.model +import dev.usbharu.multim.misskey.v12.model.components.MisskeyNeedAuth import dev.usbharu.multim.misskey.v12.model.components.Note import kotlinx.serialization.Serializable @@ -16,7 +17,7 @@ data class UsersNotesRequest( val withFile: Boolean? = false, val fileType: List = emptyList(), val excludeNsfw: Boolean = false -) +) : MisskeyNeedAuth() typealias UsersNotesResponse = List diff --git a/impl/misskey/src/test/kotlin/MisskeyTestUtil.kt b/impl/misskey/src/test/kotlin/MisskeyTestUtil.kt index 317a7bc..5efbcf9 100644 --- a/impl/misskey/src/test/kotlin/MisskeyTestUtil.kt +++ b/impl/misskey/src/test/kotlin/MisskeyTestUtil.kt @@ -2,15 +2,19 @@ import com.github.michaelbull.result.Err import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Result import com.github.michaelbull.result.getError +import dev.usbharu.multim.misskey.v12.common.api.MisskeyApiClient import dev.usbharu.multim.misskey.v12.model.components.Note import dev.usbharu.multim.misskey.v12.model.components.UserLite +import dev.usbharu.multim.model.SingleTokenAuth import io.ktor.client.* import io.ktor.client.engine.mock.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* +import io.mockk.InternalPlatformDsl.toStr import kotlinx.datetime.Clock +import kotlinx.serialization.SerializationStrategy import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonObject @@ -21,6 +25,43 @@ object MisskeyTestUtil { val json = Json { ignoreUnknownKeys = true;isLenient = true } + val baseUrl = "https://localhsot/" + + internal fun apiClient(httpClient: HttpClient): MisskeyApiClient { + return MisskeyApiClient(SingleTokenAuth("cdgj2h71"), baseUrl, httpClient) + } + + inline fun createMockHttpClient( + content: T, + checkAuth: Boolean, + url: String? = null, + serializer:SerializationStrategy, + statusCode: HttpStatusCode = HttpStatusCode.OK, + ): HttpClient { + return HttpClient(MockEngine { + if (!checkAuth || "i" in json.parseToJsonElement(it.body.toByteArray().decodeToString()).jsonObject) { + //ok + } else { + Fail.fail("No auth.") + } + if (url == null || it.url.toStr() == url) { + //ok + }else { + Fail.fail("Illegal URL expected: $url actual: ${it.url.toStr()}") + } + + respond( + content = json.encodeToString(serializer,content), + status = statusCode, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + }) { + install(ContentNegotiation) { + json(json) + } + } + } + fun createMockHttpClient( content: String = "", contentType: String = "application/json", diff --git a/impl/misskey/src/test/kotlin/dev/usbharu/multim/api/MisskeyApiClientTest.kt b/impl/misskey/src/test/kotlin/dev/usbharu/multim/api/MisskeyApiClientTest.kt new file mode 100644 index 0000000..51485b0 --- /dev/null +++ b/impl/misskey/src/test/kotlin/dev/usbharu/multim/api/MisskeyApiClientTest.kt @@ -0,0 +1,89 @@ +package dev.usbharu.multim.api + +import MisskeyTestUtil +import dev.usbharu.multim.Logger +import io.ktor.client.* +import io.ktor.client.engine.mock.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* +import kotlinx.serialization.encodeToString + +class MisskeyApiClientTest : ApiClientTest() { + override val apiClient: ApiClient + get() { + return MisskeyTestUtil.apiClient(HttpClient(MockEngine { + when (it.url.encodedPath.replaceFirst("/", "")) { + postEmpty_emptyRequest_returnOk -> { + respond(PostEmptyData("data")) + } + + postEmpty_illegalRequest_returnErr -> { + respondBadRequest() + } + + postEmpty_serverError_returnErr -> { + respondError(HttpStatusCode.NotImplemented) + } + + post_request_returnOkWithEchoBody -> { + respond(it.body.toByteArray().decodeToString(), HttpStatusCode.OK, headersOf(HttpHeaders.ContentType,"application/json")) + } + + post_IllegalRequest_returnErr -> { + respondBadRequest() + } + + post_serverError_returnErr -> { + respondError(HttpStatusCode.NotImplemented) + } + + postWithoutResponse_request_returnOk -> { + respondOk() + } + + postWithoutResponse_IllegalRequest_returnErr -> { + respondBadRequest() + } + + postWithoutResponse_serverError_returnErr -> { + respondError(HttpStatusCode.NotImplemented) + } + + get_request_returnOk -> { + respond(PostEmptyData("43c56ee1-ad7a-418e-9411-2fcb61b34cf9")) + } + + get_IllegalRequest_returnErr -> { + respondBadRequest() + } + + get_serverError_returnErr -> { + respondError(HttpStatusCode.NotImplemented) + } + + else -> { + Logger.error("不明なエンドポイント ${it.url.encodedPath}") + respondBadRequest() + } + } + }) { + install(ContentNegotiation) { + json(MisskeyTestUtil.json, ContentType.Any) + } + }) + } + + private fun PostEmptyData.toJson(): String { + return DefaultJson.encodeToString(this) + } + + private fun MockRequestHandleScope.respond( + postEmptyData: PostEmptyData, + statusCode: HttpStatusCode = HttpStatusCode.OK, + headers: Headers = headersOf(HttpHeaders.ContentType, "application/json") + ): HttpResponseData { + return respond(postEmptyData.toJson(), statusCode, headers) + } +} diff --git a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/ApTest.kt b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/ApTest.kt index 551ff8d..5bf59dc 100644 --- a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/ApTest.kt +++ b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/ApTest.kt @@ -5,30 +5,26 @@ package dev.usbharu.multim.misskey.v12.api import MisskeyTestUtil.createFakeNoteToString import MisskeyTestUtil.createMockHttpClient import MisskeyTestUtil.json -import dev.usbharu.multim.MultiM import dev.usbharu.multim.TestUtil.failOnError import dev.usbharu.multim.misskey.v12.common.api.MisskeyApiClient import dev.usbharu.multim.misskey.v12.model.ApShowRequest import dev.usbharu.multim.misskey.v12.model.ApShowResponse -import dev.usbharu.multim.misskey.v12.model.NotesNotesRequest +import dev.usbharu.multim.misskey.v12.model.components.Note +import dev.usbharu.multim.misskey.v12.model.components.UserDetailedNotMe +import dev.usbharu.multim.misskey.v12.model.components.UserLite import dev.usbharu.multim.model.SingleTokenAuth -import io.github.artsok.RepeatedIfExceptionsTest +import io.ktor.client.* import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.delay -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest +import kotlinx.datetime.Instant import kotlinx.serialization.decodeFromString -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test +@OptIn(ExperimentalCoroutinesApi::class) class ApTest { - - val misskeyApiClient = MisskeyApiClient( - SingleTokenAuth(System.getProperty("multim_misskey_token")), - System.getProperty("multim_misskey_instance"), - MultiM.httpClientWithJson.config {} - ) + val baseUrl = "https://localhost/" @Test fun show_showUserMockRequest_respondTypeUser() = runTest { @@ -54,6 +50,71 @@ class ApTest { } + @Test + fun show_userUrl_returnUser() = runTest { + val userDetailedNotMe = UserDetailedNotMe( + id = "Xqxv", + name = "fakeUser", + username = "fakeUserName", + host = "example.com", + avatarUrl = "https://example.com", + avatarBlurhash = "jvwxIWI", + avatarColor = null, + isAdmin = false, + isModerator = false, + isBot = false, + isCat = false, + emojis = emptyList(), + onlineStatus = "unknown", + url = "https://example.com", + uri = "https://example.com", + createdAt = Instant.parse("2023-03-07T20:33:58.868Z"), + updatedAt = Instant.parse("2023-03-07T20:33:58.868Z"), + lastFetchedAt = Instant.parse("2023-03-07T20:33:58.868Z"), + bannerUrl = null, + bannerBlurhash = null, + bannerColor = null, + isLocked = false, + isSilenced = false, + isSuspended = false, + description = "fake user deskription", + location = null, + birthday = null, + lang = null, + fields = emptyList(), + followersCount = 1, + followingCount = 1, + notesCount = 10, + pinnedNoteIds = emptyList(), + pinnedNotes = emptyList(), + pinnedPageId = null, + pinnedPage = null, + publicReactions = false, + twoFactorEnabled = false, + usePasswordLessLogin = false, + securityKeys = false, + isFollowing = true, + isFollowed = true, + hasPendingFollowRequestFromYou = false, + hasPendingFollowRequestToYou = false, + isBlocking = false, + isBlocked = false, + isMuted = false + ) + val typeUser = ApShowResponse.TypeUser(userDetailedNotMe) + + val apShowResponse = Ap( + apiClient( + createMockHttpClient( + typeUser, + false, + baseUrl + "api/ap/show", ApShowResponse.serializer() + ) + ) + ).show(ApShowRequest("https://example.com")).failOnError() + assertEquals(typeUser, apShowResponse) + } + @Test fun show_showNoteRequestMock_respondTypeNote() = runTest { val typeNote = """ @@ -70,44 +131,66 @@ class ApTest { Ap(misskeyApiClient).show(ApShowRequest("https://localhost/test/C56WI")).failOnError() assertEquals(json.decodeFromString(typeNote), show) } -} - -class ApTestE2E { - val misskeyApiClient = MisskeyApiClient( - SingleTokenAuth(System.getProperty("multim_misskey_token")), - System.getProperty("multim_misskey_instance"), - MultiM.httpClientWithJson.config {} - ) - - @RepeatedIfExceptionsTest(repeats = 4) -// @Test - fun show_showUserRequest_respondTypeUser() = runBlocking { - val show = - Ap(misskeyApiClient).show( - ApShowRequest( - System.getProperty("multim_misskey_instance") + "@" + I( - misskeyApiClient - ).i().failOnError().username + @Test + fun show_noteUrl_returnNote() = runTest { + val note = Note( + id = "rKiw2x4", + createdAt = Instant.parse("2023-03-07T20:33:58.868Z"), + text = "fake note", + cw = null, + userId = "A7pFuM", + user = UserLite( + id = "A7pFuM", + name = "fakeUser", + username = "fakeUsername", + host = "example.com", + avatarUrl = "https://exapmple.com", + avatarBlurhash = "CpIBR1B", + avatarColor = null, + isAdmin = false, + isModerator = false, + isBot = false, + isCat = false, + emojis = emptyList(), + onlineStatus = "online" + ), + replyId = null, + renoteId = null, + reply = null, + renote = null, + isHidden = false, + visibility = "public", + mentions = emptyList(), + visibleUserIds = emptyList(), + fileIds = emptyList(), + files = emptyList(), + tags = emptyList(), + poll = null, + channelId = null, + channel = null, + localOnly = false, + emojis = emptyList(), + reactions = emptyMap(), + renoteCount = 0, repliesCount = 0, uri = "https://example.com/asjfl" + ) + val typeNote = ApShowResponse.TypeNote(note) + val apShowResponse = + Ap( + apiClient( + createMockHttpClient( + typeNote, + true, + baseUrl + "api/ap/show", + ApShowResponse.serializer() + ) ) - ) - .failOnError() - delay(1000) - assertInstanceOf(ApShowResponse.TypeUser::class.java, show) + ).show(ApShowRequest("https://example.com/test/afasfa")).failOnError() + + assertEquals(typeNote, apShowResponse) } - @RepeatedIfExceptionsTest(repeats = 4) -// @Test - fun show_showNoteRequest_respondTypeNote() = runBlocking { - val show = - Ap(misskeyApiClient).show( - ApShowRequest( - Notes(misskeyApiClient).notes(NotesNotesRequest()).failOnError().first().uri - ?: fail() - ) - ) - .failOnError() - delay(1000) - assertInstanceOf(ApShowResponse.TypeNote::class.java, show) + private fun apiClient(httpClient: HttpClient): MisskeyApiClient { + return MisskeyApiClient(SingleTokenAuth("cdgj2h71"), baseUrl, httpClient) } } diff --git a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/ApTestE2E.kt b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/ApTestE2E.kt new file mode 100644 index 0000000..b832641 --- /dev/null +++ b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/ApTestE2E.kt @@ -0,0 +1,53 @@ +package dev.usbharu.multim.misskey.v12.api + +import dev.usbharu.multim.MultiM +import dev.usbharu.multim.TestUtil.failOnError +import dev.usbharu.multim.misskey.v12.common.api.MisskeyApiClient +import dev.usbharu.multim.misskey.v12.model.ApShowRequest +import dev.usbharu.multim.misskey.v12.model.ApShowResponse +import dev.usbharu.multim.misskey.v12.model.NotesNotesRequest +import dev.usbharu.multim.model.SingleTokenAuth +import io.github.artsok.RepeatedIfExceptionsTest +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions + +class ApTestE2E { + + val misskeyApiClient = MisskeyApiClient( + SingleTokenAuth(System.getProperty("multim_misskey_token")), + System.getProperty("multim_misskey_instance"), + MultiM.httpClientWithJson.config {} + ) + + @RepeatedIfExceptionsTest(repeats = 4) +// @Test + fun show_showUserRequest_respondTypeUser() = runBlocking { + val show = + Ap(misskeyApiClient).show( + ApShowRequest( + System.getProperty("multim_misskey_instance") + "@" + I( + misskeyApiClient + ).i().failOnError().username + ) + ) + .failOnError() + delay(1000) + Assertions.assertInstanceOf(ApShowResponse.TypeUser::class.java, show) + } + + @RepeatedIfExceptionsTest(repeats = 4) +// @Test + fun show_showNoteRequest_respondTypeNote() = runBlocking { + val show = + Ap(misskeyApiClient).show( + ApShowRequest( + Notes(misskeyApiClient).notes(NotesNotesRequest()).failOnError().first().uri + ?: Assertions.fail() + ) + ) + .failOnError() + delay(1000) + Assertions.assertInstanceOf(ApShowResponse.TypeNote::class.java, show) + } +} diff --git a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/MetaTest.kt b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/MetaTest.kt index 3070c37..709bf89 100644 --- a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/MetaTest.kt +++ b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/MetaTest.kt @@ -1,28 +1,75 @@ package dev.usbharu.multim.misskey.v12.api -import dev.usbharu.multim.MultiM +import MisskeyTestUtil.apiClient +import MisskeyTestUtil.baseUrl +import MisskeyTestUtil.createMockHttpClient import dev.usbharu.multim.TestUtil.failOnError -import dev.usbharu.multim.misskey.v12.common.api.MisskeyApiClient import dev.usbharu.multim.misskey.v12.model.MetaRequest -import dev.usbharu.multim.model.SingleTokenAuth +import dev.usbharu.multim.misskey.v12.model.MetaResponse import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test -class MetaTest - @OptIn(ExperimentalCoroutinesApi::class) -class MetaTestE2E { - - val misskeyApiClient = MisskeyApiClient( - SingleTokenAuth(System.getProperty("multim_misskey_token")), - System.getProperty("multim_misskey_instance"), - MultiM.httpClientWithJson.config {} - ) +class MetaTest { @Test - fun meta() = runTest { - val meta = Meta(misskeyApiClient).meta(MetaRequest()).failOnError() + fun meta_detailTrue_returnMeta() = runTest { + val metaResponse = MetaResponse( + maintainerName = "maintainerName", + maintainerEmail = "maintainer@example.com", + version = "12.119.2", + name = "misskey", + uri = "https://example.com", + description = "test instance", + langs = emptyList(), + tosUrl = null, + repositoryUrl = "https://example.com", + feedbackUrl = "https://example.com", + defaultDarkTheme = "darkTheme", + defaultLightTheme = "lightTheme", + disableRegistration = false, + disableLocalTimeline = false, + disableGlobalTimeline = false, + driveCapacityPerLocalUserMb = 1000L, + cacheRemoteFiles = true, + emailRequiredForSignup = false, + enableHcaptcha = false, + hcaptchaSiteKey = null, + enableRecaptcha = false, + recaptchaSiteKey = null, + swPublickey = null, + mascotImageUrl = "/assets/ai.png", + bannerUrl = null, + errorImageUrl = "https://example.com", + iconUrl = null, + maxNoteTextLength = 3000, + emojis = emptyList(), + ads = emptyList(), + requireSetup = false, + enableEmail = false, + enableTwitterIntegration = false, + enableGithubIntegration = false, + enableDiscordIntegration = false, + enableServiceWorker = false, + translatorAvailable = false, + proxyAccountName = "proxy", + features = null + ) + + val response = Meta( + apiClient( + createMockHttpClient( + metaResponse, + false, + baseUrl + "api/meta", + MetaResponse.serializer() + ) + ) + ).meta( + MetaRequest() + ).failOnError() + assertEquals(metaResponse,response) } } diff --git a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/MetaTestE2E.kt b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/MetaTestE2E.kt new file mode 100644 index 0000000..4f6dca7 --- /dev/null +++ b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/MetaTestE2E.kt @@ -0,0 +1,25 @@ +package dev.usbharu.multim.misskey.v12.api + +import dev.usbharu.multim.MultiM +import dev.usbharu.multim.TestUtil.failOnError +import dev.usbharu.multim.misskey.v12.common.api.MisskeyApiClient +import dev.usbharu.multim.misskey.v12.model.MetaRequest +import dev.usbharu.multim.model.SingleTokenAuth +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Test + +@OptIn(ExperimentalCoroutinesApi::class) +class MetaTestE2E { + + val misskeyApiClient = MisskeyApiClient( + SingleTokenAuth(System.getProperty("multim_misskey_token")), + System.getProperty("multim_misskey_instance"), + MultiM.httpClientWithJson.config {} + ) + + @Test + fun meta() = runTest { + val meta = Meta(misskeyApiClient).meta(MetaRequest()).failOnError() + } +} diff --git a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/NotesTest.kt b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/NotesTest.kt index 9e689d6..4aa47d8 100644 --- a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/NotesTest.kt +++ b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/NotesTest.kt @@ -7,12 +7,10 @@ import MisskeyTestUtil.createFakeNote import MisskeyTestUtil.createMockHttpClient import MisskeyTestUtil.json import com.github.michaelbull.result.* -import dev.usbharu.multim.MultiM import dev.usbharu.multim.TestUtil.failOnError import dev.usbharu.multim.misskey.v12.common.api.MisskeyApiClient import dev.usbharu.multim.misskey.v12.model.* import dev.usbharu.multim.model.SingleTokenAuth -import io.github.artsok.RepeatedIfExceptionsTest import io.ktor.client.* import io.ktor.client.engine.mock.* import io.ktor.client.plugins.* @@ -23,9 +21,7 @@ import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant import kotlinx.serialization.encodeToString import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows import java.util.* @OptIn(ExperimentalCoroutinesApi::class) @@ -184,304 +180,3 @@ class NotesTest { ) ) } - -class NotesTestE2E { - - private val client = MisskeyApiClient( - SingleTokenAuth(System.getProperty("multim_misskey_token")), - System.getProperty("multim_misskey_instance"), - MultiM.httpClientWithJson.config {} - ) - private val notes = Notes(client) - private val drive = Drive(client) - - @Test - fun globalTimeline() = runTest { - notes.globalTimeline(NotesGlobalTimelineRequest()).failOnError() - } - - @Test - fun hybridTimeline() = runTest { - notes.hybridTimeline(NotesHybridTimelineRequest()).failOnError() - } - - @Test - fun localTimeline() = runTest { - notes.localTimeline(NotesLocalTimelineRequest()).failOnError() - } - - @Test - fun show() = runTest { - val show = - notes.show(NotesShowRequest(notes.notes(NotesNotesRequest()).failOnError().first().id)) - .failOnError() - - } - - @Test - fun create() = runTest { - notes.create( - NotesCreateRequest( - visibility = NotesCreateRequest.Visibility.HOME, - text = "このノートはMultim のテストで作成されました。${this@NotesTestE2E::class} create Test" - ) - ).failOnError() - } - - @Test - fun createWithFile() = runTest { - val encode: ByteArray = withContext(Dispatchers.IO) { - NotesTestE2E::class.java.classLoader.getResourceAsStream("notes/create/files/note_with_file_test.jpg")!! - .readBytes() - } - - val driveFile = drive.Files().create(DriveFilesCreateRequest(file = encode)) - val createdNote = notes.create( - NotesCreateRequest( - text = "このノートはMultiMのテストで作成され、ファイル添付のテストで使用されます。", - fileIds = setOf(driveFile.id) - ) - ).failOnError() - - assertEquals(driveFile, createdNote.createdNote.files?.firstOrNull()) - } - - @Test - fun createWithPoll() = runTest { - val poll = NotesCreateRequest.Poll(choices = setOf("a", "b", "c")) - val create = notes.create( - NotesCreateRequest( - text = "このノートはMultiMのテストで作成され、投票付きノートの作成で使用されます。 ${this@NotesTestE2E::class} create note with poll", - poll = poll - ) - ).failOnError() - assertEquals(poll.choices.map { it }, create.createdNote.poll?.choices?.map { it.text }) - } - - @Test - fun delete() = runTest { - val create = notes.create( - NotesCreateRequest( - visibility = NotesCreateRequest.Visibility.HOME, - text = "このノートはMultim のテストで作成され、削除される予定です。 ${this@NotesTestE2E::class} delete Test" - ) - ) - val deleteNote = when (create) { - is Ok -> create.value.createdNote.id - is Err -> fail(create.error.message, create.error._throwable) - } - notes.delete(NotesDeleteRequest(deleteNote)) - assertInstanceOf(Err::class.java, notes.show(NotesShowRequest(deleteNote))) - //消せていたら失敗する - - } - - @Test - fun featured() = runTest { - notes.featured().failOnError() - } - - @Test - fun children() = runTest { - val create = - notes.create(NotesCreateRequest(text = "このノートはMultiMのテストで作成され、子ノート取得のテストで使用されます。${this@NotesTestE2E::class} children")) - val id = create.failOnError().createdNote.id - val children = notes.children(NotesChildrenRequest(id)).failOnError() - } - - @Test - fun conversation() = runTest { - val create = - notes.create(NotesCreateRequest(text = "このノートはMultiMのテストで作成され、関連ノート取得のテストで使用されます。 ${this@NotesTestE2E::class} conversation")) - .failOnError() - val conversation = - notes.conversation(NotesConversationRequest(create.createdNote.id)).failOnError() - } - - @Test - fun state() = runTest { - val create = notes.create(NotesCreateRequest(text="このノートはMultiMのテストで作成され、ノートの状態を取得するテストで使用されます。 ${this@NotesTestE2E::class} state")).failOnError() - val state = notes.state(NotesStateRequest(create.createdNote.id)).failOnError() - } - - @Test - fun favoritesCreate() = runTest { - val create = - notes.create(NotesCreateRequest(text = "このノートはMultim のテストで作成され、お気に入り登録のテストで使用されます。 ${this@NotesTestE2E::class} favorites create test")) - .failOnError() - NotesFavoritesCreateRequest(create.createdNote.id) - .let { notes.Favorites().create(it) } - assertTrue( - NotesStateRequest(create.createdNote.id) - .let { notes.state(it).failOnError().isFavorited }) -//todo ネストがやばいことになってるのでnullが返ってきた時点で失敗にする - } - - @Test - fun favoritesDelete() = runTest { - val result = - notes.create(NotesCreateRequest(text = "このノートはMultim のテストで作成され、お気に入り削除のテストで使用されます。 ${this@NotesTestE2E::class} favorites delete test")) - val create = - when (result) { - is Ok -> result.value - is Err -> fail(result.error.message, result.error._throwable) - } - notes.Favorites().create(NotesFavoritesCreateRequest(create.createdNote.id)) - assertTrue(notes.state(NotesStateRequest(create.createdNote.id)).failOnError().isFavorited) - notes.Favorites().delete(NotesFavoritesDeleteRequest(create.createdNote.id)) - assertFalse( - notes.state(NotesStateRequest(create.createdNote.id)).failOnError().isFavorited - ) - } - - @Test - fun mentions() = runTest { - val mentions = notes.mentions(NotesMentionsRequest()).failOnError() - } - - @Test - fun reactions() = runTest { - val create = notes.create(NotesCreateRequest(text = "このノートはMultiMのテストで作成され、リアクション取得のテストで使用されます。 ${this@NotesTestE2E::class} reactions")).failOnError() - val reactions = notes.reactions(NotesReactionsRequest(create.createdNote.id)) - } - - @Test - fun renotes() = runTest { - val create = - notes.create(NotesCreateRequest(text = "このノートはMultim のテストで作成され、リノートのテストで使用されます。 ${this@NotesTestE2E::class} renotes test")) - .failOnError() - val notesCreateResponse = - notes.create(NotesCreateRequest(renoteId = create.createdNote.id)).failOnError() - val renotes = NotesRenoteRequest(create.createdNote.id) - .let { notes.renotes(it) }.failOnError() - assertEquals(listOf(notesCreateResponse.createdNote), renotes) - } - - @Test - fun replies() = runTest { - val root = - notes.create(NotesCreateRequest(text = "このノートはMultim のテストで作成され、返信取得のテストで使用されます。 ${this@NotesTestE2E::class} replies test")) - .failOnError() - val reply1 = notes.create( - NotesCreateRequest( - text = "返信1 このノートはMultimのテストで作成され、返信取得のテストで使用されます。 ${this@NotesTestE2E::class} replies test", - replyId = root.createdNote.id - ) - ).failOnError() - val reply2 = notes.create( - NotesCreateRequest( - text = "返信2 このノートはMultimのテストで作成され、返信取得のテストで使用されます。 ${this@NotesTestE2E::class} replies test", - replyId = root.createdNote.id - ) - ).failOnError() - val replies = root.createdNote.id.let { NotesRepliesRequest(it) } - .let { notes.replies(it) }.failOnError() - assertEquals( - listOf(reply1.createdNote, reply2.createdNote).sortedBy { note -> note.id }, - replies.sortedBy { note -> note.id }) - } - - @Test - fun searchByTag() = runTest { - val tag = UUID.randomUUID().toString() - val tagedNote = - notes.create(NotesCreateRequest(text = "#$tag このノートはMultimのテストで作成され、タグ検索のテストで使用されます。 ${this@NotesTestE2E::class} search by tag test")) - .failOnError() - val searchByTag = notes.searchByTag(NotesSearchByTagRequest(tag)).failOnError() - org.assertj.core.api.Assertions.assertThat(searchByTag)?.isNotEmpty - assertTrue(searchByTag.contains(tagedNote.createdNote)) - } - - @Test - fun threadMutingCreate() = runTest { - val create = - notes.create(NotesCreateRequest(text = "このノートはMultimのテストで作成され、スレッドミュートのテストで使用されます。 ${this@NotesTestE2E::class} thread mute create test")) - .failOnError() - assertFalse( - NotesStateRequest(create.createdNote.id) - .let { notes.state(it).failOnError().isMutedThread }) - NotesThreadMutingCreateRequest(create.createdNote.id) - .let { notes.ThreadMuting().create(it) } - assertTrue( - NotesStateRequest(create.createdNote.id) - .let { notes.state(it).failOnError().isMutedThread }) - } - - @Test - fun threadMutingDelete() = runTest { - val create = - notes.create(NotesCreateRequest(text = "このノートはMultimのテストで作成され、スレッドミュート解除のテストで使用されます。 ${this@NotesTestE2E::class} thread mute delete test")) - .failOnError() - assertFalse( - notes.state(NotesStateRequest(create.createdNote.id)).failOnError().isMutedThread - ) - NotesThreadMutingCreateRequest(create.createdNote.id) - .let { notes.ThreadMuting().create(it) } - assertTrue( - NotesStateRequest(create.createdNote.id) - .let { notes.state(it).failOnError().isMutedThread }) - NotesThreadMutingDeleteRequest(create.createdNote.id) - .let { notes.ThreadMuting().delete(it) } - assertFalse( - NotesStateRequest(create.createdNote.id) - .let { notes.state(it).failOnError().isMutedThread }) - } - - @Test - fun timeline() = runTest { - val timeline = notes.timeline(NotesTimelineRequest()).failOnError() - } - - @RepeatedIfExceptionsTest(repeats = 4) -// @Test - fun unrenote() = runBlocking { - val create = - notes.create(NotesCreateRequest(text = "このノートはMultimのテストで作成され、リノート取り消しのテストで使用されます。 ${this@NotesTestE2E::class} unrenote test")) - .failOnError() - delay(1000) - val renoted = - notes.create(NotesCreateRequest(renoteId = create.createdNote.id)).failOnError() - delay(1000) - NotesUnrenoteRequest(create.createdNote.id).let { notes.unrenote(it) } - delay(1000) - assertThrows { - NotesShowRequest( - renoted.createdNote.id - ).let { notes.show(it) } - } - - } - - @Test - @Disabled("リスト操作系のAPIが未実装なため無効化") - // TODO: リスト操作系のAPI追加後、リストを取得してテストするように - fun userListTimeline() = runTest { - val userListTimeline = notes.userListTimeline(NotesUserListTimelineRequest("9ady10e6z5")) - } - - @Test - @Disabled("自分以外ということが確定しているノートを取得できない為無効化") - // TODO: 自分以外のノートを取得できるようになってからテストを追加 - fun watchingCreate() = runTest { - - val noteId = "9bk3hn1qd0" - val state = notes.state(NotesStateRequest(noteId)).failOnError() - if (state.isWatching) { - notes.Watching().delete(NotesWatchingDeleteRequest(noteId)) - } - notes.Watching().create(NotesWatchingCreateRequest(noteId)).failOnError() - assertTrue(notes.state(NotesStateRequest(noteId)).failOnError().isWatching) - } - - @Test - @Disabled("自分以外ということが確定しているノートを取得できない為無効化") - fun watchingDelete() = runTest { - val noteId = "9bk3hn1qd0" - val state = notes.state(NotesStateRequest(noteId)).failOnError() - if (!state.isWatching) { - notes.Watching().create(NotesWatchingCreateRequest(noteId)) - } - notes.Watching().delete(NotesWatchingDeleteRequest(noteId)) - assertFalse(notes.state(NotesStateRequest(noteId)).failOnError().isWatching) - } -} diff --git a/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/NotesTestE2E.kt b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/NotesTestE2E.kt new file mode 100644 index 0000000..93a5a65 --- /dev/null +++ b/impl/misskey/src/test/kotlin/dev/usbharu/multim/misskey/v12/api/NotesTestE2E.kt @@ -0,0 +1,335 @@ +package dev.usbharu.multim.misskey.v12.api + +import com.github.michaelbull.result.Err +import com.github.michaelbull.result.Ok +import dev.usbharu.multim.MultiM +import dev.usbharu.multim.TestUtil.failOnError +import dev.usbharu.multim.misskey.v12.common.api.MisskeyApiClient +import dev.usbharu.multim.misskey.v12.model.* +import dev.usbharu.multim.model.SingleTokenAuth +import io.github.artsok.RepeatedIfExceptionsTest +import io.ktor.client.plugins.* +import kotlinx.coroutines.* +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.util.* + +@OptIn(ExperimentalCoroutinesApi::class) +class NotesTestE2E { + + private val client = MisskeyApiClient( + SingleTokenAuth(System.getProperty("multim_misskey_token")), + System.getProperty("multim_misskey_instance"), + MultiM.httpClientWithJson.config {} + ) + private val notes = Notes(client) + private val drive = Drive(client) + + @Test + fun globalTimeline() = runTest { + notes.globalTimeline(NotesGlobalTimelineRequest()).failOnError() + } + + @Test + fun hybridTimeline() = runTest { + notes.hybridTimeline(NotesHybridTimelineRequest()).failOnError() + } + + @Test + fun localTimeline() = runTest { + notes.localTimeline(NotesLocalTimelineRequest()).failOnError() + } + + @Test + fun show() = runTest { + val show = + notes.show(NotesShowRequest(notes.notes(NotesNotesRequest()).failOnError().first().id)) + .failOnError() + + } + + @Test + fun create() = runTest { + notes.create( + NotesCreateRequest( + visibility = NotesCreateRequest.Visibility.HOME, + text = "このノートはMultim のテストで作成されました。${this@NotesTestE2E::class} create Test" + ) + ).failOnError() + } + + @Test + fun createFollowOnly() = runTest { + val notesCreateResponse = notes.create( + NotesCreateRequest( + visibility = NotesCreateRequest.Visibility.FOLLOWERS, + text = "このノートはMultiMのテストで作成され、公開範囲 フォロワーのみ のテストに使用されます。 ${this@NotesTestE2E::class} create note with followers only" + ) + ).failOnError() + Assertions.assertEquals("followers", notesCreateResponse.createdNote.visibility) + } + + @Test + fun createWithFile() = runTest { + val encode: ByteArray = withContext(Dispatchers.IO) { + NotesTestE2E::class.java.classLoader.getResourceAsStream("notes/create/files/note_with_file_test.jpg")!! + .readBytes() + } + + val driveFile = drive.Files().create(DriveFilesCreateRequest(file = encode)) + val createdNote = notes.create( + NotesCreateRequest( + text = "このノートはMultiMのテストで作成され、ファイル添付のテストで使用されます。", + fileIds = setOf(driveFile.id) + ) + ).failOnError() + + Assertions.assertEquals(driveFile, createdNote.createdNote.files?.firstOrNull()) + } + + @Test + fun createWithPoll() = runTest { + val poll = NotesCreateRequest.Poll(choices = setOf("a", "b", "c")) + val create = notes.create( + NotesCreateRequest( + text = "このノートはMultiMのテストで作成され、投票付きノートの作成で使用されます。 ${this@NotesTestE2E::class} create note with poll", + poll = poll + ) + ).failOnError() + Assertions.assertEquals(poll.choices.map { it }, create.createdNote.poll?.choices?.map { it.text }) + } + + @Test + fun delete() = runTest { + val create = notes.create( + NotesCreateRequest( + visibility = NotesCreateRequest.Visibility.HOME, + text = "このノートはMultim のテストで作成され、削除される予定です。 ${this@NotesTestE2E::class} delete Test" + ) + ) + val deleteNote = when (create) { + is Ok -> create.value.createdNote.id + is Err -> Assertions.fail(create.error.message, create.error._throwable) + } + notes.delete(NotesDeleteRequest(deleteNote)) + Assertions.assertInstanceOf(Err::class.java, notes.show(NotesShowRequest(deleteNote))) + //消せていたら失敗する + + } + + @Test + fun featured() = runTest { + notes.featured().failOnError() + } + + @Test + fun children() = runTest { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultiMのテストで作成され、子ノート取得のテストで使用されます。${this@NotesTestE2E::class} children")) + val id = create.failOnError().createdNote.id + val children = notes.children(NotesChildrenRequest(id)).failOnError() + } + + @Test + fun conversation() = runTest { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultiMのテストで作成され、関連ノート取得のテストで使用されます。 ${this@NotesTestE2E::class} conversation")) + .failOnError() + val conversation = + notes.conversation(NotesConversationRequest(create.createdNote.id)).failOnError() + } + + @Test + fun state() = runTest { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultiMのテストで作成され、ノートの状態を取得するテストで使用されます。 ${this@NotesTestE2E::class} state")) + .failOnError() + val state = notes.state(NotesStateRequest(create.createdNote.id)).failOnError() + } + + @Test + fun favoritesCreate() = runTest { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultim のテストで作成され、お気に入り登録のテストで使用されます。 ${this@NotesTestE2E::class} favorites create test")) + .failOnError() + NotesFavoritesCreateRequest(create.createdNote.id) + .let { notes.Favorites().create(it) } + Assertions.assertTrue( + NotesStateRequest(create.createdNote.id) + .let { notes.state(it).failOnError().isFavorited }) +//todo ネストがやばいことになってるのでnullが返ってきた時点で失敗にする + } + + @Test + fun favoritesDelete() = runTest { + val result = + notes.create(NotesCreateRequest(text = "このノートはMultim のテストで作成され、お気に入り削除のテストで使用されます。 ${this@NotesTestE2E::class} favorites delete test")) + val create = + when (result) { + is Ok -> result.value + is Err -> Assertions.fail(result.error.message, result.error._throwable) + } + notes.Favorites().create(NotesFavoritesCreateRequest(create.createdNote.id)) + Assertions.assertTrue(notes.state(NotesStateRequest(create.createdNote.id)).failOnError().isFavorited) + notes.Favorites().delete(NotesFavoritesDeleteRequest(create.createdNote.id)) + Assertions.assertFalse( + notes.state(NotesStateRequest(create.createdNote.id)).failOnError().isFavorited + ) + } + + @Test + fun mentions() = runTest { + val mentions = notes.mentions(NotesMentionsRequest()).failOnError() + } + + @Test + fun reactions() = runTest { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultiMのテストで作成され、リアクション取得のテストで使用されます。 ${this@NotesTestE2E::class} reactions")) + .failOnError() + val reactions = notes.reactions(NotesReactionsRequest(create.createdNote.id)) + } + + @Test + fun renotes() = runTest { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultim のテストで作成され、リノートのテストで使用されます。 ${this@NotesTestE2E::class} renotes test")) + .failOnError() + val notesCreateResponse = + notes.create(NotesCreateRequest(renoteId = create.createdNote.id)).failOnError() + val renotes = NotesRenoteRequest(create.createdNote.id) + .let { notes.renotes(it) }.failOnError() + Assertions.assertEquals(listOf(notesCreateResponse.createdNote), renotes) + } + + @Test + fun replies() = runTest { + val root = + notes.create(NotesCreateRequest(text = "このノートはMultim のテストで作成され、返信取得のテストで使用されます。 ${this@NotesTestE2E::class} replies test")) + .failOnError() + val reply1 = notes.create( + NotesCreateRequest( + text = "返信1 このノートはMultimのテストで作成され、返信取得のテストで使用されます。 ${this@NotesTestE2E::class} replies test", + replyId = root.createdNote.id + ) + ).failOnError() + val reply2 = notes.create( + NotesCreateRequest( + text = "返信2 このノートはMultimのテストで作成され、返信取得のテストで使用されます。 ${this@NotesTestE2E::class} replies test", + replyId = root.createdNote.id + ) + ).failOnError() + val replies = root.createdNote.id.let { NotesRepliesRequest(it) } + .let { notes.replies(it) }.failOnError() + Assertions.assertEquals( + listOf(reply1.createdNote, reply2.createdNote).sortedBy { note -> note.id }, + replies.sortedBy { note -> note.id }) + } + + @Test + fun searchByTag() = runTest { + val tag = UUID.randomUUID().toString() + val tagedNote = + notes.create(NotesCreateRequest(text = "#$tag このノートはMultimのテストで作成され、タグ検索のテストで使用されます。 ${this@NotesTestE2E::class} search by tag test")) + .failOnError() + val searchByTag = notes.searchByTag(NotesSearchByTagRequest(tag)).failOnError() + org.assertj.core.api.Assertions.assertThat(searchByTag)?.isNotEmpty + Assertions.assertTrue(searchByTag.contains(tagedNote.createdNote)) + } + + @Test + fun threadMutingCreate() = runTest { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultimのテストで作成され、スレッドミュートのテストで使用されます。 ${this@NotesTestE2E::class} thread mute create test")) + .failOnError() + Assertions.assertFalse( + NotesStateRequest(create.createdNote.id) + .let { notes.state(it).failOnError().isMutedThread }) + NotesThreadMutingCreateRequest(create.createdNote.id) + .let { notes.ThreadMuting().create(it) } + Assertions.assertTrue( + NotesStateRequest(create.createdNote.id) + .let { notes.state(it).failOnError().isMutedThread }) + } + + @Test + fun threadMutingDelete() = runTest { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultimのテストで作成され、スレッドミュート解除のテストで使用されます。 ${this@NotesTestE2E::class} thread mute delete test")) + .failOnError() + Assertions.assertFalse( + notes.state(NotesStateRequest(create.createdNote.id)).failOnError().isMutedThread + ) + NotesThreadMutingCreateRequest(create.createdNote.id) + .let { notes.ThreadMuting().create(it) } + Assertions.assertTrue( + NotesStateRequest(create.createdNote.id) + .let { notes.state(it).failOnError().isMutedThread }) + NotesThreadMutingDeleteRequest(create.createdNote.id) + .let { notes.ThreadMuting().delete(it) } + Assertions.assertFalse( + NotesStateRequest(create.createdNote.id) + .let { notes.state(it).failOnError().isMutedThread }) + } + + @Test + fun timeline() = runTest { + val timeline = notes.timeline(NotesTimelineRequest()).failOnError() + } + + @RepeatedIfExceptionsTest(repeats = 4) +// @Test + fun unrenote() = runBlocking { + val create = + notes.create(NotesCreateRequest(text = "このノートはMultimのテストで作成され、リノート取り消しのテストで使用されます。 ${this@NotesTestE2E::class} unrenote test")) + .failOnError() + delay(1000) + val renoted = + notes.create(NotesCreateRequest(renoteId = create.createdNote.id)).failOnError() + delay(1000) + NotesUnrenoteRequest(create.createdNote.id).let { notes.unrenote(it) } + delay(1000) + assertThrows { + NotesShowRequest( + renoted.createdNote.id + ).let { notes.show(it) } + } + + } + + @Test + @Disabled("リスト操作系のAPIが未実装なため無効化") + // TODO: リスト操作系のAPI追加後、リストを取得してテストするように + fun userListTimeline() = runTest { + val userListTimeline = notes.userListTimeline(NotesUserListTimelineRequest("9ady10e6z5")) + } + + @Test + @Disabled("自分以外ということが確定しているノートを取得できない為無効化") + // TODO: 自分以外のノートを取得できるようになってからテストを追加 + fun watchingCreate() = runTest { + + val noteId = "9bk3hn1qd0" + val state = notes.state(NotesStateRequest(noteId)).failOnError() + if (state.isWatching) { + notes.Watching().delete(NotesWatchingDeleteRequest(noteId)) + } + notes.Watching().create(NotesWatchingCreateRequest(noteId)).failOnError() + Assertions.assertTrue(notes.state(NotesStateRequest(noteId)).failOnError().isWatching) + } + + @Test + @Disabled("自分以外ということが確定しているノートを取得できない為無効化") + fun watchingDelete() = runTest { + val noteId = "9bk3hn1qd0" + val state = notes.state(NotesStateRequest(noteId)).failOnError() + if (!state.isWatching) { + notes.Watching().create(NotesWatchingCreateRequest(noteId)) + } + notes.Watching().delete(NotesWatchingDeleteRequest(noteId)) + Assertions.assertFalse(notes.state(NotesStateRequest(noteId)).failOnError().isWatching) + } +}