feat(deployment): 배포 식별자 엔드포인트를 추가한다

This commit is contained in:
2026-09-14 11:58:15 +09:00
parent 7aeb070615
commit ca1f9b9d00
3 changed files with 156 additions and 0 deletions
@@ -0,0 +1,50 @@
package kr.co.vividnext.sodalive.deployment
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.boot.test.web.server.LocalManagementPort
import org.springframework.http.HttpStatus
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = [
"management.server.port=0",
"deployment.artifact-version=1.2.3-20260914",
"deployment.config-commit=1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d",
"spring.datasource.url=jdbc:h2:mem:deployment-endpoint-injected-integration;" +
"MODE=MySQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=VALUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
]
)
@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class])
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
class DeploymentEndpointInjectedValueIntegrationTest @Autowired constructor(
private val restTemplate: TestRestTemplate
) {
@LocalManagementPort
private var managementPort: Int = 0
@Test
@DisplayName("배포 식별자가 주입되면 /actuator/deployment는 주입된 값을 반환한다")
fun shouldReturnInjectedDeploymentIdentity() {
val response = restTemplate.getForEntity(
"http://localhost:$managementPort/actuator/deployment",
Map::class.java
)
assertEquals(HttpStatus.OK, response.statusCode)
assertEquals(
mapOf(
"application_artifact_version" to "1.2.3-20260914",
"config_commit" to "1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d"
),
response.body
)
}
}
@@ -0,0 +1,85 @@
package kr.co.vividnext.sodalive.deployment
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.boot.test.web.server.LocalManagementPort
import org.springframework.boot.test.web.server.LocalServerPort
import org.springframework.http.HttpStatus
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = [
"management.server.port=0",
"spring.datasource.url=jdbc:h2:mem:deployment-endpoint-integration;" +
"MODE=MySQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=VALUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
]
)
@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class])
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
class DeploymentEndpointIntegrationTest @Autowired constructor(
private val restTemplate: TestRestTemplate
) {
@LocalServerPort
private var serverPort: Int = 0
@LocalManagementPort
private var managementPort: Int = 0
@Test
@DisplayName("애플리케이션 포트의 /readyz는 인증 없이 200을 반환한다")
fun shouldReturnOkWhenReadyzIsCalledOnServerPort() {
val response = restTemplate.getForEntity("http://localhost:$serverPort/readyz", String::class.java)
assertEquals(HttpStatus.OK, response.statusCode)
}
@Test
@DisplayName("management 포트의 /actuator/health/readiness는 인증 없이 200을 반환한다")
fun shouldReturnOkWhenReadinessProbeIsCalledOnManagementPort() {
val response = restTemplate.getForEntity(
"http://localhost:$managementPort/actuator/health/readiness",
String::class.java
)
assertEquals(HttpStatus.OK, response.statusCode)
}
@Test
@DisplayName("환경변수가 없으면 /actuator/deployment는 기본 배포 식별자를 snake_case로 반환한다")
fun shouldReturnDefaultDeploymentIdentityWhenEnvironmentVariablesAreNotProvided() {
val response = restTemplate.getForEntity(
"http://localhost:$managementPort/actuator/deployment",
Map::class.java
)
assertEquals(HttpStatus.OK, response.statusCode)
assertEquals(
mapOf(
"application_artifact_version" to "local",
"config_commit" to "0000000000000000000000000000000000000000"
),
response.body
)
}
@Test
@DisplayName("애플리케이션 포트에서는 /actuator/deployment에 접근할 수 없다")
fun shouldNotExposeDeploymentEndpointOnServerPort() {
val response = restTemplate.getForEntity(
"http://localhost:$serverPort/actuator/deployment",
String::class.java
)
assertNotEquals(HttpStatus.OK, response.statusCode)
assertFalse(response.body?.contains("application_artifact_version") ?: false)
}
}