test: InboxControllerImplのテストを追加

This commit is contained in:
usbharu 2024-02-20 13:13:04 +09:00
parent 526354df1f
commit 0d24f41145
1 changed files with 441 additions and 73 deletions

View File

@ -19,13 +19,17 @@ package dev.usbharu.hideout.activitypub.interfaces.api.inbox
import dev.usbharu.hideout.activitypub.domain.exception.JsonParseException
import dev.usbharu.hideout.activitypub.service.common.APService
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureHeaderChecker
import dev.usbharu.hideout.util.Base64Util
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeEach
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.*
import org.springframework.http.MediaType
@ -33,12 +37,21 @@ import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import org.springframework.test.web.servlet.post
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import java.net.URI
import java.security.MessageDigest
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.util.*
@ExtendWith(MockitoExtension::class)
class InboxControllerImplTest {
private lateinit var mockMvc: MockMvc
@Spy
private val httpSignatureHeaderChecker =
HttpSignatureHeaderChecker(ApplicationConfig(URI.create("https://example.com").toURL()))
@Mock
private lateinit var apService: APService
@ -50,6 +63,10 @@ class InboxControllerImplTest {
mockMvc = MockMvcBuilders.standaloneSetup(inboxController).build()
}
private val dateTimeFormatter: DateTimeFormatter =
DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US)
@Test
fun `inbox 正常なPOSTリクエストをしたときAcceptが返ってくる`() = runTest {
@ -58,24 +75,25 @@ class InboxControllerImplTest {
whenever(apService.parseActivity(eq(json))).doReturn(ActivityType.Follow)
whenever(
apService.processActivity(
eq(json),
eq(ActivityType.Follow),
any(),
any()
eq(json), eq(ActivityType.Follow), any(), any()
)
).doReturn(Unit)
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
}
.asyncDispatch()
.andExpect {
status { isAccepted() }
}
val sha256 = MessageDigest.getInstance("SHA-256")
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "a")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}.asyncDispatch().andExpect {
status { isAccepted() }
}
}
@ -83,17 +101,19 @@ class InboxControllerImplTest {
fun `inbox parseActivityに失敗したときAcceptが返ってくる`() = runTest {
val json = """{"type":"Hoge"}"""
whenever(apService.parseActivity(eq(json))).doThrow(JsonParseException::class)
val sha256 = MessageDigest.getInstance("SHA-256")
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
}
.asyncDispatch()
.andExpect {
status { isAccepted() }
}
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "a")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}.asyncDispatch().andExpect {
status { isAccepted() }
}
}
@ -103,23 +123,22 @@ class InboxControllerImplTest {
whenever(apService.parseActivity(eq(json))).doReturn(ActivityType.Follow)
whenever(
apService.processActivity(
eq(json),
eq(ActivityType.Follow),
any(),
any()
eq(json), eq(ActivityType.Follow), any(), any()
)
).doThrow(FailedToGetResourcesException::class)
val sha256 = MessageDigest.getInstance("SHA-256")
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
}
.asyncDispatch()
.andExpect {
status { isAccepted() }
}
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "a")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}.asyncDispatch().andExpect {
status { isAccepted() }
}
}
@ -137,17 +156,19 @@ class InboxControllerImplTest {
whenever(apService.processActivity(eq(json), eq(ActivityType.Follow), any(), any())).doReturn(
Unit
)
val sha256 = MessageDigest.getInstance("SHA-256")
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
}
.asyncDispatch()
.andExpect {
status { isAccepted() }
}
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "a")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}.asyncDispatch().andExpect {
status { isAccepted() }
}
}
@ -155,17 +176,19 @@ class InboxControllerImplTest {
fun `user-inbox parseActivityに失敗したときAcceptが返ってくる`() = runTest {
val json = """{"type":"Hoge"}"""
whenever(apService.parseActivity(eq(json))).doThrow(JsonParseException::class)
val sha256 = MessageDigest.getInstance("SHA-256")
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
}
.asyncDispatch()
.andExpect {
status { isAccepted() }
}
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "a")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}.asyncDispatch().andExpect {
status { isAccepted() }
}
}
@ -175,23 +198,22 @@ class InboxControllerImplTest {
whenever(apService.parseActivity(eq(json))).doReturn(ActivityType.Follow)
whenever(
apService.processActivity(
eq(json),
eq(ActivityType.Follow),
any(),
any()
eq(json), eq(ActivityType.Follow), any(), any()
)
).doThrow(FailedToGetResourcesException::class)
val sha256 = MessageDigest.getInstance("SHA-256")
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
}
.asyncDispatch()
.andExpect {
status { isAccepted() }
}
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "a")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}.asyncDispatch().andExpect {
status { isAccepted() }
}
}
@ -199,4 +221,350 @@ class InboxControllerImplTest {
fun `user-inbox GETリクエストには405を返す`() {
mockMvc.get("/users/hoge/inbox").andExpect { status { isMethodNotAllowed() } }
}
@Test
fun `inbox Dateヘッダーが無いと400`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
}
.asyncDispatch()
.andExpect {
status {
isBadRequest()
}
}
}
@Test
fun `user-inbox Dateヘッダーが無いと400`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
}
.asyncDispatch()
.andExpect {
status {
isBadRequest()
}
}
}
@Test
fun `inbox Dateヘッダーが未来だと401`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Date", ZonedDateTime.now().plusDays(1).format(dateTimeFormatter))
}
.asyncDispatch()
.andExpect {
status {
isUnauthorized()
}
}
}
@Test
fun `user-inbox Dateヘッダーが未来だと401`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Date", ZonedDateTime.now().plusDays(1).format(dateTimeFormatter))
}
.asyncDispatch()
.andExpect {
status {
isUnauthorized()
}
}
}
@Test
fun `inbox Dateヘッダーが過去過ぎると401`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Date", ZonedDateTime.now().minusDays(1).format(dateTimeFormatter))
}
.asyncDispatch()
.andExpect {
status {
isUnauthorized()
}
}
}
@Test
fun `user-inbox Dateヘッダーが過去過ぎると401`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Date", ZonedDateTime.now().minusDays(1).format(dateTimeFormatter))
}
.asyncDispatch()
.andExpect {
status {
isUnauthorized()
}
}
}
@Test
fun `inbox Hostヘッダーが無いと400`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
}
.asyncDispatch()
.andExpect {
status {
isBadRequest()
}
}
}
@Test
fun `user-inbox Hostヘッダーが無いと400`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
}
.asyncDispatch()
.andExpect {
status {
isBadRequest()
}
}
}
@Test
fun `inbox Hostヘッダーが間違ってると401`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Host", "example.jp")
}
.asyncDispatch()
.andExpect {
status {
isUnauthorized()
}
}
}
@Test
fun `user-inbox Hostヘッダーが間違ってると401`() {
val json = """{"type":"Follow"}"""
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Host", "example.jp")
}
.asyncDispatch()
.andExpect {
status {
isUnauthorized()
}
}
}
@Test
fun `inbox Digestヘッダーがないと400`() = runTest {
val json = """{"type":"Follow"}"""
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
}
.asyncDispatch()
.andExpect {
status { isBadRequest() }
}
}
@Test
fun `inbox Digestヘッダーが間違ってると401`() = runTest {
val json = """{"type":"Follow"}"""
val sha256 = MessageDigest.getInstance("SHA-256")
val digest = Base64Util.encode(sha256.digest(("$json aaaaaaaa").toByteArray()))
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}
.asyncDispatch()
.andExpect {
status { isUnauthorized() }
}
}
@Test
fun `user-inbox Digestヘッダーがないと400`() = runTest {
val json = """{"type":"Follow"}"""
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
}
.asyncDispatch()
.andExpect {
status { isBadRequest() }
}
}
@Test
fun `user-inbox Digestヘッダーが間違ってると401`() = runTest {
val json = """{"type":"Follow"}"""
val sha256 = MessageDigest.getInstance("SHA-256")
val digest = Base64Util.encode(sha256.digest(("$json aaaaaaaa").toByteArray()))
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}
.asyncDispatch()
.andExpect {
status { isUnauthorized() }
}
}
@Test
fun `inbox Signatureヘッダーがないと401`() = runTest {
val json = """{"type":"Follow"}"""
val sha256 = MessageDigest.getInstance("SHA-256")
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}
.asyncDispatch()
.andExpect {
status { isUnauthorized() }
}
}
@Test
fun `inbox Signatureヘッダーが空だと401`() = runTest {
val json = """{"type":"Follow"}"""
val sha256 = MessageDigest.getInstance("SHA-256")
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc
.post("/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}
.asyncDispatch()
.andExpect {
status { isUnauthorized() }
}
}
@Test
fun `user-inbox Digestヘッダーがないと401`() = runTest {
val json = """{"type":"Follow"}"""
val sha256 = MessageDigest.getInstance("SHA-256")
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}
.asyncDispatch()
.andExpect {
status { isUnauthorized() }
}
}
@Test
fun `user-inbox Digestヘッダーが空だと401`() = runTest {
val json = """{"type":"Follow"}"""
val sha256 = MessageDigest.getInstance("SHA-256")
val digest = Base64Util.encode(sha256.digest(json.toByteArray()))
mockMvc
.post("/users/hoge/inbox") {
content = json
contentType = MediaType.APPLICATION_JSON
header("Signature", "")
header("Host", "example.com")
header("Date", ZonedDateTime.now().format(dateTimeFormatter))
header("Digest", digest)
}
.asyncDispatch()
.andExpect {
status { isUnauthorized() }
}
}
}