From 0825be76b32cb59fcfa27deffbf53223964cbf4d Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:43:14 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=E3=83=86=E3=82=B9=E3=83=88=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/actor/DeleteLocalActor.kt | 5 ++ .../DeleteLocalActorApplicationService.kt | 37 --------- .../actor/GetUserDetailApplicationService.kt | 6 +- .../RegisterLocalActorApplicationService.kt | 6 +- ...StartDeleteLocalActorApplicationService.kt | 46 +++++++++++ .../SuspendLocalActorApplicationService.kt | 4 +- .../exception/InternalServerException.kt | 14 ++++ .../exception/PermissionDeniedException.kt | 14 ++++ .../LocalUserAbstractApplicationService.kt | 2 +- .../GetUserDetailApplicationServiceTest.kt | 78 +++++++++++++++++++ ...tDeleteLocalActorApplicationServiceTest.kt | 64 +++++++++++++++ 11 files changed, 232 insertions(+), 44 deletions(-) create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/DeleteLocalActor.kt delete mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/DeleteLocalActorApplicationService.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/StartDeleteLocalActorApplicationService.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/InternalServerException.kt create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/PermissionDeniedException.kt create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/actor/GetUserDetailApplicationServiceTest.kt create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/actor/StartDeleteLocalActorApplicationServiceTest.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/DeleteLocalActor.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/DeleteLocalActor.kt new file mode 100644 index 00000000..a00a4556 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/DeleteLocalActor.kt @@ -0,0 +1,5 @@ +package dev.usbharu.hideout.core.application.actor + +import dev.usbharu.hideout.core.domain.model.actor.ActorId + +data class DeleteLocalActor(val actorId: ActorId) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/DeleteLocalActorApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/DeleteLocalActorApplicationService.kt deleted file mode 100644 index 73ef9151..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/DeleteLocalActorApplicationService.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.application.actor - -import dev.usbharu.hideout.core.application.shared.Transaction -import dev.usbharu.hideout.core.domain.model.actor.ActorId -import dev.usbharu.hideout.core.domain.model.actor.ActorRepository -import org.springframework.stereotype.Service - -@Service -class DeleteLocalActorApplicationService( - private val transaction: Transaction, - private val actorRepository: ActorRepository, -) { - suspend fun delete(actorId: Long, executor: ActorId) { - transaction.transaction { - val id = ActorId(actorId) - val findById = actorRepository.findById(id)!! - findById.delete() - actorRepository.delete(findById) - } - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/GetUserDetailApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/GetUserDetailApplicationService.kt index 1b025ed4..6d990ee2 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/GetUserDetailApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/GetUserDetailApplicationService.kt @@ -16,6 +16,7 @@ package dev.usbharu.hideout.core.application.actor +import dev.usbharu.hideout.core.application.exception.InternalServerException import dev.usbharu.hideout.core.application.shared.AbstractApplicationService import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.domain.model.actor.ActorRepository @@ -36,8 +37,9 @@ class GetUserDetailApplicationService( AbstractApplicationService(transaction, Companion.logger) { override suspend fun internalExecute(command: GetUserDetail, principal: Principal): UserDetail { val userDetail = userDetailRepository.findById(UserDetailId(command.id)) - ?: throw IllegalArgumentException("actor does not exist") - val actor = actorRepository.findById(userDetail.actorId)!! + ?: throw IllegalArgumentException("User ${command.id} does not exist") + val actor = actorRepository.findById(userDetail.actorId) + ?: throw InternalServerException("Actor ${userDetail.actorId} not found") val emojis = customEmojiRepository.findByIds(actor.emojis.map { it.emojiId }) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt index 5819b4c1..202c82e8 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/RegisterLocalActorApplicationService.kt @@ -16,6 +16,7 @@ package dev.usbharu.hideout.core.application.actor +import dev.usbharu.hideout.core.application.exception.InternalServerException import dev.usbharu.hideout.core.application.shared.AbstractApplicationService import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.config.ApplicationConfig @@ -49,9 +50,10 @@ class RegisterLocalActorApplicationService( override suspend fun internalExecute(command: RegisterLocalActor, principal: Principal): URI { if (actorDomainService.usernameAlreadyUse(command.name)) { // todo 適切な例外を考える - throw Exception("Username already exists") + throw IllegalArgumentException("Username already exists") } - val instance = instanceRepository.findByUrl(applicationConfig.url.toURI())!! + val instance = instanceRepository.findByUrl(applicationConfig.url.toURI()) + ?: throw InternalServerException("Local instance not found.") val actor = actorFactoryImpl.createLocal( command.name, diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/StartDeleteLocalActorApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/StartDeleteLocalActorApplicationService.kt new file mode 100644 index 00000000..9fd8669b --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/StartDeleteLocalActorApplicationService.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.usbharu.hideout.core.application.actor + +import dev.usbharu.hideout.core.application.exception.InternalServerException +import dev.usbharu.hideout.core.application.exception.PermissionDeniedException +import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService +import dev.usbharu.hideout.core.application.shared.Transaction +import dev.usbharu.hideout.core.domain.model.actor.ActorRepository +import dev.usbharu.hideout.core.domain.model.support.principal.FromApi +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service + +@Service +class StartDeleteLocalActorApplicationService( + transaction: Transaction, + private val actorRepository: ActorRepository, +) : LocalUserAbstractApplicationService(transaction, logger) { + override suspend fun internalExecute(command: DeleteLocalActor, principal: FromApi) { + if (command.actorId != principal.actorId) { + throw PermissionDeniedException() + } + val findById = actorRepository.findById(command.actorId) + ?: throw InternalServerException("Actor ${command.actorId} Not found") + findById.delete() + actorRepository.save(findById) + } + + companion object { + private val logger = LoggerFactory.getLogger(StartDeleteLocalActorApplicationService::class.java) + } +} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/SuspendLocalActorApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/SuspendLocalActorApplicationService.kt index 082208b3..809b3a36 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/SuspendLocalActorApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/SuspendLocalActorApplicationService.kt @@ -30,8 +30,8 @@ class SuspendLocalActorApplicationService( transaction.transaction { val id = ActorId(actorId) - val findById = actorRepository.findById(id)!! - findById.suspend = true + val actor = actorRepository.findById(id)!! + actor.suspend = true } } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/InternalServerException.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/InternalServerException.kt new file mode 100644 index 00000000..8acf6a72 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/InternalServerException.kt @@ -0,0 +1,14 @@ +package dev.usbharu.hideout.core.application.exception + +class InternalServerException : RuntimeException { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) + constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super( + message, + cause, + enableSuppression, + writableStackTrace + ) +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/PermissionDeniedException.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/PermissionDeniedException.kt new file mode 100644 index 00000000..c583ae0b --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/PermissionDeniedException.kt @@ -0,0 +1,14 @@ +package dev.usbharu.hideout.core.application.exception + +class PermissionDeniedException : RuntimeException { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) + constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super( + message, + cause, + enableSuppression, + writableStackTrace + ) +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/LocalUserAbstractApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/LocalUserAbstractApplicationService.kt index e84702d2..cc4ddef8 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/LocalUserAbstractApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/shared/LocalUserAbstractApplicationService.kt @@ -11,5 +11,5 @@ abstract class LocalUserAbstractApplicationService(transaction: Tran return internalExecute(command, principal) } - abstract suspend fun internalExecute(command: T, principal: FromApi): R + protected abstract suspend fun internalExecute(command: T, principal: FromApi): R } \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/actor/GetUserDetailApplicationServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/actor/GetUserDetailApplicationServiceTest.kt new file mode 100644 index 00000000..494a381c --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/actor/GetUserDetailApplicationServiceTest.kt @@ -0,0 +1,78 @@ +package dev.usbharu.hideout.core.application.actor + +import dev.usbharu.hideout.core.application.exception.InternalServerException +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.actor.ActorRepository +import dev.usbharu.hideout.core.domain.model.actor.TestActorFactory +import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiRepository +import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailHashedPassword +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Spy +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever +import utils.TestTransaction + +@ExtendWith(MockitoExtension::class) +class GetUserDetailApplicationServiceTest { + @InjectMocks + lateinit var service: GetUserDetailApplicationService + + @Mock + lateinit var actorRepository: ActorRepository + + @Mock + lateinit var userDetailRepository: UserDetailRepository + + @Mock + lateinit var customEmojiRepository: CustomEmojiRepository + + @Spy + val transaction = TestTransaction + + @Test + fun userDetailを取得できる() = runTest { + whenever(userDetailRepository.findById(UserDetailId(1))).doReturn( + UserDetail.create( + UserDetailId(1), ActorId(1), + UserDetailHashedPassword("") + ) + ) + whenever(actorRepository.findById(ActorId(1))).doReturn(TestActorFactory.create(1)) + whenever(customEmojiRepository.findByIds(any())).doReturn(listOf()) + + service.execute(GetUserDetail(1), Anonymous) + } + + @Test + fun userDetailが存在しない場合失敗() = runTest { + + assertThrows { + service.execute(GetUserDetail(2), Anonymous) + } + } + + @Test + fun userDetailが存在するけどActorが存在しない場合はInternalServerException() = runTest { + whenever(userDetailRepository.findById(UserDetailId(2))).doReturn( + UserDetail.create( + UserDetailId(2), ActorId(2), + UserDetailHashedPassword("") + ) + ) + + assertThrows { + service.execute(GetUserDetail(2), Anonymous) + } + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/actor/StartDeleteLocalActorApplicationServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/actor/StartDeleteLocalActorApplicationServiceTest.kt new file mode 100644 index 00000000..f99645bf --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/actor/StartDeleteLocalActorApplicationServiceTest.kt @@ -0,0 +1,64 @@ +package dev.usbharu.hideout.core.application.actor + +import dev.usbharu.hideout.core.application.exception.InternalServerException +import dev.usbharu.hideout.core.application.exception.PermissionDeniedException +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.actor.ActorRepository +import dev.usbharu.hideout.core.domain.model.actor.TestActorFactory +import dev.usbharu.hideout.core.domain.model.support.acct.Acct +import dev.usbharu.hideout.core.domain.model.support.principal.FromApi +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Spy +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever +import utils.TestTransaction + +@ExtendWith(MockitoExtension::class) +class StartDeleteLocalActorApplicationServiceTest { + + @InjectMocks + lateinit var service: StartDeleteLocalActorApplicationService + + @Mock + lateinit var actorRepository: ActorRepository + + @Spy + val transaction = TestTransaction + + @Test + fun ローカルActorを削除できる() = runTest { + whenever(actorRepository.findById(ActorId(1))).doReturn(TestActorFactory.create(1)) + + service.execute( + DeleteLocalActor(ActorId(1)), + FromApi(ActorId(1), UserDetailId((1)), Acct("test", "example.com")) + ) + } + + @Test + fun ログイン中のユーザーと一致しない場合失敗() = runTest { + assertThrows { + service.execute( + DeleteLocalActor(ActorId(2)), + FromApi(ActorId(1), UserDetailId((1)), Acct("test", "example.com")) + ) + } + } + + @Test + fun ユーザーが存在しない場合失敗() = runTest { + assertThrows { + service.execute( + DeleteLocalActor(ActorId(1)), + FromApi(ActorId(1), UserDetailId((1)), Acct("test", "example.com")) + ) + } + } +} \ No newline at end of file