テストを追加

This commit is contained in:
usbharu 2024-08-09 23:06:43 +09:00
parent 29d356efac
commit 3ab86fc511
Signed by: usbharu
GPG Key ID: 6556747BF94EEBC8
12 changed files with 606 additions and 67 deletions

View File

@ -16,14 +16,17 @@
package dev.usbharu.hideout.core.application.application package dev.usbharu.hideout.core.application.application
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.application.Application import dev.usbharu.hideout.core.domain.model.application.Application
import dev.usbharu.hideout.core.domain.model.application.ApplicationId import dev.usbharu.hideout.core.domain.model.application.ApplicationId
import dev.usbharu.hideout.core.domain.model.application.ApplicationName import dev.usbharu.hideout.core.domain.model.application.ApplicationName
import dev.usbharu.hideout.core.domain.model.application.ApplicationRepository import dev.usbharu.hideout.core.domain.model.application.ApplicationRepository
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
import dev.usbharu.hideout.core.domain.service.userdetail.PasswordEncoder import dev.usbharu.hideout.core.domain.service.userdetail.PasswordEncoder
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.SecureTokenGenerator import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.SecureTokenGenerator
import org.slf4j.LoggerFactory
import org.springframework.security.oauth2.core.AuthorizationGrantType import org.springframework.security.oauth2.core.AuthorizationGrantType
import org.springframework.security.oauth2.core.ClientAuthenticationMethod import org.springframework.security.oauth2.core.ClientAuthenticationMethod
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient import org.springframework.security.oauth2.server.authorization.client.RegisteredClient
@ -39,53 +42,57 @@ class RegisterApplicationApplicationService(
private val passwordEncoder: PasswordEncoder, private val passwordEncoder: PasswordEncoder,
private val secureTokenGenerator: SecureTokenGenerator, private val secureTokenGenerator: SecureTokenGenerator,
private val registeredClientRepository: RegisteredClientRepository, private val registeredClientRepository: RegisteredClientRepository,
private val transaction: Transaction, transaction: Transaction,
private val applicationRepository: ApplicationRepository, private val applicationRepository: ApplicationRepository,
) { ) : AbstractApplicationService<RegisterApplication, RegisteredApplication>(transaction, logger) {
suspend fun register(registerApplication: RegisterApplication): RegisteredApplication {
return transaction.transaction {
val id = idGenerateService.generateId()
val clientSecret = secureTokenGenerator.generate()
val registeredClient = RegisteredClient
.withId(id.toString())
.clientId(id.toString())
.clientSecret(passwordEncoder.encode(clientSecret))
.clientName(registerApplication.name)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.apply {
if (registerApplication.useRefreshToken) {
authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
} else {
tokenSettings(
TokenSettings
.builder()
.accessTokenTimeToLive(Duration.ofSeconds(31536000000))
.build()
)
}
}
.redirectUris { set ->
set.addAll(registerApplication.redirectUris.map { it.toString() })
}
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.scopes { it.addAll(registerApplication.scopes) }
.build()
registeredClientRepository.save(registeredClient)
val application = Application(ApplicationId(id), ApplicationName(registerApplication.name)) override suspend fun internalExecute(command: RegisterApplication, principal: Principal): RegisteredApplication {
val id = idGenerateService.generateId()
val clientSecret = secureTokenGenerator.generate()
val registeredClient = RegisteredClient
.withId(id.toString())
.clientId(id.toString())
.clientSecret(passwordEncoder.encode(clientSecret))
.clientName(command.name)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_JWT)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.apply {
if (command.useRefreshToken) {
authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
} else {
tokenSettings(
TokenSettings
.builder()
.accessTokenTimeToLive(Duration.ofSeconds(31536000000))
.build()
)
}
}
.redirectUris { set ->
set.addAll(command.redirectUris.map { it.toString() })
}
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.scopes { it.addAll(command.scopes) }
.build()
registeredClientRepository.save(registeredClient)
applicationRepository.save(application) val application = Application(ApplicationId(id), ApplicationName(command.name))
RegisteredApplication(
id = id, applicationRepository.save(application)
name = registerApplication.name, return RegisteredApplication(
clientSecret = clientSecret, id = id,
clientId = id.toString(), name = command.name,
redirectUris = registerApplication.redirectUris clientSecret = clientSecret,
) clientId = id.toString(),
} redirectUris = command.redirectUris
)
}
companion object {
private val logger = LoggerFactory.getLogger(RegisterApplicationApplicationService::class.java)
} }
} }

View File

@ -16,22 +16,27 @@
package dev.usbharu.hideout.core.application.filter package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService 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.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.filter.FilterId import dev.usbharu.hideout.core.domain.model.filter.FilterId
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
import dev.usbharu.hideout.core.domain.model.support.principal.Principal import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class UserDeleteFilterApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) : class UserDeleteFilterApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
AbstractApplicationService<DeleteFilter, Unit>( LocalUserAbstractApplicationService<DeleteFilter, Unit>(
transaction, transaction,
logger logger
) { ) {
override suspend fun internalExecute(command: DeleteFilter, principal: Principal) { override suspend fun internalExecute(command: DeleteFilter, principal: FromApi) {
val filter = filterRepository.findByFilterId(FilterId(command.filterId)) ?: throw Exception("not found") val filter =
filterRepository.findByFilterId(FilterId(command.filterId)) ?: throw IllegalArgumentException("not found")
if (filter.userDetailId != principal.userDetailId) {
throw PermissionDeniedException()
}
filterRepository.delete(filter) filterRepository.delete(filter)
} }

View File

@ -16,23 +16,27 @@
package dev.usbharu.hideout.core.application.filter package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService 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.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.filter.FilterId import dev.usbharu.hideout.core.domain.model.filter.FilterId
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
import dev.usbharu.hideout.core.domain.model.support.principal.Principal import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class UserGetFilterApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) : class UserGetFilterApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
AbstractApplicationService<GetFilter, Filter>( LocalUserAbstractApplicationService<GetFilter, Filter>(
transaction, transaction,
logger logger
) { ) {
override suspend fun internalExecute(command: GetFilter, principal: Principal): Filter { override suspend fun internalExecute(command: GetFilter, principal: FromApi): Filter {
val filter = filterRepository.findByFilterId(FilterId(command.filterId)) ?: throw Exception("Not Found") val filter =
filterRepository.findByFilterId(FilterId(command.filterId)) ?: throw IllegalArgumentException("Not Found")
if (filter.userDetailId != principal.userDetailId) {
throw PermissionDeniedException()
}
return Filter.of(filter) return Filter.of(filter)
} }

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.acceptfollowrequest package dev.usbharu.hideout.core.application.relationship.acceptfollowrequest
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
@ -23,7 +24,6 @@ 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.ActorRepository
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -32,18 +32,17 @@ class UserAcceptFollowRequestApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
) : ) :
LocalUserAbstractApplicationService<AcceptFollowRequest, Unit>(transaction, logger) { LocalUserAbstractApplicationService<AcceptFollowRequest, Unit>(transaction, logger) {
override suspend fun internalExecute(command: AcceptFollowRequest, principal: FromApi) { override suspend fun internalExecute(command: AcceptFollowRequest, principal: FromApi) {
val userDetail = userDetailRepository.findById(principal.userDetailId)!! val actor = actorRepository.findById(principal.actorId)
val actor = actorRepository.findById(userDetail.actorId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found")
val targetId = ActorId(command.sourceActorId) val targetId = ActorId(command.sourceActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(targetId, actor.id) val relationship = relationshipRepository.findByActorIdAndTargetId(targetId, actor.id)
?: throw Exception("Follow request not found") ?: throw InternalServerException("Follow request not found")
relationship.acceptFollowRequest() relationship.acceptFollowRequest()

View File

@ -56,6 +56,20 @@ class Filter(
) )
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Filter
return id == other.id
}
override fun hashCode(): Int {
return id.hashCode()
}
companion object { companion object {
fun isAllow(user: UserDetail, action: Action, resource: Filter): Boolean { fun isAllow(user: UserDetail, action: Action, resource: Filter): Boolean {
return when (action) { return when (action) {

View File

@ -0,0 +1,84 @@
package dev.usbharu.hideout.core.application.application
import dev.usbharu.hideout.core.domain.model.application.ApplicationRepository
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
import dev.usbharu.hideout.core.infrastructure.other.TwitterSnowflakeIdGenerateService
import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityPasswordEncoder
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.SecureTokenGenerator
import kotlinx.coroutines.test.runTest
import org.assertj.core.api.Assertions.assertThat
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.argumentCaptor
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.oauth2.core.AuthorizationGrantType
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository
import utils.TestTransaction
import java.net.URI
import java.time.Duration
@ExtendWith(MockitoExtension::class)
class RegisterApplicationApplicationServiceTest {
@InjectMocks
lateinit var service: RegisterApplicationApplicationService
@Mock
lateinit var secureTokenGenerator: SecureTokenGenerator
@Mock
lateinit var registeredClientRepository: RegisteredClientRepository
@Mock
lateinit var applicationRepository: ApplicationRepository
@Spy
val idGenerateService = TwitterSnowflakeIdGenerateService
@Spy
val passwordEncoder = SpringSecurityPasswordEncoder(BCryptPasswordEncoder())
@Spy
val transaction = TestTransaction
@Test
fun applicationを作成できる() = runTest {
whenever(secureTokenGenerator.generate()).doReturn("very-secure-token")
service.execute(
RegisterApplication("test", setOf(URI.create("https://example.com")), false, setOf("write")),
Anonymous
)
argumentCaptor<RegisteredClient> {
verify(registeredClientRepository).save(capture())
val first = allValues.first()
assertThat(first.tokenSettings.accessTokenTimeToLive).isGreaterThanOrEqualTo(Duration.ofSeconds(31536000000))
}
}
@Test
fun refreshTokenを有効化してapplicationを作成できる() = runTest {
whenever(secureTokenGenerator.generate()).doReturn("very-secure-token")
service.execute(
RegisterApplication("test", setOf(URI.create("https://example.com")), true, setOf("write")),
Anonymous
)
argumentCaptor<RegisteredClient> {
verify(registeredClientRepository).save(capture())
val first = allValues.first()
assertThat(first.authorizationGrantTypes).contains(AuthorizationGrantType.REFRESH_TOKEN)
}
}
}

View File

@ -0,0 +1,89 @@
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.filter.*
import dev.usbharu.hideout.core.domain.model.filter.Filter
import dev.usbharu.hideout.core.domain.model.filter.FilterKeyword
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.*
import utils.TestTransaction
@ExtendWith(MockitoExtension::class)
class UserDeleteFilterApplicationServiceTest {
@InjectMocks
lateinit var service: UserDeleteFilterApplicationService
@Spy
val transaction = TestTransaction
@Mock
lateinit var filterRepository: FilterRepository
@Test
fun フィルターを削除できる() = runTest {
val filter = Filter(
FilterId(1), UserDetailId(1), FilterName("filter"), setOf(FilterContext.HOME), FilterAction.HIDE, setOf(
FilterKeyword(
FilterKeywordId(1), FilterKeywordKeyword("aaa"), FilterMode.NONE
)
)
)
whenever(filterRepository.findByFilterId(FilterId(1))).doReturn(filter)
service.execute(
DeleteFilter(1), FromApi(
ActorId(1), UserDetailId(1),
Acct("test", "example.com")
)
)
verify(filterRepository, times(1)).delete(eq(filter))
}
@Test
fun フィルターが見つからない場合失敗() = runTest {
assertThrows<IllegalArgumentException> {
service.execute(
DeleteFilter(1), FromApi(
ActorId(1), UserDetailId(1),
Acct("test", "example.com")
)
)
}
}
@Test
fun フィルターのオーナー以外は失敗() = runTest {
val filter = Filter(
FilterId(1), UserDetailId(1), FilterName("filter"), setOf(FilterContext.HOME), FilterAction.HIDE, setOf(
FilterKeyword(
FilterKeywordId(1), FilterKeywordKeyword("aaa"), FilterMode.NONE
)
)
)
whenever(filterRepository.findByFilterId(FilterId(1))).doReturn(filter)
assertThrows<PermissionDeniedException> {
service.execute(
DeleteFilter(1), FromApi(
ActorId(3), UserDetailId(3),
Acct("test", "example.com")
)
)
}
verify(filterRepository, never()).delete(any())
}
}

View File

@ -0,0 +1,86 @@
package dev.usbharu.hideout.core.application.filter
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.filter.*
import dev.usbharu.hideout.core.domain.model.filter.Filter
import dev.usbharu.hideout.core.domain.model.filter.FilterKeyword
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 UserGetFilterApplicationServiceTest {
@InjectMocks
lateinit var service: UserGetFilterApplicationService
@Mock
lateinit var filterRepository: FilterRepository
@Spy
val transaction = TestTransaction
@Test
fun オーナーのみ取得できる() = runTest {
val filter = Filter(
FilterId(1), UserDetailId(1), FilterName("filter"), setOf(FilterContext.HOME), FilterAction.HIDE, setOf(
FilterKeyword(
FilterKeywordId(1), FilterKeywordKeyword("aaa"), FilterMode.NONE
)
)
)
whenever(filterRepository.findByFilterId(FilterId(1))).doReturn(filter)
service.execute(
GetFilter(1), FromApi(
ActorId(1), UserDetailId(1),
Acct("test", "example.com")
)
)
}
@Test
fun オーナー以外は失敗() = runTest {
val filter = Filter(
FilterId(1), UserDetailId(1), FilterName("filter"), setOf(FilterContext.HOME), FilterAction.HIDE, setOf(
FilterKeyword(
FilterKeywordId(1), FilterKeywordKeyword("aaa"), FilterMode.NONE
)
)
)
whenever(filterRepository.findByFilterId(FilterId(1))).doReturn(filter)
assertThrows<PermissionDeniedException> {
service.execute(
GetFilter(1), FromApi(
ActorId(3), UserDetailId(3),
Acct("test", "example.com")
)
)
}
}
@Test
fun フィルターが見つからない場合失敗() = runTest {
assertThrows<IllegalArgumentException> {
service.execute(
GetFilter(1), FromApi(
ActorId(3), UserDetailId(3),
Acct("test", "example.com")
)
)
}
}
}

View File

@ -1,9 +1,11 @@
package dev.usbharu.hideout.core.application.post package dev.usbharu.hideout.core.application.post
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.ActorId
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository 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.actor.TestActorFactory
import dev.usbharu.hideout.core.domain.model.post.PostRepository import dev.usbharu.hideout.core.domain.model.post.PostRepository
import dev.usbharu.hideout.core.domain.model.post.TestPostFactory
import dev.usbharu.hideout.core.domain.model.post.Visibility import dev.usbharu.hideout.core.domain.model.post.Visibility
import dev.usbharu.hideout.core.domain.model.support.acct.Acct 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.support.principal.FromApi
@ -11,14 +13,13 @@ import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
import dev.usbharu.hideout.core.infrastructure.factory.PostFactoryImpl import dev.usbharu.hideout.core.infrastructure.factory.PostFactoryImpl
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.InjectMocks import org.mockito.InjectMocks
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Spy import org.mockito.Spy
import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.doReturn import org.mockito.kotlin.*
import org.mockito.kotlin.eq
import org.mockito.kotlin.whenever
import utils.TestTransaction import utils.TestTransaction
@ExtendWith(MockitoExtension::class) @ExtendWith(MockitoExtension::class)
@ -41,17 +42,39 @@ class RegisterLocalPostApplicationServiceTest {
@Test @Test
fun postを作成できる() = runTest { fun postを作成できる() = runTest {
val actor = TestActorFactory.create(id = 1) val actor = TestActorFactory.create(id = 1)
val post = TestPostFactory.create()
whenever(actorRepository.findById(ActorId(1))) doReturn actor whenever(actorRepository.findById(ActorId(1))) doReturn actor
whenever( whenever(
postFactoryImpl.createLocal( postFactoryImpl.createLocal(
eq(actor), eq(actor),
anyValueClass(),
isNull(),
eq("content test"),
eq(Visibility.PUBLIC),
isNull(),
isNull(),
eq(false),
eq(emptyList())
) )
) ).doReturn(post)
service.execute( service.execute(
RegisterLocalPost("content test", null, Visibility.PUBLIC, null, false, emptyList<>()), FromApi( RegisterLocalPost("content test", null, Visibility.PUBLIC, null, null, false, emptyList()), FromApi(
ActorId(1), UserDetailId(1), Acct("test", "example.com") ActorId(1), UserDetailId(1), Acct("test", "example.com")
) )
) )
verify(postRepository, times(1)).save(eq(post))
}
@Test
fun actorが見つからないと失敗() = runTest {
assertThrows<InternalServerException> {
service.execute(
RegisterLocalPost("content test", null, Visibility.PUBLIC, null, null, false, emptyList()), FromApi(
ActorId(1), UserDetailId(1), Acct("test", "example.com")
)
)
}
} }
} }

View File

@ -0,0 +1,81 @@
package dev.usbharu.hideout.core.application.relationship.acceptfollowrequest
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.relationship.Relationship
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
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.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
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.argumentCaptor
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import utils.TestTransaction
@ExtendWith(MockitoExtension::class)
class UserAcceptFollowRequestApplicationServiceTest {
@InjectMocks
lateinit var service: UserAcceptFollowRequestApplicationService
@Mock
lateinit var relationshipRepository: RelationshipRepository
@Mock
lateinit var actorRepository: ActorRepository
@Spy
val transaction = TestTransaction
@Test
fun actorが見つからない場合失敗() = runTest {
assertThrows<InternalServerException> {
service.execute(AcceptFollowRequest(1), FromApi(ActorId(2), UserDetailId(2), Acct("test", "example.com")))
}
}
@Test
fun relationshipが見つからない場合失敗() = runTest {
whenever(actorRepository.findById(ActorId(2))).doReturn(TestActorFactory.create(id = 2))
assertThrows<InternalServerException> {
service.execute(AcceptFollowRequest(1), FromApi(ActorId(2), UserDetailId(2), Acct("test", "example.com")))
}
}
@Test
fun フォローリクエストを承認できる() = runTest {
whenever(actorRepository.findById(ActorId(2))).doReturn(TestActorFactory.create(id = 2))
whenever(relationshipRepository.findByActorIdAndTargetId(ActorId(1), ActorId(2))).doReturn(
Relationship(
actorId = ActorId(1), targetActorId = ActorId
(2),
following = false,
blocking = false,
muting = false,
followRequesting = true, mutingFollowRequest = false
)
)
service.execute(AcceptFollowRequest(1), FromApi(ActorId(2), UserDetailId(2), Acct("test", "example.com")))
argumentCaptor<Relationship> {
verify(relationshipRepository).save(capture())
val first = allValues.first()
assertFalse(first.followRequesting)
assertTrue(first.following)
}
}
}

View File

@ -345,4 +345,150 @@ class DefaultTimelineStoreTest {
} }
} }
} }
@Test
fun repostがあるときはRepostを含めたTimelineObjectが作成される() = runTest {
val repost = TestPostFactory.create()
val post = TestPostFactory.create(repostId = repost.id.id)
whenever(postRepository.findById(repost.id)).doReturn(repost)
whenever(timelineRelationshipRepository.findByActorId(post.actorId)).doReturn(
listOf(
TimelineRelationship(
TimelineRelationshipId(1),
TimelineId(12),
post.actorId,
Visible.PUBLIC
)
)
)
whenever(timelineRepository.findByIds(listOf(TimelineId(12)))).doReturn(
listOf(
Timeline(
id = TimelineId(12),
userDetailId = UserDetailId(post.actorId.id),
name = TimelineName("timeline"),
visibility = TimelineVisibility.PUBLIC,
isSystem = false
)
)
)
val filters = listOf(
Filter(
id = FilterId(13),
userDetailId = UserDetailId(post.actorId.id),
name = FilterName("filter"),
filterContext = setOf(FilterContext.HOME),
filterAction = FilterAction.HIDE,
filterKeywords = setOf(
FilterKeyword(FilterKeywordId(14), FilterKeywordKeyword("aa"), FilterMode.NONE)
)
)
)
whenever(filterRepository.findByUserDetailId(UserDetailId(post.actorId.id))).doReturn(filters)
whenever(filterDomainService.apply(post, FilterContext.HOME, filters)).doReturn(
FilteredPost(
post, listOf(
FilterResult(filters.first(), "aaa")
)
)
)
timelineStore.addPost(post)
argumentCaptor<List<TimelineObject>> {
verify(internalTimelineObjectRepository, times(1)).saveAll(capture())
val timelineObjectList = allValues.first()
assertThat(timelineObjectList).allSatisfy {
assertThat(it.postId).isEqualTo(post.id)
assertThat(it.postActorId).isEqualTo(post.actorId)
assertThat(it.replyId).isNull()
assertThat(it.replyActorId).isNull()
assertThat(it.repostId).isEqualTo(repost.id)
assertThat(it.repostActorId).isEqualTo(repost.actorId)
assertThat(it.userDetailId).isEqualTo(UserDetailId(post.actorId.id))
assertThat(it.timelineId).isEqualTo(TimelineId(12))
assertThat(it.warnFilters).contains(TimelineObjectWarnFilter(FilterId(13), "aaa"))
}
}
}
@Test
fun replyがあるときはReplyを含めたTimeineObjectが作成される() = runTest {
val reply = TestPostFactory.create()
val post = TestPostFactory.create(replyId = reply.id.id)
whenever(postRepository.findById(reply.id)).doReturn(reply)
whenever(timelineRelationshipRepository.findByActorId(post.actorId)).doReturn(
listOf(
TimelineRelationship(
TimelineRelationshipId(1),
TimelineId(12),
post.actorId,
Visible.PUBLIC
)
)
)
whenever(timelineRepository.findByIds(listOf(TimelineId(12)))).doReturn(
listOf(
Timeline(
id = TimelineId(12),
userDetailId = UserDetailId(post.actorId.id),
name = TimelineName("timeline"),
visibility = TimelineVisibility.PUBLIC,
isSystem = false
)
)
)
val filters = listOf(
Filter(
id = FilterId(13),
userDetailId = UserDetailId(post.actorId.id),
name = FilterName("filter"),
filterContext = setOf(FilterContext.HOME),
filterAction = FilterAction.HIDE,
filterKeywords = setOf(
FilterKeyword(FilterKeywordId(14), FilterKeywordKeyword("aa"), FilterMode.NONE)
)
)
)
whenever(filterRepository.findByUserDetailId(UserDetailId(post.actorId.id))).doReturn(filters)
whenever(filterDomainService.apply(post, FilterContext.HOME, filters)).doReturn(
FilteredPost(
post, listOf(
FilterResult(filters.first(), "aaa")
)
)
)
timelineStore.addPost(post)
argumentCaptor<List<TimelineObject>> {
verify(internalTimelineObjectRepository, times(1)).saveAll(capture())
val timelineObjectList = allValues.first()
assertThat(timelineObjectList).allSatisfy {
assertThat(it.postId).isEqualTo(post.id)
assertThat(it.postActorId).isEqualTo(post.actorId)
assertThat(it.repostId).isNull()
assertThat(it.repostActorId).isNull()
assertThat(it.replyId).isEqualTo(reply.id)
assertThat(it.replyActorId).isEqualTo(reply.actorId)
assertThat(it.userDetailId).isEqualTo(UserDetailId(post.actorId.id))
assertThat(it.timelineId).isEqualTo(TimelineId(12))
assertThat(it.warnFilters).contains(TimelineObjectWarnFilter(FilterId(13), "aaa"))
}
}
}
} }

View File

@ -18,6 +18,7 @@ package dev.usbharu.hideout.mastodon.interfaces.api
import dev.usbharu.hideout.core.application.application.RegisterApplication import dev.usbharu.hideout.core.application.application.RegisterApplication
import dev.usbharu.hideout.core.application.application.RegisterApplicationApplicationService import dev.usbharu.hideout.core.application.application.RegisterApplicationApplicationService
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
import dev.usbharu.hideout.mastodon.interfaces.api.generated.AppApi import dev.usbharu.hideout.mastodon.interfaces.api.generated.AppApi
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Application import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Application
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.AppsRequest import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.AppsRequest
@ -35,7 +36,7 @@ class SpringAppApi(private val registerApplicationApplicationService: RegisterAp
false, false,
appsRequest.scopes?.split(" ").orEmpty().toSet().ifEmpty { setOf("read") } appsRequest.scopes?.split(" ").orEmpty().toSet().ifEmpty { setOf("read") }
) )
val registeredApplication = registerApplicationApplicationService.register(registerApplication) val registeredApplication = registerApplicationApplicationService.execute(registerApplication, Anonymous)
return ResponseEntity.ok( return ResponseEntity.ok(
Application( Application(
registeredApplication.name, registeredApplication.name,