diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNote.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNote.kt index 49546b6d..64ce9831 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNote.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNote.kt @@ -16,13 +16,10 @@ package dev.usbharu.hideout.core.application.post -import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId - data class UpdateLocalNote( val postId: Long, val overview: String?, val content: String, val sensitive: Boolean, - val mediaIds: List, - val userDetailId: UserDetailId + val mediaIds: List ) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationService.kt index 6a24184c..17bafb70 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationService.kt @@ -16,14 +16,16 @@ package dev.usbharu.hideout.core.application.post -import dev.usbharu.hideout.core.application.shared.AbstractApplicationService +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.media.MediaId import dev.usbharu.hideout.core.domain.model.post.PostId import dev.usbharu.hideout.core.domain.model.post.PostOverview import dev.usbharu.hideout.core.domain.model.post.PostRepository -import dev.usbharu.hideout.core.domain.model.support.principal.Principal +import dev.usbharu.hideout.core.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository import dev.usbharu.hideout.core.infrastructure.factory.PostContentFactoryImpl import org.slf4j.LoggerFactory @@ -36,13 +38,19 @@ class UpdateLocalNoteApplicationService( private val postContentFactoryImpl: PostContentFactoryImpl, private val userDetailRepository: UserDetailRepository, private val actorRepository: ActorRepository, -) : AbstractApplicationService(transaction, logger) { +) : LocalUserAbstractApplicationService(transaction, logger) { - override suspend fun internalExecute(command: UpdateLocalNote, principal: Principal) { + override suspend fun internalExecute(command: UpdateLocalNote, principal: FromApi) { + val post = postRepository.findById(PostId(command.postId)) + ?: throw IllegalArgumentException("Post ${command.postId} not found.") + if (post.actorId != principal.actorId) { + throw PermissionDeniedException() + } - val userDetail = userDetailRepository.findById(command.userDetailId)!! - val actor = actorRepository.findById(userDetail.actorId)!! - val post = postRepository.findById(PostId(command.postId))!! + val userDetail = userDetailRepository.findById(principal.userDetailId) + ?: throw InternalServerException("User detail ${principal.userDetailId} not found.") + val actor = actorRepository.findById(userDetail.actorId) + ?: throw InternalServerException("Actor ${principal.actorId} not found.") post.setContent(postContentFactoryImpl.create(command.content), actor) post.setOverview(command.overview?.let { PostOverview(it) }, actor) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/post/DeleteLocalPostApplicationServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/post/DeleteLocalPostApplicationServiceTest.kt index a52808ee..b4c747ba 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/post/DeleteLocalPostApplicationServiceTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/post/DeleteLocalPostApplicationServiceTest.kt @@ -1,5 +1,6 @@ package dev.usbharu.hideout.core.application.post +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 @@ -11,6 +12,7 @@ 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 @@ -41,4 +43,13 @@ class DeleteLocalPostApplicationServiceTest { service.execute(DeleteLocalPost(1), FromApi(ActorId(2), UserDetailId(2), Acct("test", "example.com"))) } + + @Test + fun Post主以外はローカルPostを削除できない() = runTest { + whenever(postRepository.findById(PostId(1))).doReturn(TestPostFactory.create(actorId = 2)) + + assertThrows { + service.execute(DeleteLocalPost(1), FromApi(ActorId(3), UserDetailId(3), Acct("test", "example.com"))) + } + } } \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationServiceTest.kt new file mode 100644 index 00000000..e5ad0714 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationServiceTest.kt @@ -0,0 +1,109 @@ +package dev.usbharu.hideout.core.application.post + +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.post.* +import dev.usbharu.hideout.core.domain.model.post.Post +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.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 dev.usbharu.hideout.core.infrastructure.factory.PostContentFactoryImpl +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Assertions.assertEquals +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.* +import utils.TestTransaction + +@ExtendWith(MockitoExtension::class) +class UpdateLocalNoteApplicationServiceTest { + @InjectMocks + lateinit var service: UpdateLocalNoteApplicationService + + @Mock + lateinit var postRepository: PostRepository + + @Mock + lateinit var userDetailRepository: UserDetailRepository + + @Mock + lateinit var actorRepository: ActorRepository + + @Mock + lateinit var postContentFactoryImpl: PostContentFactoryImpl + + @Spy + val transaction = TestTransaction + + + @Test + fun Post主はPostを編集できる() = runTest { + val post = TestPostFactory.create() + + whenever(postRepository.findById(post.id)).doReturn(post) + whenever(userDetailRepository.findById(UserDetailId(1))).doReturn( + UserDetail.create( + UserDetailId(1), post.actorId, + UserDetailHashedPassword("") + ) + ) + whenever(actorRepository.findById(post.actorId)).doReturn(TestActorFactory.create(id = post.actorId.id)) + val content = PostContent("

test

", "test", emptyList()) + whenever(postContentFactoryImpl.create(eq("test"))).doReturn(content) + + service.execute( + UpdateLocalNote(post.id.id, null, "test", false, emptyList()), FromApi( + post.actorId, + UserDetailId(1), + Acct("test", "example.com") + ) + ) + + argumentCaptor { + verify(postRepository, times(1)).save(capture()) + val first = allValues.first() + + assertEquals( + content, first.content + ) + } + } + + @Test + fun postが見つからない場合失敗() = runTest { + assertThrows { + service.execute( + UpdateLocalNote(1, null, "test", false, emptyList()), FromApi( + ActorId(1), + UserDetailId(1), Acct("test", "example.com") + ) + ) + } + } + + @Test + fun post主じゃない場合失敗() = runTest { + whenever(postRepository.findById(PostId(1))).doReturn(TestPostFactory.create(id = 1, actorId = 3)) + + assertThrows { + service.execute( + UpdateLocalNote(1, null, "test", false, emptyList()), FromApi( + ActorId(1), + UserDetailId(1), Acct("test", "example.com") + ) + ) + } + } + + +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/shared/LocalUserAbstractApplicationServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/shared/LocalUserAbstractApplicationServiceTest.kt new file mode 100644 index 00000000..a52a29d7 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/application/shared/LocalUserAbstractApplicationServiceTest.kt @@ -0,0 +1,24 @@ +package dev.usbharu.hideout.core.application.shared + +import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous +import dev.usbharu.hideout.core.domain.model.support.principal.FromApi +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Test +import org.slf4j.LoggerFactory +import utils.TestTransaction + +class LocalUserAbstractApplicationServiceTest { + @Test + fun requireFromAPI() = runTest { + val logger = LoggerFactory.getLogger(javaClass) + val value = object : LocalUserAbstractApplicationService(TestTransaction, logger) { + override suspend fun internalExecute(command: Unit, principal: FromApi) { + + } + } + + org.junit.jupiter.api.assertThrows { + value.execute(Unit, Anonymous) + } + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/support/domain/DomainTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/support/domain/DomainTest.kt new file mode 100644 index 00000000..861d2857 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/support/domain/DomainTest.kt @@ -0,0 +1,14 @@ +package dev.usbharu.hideout.core.domain.model.support.domain + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + + +class DomainTest { + @Test + fun `1000超過の長さは失敗`() { + assertThrows { + Domain("a".repeat(1001)) + } + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorDomainServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorDomainServiceImplTest.kt new file mode 100644 index 00000000..a5fcf1a1 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorDomainServiceImplTest.kt @@ -0,0 +1,51 @@ +package dev.usbharu.hideout.core.domain.service.actor.local + +import dev.usbharu.hideout.core.config.ApplicationConfig +import dev.usbharu.hideout.core.domain.model.actor.ActorRepository +import dev.usbharu.hideout.core.domain.model.actor.TestActorFactory +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +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.eq +import org.mockito.kotlin.whenever +import java.net.URL + +@ExtendWith(MockitoExtension::class) +class LocalActorDomainServiceImplTest { + @InjectMocks + lateinit var service: LocalActorDomainServiceImpl + + @Mock + lateinit var actorRepository: ActorRepository + + @Spy + val applicationConfig = ApplicationConfig(URL("http://example.com")) + + @Test + fun findByNameAndDomainがnullならfalse() = runTest { + val actual = service.usernameAlreadyUse("test") + + assertFalse(actual) + } + + @Test + fun findByNameAndDomainがnullならtrue() = runTest { + whenever(actorRepository.findByNameAndDomain(eq("test"), eq("example.com"))).doReturn(TestActorFactory.create()) + + val actual = service.usernameAlreadyUse("test") + + assertTrue(actual) + } + + @Test + fun generateKeyPair() = runTest { + service.generateKeyPair() + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorMigrationCheckDomainServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorMigrationCheckDomainServiceImplTest.kt index c44382b9..3617fae9 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorMigrationCheckDomainServiceImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/service/actor/local/LocalActorMigrationCheckDomainServiceImplTest.kt @@ -8,8 +8,29 @@ import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Assertions.assertInstanceOf import org.junit.jupiter.api.Test +import java.time.Instant +import kotlin.time.Duration.Companion.days +import kotlin.time.toJavaDuration class LocalActorMigrationCheckDomainServiceImplTest { + + @Test + fun 最終お引越しから30日以内だと失敗() = runTest { + val from = TestActorFactory.create() + val to = TestActorFactory.create() + val userDetail = UserDetail.create( + UserDetailId(1), + ActorId(1), UserDetailHashedPassword("") + ) + userDetail.lastMigration = Instant.now().minusSeconds(100) + + val localActorMigrationCheckDomainServiceImpl = LocalActorMigrationCheckDomainServiceImpl() + + val canAccountMigration = localActorMigrationCheckDomainServiceImpl.canAccountMigration(userDetail, to, from) + + assertInstanceOf(AccountMigrationCheck.MigrationCoolDown::class.java, canAccountMigration) + } + @Test fun 自分自身に引っ越しできない(): Unit = runTest { @@ -86,4 +107,20 @@ class LocalActorMigrationCheckDomainServiceImplTest { assertInstanceOf(AccountMigrationCheck.CanAccountMigration::class.java, canAccountMigration) } + + @Test + fun お引越し履歴があっても30日以上経っていたら成功する() = runTest { + val from = TestActorFactory.create() + val to = TestActorFactory.create(alsoKnownAs = setOf(from.id, ActorId(100))) + val userDetail = UserDetail.create( + UserDetailId(1), + ActorId(1), UserDetailHashedPassword("") + ) + userDetail.lastMigration = Instant.now().minus(31.days.toJavaDuration()) + val localActorMigrationCheckDomainServiceImpl = LocalActorMigrationCheckDomainServiceImpl() + + val canAccountMigration = localActorMigrationCheckDomainServiceImpl.canAccountMigration(userDetail, from, to) + + assertInstanceOf(AccountMigrationCheck.CanAccountMigration::class.java, canAccountMigration) + } } \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImplTest.kt new file mode 100644 index 00000000..bb253ef6 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImplTest.kt @@ -0,0 +1,91 @@ +package dev.usbharu.hideout.core.infrastructure.springframework.oauth2 + +import dev.usbharu.hideout.core.config.ApplicationConfig +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.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.* +import org.springframework.security.core.userdetails.UsernameNotFoundException +import utils.TestTransaction +import java.net.URL +import kotlin.test.assertEquals + +@ExtendWith(MockitoExtension::class) +class UserDetailsServiceImplTest { + @InjectMocks + lateinit var service: UserDetailsServiceImpl + + @Mock + lateinit var actorRepository: ActorRepository + + @Mock + lateinit var userDetailRepository: UserDetailRepository + + @Spy + val applicationConfig = ApplicationConfig(URL("http://example.com")) + + @Spy + val transaction = TestTransaction + + @Test + fun usernameがnullなら失敗() = runTest { + assertThrows { + service.loadUserByUsername(null) + } + verify(actorRepository, never()).findByNameAndDomain(any(), any()) + } + + @Test + fun actorが見つからない場合失敗() = runTest { + assertThrows { + service.loadUserByUsername("test") + } + verify(actorRepository, times(1)).findByNameAndDomain(eq("test"), eq("example.com")) + } + + @Test + fun userDetailが見つからない場合失敗() = runTest { + whenever(actorRepository.findByNameAndDomain(eq("test"), eq("example.com"))).doReturn( + TestActorFactory.create( + actorName = "test", id = 1 + ) + ) + assertThrows { + service.loadUserByUsername("test") + } + verify(actorRepository, times(1)).findByNameAndDomain(eq("test"), eq("example.com")) + verify(userDetailRepository, times(1)).findByActorId(eq(1)) + } + + @Test + fun 全部見つかったら成功() = runTest { + whenever( + actorRepository.findByNameAndDomain( + eq("test"), + eq("example.com") + ) + ).doReturn(TestActorFactory.create(id = 1)) + whenever(userDetailRepository.findByActorId(eq(1))).doReturn( + UserDetail.create( + UserDetailId(1), + ActorId(1), UserDetailHashedPassword("") + ) + ) + + val actual = service.loadUserByUsername("test") + + assertEquals(HideoutUserDetails(HashSet(), "", "test-1", 1), actual) + } +} \ No newline at end of file