Merge pull request #104 from usbharu/feature/test-2

Feature/test 2
This commit is contained in:
usbharu 2023-11-01 13:32:18 +09:00 committed by GitHub
commit 6995c88d10
7 changed files with 303 additions and 150 deletions

View File

@ -33,21 +33,21 @@ class ApNoteJobServiceImpl(
objectMapper.readValue<List<dev.usbharu.hideout.domain.model.hideout.entity.Media>>( objectMapper.readValue<List<dev.usbharu.hideout.domain.model.hideout.entity.Media>>(
props[DeliverPostJob.media] props[DeliverPostJob.media]
) )
val note = Note(
name = "Note",
id = postEntity.url,
attributedTo = actor,
content = postEntity.text,
published = Instant.ofEpochMilli(postEntity.createdAt).toString(),
to = listOf(APNoteServiceImpl.public, "$actor/follower"),
attachment = mediaList.map { Document(mediaType = "image/jpeg", url = it.url) }
)
val inbox = props[DeliverPostJob.inbox]
logger.debug("createNoteJob: actor={}, note={}, inbox={}", actor, postEntity, inbox)
transaction.transaction { transaction.transaction {
val signer = userQueryService.findByUrl(actor) val signer = userQueryService.findByUrl(actor)
val note = Note(
name = "Note",
id = postEntity.url,
attributedTo = actor,
content = postEntity.text,
published = Instant.ofEpochMilli(postEntity.createdAt).toString(),
to = listOfNotNull(APNoteServiceImpl.public, signer.followers),
attachment = mediaList.map { Document(mediaType = "image/jpeg", url = it.url) }
)
val inbox = props[DeliverPostJob.inbox]
logger.debug("createNoteJob: actor={}, note={}, inbox={}", actor, postEntity, inbox)
apRequestService.apPost( apRequestService.apPost(
inbox, inbox,
Create( Create(

View File

@ -47,6 +47,7 @@ class ApReactionJobServiceImpl(
val inbox = props[DeliverRemoveReactionJob.inbox] val inbox = props[DeliverRemoveReactionJob.inbox]
val actor = props[DeliverRemoveReactionJob.actor] val actor = props[DeliverRemoveReactionJob.actor]
val like = objectMapper.readValue<Like>(props[DeliverRemoveReactionJob.like]) val like = objectMapper.readValue<Like>(props[DeliverRemoveReactionJob.like])
val id = props[DeliverRemoveReactionJob.id]
val signer = userQueryService.findByUrl(actor) val signer = userQueryService.findByUrl(actor)
@ -56,7 +57,7 @@ class ApReactionJobServiceImpl(
name = "Undo Reaction", name = "Undo Reaction",
actor = actor, actor = actor,
`object` = like, `object` = like,
id = "${applicationConfig.url}/undo/note/${like.id}", id = "${applicationConfig.url}/undo/note/$id",
published = Instant.now() published = Instant.now()
), ),
signer signer

View File

@ -1,4 +1,4 @@
@file:OptIn(ExperimentalCoroutinesApi::class) @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") @file:OptIn(ExperimentalCoroutinesApi::class)
package dev.usbharu.hideout.service.ap package dev.usbharu.hideout.service.ap
@ -20,7 +20,6 @@ import dev.usbharu.hideout.query.PostQueryService
import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.repository.PostRepository import dev.usbharu.hideout.repository.PostRepository
import dev.usbharu.hideout.service.ap.APNoteServiceImpl.Companion.public import dev.usbharu.hideout.service.ap.APNoteServiceImpl.Companion.public
import dev.usbharu.hideout.service.ap.job.ApNoteJobServiceImpl
import dev.usbharu.hideout.service.ap.resource.APResourceResolveService import dev.usbharu.hideout.service.ap.resource.APResourceResolveService
import dev.usbharu.hideout.service.core.TwitterSnowflakeIdGenerateService import dev.usbharu.hideout.service.core.TwitterSnowflakeIdGenerateService
import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.job.JobQueueParentService
@ -35,12 +34,10 @@ import io.ktor.http.*
import io.ktor.http.content.* import io.ktor.http.content.*
import io.ktor.util.* import io.ktor.util.*
import io.ktor.util.date.* import io.ktor.util.date.*
import kjob.core.job.JobProps
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
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
@ -48,7 +45,6 @@ import org.mockito.Mockito.anyLong
import org.mockito.kotlin.* import org.mockito.kotlin.*
import utils.JsonObjectMapper.objectMapper import utils.JsonObjectMapper.objectMapper
import utils.PostBuilder import utils.PostBuilder
import utils.TestTransaction
import utils.UserBuilder import utils.UserBuilder
import java.net.URL import java.net.URL
import java.time.Instant import java.time.Instant
@ -412,31 +408,5 @@ class APNoteServiceImplTest {
assertEquals(note, fetchNote) assertEquals(note, fetchNote)
} }
@Test
fun `createPostJob 新しい投稿のJob`() {
runTest {
val activityPubNoteService = ApNoteJobServiceImpl(
userQueryService = mock(),
objectMapper = objectMapper,
apRequestService = mock(),
transaction = TestTransaction,
applicationConfig = ApplicationConfig(URL("https://example.com"))
)
activityPubNoteService.createNoteJob(
JobProps(
data = mapOf<String, Any>(
DeliverPostJob.actor.name to "https://follower.example.com", DeliverPostJob.post.name to """{
"id": 1,
"userId": 1,
"text": "test text",
"createdAt": 132525324,
"visibility": 0,
"url": "https://example.com"
}""", DeliverPostJob.inbox.name to "https://follower.example.com/inbox", DeliverPostJob.media.name to "[]"
), json = Json
)
)
}
}
} }

View File

@ -0,0 +1,78 @@
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package dev.usbharu.hideout.service.ap.job
import dev.usbharu.hideout.config.ApplicationConfig
import dev.usbharu.hideout.domain.model.ap.Create
import dev.usbharu.hideout.domain.model.ap.Note
import dev.usbharu.hideout.domain.model.job.DeliverPostJob
import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.service.ap.APNoteServiceImpl
import dev.usbharu.hideout.service.ap.APRequestService
import kjob.core.job.JobProps
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import org.junit.jupiter.api.Test
import org.mockito.kotlin.*
import utils.JsonObjectMapper
import utils.TestTransaction
import utils.UserBuilder
import java.net.URL
import java.time.Instant
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,
objectMapper = JsonObjectMapper.objectMapper,
apRequestService = apRequestService,
transaction = TestTransaction,
applicationConfig = ApplicationConfig(URL("https://example.com"))
)
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

@ -0,0 +1,128 @@
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package dev.usbharu.hideout.service.ap.job
import dev.usbharu.hideout.config.ApplicationConfig
import dev.usbharu.hideout.domain.model.ap.Like
import dev.usbharu.hideout.domain.model.ap.Undo
import dev.usbharu.hideout.domain.model.job.DeliverReactionJob
import dev.usbharu.hideout.domain.model.job.DeliverRemoveReactionJob
import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.service.ap.APRequestService
import kjob.core.job.JobProps
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import org.junit.jupiter.api.Test
import org.mockito.Mockito.mockStatic
import org.mockito.kotlin.*
import utils.JsonObjectMapper.objectMapper
import utils.UserBuilder
import java.net.URL
import java.time.Instant
class ApReactionJobServiceImplTest {
@Test
fun `reactionJob Likeが配送される`() = runTest {
val localUser = UserBuilder.localUserOf()
val remoteUser = UserBuilder.remoteUserOf()
val userQueryService = mock<UserQueryService> {
onBlocking { findByUrl(localUser.url) } doReturn localUser
}
val apRequestService = mock<APRequestService>()
val apReactionJobServiceImpl = ApReactionJobServiceImpl(
userQueryService = userQueryService,
apRequestService = apRequestService,
applicationConfig = ApplicationConfig(URL("https://example.com")),
objectMapper = objectMapper
)
val postUrl = "${remoteUser.url}/posts/1234"
apReactionJobServiceImpl.reactionJob(
JobProps(
data = mapOf(
DeliverReactionJob.inbox.name to remoteUser.inbox,
DeliverReactionJob.actor.name to localUser.url,
DeliverReactionJob.postUrl.name to postUrl,
DeliverReactionJob.id.name to "1234",
DeliverReactionJob.reaction.name to "",
),
json = Json
)
)
val body = Like(
name = "Like",
actor = localUser.url,
`object` = postUrl,
id = "https://example.com/like/note/1234",
content = ""
)
verify(apRequestService, times(1)).apPost(eq(remoteUser.inbox), eq(body), eq(localUser))
}
@Test
fun `removeReactionJob LikeのUndoが配送される`() = runTest {
val localUser = UserBuilder.localUserOf()
val remoteUser = UserBuilder.remoteUserOf()
val userQueryService = mock<UserQueryService> {
onBlocking { findByUrl(localUser.url) } doReturn localUser
}
val apRequestService = mock<APRequestService>()
val apReactionJobServiceImpl = ApReactionJobServiceImpl(
userQueryService = userQueryService,
apRequestService = apRequestService,
applicationConfig = ApplicationConfig(URL("https://example.com")),
objectMapper = objectMapper
)
val postUrl = "${remoteUser.url}/posts/1234"
val like = Like(
name = "Like",
actor = remoteUser.url,
`object` = postUrl,
id = "https://example.com/like/note/1234",
content = ""
)
val now = Instant.now()
val body = mockStatic(Instant::class.java).use {
it.`when`<Instant>(Instant::now).thenReturn(now)
apReactionJobServiceImpl.removeReactionJob(
JobProps(
data = mapOf(
DeliverRemoveReactionJob.inbox.name to remoteUser.inbox,
DeliverRemoveReactionJob.actor.name to localUser.url,
DeliverRemoveReactionJob.id.name to "1234",
DeliverRemoveReactionJob.like.name to objectMapper.writeValueAsString(like),
),
json = Json
)
)
Undo(
name = "Undo Reaction",
actor = localUser.url,
`object` = like,
id = "https://example.com/undo/note/1234",
published = now
)
}
verify(apRequestService, times(1)).apPost(eq(remoteUser.inbox), eq(body), eq(localUser))
}
}

View File

@ -6,25 +6,19 @@ import dev.usbharu.hideout.domain.model.ap.Object
import dev.usbharu.hideout.domain.model.hideout.entity.Post import dev.usbharu.hideout.domain.model.hideout.entity.Post
import dev.usbharu.hideout.domain.model.hideout.entity.User import dev.usbharu.hideout.domain.model.hideout.entity.User
import dev.usbharu.hideout.repository.UserRepository import dev.usbharu.hideout.repository.UserRepository
import io.ktor.client.* import dev.usbharu.hideout.service.ap.APRequestService
import io.ktor.client.engine.mock.*
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.junit.jupiter.MockitoExtension import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.any import org.mockito.kotlin.*
import org.mockito.kotlin.doReturn import utils.UserBuilder
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import java.net.URL import java.net.URL
import java.time.Instant
import kotlin.test.assertEquals
@ExtendWith(MockitoExtension::class) @ExtendWith(MockitoExtension::class)
@Disabled
class APResourceResolveServiceImplTest { class APResourceResolveServiceImplTest {
val userBuilder = User.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com"))) val userBuilder = User.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com")))
@ -33,109 +27,89 @@ class APResourceResolveServiceImplTest {
@Test @Test
fun `単純な一回のリクエスト`() = runTest { fun `単純な一回のリクエスト`() = runTest {
var count = 0
val httpClient = HttpClient(MockEngine { request ->
count++
respondOk("{}")
})
val userRepository = mock<UserRepository>() val userRepository = mock<UserRepository>()
whenever(userRepository.findById(any())).doReturn( val user = UserBuilder.localUserOf()
userBuilder.of( whenever(userRepository.findById(any())) doReturn user
2L,
"follower",
"follower.example.com",
"followerUser",
"test follower user",
"https://follower.example.com/inbox",
"https://follower.example.com/outbox",
"https://follower.example.com",
"https://follower.example.com",
publicKey = "",
createdAt = Instant.now(),
keyId = ""
)
)
val apRequestService = mock<APRequestService> {
onBlocking {
apGet(
eq("https"),
eq(user),
eq(Object::class.java)
)
} doReturn dev.usbharu.hideout.domain.model.ap.Object(
emptyList()
)
}
val apResourceResolveService = val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager()) APResourceResolveServiceImpl(apRequestService, userRepository, InMemoryCacheManager())
apResourceResolveService.resolve<Object>("https", 0) apResourceResolveService.resolve<Object>("https", 0)
assertEquals(1, count) verify(apRequestService, times(1)).apGet(eq("https"), eq(user), eq(Object::class.java))
} }
@Test @Test
fun 複数回の同じリクエストが重複して発行されない() = runTest { fun 複数回の同じリクエストが重複して発行されない() = runTest {
var count = 0
val httpClient = HttpClient(MockEngine { request ->
count++
respondOk("{}")
})
val userRepository = mock<UserRepository>() val userRepository = mock<UserRepository>()
whenever(userRepository.findById(any())).doReturn( val user = UserBuilder.localUserOf()
userBuilder.of( whenever(userRepository.findById(any())) doReturn user
2L,
"follower", val apRequestService = mock<APRequestService> {
"follower.example.com", onBlocking {
"followerUser", apGet(
"test follower user", eq("https"),
"https://follower.example.com/inbox", eq(user),
"https://follower.example.com/outbox", eq(Object::class.java)
"https://follower.example.com", )
"https://follower.example.com", } doReturn dev.usbharu.hideout.domain.model.ap.Object(
publicKey = "", emptyList()
createdAt = Instant.now(),
keyId = ""
) )
) }
val apResourceResolveService = val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager()) APResourceResolveServiceImpl(apRequestService, userRepository, InMemoryCacheManager())
apResourceResolveService.resolve<Object>("https", 0) apResourceResolveService.resolve<Object>("https", 0)
apResourceResolveService.resolve<Object>("https", 0) apResourceResolveService.resolve<Object>("https", 0)
apResourceResolveService.resolve<Object>("https", 0) apResourceResolveService.resolve<Object>("https", 0)
apResourceResolveService.resolve<Object>("https", 0) apResourceResolveService.resolve<Object>("https", 0)
assertEquals(1, count) verify(apRequestService, times(1)).apGet(
eq("https"),
eq(user),
eq(Object::class.java)
)
} }
@Test @Test
fun 複数回の同じリクエストが同時に発行されても重複して発行されない() = runTest { fun 複数回の同じリクエストが同時に発行されても重複して発行されない() = runTest {
var count = 0
val httpClient = HttpClient(MockEngine { request ->
count++
respondOk("{}")
})
val userRepository = mock<UserRepository>() val userRepository = mock<UserRepository>()
val user = UserBuilder.localUserOf()
whenever(userRepository.findById(any())).doReturn( whenever(userRepository.findById(any())) doReturn user
userBuilder.of(
2L,
"follower", val apRequestService = mock<APRequestService> {
"follower.example.com", onBlocking {
"followerUser", apGet(
"test follower user", eq("https"),
"https://follower.example.com/inbox", eq(user),
"https://follower.example.com/outbox", eq(Object::class.java)
"https://follower.example.com", )
"https://follower.example.com", } doReturn dev.usbharu.hideout.domain.model.ap.Object(
publicKey = "", emptyList()
createdAt = Instant.now(),
keyId = ""
) )
) }
val apResourceResolveService = val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager()) APResourceResolveServiceImpl(apRequestService, userRepository, InMemoryCacheManager())
repeat(10) { repeat(10) {
awaitAll( awaitAll(
@ -153,45 +127,47 @@ class APResourceResolveServiceImplTest {
) )
} }
assertEquals(1, count) verify(apRequestService, times(1)).apGet(
eq("https"),
eq(user),
eq(Object::class.java)
)
} }
@Test @Test
fun 関係のないリクエストは発行する() = runTest { fun 関係のないリクエストは発行する() = runTest {
var count = 0
val httpClient = HttpClient(MockEngine { request ->
count++
respondOk("{}")
})
val userRepository = mock<UserRepository>() val userRepository = mock<UserRepository>()
val user = UserBuilder.localUserOf()
whenever(userRepository.findById(any())).doReturn( whenever(userRepository.findById(any())).doReturn(
userBuilder.of( user
2L,
"follower",
"follower.example.com",
"followerUser",
"test follower user",
"https://follower.example.com/inbox",
"https://follower.example.com/outbox",
"https://follower.example.com",
"https://follower.example.com",
publicKey = "",
createdAt = Instant.now(),
keyId = ""
)
) )
val apRequestService = mock<APRequestService> {
onBlocking {
apGet(
any(),
eq(user),
eq(Object::class.java)
)
} doReturn dev.usbharu.hideout.domain.model.ap.Object(
emptyList()
)
}
val apResourceResolveService = val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager()) APResourceResolveServiceImpl(apRequestService, userRepository, InMemoryCacheManager())
apResourceResolveService.resolve<Object>("abcd", 0) apResourceResolveService.resolve<Object>("abcd", 0)
apResourceResolveService.resolve<Object>("1234", 0) apResourceResolveService.resolve<Object>("1234", 0)
apResourceResolveService.resolve<Object>("aaaa", 0) apResourceResolveService.resolve<Object>("aaaa", 0)
assertEquals(3, count) verify(apRequestService, times(3)).apGet(
any(),
eq(user),
eq(Object::class.java)
)
} }

View File

@ -44,8 +44,8 @@ object UserBuilder {
privateKey = privateKey, privateKey = privateKey,
createdAt = createdAt, createdAt = createdAt,
keyId = keyId, keyId = keyId,
followers = following, followers = followers,
following = followers following = following
) )
} }
@ -78,8 +78,8 @@ object UserBuilder {
privateKey = null, privateKey = null,
createdAt = createdAt, createdAt = createdAt,
keyId = keyId, keyId = keyId,
followers = following, followers = followers,
following = followers following = following
) )
} }