Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[개선] Shop 엔티티 식별자 UUID로 개선(issue#85) #87

Merged
merged 12 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.mealkitary.common.utils.UUIDUtils
import com.mealkitary.reservation.application.port.input.GetReservationQuery
import com.mealkitary.reservation.application.port.input.ReservationResponse
import org.springframework.http.ResponseEntity
import org.springframework.util.StringUtils
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
Expand All @@ -22,10 +23,18 @@ class GetReservationController(
getReservationQuery.loadOneReservationById(UUIDUtils.fromString(reservationId))

@GetMapping
fun getAllReservation(@RequestParam("shopId") shopIdParam: Long?): ResponseEntity<List<ReservationResponse>> {
val shopId = requireNotNull(shopIdParam) { "가게 식별자는 필수입니다." }
fun getAllReservation(@RequestParam("shopId") shopId: String?): ResponseEntity<List<ReservationResponse>> {
if (!StringUtils.hasText(shopId)) {
throw IllegalArgumentException("가게 식별자는 필수입니다.")
}

return HttpResponseUtils
.mapToResponseEntity(emptiableList = getReservationQuery.loadAllReservationByShopId(shopId))
.mapToResponseEntity(
emptiableList = getReservationQuery.loadAllReservationByShopId(
UUIDUtils.fromString(
shopId!!
)
)
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mealkitary.reservation.web.request

import com.mealkitary.common.utils.UUIDUtils
import com.mealkitary.common.validation.DateValid
import com.mealkitary.reservation.application.port.input.ReserveProductRequest
import java.time.LocalDateTime
Expand All @@ -8,7 +9,7 @@ import javax.validation.constraints.NotNull

data class ReserveProductWebRequest(
@field:NotNull(message = "예약 대상 가게 식별자는 필수입니다.")
val shopId: Long? = null,
val shopId: String? = null,

@field:Valid
@field:NotNull(message = "예약 상품 목록은 필수입니다.")
Expand All @@ -21,7 +22,7 @@ data class ReserveProductWebRequest(

fun mapToServiceRequest(): ReserveProductRequest {
return ReserveProductRequest(
shopId!!,
UUIDUtils.fromString(shopId!!),
products!!.map { it.mapToServiceObject() },
LocalDateTime.parse(reservedAt!!)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mealkitary.shop.web

import com.mealkitary.common.utils.HttpResponseUtils
import com.mealkitary.common.utils.UUIDUtils
import com.mealkitary.shop.application.port.input.GetProductQuery
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
Expand All @@ -14,8 +15,8 @@ class GetProductController(
) {

@GetMapping("/{shopId}/products")
fun getAllProductOfShop(@PathVariable("shopId") shopId: Long) =
fun getAllProductOfShop(@PathVariable("shopId") shopId: String) =
HttpResponseUtils.mapToResponseEntity(
emptiableList = getProductQuery.loadAllProductByShopId(shopId)
emptiableList = getProductQuery.loadAllProductByShopId(UUIDUtils.fromString(shopId))
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mealkitary.shop.web

import com.mealkitary.common.utils.HttpResponseUtils
import com.mealkitary.common.utils.UUIDUtils
import com.mealkitary.shop.application.port.input.GetReservableTimeQuery
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
Expand All @@ -14,8 +15,8 @@ class GetReservableTimeController(
) {

@GetMapping("/{shopId}/reservable-time")
fun getAllReservableTimeOfShop(@PathVariable("shopId") shopId: Long) =
fun getAllReservableTimeOfShop(@PathVariable("shopId") shopId: String) =
HttpResponseUtils.mapToResponseEntity(
emptiableList = getReservableTimeQuery.loadAllReservableTimeByShopId(shopId)
emptiableList = getReservableTimeQuery.loadAllReservableTimeByShopId(UUIDUtils.fromString(shopId))
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mealkitary.shop.web

import com.mealkitary.common.utils.UUIDUtils
import com.mealkitary.shop.application.port.input.UpdateShopStatusUseCase
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PathVariable
Expand All @@ -14,8 +15,8 @@ class UpdateShopStatusController(
) {

@PostMapping("/{shopId}/status")
fun updateShopStatus(@PathVariable("shopId") shopId: Long): ResponseEntity<Unit> {
updateShopStatusUseCase.update(shopId)
fun updateShopStatus(@PathVariable("shopId") shopId: String): ResponseEntity<Unit> {
updateShopStatusUseCase.update(UUIDUtils.fromString(shopId))

return ResponseEntity.noContent().build()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,11 @@ class GetReservationControllerDocsTest : RestDocsSupport() {
@Test
fun `api docs test - getAllReservation`() {
val reservationId = UUID.randomUUID()
val shopId = UUID.randomUUID()
val reserveAt = LocalDateTime.of(
LocalDate.of(2023, 6, 23), LocalTime.of(6, 30)
)
every { getReservationQuery.loadAllReservationByShopId(1L) } answers {
every { getReservationQuery.loadAllReservationByShopId(shopId) } answers {
listOf(
ReservationResponse(
reservationId,
Expand All @@ -119,7 +120,7 @@ class GetReservationControllerDocsTest : RestDocsSupport() {
)
}

mvc.perform(RestDocumentationRequestBuilders.get("/reservations?shopId=1"))
mvc.perform(RestDocumentationRequestBuilders.get("/reservations?shopId=$shopId"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andDo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ class ReserveProductControllerDocsTest : RestDocsSupport() {
@Test
fun `api docs test - reserveProduct`() {
val id = UUID.randomUUID()
val shopId = UUID.randomUUID()
every { reserveProductUseCase.reserve(any()) }.answers { id }
val reserveProductWebRequest = ReserveProductWebRequest(
1L,
shopId.toString(),
listOf(
ReservedWebProduct(
2L,
Expand Down Expand Up @@ -62,7 +63,7 @@ class ReserveProductControllerDocsTest : RestDocsSupport() {
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint()),
requestFields(
fieldWithPath("shopId").type(JsonFieldType.NUMBER).description("예약 대상 가게 식별자"),
fieldWithPath("shopId").type(JsonFieldType.STRING).description("예약 대상 가게 식별자"),
fieldWithPath("products.[].productId").type(JsonFieldType.NUMBER).description("예약 대상 상품 식별자"),
fieldWithPath("products.[].name").type(JsonFieldType.STRING).description("예약 대상 상품명"),
fieldWithPath("products.[].price").type(JsonFieldType.NUMBER).description("예약 대상 상품 가격"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@ import org.springframework.restdocs.request.RequestDocumentation.parameterWithNa
import org.springframework.restdocs.request.RequestDocumentation.pathParameters
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.util.UUID

class GetProductControllerDocsTest : RestDocsSupport() {

private val getProductQuery = mockk<GetProductQuery>()

@Test
fun `api docs test - getAllProductOfShopTest`() {
every { getProductQuery.loadAllProductByShopId(1L) }.answers {
val shopId = UUID.randomUUID()
every { getProductQuery.loadAllProductByShopId(shopId) }.answers {
listOf(ProductResponse(1L, "부대찌개", 15000))
}

mvc.perform(RestDocumentationRequestBuilders.get("/shops/{shopId}/products", 1))
mvc.perform(RestDocumentationRequestBuilders.get("/shops/{shopId}/products", shopId))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andDo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,20 @@ import org.springframework.restdocs.request.RequestDocumentation.pathParameters
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.time.LocalTime
import java.util.UUID

class GetReservableTimeControllerDocsTest : RestDocsSupport() {

private val getReservableTimeQuery = mockk<GetReservableTimeQuery>()

@Test
fun `api docs test - getAllReservableTimeOfShopTest`() {
every { getReservableTimeQuery.loadAllReservableTimeByShopId(1L) }.answers {
val shopId = UUID.randomUUID()
every { getReservableTimeQuery.loadAllReservableTimeByShopId(shopId) }.answers {
listOf(LocalTime.of(6, 30))
}

mvc.perform(RestDocumentationRequestBuilders.get("/shops/{shopId}/reservable-time", 1))
mvc.perform(RestDocumentationRequestBuilders.get("/shops/{shopId}/reservable-time", shopId))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andDo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ import org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath
import org.springframework.restdocs.payload.PayloadDocumentation.responseFields
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.util.UUID

class GetShopControllerDocsTest : RestDocsSupport() {

private val getShopQuery = mockk<GetShopQuery>()

@Test
fun `api docs test - getAllShopTest`() {
val shopId = UUID.randomUUID()
every { getShopQuery.loadAllShop() }.answers {
listOf(ShopResponse(1L, "집밥뚝딱"))
listOf(ShopResponse(shopId, "집밥뚝딱"))
}

mvc.perform(RestDocumentationRequestBuilders.get("/shops/"))
Expand All @@ -38,7 +40,7 @@ class GetShopControllerDocsTest : RestDocsSupport() {
preprocessResponse(prettyPrint()),
responseFields(
fieldWithPath("[]").type(JsonFieldType.ARRAY).description("가게 목록 배열"),
fieldWithPath("[].id").type(JsonFieldType.NUMBER).description("가게 식별자"),
fieldWithPath("[].id").type(JsonFieldType.STRING).description("가게 식별자"),
fieldWithPath("[].title").type(JsonFieldType.STRING).description("가게명")
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ import org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath
import org.springframework.restdocs.payload.PayloadDocumentation.requestFields
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.header
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.util.UUID

class RegisterShopControllerDocsTest : RestDocsSupport() {

private val registerShopUseCase = mockk<RegisterShopUseCase>()

@Test
fun `api docs test - registerShop`() {
every { registerShopUseCase.register(any()) } answers { 1L }
val shopId = UUID.randomUUID()
every { registerShopUseCase.register(any()) } answers { shopId }

val registerShopWebRequest = RegisterShopWebRequest("집밥뚝딱 안양점", "123-23-12345", "경기도 안양시 동안구 벌말로")

Expand All @@ -36,7 +38,7 @@ class RegisterShopControllerDocsTest : RestDocsSupport() {
.content(objectMapper.writeValueAsString(registerShopWebRequest))
)
.andExpect(status().isCreated)
.andExpect(header().string("Location", "http://localhost/shops/1"))
.andExpect(header().string("Location", "http://localhost/shops/$shopId"))
.andDo(
MockMvcRestDocumentation.document(
"shop-post",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ import org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPri
import org.springframework.restdocs.request.RequestDocumentation.parameterWithName
import org.springframework.restdocs.request.RequestDocumentation.pathParameters
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.util.UUID

class UpdateShopStatusControllerDocsTest : RestDocsSupport() {

private val updateShopStatsUseCase = mockk<UpdateShopStatusUseCase>()

@Test
fun `api docs test - updateShopStatus`() {
val shopId = 1L
val shopId = UUID.randomUUID()
every { updateShopStatsUseCase.update(shopId) }.answers { }

mvc.perform(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ class GetReservationControllerTest : WebIntegrationTestSupport() {
@Test
fun `api integration test - getAllReservation`() {
val reservationId = UUID.randomUUID()
val shopId = UUID.randomUUID()
val reserveAt = LocalDateTime.of(
LocalDate.of(2023, 6, 23), LocalTime.of(6, 30)
)
every { getReservationQuery.loadAllReservationByShopId(1L) } answers {
every { getReservationQuery.loadAllReservationByShopId(any()) } answers {
listOf(
ReservationResponse(
reservationId,
Expand All @@ -98,7 +99,7 @@ class GetReservationControllerTest : WebIntegrationTestSupport() {
)
}

mvc.perform(get("/reservations?shopId=1"))
mvc.perform(get("/reservations?shopId=$shopId"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.[0].reservationId").value(reservationId.toString()))
Expand Down Expand Up @@ -133,7 +134,7 @@ class GetReservationControllerTest : WebIntegrationTestSupport() {
fun `api integration test - getAllReservation - 해당 가게의 예약이 존재하지 않으면 204 NoContent를 반환한다`() {
every { getReservationQuery.loadAllReservationByShopId(any()) } answers { emptyList() }

mvc.perform(get("/reservations?shopId=1"))
mvc.perform(get("/reservations?shopId=${UUID.randomUUID()}"))
.andExpect(status().isNoContent())
}

Expand All @@ -147,6 +148,16 @@ class GetReservationControllerTest : WebIntegrationTestSupport() {
.andExpect(jsonPath("$.message").value("잘못된 UUID 형식입니다."))
}

@Test
fun `api integration test - 가게 식별자가 UUID 형태가 아니라면 400 에러를 발생한다`() {
mvc.perform(
get("/reservations?shopId=invalid-uuid-test")
)
.andExpect(status().isBadRequest)
.andExpect(jsonPath("$.status").value("400"))
.andExpect(jsonPath("$.message").value("잘못된 UUID 형식입니다."))
}

@Test
fun `api integration test - getOneReservation - 내부에서 EntityNotFound 에러가 발생하면 404 에러를 발생한다`() {
every { getReservationQuery.loadOneReservationById(any()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ class ReserveProductControllerTest : WebIntegrationTestSupport() {
@Test
fun `api integration test - reserveProduct`() {
val id = UUID.randomUUID()
val shopId = UUID.randomUUID()
every { reserveProductUseCase.reserve(any()) }.answers {
id
}
val reserveProductWebRequest = ReserveProductWebRequest(
1L,
shopId.toString(),
listOf(
ReservedWebProduct(
2L,
Expand Down Expand Up @@ -80,7 +81,7 @@ class ReserveProductControllerTest : WebIntegrationTestSupport() {
@Test
fun `api integration test - 예약 시간이 누락된 경우 400 에러를 발생한다`() {
val reserveProductWebRequest = ReserveProductWebRequest(
shopId = 2,
shopId = UUID.randomUUID().toString(),
products = listOf(
ReservedWebProduct(
2L,
Expand Down Expand Up @@ -111,7 +112,7 @@ class ReserveProductControllerTest : WebIntegrationTestSupport() {
@Test
fun `api integration test - 예약 상품 목록이 누락된 경우 400 에러를 발생한다`() {
val reserveProductWebRequest = ReserveProductWebRequest(
shopId = 2,
shopId = UUID.randomUUID().toString(),
reservedAt = LocalDateTime.of(
LocalDate.now().plusDays(1),
LocalTime.of(16, 0)
Expand Down Expand Up @@ -142,12 +143,40 @@ class ReserveProductControllerTest : WebIntegrationTestSupport() {
.andExpect(jsonPath("$.message").value("JSON 형식이 잘못되었습니다."))
}

@Test
fun `api integration test - 가게 식별자가 UUID 형태가 아니라면 400 에러를 발생한다`() {
val reserveProductWebRequest = ReserveProductWebRequest(
shopId = "invalid-uuid-test",
products = listOf(
ReservedWebProduct(
2L,
"부대찌개",
3000,
3
)
),
reservedAt = LocalDateTime.of(
LocalDate.now().plusDays(1),
LocalTime.of(16, 0)
).toString()
)

mvc.perform(
post("/reservations")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reserveProductWebRequest))
)
.andExpect(status().isBadRequest)
.andExpect(jsonPath("$.status").value("400"))
.andExpect(jsonPath("$.message").value("잘못된 UUID 형식입니다."))
}

@Test
fun `api integration test - 예약 대상 가게가 존재하지 않는 경우 404 에러를 발생한다`() {
every { reserveProductUseCase.reserve(any()) }
.throws(EntityNotFoundException("존재하지 않는 가게입니다."))
val reserveProductWebRequest = ReserveProductWebRequest(
1L,
UUID.randomUUID().toString(),
listOf(
ReservedWebProduct(
2L,
Expand Down
Loading