generated from pricelees/issue-pr-template
[#48] Tosspay mocking 서버 구현을 위한 멀티모듈 전환 #49
@ -0,0 +1,75 @@
|
||||
package com.sangdol.common.web.support.log
|
||||
|
||||
import com.sangdol.common.log.constant.LogType
|
||||
import com.sangdol.common.utils.MdcPrincipalIdUtil
|
||||
import com.sangdol.common.utils.MdcStartTimeUtil
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
|
||||
class LogPayloadBuilder(
|
||||
private val type: LogType,
|
||||
private val servletRequest: HttpServletRequest,
|
||||
private val payload: MutableMap<String, Any> = mutableMapOf("type" to type)
|
||||
) {
|
||||
fun endpoint(): LogPayloadBuilder {
|
||||
payload["endpoint"] = "${servletRequest.method} ${servletRequest.requestURI}"
|
||||
return this
|
||||
}
|
||||
|
||||
fun clientIp(): LogPayloadBuilder {
|
||||
servletRequest.remoteAddr?.let { payload["client_ip"] = it }
|
||||
return this
|
||||
}
|
||||
|
||||
fun userAgent(): LogPayloadBuilder {
|
||||
servletRequest.getHeader("User-Agent")?.let { payload["user_agent"] = it }
|
||||
return this
|
||||
}
|
||||
|
||||
fun queryString(): LogPayloadBuilder {
|
||||
servletRequest.queryString?.let { payload["query_params"] = it }
|
||||
return this
|
||||
}
|
||||
|
||||
fun httpStatus(statusCode: Int?): LogPayloadBuilder {
|
||||
statusCode?.let { payload["status_code"] = it }
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun responseBody(body: Any?): LogPayloadBuilder {
|
||||
body?.let { payload["response_body"] = it }
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun durationMs(): LogPayloadBuilder {
|
||||
MdcStartTimeUtil.extractDurationMsOrNull()?.let { payload["duration_ms"] = it }
|
||||
return this
|
||||
}
|
||||
|
||||
fun principalId(): LogPayloadBuilder {
|
||||
MdcPrincipalIdUtil.extractAsLongOrNull()
|
||||
?.let { payload["principal_id"] = it }
|
||||
?: run { payload["principal_id"] = "UNKNOWN" }
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun exception(exception: Exception?): LogPayloadBuilder {
|
||||
exception?.let {
|
||||
payload["exception"] = mapOf(
|
||||
"class" to it.javaClass.simpleName,
|
||||
"message" to it.message
|
||||
)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun additionalPayloads(payload: Map<String, Any>): LogPayloadBuilder {
|
||||
this.payload.putAll(payload)
|
||||
return this
|
||||
}
|
||||
|
||||
fun build(): Map<String, Any> = payload
|
||||
}
|
||||
@ -0,0 +1,233 @@
|
||||
package com.sangdol.common.web.support.log
|
||||
|
||||
import com.sangdol.common.log.constant.LogType
|
||||
import com.sangdol.common.utils.MdcPrincipalIdUtil
|
||||
import com.sangdol.common.utils.MdcStartTimeUtil
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.nulls.shouldNotBeNull
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
|
||||
class LogPayloadBuilderTest : FunSpec({
|
||||
val servletRequest: HttpServletRequest = mockk()
|
||||
|
||||
lateinit var method: String
|
||||
lateinit var requestUri: String
|
||||
lateinit var remoteAddr: String
|
||||
lateinit var userAgent: String
|
||||
lateinit var queryString: String
|
||||
|
||||
beforeTest {
|
||||
method = "GET".also { every { servletRequest.method } returns it }
|
||||
requestUri = "/converter/test".also { every { servletRequest.requestURI } returns it }
|
||||
remoteAddr = "localhost".also { every { servletRequest.remoteAddr } returns it }
|
||||
userAgent = "Mozilla/5.0".also { every { servletRequest.getHeader("User-Agent") } returns it }
|
||||
queryString = "key=value".also { every { servletRequest.queryString } returns it }
|
||||
}
|
||||
|
||||
afterSpec {
|
||||
clearMocks(servletRequest)
|
||||
}
|
||||
|
||||
context("endpoint") {
|
||||
test("정상 응답") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.endpoint()
|
||||
.build()
|
||||
|
||||
result["endpoint"] shouldBe "$method $requestUri"
|
||||
}
|
||||
|
||||
test("ServletRequest에서 null이 반환되면 그대로 들어간다.") {
|
||||
every { servletRequest.method } returns null
|
||||
every { servletRequest.requestURI } returns null
|
||||
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.endpoint()
|
||||
.build()
|
||||
|
||||
result["endpoint"] shouldBe "null null"
|
||||
}
|
||||
}
|
||||
|
||||
context("clientIp") {
|
||||
test("정상 응답") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.clientIp()
|
||||
.build()
|
||||
|
||||
result["client_ip"] shouldBe remoteAddr
|
||||
}
|
||||
|
||||
test("ServletRequest에서 null이 반환되면 추가되지 않는다.") {
|
||||
every { servletRequest.remoteAddr } returns null
|
||||
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.clientIp()
|
||||
.build()
|
||||
|
||||
result["client_ip"] shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
context("userAgent") {
|
||||
test("정상 응답") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.userAgent()
|
||||
.build()
|
||||
|
||||
result["user_agent"] shouldBe userAgent
|
||||
}
|
||||
|
||||
test("ServletRequest에서 null이 반환되면 추가되지 않는다.") {
|
||||
every { servletRequest.getHeader("User-Agent") } returns null
|
||||
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.userAgent()
|
||||
.build()
|
||||
|
||||
result["user_agent"] shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
context("queryString") {
|
||||
test("정상 응답") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.queryString()
|
||||
.build()
|
||||
|
||||
result["query_params"] shouldBe queryString
|
||||
}
|
||||
|
||||
test("ServletRequest에서 null이 반환되면 추가되지 않는다.") {
|
||||
every { servletRequest.queryString } returns null
|
||||
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.queryString()
|
||||
.build()
|
||||
|
||||
result["query_params"] shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
context("httpStatus") {
|
||||
test("정상 응답") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.httpStatus(200)
|
||||
.build()
|
||||
|
||||
result["status_code"] shouldBe 200
|
||||
}
|
||||
|
||||
test("null을 입력하면 추가되지 않는다.") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.httpStatus(null)
|
||||
.build()
|
||||
|
||||
result["status_code"] shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
context("responseBody") {
|
||||
test("정상 응답") {
|
||||
val body = mapOf("key" to "value")
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.responseBody(body)
|
||||
.build()
|
||||
|
||||
result["response_body"] shouldBe body
|
||||
}
|
||||
|
||||
test("null을 입력하면 추가되지 않는다.") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.responseBody(null)
|
||||
.build()
|
||||
|
||||
result["response_body"] shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
context("durationMs") {
|
||||
test("정상 응답") {
|
||||
MdcStartTimeUtil.setCurrentTime()
|
||||
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.durationMs()
|
||||
.build()
|
||||
|
||||
result["duration_ms"].shouldNotBeNull()
|
||||
MdcStartTimeUtil.clear()
|
||||
}
|
||||
|
||||
test("MDC에서 값을 가져올 수 없으면 추가되지 않는다.") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.durationMs()
|
||||
.build()
|
||||
|
||||
result["duration_ms"] shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
context("principalId") {
|
||||
test("정상 응답") {
|
||||
val principalId = 759980174446956066L.also {
|
||||
MdcPrincipalIdUtil.set(it.toString())
|
||||
}
|
||||
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.principalId()
|
||||
.build()
|
||||
|
||||
result["principal_id"] shouldBe principalId
|
||||
MdcPrincipalIdUtil.clear()
|
||||
}
|
||||
|
||||
test("MDC에서 값을 가져올 수 없으면 UNKNOWN 으로 표기된다.") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.principalId()
|
||||
.build()
|
||||
|
||||
result["principal_id"] shouldBe "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
context("exception") {
|
||||
test("정상 응답") {
|
||||
val exception = RuntimeException("hello")
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.exception(exception)
|
||||
.build()
|
||||
|
||||
result["exception"] shouldBe mapOf(
|
||||
"class" to exception.javaClass.simpleName,
|
||||
"message" to exception.message
|
||||
)
|
||||
}
|
||||
|
||||
test("null을 입력하면 추가되지 않는다.") {
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.exception(null)
|
||||
.build()
|
||||
|
||||
result["exception"] shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
context("additionalPayloads") {
|
||||
test("정상 응답") {
|
||||
val payload = mapOf(
|
||||
"key1" to "value1",
|
||||
"key2" to "value2"
|
||||
)
|
||||
val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest)
|
||||
.additionalPayloads(payload)
|
||||
.build()
|
||||
|
||||
result["key1"] shouldBe "value1"
|
||||
result["key2"] shouldBe "value2"
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user