Merge pull request #379 from usbharu/mock

モックの作成をアノテーションベースに変更する
This commit is contained in:
usbharu 2024-05-18 15:28:08 +09:00 committed by GitHub
commit 525c2acdc3
3 changed files with 143 additions and 255 deletions

View File

@ -23,16 +23,18 @@ import dev.usbharu.hideout.activitypub.domain.model.Image
import dev.usbharu.hideout.activitypub.domain.model.Key import dev.usbharu.hideout.activitypub.domain.model.Key
import dev.usbharu.hideout.activitypub.domain.model.Note import dev.usbharu.hideout.activitypub.domain.model.Note
import dev.usbharu.hideout.activitypub.domain.model.Person import dev.usbharu.hideout.activitypub.domain.model.Person
import dev.usbharu.hideout.activitypub.query.AnnounceQueryService
import dev.usbharu.hideout.activitypub.query.NoteQueryService import dev.usbharu.hideout.activitypub.query.NoteQueryService
import dev.usbharu.hideout.activitypub.service.common.APResourceResolveService import dev.usbharu.hideout.activitypub.service.common.APResourceResolveService
import dev.usbharu.hideout.activitypub.service.objects.emoji.EmojiService
import dev.usbharu.hideout.activitypub.service.objects.note.APNoteServiceImpl.Companion.public import dev.usbharu.hideout.activitypub.service.objects.note.APNoteServiceImpl.Companion.public
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
import dev.usbharu.hideout.application.config.CharacterLimit import dev.usbharu.hideout.application.config.CharacterLimit
import dev.usbharu.hideout.application.config.HtmlSanitizeConfig import dev.usbharu.hideout.application.config.HtmlSanitizeConfig
import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.post.Post import dev.usbharu.hideout.core.domain.model.post.Post
import dev.usbharu.hideout.core.domain.model.post.PostRepository import dev.usbharu.hideout.core.domain.model.post.PostRepository
import dev.usbharu.hideout.core.service.media.MediaService
import dev.usbharu.hideout.core.service.post.DefaultPostContentFormatter import dev.usbharu.hideout.core.service.post.DefaultPostContentFormatter
import dev.usbharu.hideout.core.service.post.PostService import dev.usbharu.hideout.core.service.post.PostService
import io.ktor.client.* import io.ktor.client.*
@ -53,28 +55,58 @@ import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows 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.mockito.kotlin.*
import utils.PostBuilder import utils.PostBuilder
import utils.UserBuilder import utils.UserBuilder
import java.time.Instant import java.time.Instant
@ExtendWith(MockitoExtension::class)
class APNoteServiceImplTest { class APNoteServiceImplTest {
val postBuilder = Post.PostBuilder( @Mock
private lateinit var postRepository: PostRepository
@Mock
private lateinit var apUserService: APUserService
@Mock
private lateinit var postService: PostService
@Mock
private lateinit var apResourceResolverService: APResourceResolveService
@Spy
private val postBuilder: Post.PostBuilder = Post.PostBuilder(
CharacterLimit(), DefaultPostContentFormatter(HtmlSanitizeConfig().policy()), CharacterLimit(), DefaultPostContentFormatter(HtmlSanitizeConfig().policy()),
Validation.buildDefaultValidatorFactory().validator Validation.buildDefaultValidatorFactory().validator
) )
@Mock
private lateinit var noteQueryService: NoteQueryService
@Mock
private lateinit var mediaService: MediaService
@Mock
private lateinit var emojiService: EmojiService
@Mock
private lateinit var announceQueryService: AnnounceQueryService
@InjectMocks
private lateinit var apNoteServiceImpl: APNoteServiceImpl
@Test @Test
fun `fetchNote(String,String) ートが既に存在する場合はDBから取得したものを返す`() = runTest { fun `fetchNote(String,String) ートが既に存在する場合はDBから取得したものを返す`() = runTest {
val url = "https://example.com/note" val url = "https://example.com/note"
val post = PostBuilder.of() val post = PostBuilder.of()
val user = UserBuilder.localUserOf(id = post.actorId) val user = UserBuilder.localUserOf(id = post.actorId)
val actorQueryService = mock<ActorRepository> {
onBlocking { findById(eq(post.actorId)) } doReturn user
}
val expected = Note( val expected = Note(
id = post.apId, id = post.apId,
attributedTo = user.url, attributedTo = user.url,
@ -85,20 +117,8 @@ class APNoteServiceImplTest {
cc = listOfNotNull(public, user.followers), cc = listOfNotNull(public, user.followers),
inReplyTo = null inReplyTo = null
) )
val noteQueryService = mock<NoteQueryService> {
onBlocking { findByApid(eq(url)) } doReturn (expected to post) whenever(noteQueryService.findByApid(eq(url))).doReturn(expected to post)
}
val apNoteServiceImpl = APNoteServiceImpl(
postRepository = mock(),
apUserService = mock(),
postService = mock(),
apResourceResolveService = mock(),
postBuilder = postBuilder,
noteQueryService = noteQueryService,
mock(),
mock(),
mock()
)
val actual = apNoteServiceImpl.fetchNote(url) val actual = apNoteServiceImpl.fetchNote(url)
@ -123,12 +143,11 @@ class APNoteServiceImplTest {
cc = listOfNotNull(public, user.followers), cc = listOfNotNull(public, user.followers),
inReplyTo = null inReplyTo = null
) )
val apResourceResolveService = mock<APResourceResolveService> {
onBlocking { resolve<Note>(eq(url), any(), isNull<Long>()) } doReturn note whenever(apResourceResolverService.resolve<Note>(eq(url), any(), isNull<Long>())).doReturn(note)
}
val noteQueryService = mock<NoteQueryService> { whenever(noteQueryService.findByApid(eq(url))).doReturn(null)
onBlocking { findByApid(eq(url)) } doReturn null
}
val person = Person( val person = Person(
name = user.name, name = user.name,
id = user.url, id = user.url,
@ -153,23 +172,16 @@ class APNoteServiceImplTest {
manuallyApprovesFollowers = false manuallyApprovesFollowers = false
) )
val apUserService = mock<APUserService> {
onBlocking { fetchPersonWithEntity(eq(note.attributedTo), isNull(), anyOrNull()) } doReturn (person to user) whenever(
} apUserService.fetchPersonWithEntity(
val postRepository = mock<PostRepository> { eq(note.attributedTo),
onBlocking { generateId() } doReturn TwitterSnowflakeIdGenerateService.generateId() isNull(),
} anyOrNull()
val apNoteServiceImpl = APNoteServiceImpl( )
postRepository = postRepository, ).doReturn(person to user)
apUserService = apUserService,
postService = mock(), whenever(postRepository.generateId()).doReturn(TwitterSnowflakeIdGenerateService.generateId())
apResourceResolveService = apResourceResolveService,
postBuilder = postBuilder,
noteQueryService = noteQueryService,
mock(),
mock { },
mock()
)
val actual = apNoteServiceImpl.fetchNote(url) val actual = apNoteServiceImpl.fetchNote(url)
@ -181,17 +193,16 @@ class APNoteServiceImplTest {
fun `fetchNote(String,String) ートをリモートから取得した際にエラーが返ってきたらFailedToGetActivityPubResourceExceptionがthrowされる`() = fun `fetchNote(String,String) ートをリモートから取得した際にエラーが返ってきたらFailedToGetActivityPubResourceExceptionがthrowされる`() =
runTest { runTest {
val url = "https://example.com/note" val url = "https://example.com/note"
val responseData = HttpResponseData(
val apResourceResolveService = mock<APResourceResolveService> { HttpStatusCode.BadRequest,
val responseData = HttpResponseData( GMTDate(),
HttpStatusCode.BadRequest, Headers.Empty,
GMTDate(), HttpProtocolVersion.HTTP_1_1,
Headers.Empty, NullBody,
HttpProtocolVersion.HTTP_1_1, Dispatchers.IO
NullBody, )
Dispatchers.IO whenever(apResourceResolverService.resolve<Note>(eq(url), any(), isNull<Long>())).doThrow(
) ClientRequestException(
onBlocking { resolve<Note>(eq(url), any(), isNull<Long>()) } doThrow ClientRequestException(
DefaultHttpResponse( DefaultHttpResponse(
HttpClientCall( HttpClientCall(
HttpClient(), HttpRequestData( HttpClient(), HttpRequestData(
@ -205,22 +216,10 @@ class APNoteServiceImplTest {
), responseData ), responseData
), "" ), ""
) )
}
val noteQueryService = mock<NoteQueryService> {
onBlocking { findByApid(eq(url)) } doReturn null
}
val apNoteServiceImpl = APNoteServiceImpl(
postRepository = mock(),
apUserService = mock(),
postService = mock(),
apResourceResolveService = apResourceResolveService,
postBuilder = postBuilder,
noteQueryService = noteQueryService,
mock(),
mock(),
mock { }
) )
whenever(noteQueryService.findByApid(eq(url))).doReturn(null)
assertThrows<FailedToGetActivityPubResourceException> { apNoteServiceImpl.fetchNote(url) } assertThrows<FailedToGetActivityPubResourceException> { apNoteServiceImpl.fetchNote(url) }
} }
@ -230,9 +229,9 @@ class APNoteServiceImplTest {
val user = UserBuilder.localUserOf() val user = UserBuilder.localUserOf()
val generateId = TwitterSnowflakeIdGenerateService.generateId() val generateId = TwitterSnowflakeIdGenerateService.generateId()
val post = PostBuilder.of(id = generateId, userId = user.id) val post = PostBuilder.of(id = generateId, userId = user.id)
val postRepository = mock<PostRepository> {
onBlocking { generateId() } doReturn generateId whenever(postRepository.generateId()).doReturn(generateId)
}
val person = Person( val person = Person(
name = user.name, name = user.name,
id = user.url, id = user.url,
@ -254,24 +253,10 @@ class APNoteServiceImplTest {
following = user.following, following = user.following,
followers = user.followers followers = user.followers
) )
val apUserService = mock<APUserService> {
onBlocking { fetchPersonWithEntity(eq(user.url), anyOrNull(), anyOrNull()) } doReturn (person to user) whenever(apUserService.fetchPersonWithEntity(eq(user.url), anyOrNull(), anyOrNull())).doReturn(person to user)
}
val postService = mock<PostService>() whenever(noteQueryService.findByApid(eq(post.apId))).doReturn(null)
val noteQueryService = mock<NoteQueryService> {
onBlocking { findByApid(eq(post.apId)) } doReturn null
}
val apNoteServiceImpl = APNoteServiceImpl(
postRepository = postRepository,
apUserService = apUserService,
postService = postService,
apResourceResolveService = mock(),
postBuilder = postBuilder,
noteQueryService = noteQueryService,
mock(),
mock(),
mock()
)
val note = Note( val note = Note(
id = post.apId, id = post.apId,
@ -312,21 +297,8 @@ class APNoteServiceImplTest {
cc = listOfNotNull(public, user.followers), cc = listOfNotNull(public, user.followers),
inReplyTo = null inReplyTo = null
) )
val noteQueryService = mock<NoteQueryService> {
onBlocking { findByApid(eq(post.apId)) } doReturn (note to post)
}
val apNoteServiceImpl = APNoteServiceImpl(
postRepository = mock(),
apUserService = mock(),
postService = mock(),
apResourceResolveService = mock(),
postBuilder = postBuilder,
noteQueryService = noteQueryService,
mock(),
mock(),
mock()
)
whenever(noteQueryService.findByApid(post.apId)).doReturn(note to post)
val fetchNote = apNoteServiceImpl.fetchNote(note, null) val fetchNote = apNoteServiceImpl.fetchNote(note, null)
assertEquals(note, fetchNote) assertEquals(note, fetchNote)

View File

@ -1,75 +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.
*/
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package dev.usbharu.hideout.activitypub.service.objects.note
class ApNoteJobServiceImplTest {
// @Test
// fun `createPostJob 新しい投稿のJob`() = runTest {
// val apRequestService = mock<APRequestService>()
// val user = UserBuilder.localUserOf()
// val userQueryService = mock<UserQueryService> {
// onBlocking { findByUrl(eq(user.url)) } doReturn user
// }
// val activityPubNoteService = ApNoteJobServiceImpl(
//
// userQueryService = userQueryService,
// apRequestService = apRequestService,
// objectMapper = JsonObjectMapper.objectMapper,
// transaction = TestTransaction
// )
// val remoteUserOf = UserBuilder.remoteUserOf()
// activityPubNoteService.createNoteJob(
// JobProps(
// data = mapOf<String, Any>(
// DeliverPostJob.actor.name to user.url,
// DeliverPostJob.post.name to """{
// "id": 1,
// "userId": ${user.id},
// "text": "test text",
// "createdAt": 132525324,
// "visibility": 0,
// "url": "https://example.com"
// }""",
// DeliverPostJob.inbox.name to remoteUserOf.inbox,
// DeliverPostJob.media.name to "[]"
// ), json = Json
// )
// )
//
// val note = Note(
// name = "Note",
// id = "https://example.com",
// attributedTo = user.url,
// content = "test text",
// published = Instant.ofEpochMilli(132525324).toString(),
// to = listOfNotNull(APNoteServiceImpl.public, user.followers)
// )
// val create = Create(
// name = "Create Note",
// `object` = note,
// actor = note.attributedTo,
// id = "https://example.com/create/note/1"
// )
// verify(apRequestService, times(1)).apPost(
// eq(remoteUserOf.inbox),
// eq(create),
// eq(user)
// )
// }
}

View File

@ -18,18 +18,31 @@
package dev.usbharu.hideout.core.service.user package dev.usbharu.hideout.core.service.user
import dev.usbharu.hideout.activitypub.service.activity.delete.APSendDeleteService
import dev.usbharu.hideout.application.config.ApplicationConfig import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.config.CharacterLimit import dev.usbharu.hideout.application.config.CharacterLimit
import dev.usbharu.hideout.core.domain.model.actor.Actor import dev.usbharu.hideout.core.domain.model.actor.Actor
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.deletedActor.DeletedActorRepository
import dev.usbharu.hideout.core.domain.model.instance.Instance import dev.usbharu.hideout.core.domain.model.instance.Instance
import dev.usbharu.hideout.core.domain.model.post.PostRepository
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import dev.usbharu.hideout.core.service.instance.InstanceService import dev.usbharu.hideout.core.service.instance.InstanceService
import dev.usbharu.hideout.core.service.post.PostService
import dev.usbharu.owl.producer.api.OwlProducer
import jakarta.validation.Validation import jakarta.validation.Validation
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
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.assertThrows
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.anyString
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.Spy
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.* import org.mockito.kotlin.*
import utils.TestApplicationConfig.testApplicationConfig import utils.TestApplicationConfig.testApplicationConfig
import java.net.URL import java.net.URL
@ -38,40 +51,65 @@ import java.time.Instant
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNull import kotlin.test.assertNull
@ExtendWith(MockitoExtension::class)
class ActorServiceTest { class ActorServiceTest {
val actorBuilder = Actor.UserBuilder(
@Mock
private lateinit var actorRepository: ActorRepository
@Mock
private lateinit var userAuthService: UserAuthService
@Spy
private val actorBuilder = Actor.UserBuilder(
CharacterLimit(), CharacterLimit(),
ApplicationConfig(URL("https://example.com")), ApplicationConfig(URL("https://example.com")),
Validation.buildDefaultValidatorFactory().validator Validation.buildDefaultValidatorFactory().validator
) )
@Spy
private val applicationConfig: ApplicationConfig = testApplicationConfig.copy(private = false)
@Mock
private lateinit var instanceService: InstanceService
@Mock
private lateinit var userDetailRepository: UserDetailRepository
@Mock
private lateinit var deletedActorRepository: DeletedActorRepository
@Mock
private lateinit var reactionRepository: ReactionRepository
@Mock
private lateinit var relationshipRepository: RelationshipRepository
@Mock
private lateinit var postService: PostService
@Mock
private lateinit var apSendDeleteService: APSendDeleteService
@Mock
private lateinit var postRepository: PostRepository
@Mock
private lateinit var owlProducer: OwlProducer
@InjectMocks
private lateinit var userService: UserServiceImpl
@Test @Test
fun `createLocalUser ローカルユーザーを作成できる`() = runTest { fun `createLocalUser ローカルユーザーを作成できる`() = runTest {
val actorRepository = mock<ActorRepository> {
onBlocking { nextId() } doReturn 110001L
}
val generateKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair() val generateKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair()
val userAuthService = mock<UserAuthService> { whenever(actorRepository.nextId()).doReturn(110001L)
onBlocking { hash(anyString()) } doReturn "hashedPassword" whenever(userAuthService.hash(anyString())).doReturn("hashedPassword")
onBlocking { generateKeyPair() } doReturn generateKeyPair whenever(userAuthService.generateKeyPair()).doReturn(generateKeyPair)
}
val userService =
UserServiceImpl(
actorRepository = actorRepository,
userAuthService = userAuthService,
actorBuilder = actorBuilder,
applicationConfig = testApplicationConfig.copy(private = false),
instanceService = mock(),
userDetailRepository = mock(),
deletedActorRepository = mock(),
reactionRepository = mock(),
relationshipRepository = mock(),
postService = mock(),
apSendDeleteService = mock(),
postRepository = mock(),
owlProducer = mock()
)
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test")) userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
verify(actorRepository, times(1)).save(any()) verify(actorRepository, times(1)).save(any())
argumentCaptor<Actor> { argumentCaptor<Actor> {
@ -91,31 +129,7 @@ class ActorServiceTest {
@Test @Test
fun `createLocalUser applicationconfig privateがtrueのときアカウントを作成できない`() = runTest { fun `createLocalUser applicationconfig privateがtrueのときアカウントを作成できない`() = runTest {
whenever(applicationConfig.private).thenReturn(true)
val actorRepository = mock<ActorRepository> {
onBlocking { nextId() } doReturn 110001L
}
val generateKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair()
val userAuthService = mock<UserAuthService> {
onBlocking { hash(anyString()) } doReturn "hashedPassword"
onBlocking { generateKeyPair() } doReturn generateKeyPair
}
val userService =
UserServiceImpl(
actorRepository = actorRepository,
userAuthService = userAuthService,
actorBuilder = actorBuilder,
applicationConfig = testApplicationConfig.copy(private = true),
instanceService = mock(),
userDetailRepository = mock(),
deletedActorRepository = mock(),
reactionRepository = mock(),
relationshipRepository = mock(),
postService = mock(),
apSendDeleteService = mock(),
postRepository = mock(),
owlProducer = mock()
)
assertThrows<IllegalStateException> { assertThrows<IllegalStateException> {
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test")) userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
@ -126,17 +140,9 @@ class ActorServiceTest {
@Test @Test
fun `createRemoteUser リモートユーザーを作成できる`() = runTest { fun `createRemoteUser リモートユーザーを作成できる`() = runTest {
val actorRepository = mock<ActorRepository> { whenever(actorRepository.nextId()).doReturn(113345L)
onBlocking { nextId() } doReturn 113345L whenever(instanceService.fetchInstance(eq("https://remote.example.com"), isNull())).doReturn(
} Instance(
val instanceService = mock<InstanceService> {
onBlocking {
fetchInstance(
eq("https://remote.example.com"),
isNull()
)
} doReturn Instance(
12345L, 12345L,
"", "",
"", "",
@ -150,23 +156,8 @@ class ActorServiceTest {
"", "",
Instant.now() Instant.now()
) )
} )
val userService =
UserServiceImpl(
actorRepository = actorRepository,
userAuthService = mock(),
actorBuilder = actorBuilder,
applicationConfig = testApplicationConfig,
instanceService = instanceService,
userDetailRepository = mock(),
deletedActorRepository = mock(),
reactionRepository = mock(),
relationshipRepository = mock(),
postService = mock(),
apSendDeleteService = mock(),
postRepository = mock(),
owlProducer = mock()
)
val user = RemoteUserCreateDto( val user = RemoteUserCreateDto(
name = "test", name = "test",
domain = "remote.example.com", domain = "remote.example.com",