add customer controller with find by guid method

This commit is contained in:
Denis Savosin
2024-10-14 12:25:30 +07:00
parent fecbee8b28
commit 0a38f7fdd8
10 changed files with 189 additions and 32 deletions

View File

@@ -0,0 +1,30 @@
package com.example.demo.http.controllers
import com.example.demo.http.exceptions.NotFoundException
import com.example.demo.services.database.customer.CustomerService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.util.*
@RestController
@RequestMapping(value = ["/api/customer"], produces = [MediaType.APPLICATION_JSON_VALUE])
class CustomerController(
@Autowired
private val customerService: CustomerService,
) {
@GetMapping("/{guid}")
@Throws(NotFoundException::class)
fun getCustomer(
@PathVariable guid: UUID,
): ResponseEntity<Any> {
val customer = customerService.findByGuid(guid) ?: throw NotFoundException()
return ResponseEntity(customer, HttpStatus.OK)
}
}

View File

@@ -10,6 +10,7 @@ import java.time.OffsetDateTime
import java.util.*
@Table("customer")
@Serializable
data class Customer(
@Id
val id: Long?,

View File

@@ -0,0 +1,9 @@
package com.example.demo.models
import kotlinx.serialization.Serializable
@Serializable
data class CustomerExtended(
val customer: Customer,
val city: City?,
)

View File

@@ -1,11 +1,12 @@
package com.example.demo.services.database.customer
import com.example.demo.models.Customer
import com.example.demo.models.CustomerExtended
import com.example.demo.services.database.exceptions.CityNotFoundException
import java.util.*
interface CustomerService {
fun findByGuid(guid: UUID): Customer?
fun findByGuid(guid: UUID): CustomerExtended?
@Throws(CityNotFoundException::class)
fun create(name: String, cityGuid: UUID?): Customer

View File

@@ -1,6 +1,7 @@
package com.example.demo.services.database.customer
import com.example.demo.models.Customer
import com.example.demo.models.CustomerExtended
import com.example.demo.providers.CityRepository
import com.example.demo.providers.CustomerRepository
import com.example.demo.services.database.exceptions.CityNotFoundException
@@ -11,7 +12,17 @@ class CustomerServiceImpl(
private val customerRepository: CustomerRepository,
private val cityRepository: CityRepository
): CustomerService {
override fun findByGuid(guid: UUID): Customer? = customerRepository.findByGuid(guid)
override fun findByGuid(guid: UUID): CustomerExtended? {
val customer = customerRepository.findByGuid(guid) ?: return null
if (customer.cityId == null) {
return CustomerExtended(customer, null)
}
val city = cityRepository.findById(customer.cityId)
return CustomerExtended(customer, city.orElse(null))
}
override fun create(name: String, cityGuid: UUID?): Customer {
val cityId: Long? = cityGuid?.let {

View File

@@ -0,0 +1,106 @@
package com.example.demo.http.controllers
import com.example.demo.BaseUnitTest
import com.example.demo.http.responses.ResponseStatus
import com.example.demo.models.City
import com.example.demo.models.Customer
import com.example.demo.models.CustomerExtended
import com.example.demo.services.database.customer.CustomerService
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.whenever
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import java.time.OffsetDateTime
import java.util.*
import kotlin.test.Test
@WebMvcTest(CustomerController::class)
class CustomerControllerTest(
@Autowired val mockMvc: MockMvc,
): BaseUnitTest() {
@MockBean
private lateinit var customerService: CustomerService
@Test
fun getCustomer_successWithCity() {
val customerId = 22.toLong()
val cityId = 11.toLong()
val customerGuid = UUID.randomUUID()
val customerExtended = CustomerExtended(
customer = Customer(
id = customerId,
guid = customerGuid,
name = "Test Person",
cityId = cityId,
createdAt = OffsetDateTime.now().minusHours(1),
updatedAt = OffsetDateTime.now(),
),
city = City(
id = cityId,
guid = UUID.randomUUID(),
name = "Test City",
createdAt = OffsetDateTime.now().minusWeeks(1),
updatedAt = null,
deletedAt = null
)
)
whenever(customerService.findByGuid(
eq(customerGuid),
)) doReturn customerExtended
mockMvc.get("/api/customer/$customerGuid")
.andExpect { status { isOk() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.customer.id") { value(customerId) } }
.andExpect { jsonPath("\$.customer.cityId") { value(cityId) } }
.andExpect { jsonPath("\$.city.id") { value(cityId) } }
}
@Test
fun getCustomer_successNoCity() {
val customerId = 22.toLong()
val customerGuid = UUID.randomUUID()
val customerExtended = CustomerExtended(
customer = Customer(
id = customerId,
guid = customerGuid,
name = "Test Person",
cityId = null,
createdAt = OffsetDateTime.now().minusHours(1),
updatedAt = OffsetDateTime.now(),
),
city = null,
)
whenever(customerService.findByGuid(
eq(customerGuid),
)) doReturn customerExtended
mockMvc.get("/api/customer/$customerGuid")
.andExpect { status { isOk() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.customer.id") { value(customerId) } }
.andExpect { jsonPath("\$.customer.cityId") { value(null) } }
.andExpect { jsonPath("\$.city") { value(null) } }
}
@Test
fun getCustomer_successNotFound() {
val customerGuid = UUID.randomUUID()
whenever(customerService.findByGuid(
eq(customerGuid),
)) doReturn null
mockMvc.get("/api/customer/$customerGuid")
.andExpect { status { isNotFound() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.status") { value(ResponseStatus.NOT_FOUND.status) } }
}
}

View File

@@ -5,26 +5,24 @@ import org.hamcrest.core.StringContains
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.test.web.servlet.get
import kotlin.test.Test
@WebMvcTest(GreetingController::class)
class GreetingControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
@Test
fun greetings_shouldSeeGreetingMessage() {
mockMvc.perform(get("/greeting"))
.andExpect(status().isOk)
.andExpect(content().contentType("text/plain;charset=UTF-8"))
.andExpect(content().string("Hello World!"))
mockMvc.get("/greeting")
.andExpect { status { isOk() } }
.andExpect { content { contentType("text/plain;charset=UTF-8") } }
.andExpect { content { string("Hello World!") } }
}
@Test
fun exampleHtml_shouldSeeRenderedHtml() {
mockMvc.perform(get("/example/html"))
.andExpect(status().isOk)
.andExpect(content().contentType("text/html;charset=UTF-8"))
.andExpect(content().string(StringContains("Product")))
mockMvc.get("/example/html")
.andExpect { status { isOk() } }
.andExpect { content { contentType("text/html;charset=UTF-8") } }
.andExpect { content { string(StringContains("Product")) } }
}
}

View File

@@ -52,7 +52,7 @@ class ProductControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
)) doReturn product
mockMvc.get("/api/product/$guid")
.andExpect { status { status { isOk() } } }
.andExpect { status { isOk() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.id") { value(product.id.toString()) } }
.andExpect { jsonPath("\$.guid") { value(guid.toString()) } }
@@ -70,7 +70,7 @@ class ProductControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
)) doReturn null
mockMvc.get("/api/product/$guid")
.andExpect { status { status { isNotFound() } } }
.andExpect { status { isNotFound() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.status") { value(ResponseStatus.NOT_FOUND.status) } }
}
@@ -94,7 +94,7 @@ class ProductControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
)))
mockMvc.get("/api/product?page=1&size=2&sort=createdAt,desc")
.andExpect { status { status { isOk() } } }
.andExpect { status { isOk() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.meta.total") { value(1) } }
.andExpect { jsonPath("\$.meta.pages") { value(1) } }
@@ -135,7 +135,7 @@ class ProductControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
contentType = MediaType.APPLICATION_JSON
content = reqBody
}
.andExpect { status { status { isCreated() } } }
.andExpect { status { isCreated() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.id") { value(productId) } }
}
@@ -150,7 +150,7 @@ class ProductControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
contentType = MediaType.APPLICATION_JSON
content = reqBody
}
.andExpect { status { status { isBadRequest() } } }
.andExpect { status { isBadRequest() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.status") { value(ResponseStatus.BAD_REQUEST.status) } }
.andExpect { jsonPath("\$.cause") { contains("name") } }
@@ -168,7 +168,7 @@ class ProductControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
contentType = MediaType.APPLICATION_JSON
content = reqBody
}
.andExpect { status { status { isUnprocessableEntity() } } }
.andExpect { status { isUnprocessableEntity() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.status") { value(ResponseStatus.UNPROCESSABLE.status) } }
.andExpect { jsonPath("\$.cause") { value(MethodArgumentNotValidException::class.qualifiedName) } }
@@ -194,7 +194,7 @@ class ProductControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
)
mockMvc.delete("/api/product/${guid}")
.andExpect { status { status { isOk() } } }
.andExpect { status { isOk() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.status") { value(ResponseStatus.OK.status) } }
}

View File

@@ -70,7 +70,7 @@ class ShopControllerTest(@Autowired val mockMvc: MockMvc): BaseUnitTest() {
) doReturn null
mockMvc.get("/shop/common-info")
.andExpect { status { status { isNotFound() } } }
.andExpect { status { isNotFound() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { content { json("""{"status":"not found"}""") } }
}

View File

@@ -41,22 +41,23 @@ class CustomerServiceImplDbTest: BaseDbTest() {
try {
city = cityRepository.save(city)
customerServiceImpl.create(nameOne, city.guid).let {
customerIds += it.id ?: fail("customerWithCity id is null")
assertEquals(city.id, it.cityId)
customerServiceImpl.create(nameTwo, null).let {
customerIds += it.id ?: fail("customerWithNoCity id is null")
assertNull(it.cityId)
assertNotNull(it.createdAt)
assertNull(it.updatedAt)
}
val customerWithNoCity = customerServiceImpl.create(nameTwo, null)
customerIds += customerWithNoCity.id ?: fail("customerWithNoCity id is null")
assertNull(customerWithNoCity.cityId)
assertNotNull(customerWithNoCity.createdAt)
assertNull(customerWithNoCity.updatedAt)
val customerWithCity = customerServiceImpl.create(nameOne, city.guid)
customerIds += customerWithCity.id ?: fail("customerWithCity id is null")
assertEquals(city.id, customerWithCity.cityId)
assertNotNull(customerWithCity.createdAt)
assertNull(customerWithCity.updatedAt)
val existedCustomer = customerServiceImpl.findByGuid(customerWithNoCity.guid)
val existedCustomer = customerServiceImpl.findByGuid(customerWithCity.guid)
assertNotNull(existedCustomer)
assertEquals(customerWithNoCity.id, existedCustomer.id)
assertEquals(customerWithCity.id, existedCustomer.customer.id)
assertEquals(city.id, existedCustomer.city?.id)
assertThrows<CityNotFoundException> {
customerServiceImpl.create(nameThree, UUID.randomUUID())