fix(agent-assignment): 소속 시각 UTC 변환을 적용한다

This commit is contained in:
2026-04-13 11:23:25 +09:00
parent 08ba6a6046
commit f357d426d0
4 changed files with 87 additions and 7 deletions

View File

@@ -39,6 +39,7 @@ class AdminAgentCreatorServiceTest {
@DisplayName("관리자는 에이전트와 크리에이터를 소속으로 연결할 수 있다")
fun shouldAssignCreatorToAgent() {
val assignedAt = LocalDateTime.of(2026, 4, 9, 10, 0)
val expectedUtcAssignedAt = LocalDateTime.of(2026, 4, 9, 1, 0)
val agent = Member(password = "password", nickname = "agent", role = MemberRole.AGENT)
agent.id = 11L
val creator = Member(password = "password", nickname = "creator", role = MemberRole.CREATOR)
@@ -55,7 +56,7 @@ class AdminAgentCreatorServiceTest {
Mockito.verify(relationRepository).saveAndFlush(relationCaptor.capture())
assertEquals(agent, relationCaptor.value.agent)
assertEquals(creator, relationCaptor.value.creator)
assertEquals(assignedAt, relationCaptor.value.assignedAt)
assertEquals(expectedUtcAssignedAt, relationCaptor.value.assignedAt)
assertEquals(null, relationCaptor.value.unassignedAt)
}
@@ -253,6 +254,7 @@ class AdminAgentCreatorServiceTest {
@DisplayName("종료된 이력이 있으면 이후 시각에 다시 소속 지정할 수 있다")
fun shouldAssignCreatorWhenPreviousAssignmentAlreadyEnded() {
val assignedAt = LocalDateTime.of(2026, 4, 9, 10, 0)
val previousUnassignedAt = LocalDateTime.of(2026, 4, 9, 1, 0)
val agent = Member(password = "password", nickname = "agent", role = MemberRole.AGENT)
agent.id = 11L
val creator = Member(password = "password", nickname = "creator", role = MemberRole.CREATOR)
@@ -261,7 +263,7 @@ class AdminAgentCreatorServiceTest {
existingRelation.agent = agent
existingRelation.creator = creator
existingRelation.assignedAt = LocalDateTime.of(2026, 4, 1, 0, 0)
existingRelation.unassignedAt = assignedAt
existingRelation.unassignedAt = previousUnassignedAt
val request = AssignAgentCreatorRequest(agentId = 11L, creatorId = 22L, assignedAt = assignedAt)
Mockito.`when`(memberRepository.findById(11L)).thenReturn(Optional.of(agent))
@@ -278,6 +280,7 @@ class AdminAgentCreatorServiceTest {
fun shouldCloseCreatorAssignmentWindow() {
val relation = AgentCreatorRelation()
relation.assignedAt = LocalDateTime.of(2026, 4, 1, 0, 0)
val expectedUtcUnassignedAt = LocalDateTime.of(2026, 4, 9, 1, 0)
val request = RemoveAgentCreatorRequest(
creatorId = 22L,
unassignedAt = LocalDateTime.of(2026, 4, 9, 10, 0)
@@ -294,10 +297,37 @@ class AdminAgentCreatorServiceTest {
service.removeCreator(request)
assertEquals(request.unassignedAt, relation.unassignedAt)
assertEquals(expectedUtcUnassignedAt, relation.unassignedAt)
Mockito.verify(relationRepository).save(relation)
}
@Test
@DisplayName("소속 종료 시각 비교는 한국 시간 입력을 UTC로 변환한 뒤 수행한다")
fun shouldValidateUnassignedAtAfterConvertingKstToUtc() {
val relation = AgentCreatorRelation()
relation.assignedAt = LocalDateTime.of(2026, 4, 9, 1, 0)
val request = RemoveAgentCreatorRequest(
creatorId = 22L,
unassignedAt = LocalDateTime.of(2026, 4, 9, 9, 0)
)
Mockito.`when`(memberRepository.findByIdForUpdate(22L)).thenReturn(
Member(
password = "password",
nickname = "creator",
role = MemberRole.CREATOR
).also { it.id = 22L }
)
Mockito.`when`(relationRepository.findFirstByCreatorIdAndUnassignedAtIsNull(22L)).thenReturn(relation)
val exception = assertThrows(SodaException::class.java) {
service.removeCreator(request)
}
assertEquals("partner.agent.assignment.invalid_unassigned_at", exception.messageKey)
Mockito.verify(relationRepository, Mockito.never()).save(Mockito.any(AgentCreatorRelation::class.java))
}
@Test
@DisplayName("소속 정보가 없으면 해제할 수 없다")
fun shouldThrowWhenAssignmentDoesNotExist() {

View File

@@ -0,0 +1,37 @@
package kr.co.vividnext.sodalive.extensions
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.fail
import org.junit.jupiter.api.Test
import java.time.LocalDateTime
import java.time.ZoneId
class LocalDateTimeExtensionsTest {
@Test
fun shouldConvertToUtcUsingKstByDefault() {
val localDateTime = LocalDateTime.of(2026, 4, 9, 10, 0)
val utcDateTime = invokeConvertToUtc(localDateTime)
assertEquals(LocalDateTime.of(2026, 4, 9, 1, 0), utcDateTime)
}
@Test
fun shouldConvertToUtcUsingProvidedTimezone() {
val localDateTime = LocalDateTime.of(2026, 4, 9, 10, 0)
val utcDateTime = invokeConvertToUtc(localDateTime, ZoneId.of("Asia/Bangkok"))
assertEquals(LocalDateTime.of(2026, 4, 9, 3, 0), utcDateTime)
}
private fun invokeConvertToUtc(localDateTime: LocalDateTime, timeZone: ZoneId = ZoneId.of("Asia/Seoul")): LocalDateTime {
return try {
val method = Class.forName("kr.co.vividnext.sodalive.extensions.LocalDateTimeExtensionsKt")
.getMethod("convertToUtc", LocalDateTime::class.java, ZoneId::class.java)
method.invoke(null, localDateTime, timeZone) as LocalDateTime
} catch (e: ReflectiveOperationException) {
fail("LocalDateTime.convertToUtc 확장함수를 찾을 수 없습니다.")
}
}
}