Skip to content

Commit

Permalink
Merge branch 'develop' into refactor/85
Browse files Browse the repository at this point in the history
  • Loading branch information
le2sky committed Oct 11, 2023
2 parents a379507 + 194220c commit f468708
Show file tree
Hide file tree
Showing 18 changed files with 291 additions and 26 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/mealkitary-main-develop-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ jobs:
./mealkitary-infrastructure/adapter-firebase-notification/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-business-registration-number-validator/simple-brn-validator/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-business-registration-number-validator/open-api-brn-validator/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-address-resolver/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-address-resolver/simple-address-resolver/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-address-resolver/kakao-api-address-resolver/build/test-results/**/*.xml
- name: Jacoco Coverage ๋ฆฌํฌํŠธ ์ „์†ก
uses: codecov/codecov-action@v3
Expand All @@ -71,7 +72,8 @@ jobs:
./mealkitary-infrastructure/adapter-firebase-notification/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-business-registration-number-validator/simple-brn-validator/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-business-registration-number-validator/open-api-brn-validator/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-address-resolver/build/reports/jacoco/test/jacocoTestReport.xml
./mealkitary-infrastructure/adapter-address-resolver/simple-address-resolver/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-address-resolver/kakao-api-address-resolver/build/reports/jacoco/test/jacocoTestReport.xml
name: mealkitary-codecov
verbose: true

Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/mealkitary-test-coverage-automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ jobs:
./mealkitary-infrastructure/adapter-firebase-notification/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-business-registration-number-validator/simple-brn-validator/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-business-registration-number-validator/open-api-brn-validator/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-address-resolver/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-address-resolver/simple-address-resolver/build/test-results/**/*.xml
./mealkitary-infrastructure/adapter-address-resolver/kakao-api-address-resolver/build/test-results/**/*.xml
- name: Jacoco Coverage ๋ฆฌํฌํŠธ ์ „์†ก
uses: codecov/codecov-action@v3
Expand All @@ -59,6 +60,7 @@ jobs:
./mealkitary-infrastructure/adapter-firebase-notification/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-business-registration-number-validator/simple-brn-validator/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-business-registration-number-validator/open-api-brn-validator/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-address-resolver/build/reports/jacoco/test/jacocoTestReport.xml
./mealkitary-infrastructure/adapter-address-resolver/simple-address-resolver/build/reports/jacoco/test/jacocoTestReport.xml,
./mealkitary-infrastructure/adapter-address-resolver/kakao-api-address-resolver/build/reports/jacoco/test/jacocoTestReport.xml
name: mealkitary-codecov
verbose: true
11 changes: 10 additions & 1 deletion mealkitary-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@ dependencies {
implementation(project(":mealkitary-infrastructure:adapter-paymentgateway-tosspayments"))
implementation(project(":mealkitary-infrastructure:adapter-firebase-notification"))
implementation(project(":mealkitary-infrastructure:adapter-configuration"))
implementation(project(":mealkitary-infrastructure:adapter-address-resolver"))
implementation(
project(
":mealkitary-infrastructure:adapter-address-resolver:kakao-api-address-resolver",
)
)
implementation(
project(
":mealkitary-infrastructure:adapter-address-resolver:simple-address-resolver",
)
)
implementation(
project(
":mealkitary-infrastructure:adapter-business-registration-number-validator:open-api-brn-validator",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class RegisterShopServiceTest : AnnotationSpec() {
} throws IllegalArgumentException("์˜ฌ๋ฐ”๋ฅธ ๊ฐ€๊ฒŒ ์ด๋ฆ„ ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค.(ํ•œ๊ธ€, ์˜๋ฌธ, ๊ณต๋ฐฑ, ์ˆซ์ž๋งŒ ํฌํ•จ ๊ฐ€๋Šฅ)")
every { saveShopPort.saveOne(any()) } answers { UUID.randomUUID() }
every { shopBusinessNumberValidator.validate(any()) } answers {}
every { addressResolver.resolveAddress("๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40") } returns expectedShopAddress
every { addressResolver.resolve("๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40") } returns expectedShopAddress

shouldThrow<IllegalArgumentException> {
registerShopService.register(request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import com.mealkitary.shop.domain.shop.ShopAddress

interface AddressResolver {

fun resolveAddress(address: String): ShopAddress
fun resolve(fullAddress: String): ShopAddress
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ class ShopFactory(
private val addressResolver: AddressResolver
) {

fun createOne(title: String, brn: String, address: String): Shop {
fun createOne(title: String, brn: String, fullAddress: String): Shop {
val shopBusinessNumber = ShopBusinessNumber.from(brn)

val shopAddress: ShopAddress = addressResolver.resolveAddress(address)
val shopAddress: ShopAddress = addressResolver.resolve(fullAddress)

shopBusinessNumberValidator.validate(shopBusinessNumber)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ShopFactoryTest : AnnotationSpec() {
ShopAddress.of("1234567890", Coordinates.of(0.0, 0.0), Address.of("๊ฒฝ๊ธฐ๋„", "์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ", "๋ฒŒ๋ง๋กœ", "40"))

every { shopBusinessNumberValidator.validate(any()) } answers { }
every { addressResolver.resolveAddress("๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40") } returns expectedShopAddress
every { addressResolver.resolve("๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40") } returns expectedShopAddress

val shop = shopFactory.createOne("์ง‘๋ฐฅ๋š๋”ฑ ์•ˆ์–‘์ ", "321-23-12345", "๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40")

Expand All @@ -44,7 +44,7 @@ class ShopFactoryTest : AnnotationSpec() {
ShopAddress.of("1234567890", Coordinates.of(0.0, 0.0), Address.of("๊ฒฝ๊ธฐ๋„", "์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ", "๋ฒŒ๋ง๋กœ", "40"))

every { shopBusinessNumberValidator.validate(any()) } answers { }
every { addressResolver.resolveAddress("๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40") } returns expectedShopAddress
every { addressResolver.resolve("๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40") } returns expectedShopAddress

shouldThrow<IllegalArgumentException> {
shopFactory.createOne("์ง‘๋ฐฅ๋š๋”ฑ ! ์•ˆ์–‘์ ", "321-23-12345", "๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40")
Expand All @@ -69,7 +69,7 @@ class ShopFactoryTest : AnnotationSpec() {
)

every { shopBusinessNumberValidator.validate(any()) } answers { }
every { addressResolver.resolveAddress(address) } answers { shopAddress }
every { addressResolver.resolve(address) } answers { shopAddress }

shouldThrow<IllegalArgumentException> {
shopFactory.createOne("์ง‘๋ฐฅ๋š๋”ฑ ! ์•ˆ์–‘์ ", "321-23-12345", "๊ฒฝ๊ธฐ๋„ ์•ˆ์–‘์‹œ ๋™์•ˆ๊ตฌ ๋ฒŒ๋ง๋กœ 40")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencies {
val mockWebServerVersion: String by properties
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation(project(":mealkitary-domain"))
testImplementation("com.squareup.okhttp3:mockwebserver:$mockWebServerVersion")
testImplementation("io.projectreactor:reactor-test")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.mealkitary.address

import com.mealkitary.common.model.Address
import com.mealkitary.common.model.Coordinates
import com.mealkitary.shop.domain.shop.address.ShopAddress
import com.mealkitary.shop.domain.shop.factory.AddressResolver
import org.springframework.context.annotation.Primary
import org.springframework.stereotype.Component

@Primary
@Component
class KakaoApiAddressResolver(
private val kakaoApiWebClient: KakaoApiWebClient
) : AddressResolver {

override fun resolve(fullAddress: String): ShopAddress {
val kakaoApiAddressResponse = kakaoApiWebClient.requestAddress(fullAddress)

val (x, y, address, roadAddress) = kakaoApiAddressResponse.document

val (longitude, latitude) = listOf(x, y).map {
it.toDoubleOrNull() ?: throw IllegalArgumentException("์œ ํšจํ•˜์ง€ ์•Š์€ ์ขŒํ‘œ ๋ฒ”์œ„์ž…๋‹ˆ๋‹ค.")
}

return ShopAddress.of(
roadAddress.h_code,
Coordinates.of(
longitude,
latitude
),
Address.of(
address.region_1depth_name,
address.region_2depth_name,
address.region_3depth_name,
roadAddress.road_name
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.mealkitary.address

import com.mealkitary.address.payload.KakaoApiAddressResponse
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.client.WebClient

private const val KAKAO_API_BASE_URL = "/v2/local/search/address"
private const val FORMAT = "json"

@Component
class KakaoApiWebClient(
private val webClient: WebClient,
@Value("\${kakaoapi.address.serviceKey}")
private val serviceKey: String,
) {

fun requestAddress(query: String): KakaoApiAddressResponse {
val kakaoApiAddressResponse = webClient.get()
.uri { uriBuilder ->
uriBuilder.path("$KAKAO_API_BASE_URL.$FORMAT")
.queryParam("query", query)
.build()
}
.header("Authorization", "KakaoAK $serviceKey")
.retrieve()
.bodyToMono(KakaoApiAddressResponse::class.java)
.block()

return kakaoApiAddressResponse!!
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.mealkitary.address.payload

data class KakaoApiAddressResponse(
val document: Document
) {
data class Document(
val x: String,
val y: String,
val address: Address,
val road_address: RoadAddress
)

data class Address(
val region_1depth_name: String,
val region_2depth_name: String,
val region_3depth_name: String,
)

data class RoadAddress(
val road_name: String,
val h_code: String
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.mealkitary.addess

import com.mealkitary.address.KakaoApiAddressResolver
import com.mealkitary.address.KakaoApiWebClient
import com.mealkitary.address.payload.KakaoApiAddressResponse
import io.kotest.core.spec.style.AnnotationSpec
import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockk

class KakaoApiAddressResolverTest : AnnotationSpec() {

private val kakaoApiWebClient = mockk<KakaoApiWebClient>()
private val kakaoApiAddressResolver = KakaoApiAddressResolver(kakaoApiWebClient)

@Test
fun `Kakao API๋ฅผ ํ†ตํ•ด ํ•ด๋‹นํ•˜๋Š” ์ฃผ์†Œ ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜จ๋‹ค`() {
val address = "๊ฒฝ๊ธฐ๋„ ๋‚จ์–‘์ฃผ์‹œ ๋‹ค์‚ฐ์ค‘์•™๋กœ82๋ฒˆ์•ˆ๊ธธ 132-12"
val response = KakaoApiAddressResponse(
document = KakaoApiAddressResponse.Document(
x = "127.166069448936",
y = "37.6120947950094",
address = KakaoApiAddressResponse.Address(
region_1depth_name = "๊ฒฝ๊ธฐ",
region_2depth_name = "๋‚จ์–‘์ฃผ์‹œ",
region_3depth_name = "๋‹ค์‚ฐ๋™"
),
road_address = KakaoApiAddressResponse.RoadAddress(
road_name = "๋‹ค์‚ฐ์ค‘์•™๋กœ82๋ฒˆ์•ˆ๊ธธ",
h_code = "4136011200"
)
)
)

every { kakaoApiWebClient.requestAddress(address) } returns response

val shopAddress = kakaoApiAddressResolver.resolve(address)

shopAddress.address.region1DepthName shouldBe "๊ฒฝ๊ธฐ"
shopAddress.address.region2DepthName shouldBe "๋‚จ์–‘์ฃผ์‹œ"
shopAddress.address.region3DepthName shouldBe "๋‹ค์‚ฐ๋™"
shopAddress.address.roadName shouldBe "๋‹ค์‚ฐ์ค‘์•™๋กœ82๋ฒˆ์•ˆ๊ธธ"
shopAddress.cityCode shouldBe "4136011200"
shopAddress.coordinates.longitude shouldBe 127.166069448936
shopAddress.coordinates.latitude shouldBe 37.6120947950094
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.mealkitary.addess

import com.fasterxml.jackson.databind.ObjectMapper
import com.mealkitary.address.KakaoApiWebClient
import com.mealkitary.address.payload.KakaoApiAddressResponse
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.inspectors.forAll
import io.kotest.matchers.shouldBe
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.web.reactive.function.client.WebClient
import java.lang.RuntimeException

class KakaoApiWebClientTest {

private lateinit var mockWebServer: MockWebServer
private lateinit var webClient: WebClient
private lateinit var kakaoApiWebClient: KakaoApiWebClient
private val objectMapper = ObjectMapper()

@BeforeEach
fun setUp() {
mockWebServer = MockWebServer()
mockWebServer.start()
webClient = WebClient.builder()
.baseUrl(mockWebServer.url("").toString())
.codecs { configurer ->
configurer.defaultCodecs().maxInMemorySize(5 * 1024 * 1024)
}
.defaultHeaders { headers ->
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
}
.build()

kakaoApiWebClient = KakaoApiWebClient(webClient, "serviceKey")
}

@AfterEach
fun teardown() {
mockWebServer.shutdown()
}

@Test
fun `200 OK๋ฅผ ๋ฐ›์œผ๋ฉด ์•„๋ฌด ์˜ˆ์™ธ๋„ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค`() {
val address = "๊ฒฝ๊ธฐ๋„ ๋‚จ์–‘์ฃผ์‹œ ๋‹ค์‚ฐ์ค‘์•™๋กœ82๋ฒˆ์•ˆ๊ธธ 132-12"
val response = createResponse()

mockWebServer.enqueue(
MockResponse()
.setBody(objectMapper.writeValueAsString(response))
.setResponseCode(200)
.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
)

val actualResponse = kakaoApiWebClient.requestAddress(address)

val recordedRequest = mockWebServer.takeRequest()
recordedRequest.method shouldBe "GET"

actualResponse.document.road_address.h_code shouldBe response.document.road_address.h_code
actualResponse.document.x shouldBe response.document.x
actualResponse.document.y shouldBe response.document.y
actualResponse.document.address.region_1depth_name shouldBe response.document.address.region_1depth_name
actualResponse.document.address.region_2depth_name shouldBe response.document.address.region_2depth_name
actualResponse.document.address.region_3depth_name shouldBe response.document.address.region_3depth_name
actualResponse.document.road_address.road_name shouldBe response.document.road_address.road_name
}

@Test
fun `200์ด ์•„๋‹Œ ์ฝ”๋“œ๋Š” RuntimeException์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค`() {
listOf(400, 401, 500).forAll {
mockWebServer.enqueue(
MockResponse()
.setResponseCode(it)
.setBody(objectMapper.writeValueAsString(createResponse()))
.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
)
shouldThrow<RuntimeException> {
kakaoApiWebClient.requestAddress("๊ฒฝ๊ธฐ๋„๋‚จ์–‘์ฃผ์‹œ๋‹ค์‚ฐ์ค‘์•™๋กœ82๋ฒˆ์•ˆ๊ธธ132-12")
}
}
}

private fun createResponse() = KakaoApiAddressResponse(
document = KakaoApiAddressResponse.Document(
x = "127.166069448936",
y = "37.6120947950094",
address = KakaoApiAddressResponse.Address(
region_1depth_name = "๊ฒฝ๊ธฐ",
region_2depth_name = "๋‚จ์–‘์ฃผ์‹œ",
region_3depth_name = "๋‹ค์‚ฐ๋™"
),
road_address = KakaoApiAddressResponse.RoadAddress(
road_name = "๋‹ค์‚ฐ์ค‘์•™๋กœ82๋ฒˆ์•ˆ๊ธธ",
h_code = "4136011200"
)
)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies {
implementation(project(":mealkitary-domain"))
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.mealkitary.address
package com.mealkitary

import com.mealkitary.common.model.Address
import com.mealkitary.common.model.Coordinates
Expand All @@ -11,8 +11,8 @@ private const val ADDRESS_MIN_LENGTH = 2
@Component
class SimpleAddressResolver : AddressResolver {

override fun resolveAddress(address: String): ShopAddress {
val value = address.split(" ")
override fun resolve(fullAddress: String): ShopAddress {
val value = fullAddress.split(" ")

if (value.size < ADDRESS_MIN_LENGTH) {
throw IllegalArgumentException("์ฃผ์†Œ ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
Expand Down
Loading

0 comments on commit f468708

Please sign in to comment.