generated from pricelees/issue-pr-template
[#20] 도메인별 예외 분리 #21
@ -4,17 +4,15 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
|||||||
import io.github.oshai.kotlinlogging.KLogger
|
import io.github.oshai.kotlinlogging.KLogger
|
||||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
import org.springframework.http.HttpRequest
|
import org.springframework.http.HttpRequest
|
||||||
import org.springframework.http.HttpStatus
|
|
||||||
import org.springframework.http.HttpStatusCode
|
import org.springframework.http.HttpStatusCode
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.http.client.ClientHttpResponse
|
import org.springframework.http.client.ClientHttpResponse
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import org.springframework.web.client.RestClient
|
import org.springframework.web.client.RestClient
|
||||||
import roomescape.common.exception.ErrorType
|
import roomescape.payment.exception.PaymentErrorCode
|
||||||
import roomescape.common.exception.RoomescapeException
|
import roomescape.payment.exception.PaymentException
|
||||||
import roomescape.payment.web.PaymentCancelRequest
|
import roomescape.payment.web.PaymentCancelRequest
|
||||||
import roomescape.payment.web.PaymentCancelResponse
|
import roomescape.payment.web.PaymentCancelResponse
|
||||||
import java.io.IOException
|
|
||||||
import java.util.Map
|
import java.util.Map
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@ -43,7 +41,7 @@ class TossPaymentClient(
|
|||||||
{ req: HttpRequest, res: ClientHttpResponse -> handlePaymentError(res) }
|
{ req: HttpRequest, res: ClientHttpResponse -> handlePaymentError(res) }
|
||||||
)
|
)
|
||||||
.body(PaymentApproveResponse::class.java)
|
.body(PaymentApproveResponse::class.java)
|
||||||
?: throw RoomescapeException(ErrorType.PAYMENT_SERVER_ERROR, HttpStatus.INTERNAL_SERVER_ERROR)
|
?: throw PaymentException(PaymentErrorCode.PAYMENT_PROVIDER_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cancel(cancelRequest: PaymentCancelRequest): PaymentCancelResponse {
|
fun cancel(cancelRequest: PaymentCancelRequest): PaymentCancelResponse {
|
||||||
@ -60,7 +58,7 @@ class TossPaymentClient(
|
|||||||
{ req: HttpRequest, res: ClientHttpResponse -> handlePaymentError(res) }
|
{ req: HttpRequest, res: ClientHttpResponse -> handlePaymentError(res) }
|
||||||
)
|
)
|
||||||
.body(PaymentCancelResponse::class.java)
|
.body(PaymentCancelResponse::class.java)
|
||||||
?: throw RoomescapeException(ErrorType.PAYMENT_SERVER_ERROR, HttpStatus.INTERNAL_SERVER_ERROR)
|
?: throw PaymentException(PaymentErrorCode.PAYMENT_PROVIDER_ERROR)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun logPaymentInfo(paymentRequest: PaymentApproveRequest) {
|
private fun logPaymentInfo(paymentRequest: PaymentApproveRequest) {
|
||||||
@ -80,32 +78,25 @@ class TossPaymentClient(
|
|||||||
private fun handlePaymentError(
|
private fun handlePaymentError(
|
||||||
res: ClientHttpResponse
|
res: ClientHttpResponse
|
||||||
): Nothing {
|
): Nothing {
|
||||||
val statusCode = res.statusCode
|
getErrorCodeByHttpStatus(res.statusCode).also {
|
||||||
val errorType = getErrorTypeByStatusCode(statusCode)
|
logTossPaymentError(res)
|
||||||
val errorResponse = getErrorResponse(res)
|
throw PaymentException(it)
|
||||||
|
}
|
||||||
throw RoomescapeException(
|
|
||||||
errorType,
|
|
||||||
"[ErrorCode = ${errorResponse.code}, ErrorMessage = ${errorResponse.message}]",
|
|
||||||
statusCode
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getErrorResponse(
|
private fun logTossPaymentError(res: ClientHttpResponse): TossPaymentErrorResponse {
|
||||||
res: ClientHttpResponse
|
|
||||||
): TossPaymentErrorResponse {
|
|
||||||
val body = res.body
|
val body = res.body
|
||||||
val errorResponse = objectMapper.readValue(body, TossPaymentErrorResponse::class.java)
|
val errorResponse = objectMapper.readValue(body, TossPaymentErrorResponse::class.java)
|
||||||
body.close()
|
body.close()
|
||||||
|
|
||||||
|
log.error { "결제 실패. response: $errorResponse" }
|
||||||
return errorResponse
|
return errorResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getErrorTypeByStatusCode(
|
private fun getErrorCodeByHttpStatus(statusCode: HttpStatusCode): PaymentErrorCode {
|
||||||
statusCode: HttpStatusCode
|
|
||||||
): ErrorType {
|
|
||||||
if (statusCode.is4xxClientError) {
|
if (statusCode.is4xxClientError) {
|
||||||
return ErrorType.PAYMENT_ERROR
|
return PaymentErrorCode.PAYMENT_CLIENT_ERROR
|
||||||
}
|
}
|
||||||
return ErrorType.PAYMENT_SERVER_ERROR
|
return PaymentErrorCode.PAYMENT_PROVIDER_ERROR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,8 @@ import org.springframework.test.web.client.ResponseActions
|
|||||||
import org.springframework.test.web.client.match.MockRestRequestMatchers.*
|
import org.springframework.test.web.client.match.MockRestRequestMatchers.*
|
||||||
import org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
|
import org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
|
||||||
import org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess
|
import org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess
|
||||||
import roomescape.common.exception.ErrorType
|
import roomescape.payment.exception.PaymentErrorCode
|
||||||
import roomescape.common.exception.RoomescapeException
|
import roomescape.payment.exception.PaymentException
|
||||||
import roomescape.payment.web.PaymentCancelRequest
|
import roomescape.payment.web.PaymentCancelRequest
|
||||||
import roomescape.payment.web.PaymentCancelResponse
|
import roomescape.payment.web.PaymentCancelResponse
|
||||||
|
|
||||||
@ -56,9 +56,10 @@ class TossPaymentClientTest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("400 에러 발생") {
|
context("실패 응답") {
|
||||||
|
fun runTest(httpStatus: HttpStatus, expectedError: PaymentErrorCode) {
|
||||||
commonAction().andRespond {
|
commonAction().andRespond {
|
||||||
withStatus(HttpStatus.BAD_REQUEST)
|
withStatus(httpStatus)
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
||||||
.createResponse(it)
|
.createResponse(it)
|
||||||
@ -68,16 +69,19 @@ class TossPaymentClientTest(
|
|||||||
val paymentRequest = SampleTossPaymentConst.paymentRequest
|
val paymentRequest = SampleTossPaymentConst.paymentRequest
|
||||||
|
|
||||||
// then
|
// then
|
||||||
val exception = shouldThrow<RoomescapeException> {
|
val exception = shouldThrow<PaymentException> {
|
||||||
client.confirm(paymentRequest)
|
client.confirm(paymentRequest)
|
||||||
}
|
}
|
||||||
|
exception.errorCode shouldBe expectedError
|
||||||
assertSoftly(exception) {
|
|
||||||
this.errorType shouldBe ErrorType.PAYMENT_ERROR
|
|
||||||
this.invalidValue shouldBe "[ErrorCode = ERROR_CODE, ErrorMessage = Error message]"
|
|
||||||
this.httpStatus shouldBe HttpStatus.BAD_REQUEST
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("결제 서버에서 4XX 응답 시") {
|
||||||
|
runTest(HttpStatus.BAD_REQUEST, PaymentErrorCode.PAYMENT_CLIENT_ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("결제 서버에서 5XX 응답 시") {
|
||||||
|
runTest(HttpStatus.INTERNAL_SERVER_ERROR, PaymentErrorCode.PAYMENT_PROVIDER_ERROR)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,26 +115,29 @@ class TossPaymentClientTest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("500 에러 발생") {
|
context("실패 응답") {
|
||||||
|
fun runTest(httpStatus: HttpStatus, expectedError: PaymentErrorCode) {
|
||||||
commonAction().andRespond {
|
commonAction().andRespond {
|
||||||
withStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
withStatus(httpStatus)
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
||||||
.createResponse(it)
|
.createResponse(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
|
||||||
val cancelRequest: PaymentCancelRequest = SampleTossPaymentConst.cancelRequest
|
val cancelRequest: PaymentCancelRequest = SampleTossPaymentConst.cancelRequest
|
||||||
|
|
||||||
// then
|
val exception = shouldThrow<PaymentException> {
|
||||||
val exception = shouldThrow<RoomescapeException> {
|
|
||||||
client.cancel(cancelRequest)
|
client.cancel(cancelRequest)
|
||||||
}
|
}
|
||||||
|
exception.errorCode shouldBe expectedError
|
||||||
|
}
|
||||||
|
|
||||||
assertSoftly(exception) {
|
test("결제 서버에서 4XX 응답 시") {
|
||||||
this.errorType shouldBe ErrorType.PAYMENT_SERVER_ERROR
|
runTest(HttpStatus.BAD_REQUEST, PaymentErrorCode.PAYMENT_CLIENT_ERROR)
|
||||||
this.invalidValue shouldBe "[ErrorCode = ERROR_CODE, ErrorMessage = Error message]"
|
}
|
||||||
this.httpStatus shouldBe HttpStatus.INTERNAL_SERVER_ERROR
|
|
||||||
|
test("결제 서버에서 5XX 응답 시") {
|
||||||
|
runTest(HttpStatus.INTERNAL_SERVER_ERROR, PaymentErrorCode.PAYMENT_PROVIDER_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user