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>>(
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 {
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(
inbox,
Create(

View File

@ -47,6 +47,7 @@ class ApReactionJobServiceImpl(
val inbox = props[DeliverRemoveReactionJob.inbox]
val actor = props[DeliverRemoveReactionJob.actor]
val like = objectMapper.readValue<Like>(props[DeliverRemoveReactionJob.like])
val id = props[DeliverRemoveReactionJob.id]
val signer = userQueryService.findByUrl(actor)
@ -56,7 +57,7 @@ class ApReactionJobServiceImpl(
name = "Undo Reaction",
actor = actor,
`object` = like,
id = "${applicationConfig.url}/undo/note/${like.id}",
id = "${applicationConfig.url}/undo/note/$id",
published = Instant.now()
),
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
@ -20,7 +20,6 @@ import dev.usbharu.hideout.query.PostQueryService
import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.repository.PostRepository
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.core.TwitterSnowflakeIdGenerateService
import dev.usbharu.hideout.service.job.JobQueueParentService
@ -35,12 +34,10 @@ import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.util.*
import io.ktor.util.date.*
import kjob.core.job.JobProps
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
@ -48,7 +45,6 @@ import org.mockito.Mockito.anyLong
import org.mockito.kotlin.*
import utils.JsonObjectMapper.objectMapper
import utils.PostBuilder
import utils.TestTransaction
import utils.UserBuilder
import java.net.URL
import java.time.Instant
@ -412,31 +408,5 @@ class APNoteServiceImplTest {
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.User
import dev.usbharu.hideout.repository.UserRepository
import io.ktor.client.*
import io.ktor.client.engine.mock.*
import dev.usbharu.hideout.service.ap.APRequestService
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.mockito.kotlin.*
import utils.UserBuilder
import java.net.URL
import java.time.Instant
import kotlin.test.assertEquals
@ExtendWith(MockitoExtension::class)
@Disabled
class APResourceResolveServiceImplTest {
val userBuilder = User.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com")))
@ -33,109 +27,89 @@ class APResourceResolveServiceImplTest {
@Test
fun `単純な一回のリクエスト`() = runTest {
var count = 0
val httpClient = HttpClient(MockEngine { request ->
count++
respondOk("{}")
})
val userRepository = mock<UserRepository>()
whenever(userRepository.findById(any())).doReturn(
userBuilder.of(
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 user = UserBuilder.localUserOf()
whenever(userRepository.findById(any())) doReturn user
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 =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager())
APResourceResolveServiceImpl(apRequestService, userRepository, InMemoryCacheManager())
apResourceResolveService.resolve<Object>("https", 0)
assertEquals(1, count)
verify(apRequestService, times(1)).apGet(eq("https"), eq(user), eq(Object::class.java))
}
@Test
fun 複数回の同じリクエストが重複して発行されない() = runTest {
var count = 0
val httpClient = HttpClient(MockEngine { request ->
count++
respondOk("{}")
})
val userRepository = mock<UserRepository>()
whenever(userRepository.findById(any())).doReturn(
userBuilder.of(
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 user = UserBuilder.localUserOf()
whenever(userRepository.findById(any())) doReturn user
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 =
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)
assertEquals(1, count)
verify(apRequestService, times(1)).apGet(
eq("https"),
eq(user),
eq(Object::class.java)
)
}
@Test
fun 複数回の同じリクエストが同時に発行されても重複して発行されない() = runTest {
var count = 0
val httpClient = HttpClient(MockEngine { request ->
count++
respondOk("{}")
})
val userRepository = mock<UserRepository>()
val user = UserBuilder.localUserOf()
whenever(userRepository.findById(any())).doReturn(
userBuilder.of(
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 = ""
whenever(userRepository.findById(any())) doReturn user
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 =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager())
APResourceResolveServiceImpl(apRequestService, userRepository, InMemoryCacheManager())
repeat(10) {
awaitAll(
@ -153,45 +127,47 @@ class APResourceResolveServiceImplTest {
)
}
assertEquals(1, count)
verify(apRequestService, times(1)).apGet(
eq("https"),
eq(user),
eq(Object::class.java)
)
}
@Test
fun 関係のないリクエストは発行する() = runTest {
var count = 0
val httpClient = HttpClient(MockEngine { request ->
count++
respondOk("{}")
})
val userRepository = mock<UserRepository>()
val user = UserBuilder.localUserOf()
whenever(userRepository.findById(any())).doReturn(
userBuilder.of(
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 = ""
)
user
)
val apRequestService = mock<APRequestService> {
onBlocking {
apGet(
any(),
eq(user),
eq(Object::class.java)
)
} doReturn dev.usbharu.hideout.domain.model.ap.Object(
emptyList()
)
}
val apResourceResolveService =
APResourceResolveServiceImpl(mock(), userRepository, InMemoryCacheManager())
APResourceResolveServiceImpl(apRequestService, userRepository, InMemoryCacheManager())
apResourceResolveService.resolve<Object>("abcd", 0)
apResourceResolveService.resolve<Object>("1234", 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,
createdAt = createdAt,
keyId = keyId,
followers = following,
following = followers
followers = followers,
following = following
)
}
@ -78,8 +78,8 @@ object UserBuilder {
privateKey = null,
createdAt = createdAt,
keyId = keyId,
followers = following,
following = followers
followers = followers,
following = following
)
}