test(aicharacter): 크리에이터 회원 연결 검증을 보강한다
This commit is contained in:
@@ -0,0 +1,171 @@
|
|||||||
|
package kr.co.vividnext.sodalive.chat.character.service
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.ChatCharacter
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberKind
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberRole
|
||||||
|
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||||
|
import org.junit.jupiter.api.Assertions.assertNull
|
||||||
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
|
import org.springframework.test.context.ContextConfiguration
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import javax.persistence.EntityManager
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@Transactional
|
||||||
|
@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class])
|
||||||
|
class ChatCharacterCreatorMemberServiceIntegrationTest @Autowired constructor(
|
||||||
|
private val creatorMemberService: ChatCharacterCreatorMemberService,
|
||||||
|
private val memberRepository: MemberRepository,
|
||||||
|
private val chatCharacterRepository: ChatCharacterRepository,
|
||||||
|
private val entityManager: EntityManager
|
||||||
|
) {
|
||||||
|
@Test
|
||||||
|
fun `ChatCharacter creatorMember 관계와 repository 메서드를 사용할 수 있다`() {
|
||||||
|
val member = memberRepository.save(createMember(memberKind = MemberKind.AI_CHARACTER))
|
||||||
|
val chatCharacter = chatCharacterRepository.save(createCharacter().apply { creatorMember = member })
|
||||||
|
entityManager.flush()
|
||||||
|
entityManager.clear()
|
||||||
|
|
||||||
|
val found = chatCharacterRepository.findByCreatorMemberId(member.id!!)
|
||||||
|
|
||||||
|
assertNotNull(found)
|
||||||
|
assertEquals(chatCharacter.id, found!!.id)
|
||||||
|
assertEquals(true, chatCharacterRepository.existsByCreatorMemberId(member.id!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `AI 캐릭터용 Member를 생성하고 표시 정보를 복사한다`() {
|
||||||
|
val chatCharacter = createCharacter(
|
||||||
|
name = "소다",
|
||||||
|
description = "AI 캐릭터 설명",
|
||||||
|
imagePath = "characters/1/profile.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
val member = creatorMemberService.ensureAiCharacterCreatorMember(chatCharacter)
|
||||||
|
chatCharacterRepository.save(chatCharacter)
|
||||||
|
entityManager.flush()
|
||||||
|
entityManager.clear()
|
||||||
|
|
||||||
|
val savedMember = memberRepository.findById(member.id!!).orElseThrow()
|
||||||
|
val savedCharacter = chatCharacterRepository.findByCreatorMemberId(member.id!!)
|
||||||
|
assertNotNull(savedCharacter)
|
||||||
|
assertNull(savedMember.email)
|
||||||
|
assertEquals("", savedMember.password)
|
||||||
|
assertEquals(MemberRole.CREATOR, savedMember.role)
|
||||||
|
assertEquals(MemberKind.AI_CHARACTER, savedMember.memberKind)
|
||||||
|
assertEquals("소다", savedMember.nickname)
|
||||||
|
assertEquals("characters/1/profile.png", savedMember.profileImage)
|
||||||
|
assertEquals("AI 캐릭터 설명", savedMember.introduce)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `AI 캐릭터용 Member 표시 정보를 동기화한다`() {
|
||||||
|
val member = memberRepository.save(
|
||||||
|
createMember(memberKind = MemberKind.AI_CHARACTER).apply {
|
||||||
|
nickname = "old-name"
|
||||||
|
profileImage = "old/profile.png"
|
||||||
|
introduce = "old-description"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val chatCharacter = chatCharacterRepository.save(
|
||||||
|
createCharacter(
|
||||||
|
name = "new-name",
|
||||||
|
description = "new-description",
|
||||||
|
imagePath = "new/profile.png"
|
||||||
|
).apply { creatorMember = member }
|
||||||
|
)
|
||||||
|
entityManager.flush()
|
||||||
|
entityManager.clear()
|
||||||
|
|
||||||
|
val savedCharacter = chatCharacterRepository.findById(chatCharacter.id!!).orElseThrow()
|
||||||
|
creatorMemberService.syncAiCharacterCreatorMemberDisplayFields(savedCharacter)
|
||||||
|
entityManager.flush()
|
||||||
|
entityManager.clear()
|
||||||
|
|
||||||
|
val savedMember = memberRepository.findById(member.id!!).orElseThrow()
|
||||||
|
assertEquals("new-name", savedMember.nickname)
|
||||||
|
assertEquals("new/profile.png", savedMember.profileImage)
|
||||||
|
assertEquals("new-description", savedMember.introduce)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `동기화 대상 creatorMember가 없으면 저장 실패를 위해 예외를 던진다`() {
|
||||||
|
val chatCharacter = createCharacter(
|
||||||
|
id = 1L,
|
||||||
|
name = "missing-creator-member",
|
||||||
|
description = "description"
|
||||||
|
)
|
||||||
|
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
creatorMemberService.syncAiCharacterCreatorMemberDisplayFields(chatCharacter)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `사람 크리에이터 Member 표시 정보는 덮어쓰지 않는다`() {
|
||||||
|
val member = memberRepository.save(
|
||||||
|
createMember(memberKind = MemberKind.HUMAN).apply {
|
||||||
|
nickname = "human-name"
|
||||||
|
profileImage = "human/profile.png"
|
||||||
|
introduce = "human-description"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val chatCharacter = chatCharacterRepository.save(
|
||||||
|
createCharacter(
|
||||||
|
name = "ai-name",
|
||||||
|
description = "ai-description",
|
||||||
|
imagePath = "ai/profile.png"
|
||||||
|
).apply { creatorMember = member }
|
||||||
|
)
|
||||||
|
entityManager.flush()
|
||||||
|
entityManager.clear()
|
||||||
|
|
||||||
|
val savedCharacter = chatCharacterRepository.findById(chatCharacter.id!!).orElseThrow()
|
||||||
|
creatorMemberService.syncAiCharacterCreatorMemberDisplayFields(savedCharacter)
|
||||||
|
entityManager.flush()
|
||||||
|
entityManager.clear()
|
||||||
|
|
||||||
|
val savedMember = memberRepository.findById(member.id!!).orElseThrow()
|
||||||
|
assertEquals("human-name", savedMember.nickname)
|
||||||
|
assertEquals("human/profile.png", savedMember.profileImage)
|
||||||
|
assertEquals("human-description", savedMember.introduce)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCharacter(
|
||||||
|
id: Long? = null,
|
||||||
|
name: String = "character-name",
|
||||||
|
description: String = "character-description",
|
||||||
|
imagePath: String? = null
|
||||||
|
): ChatCharacter {
|
||||||
|
val character = ChatCharacter(
|
||||||
|
characterUUID = "character-uuid-$name",
|
||||||
|
name = name,
|
||||||
|
description = description,
|
||||||
|
systemPrompt = "system-prompt"
|
||||||
|
)
|
||||||
|
character.id = id
|
||||||
|
character.imagePath = imagePath
|
||||||
|
return character
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMember(memberKind: MemberKind): Member {
|
||||||
|
return Member(
|
||||||
|
email = if (memberKind == MemberKind.HUMAN) "human-${System.nanoTime()}@example.com" else null,
|
||||||
|
password = if (memberKind == MemberKind.HUMAN) "password" else "",
|
||||||
|
nickname = "member-name",
|
||||||
|
role = MemberRole.CREATOR,
|
||||||
|
memberKind = memberKind
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,125 +7,23 @@ import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterHobbyRepo
|
|||||||
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository
|
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterRepository
|
||||||
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterTagRepository
|
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterTagRepository
|
||||||
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterValueRepository
|
import kr.co.vividnext.sodalive.chat.character.repository.ChatCharacterValueRepository
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
|
||||||
import kr.co.vividnext.sodalive.member.Member
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
import kr.co.vividnext.sodalive.member.MemberKind
|
import kr.co.vividnext.sodalive.member.MemberKind
|
||||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
|
||||||
import kr.co.vividnext.sodalive.member.MemberRole
|
import kr.co.vividnext.sodalive.member.MemberRole
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.Assertions.assertNull
|
|
||||||
import org.junit.jupiter.api.Assertions.assertSame
|
|
||||||
import org.junit.jupiter.api.Assertions.assertThrows
|
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.mockito.Mockito
|
import org.mockito.Mockito
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
|
||||||
class ChatCharacterCreatorMemberServiceTest {
|
class ChatCharacterCreatorMemberServiceTest {
|
||||||
private lateinit var memberRepository: MemberRepository
|
|
||||||
private lateinit var chatCharacterRepository: ChatCharacterRepository
|
private lateinit var chatCharacterRepository: ChatCharacterRepository
|
||||||
private lateinit var creatorMemberService: ChatCharacterCreatorMemberService
|
private lateinit var creatorMemberService: ChatCharacterCreatorMemberService
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
memberRepository = Mockito.mock(MemberRepository::class.java)
|
|
||||||
chatCharacterRepository = Mockito.mock(ChatCharacterRepository::class.java)
|
chatCharacterRepository = Mockito.mock(ChatCharacterRepository::class.java)
|
||||||
creatorMemberService = ChatCharacterCreatorMemberService(memberRepository)
|
creatorMemberService = Mockito.mock(ChatCharacterCreatorMemberService::class.java)
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `ChatCharacter creatorMember 관계와 repository 메서드를 사용할 수 있다`() {
|
|
||||||
val member = createMember(memberKind = MemberKind.AI_CHARACTER)
|
|
||||||
val chatCharacter = createCharacter().apply { creatorMember = member }
|
|
||||||
|
|
||||||
Mockito.`when`(chatCharacterRepository.findByCreatorMemberId(1L)).thenReturn(chatCharacter)
|
|
||||||
Mockito.`when`(chatCharacterRepository.existsByCreatorMemberId(1L)).thenReturn(true)
|
|
||||||
|
|
||||||
assertSame(member, chatCharacter.creatorMember)
|
|
||||||
assertSame(chatCharacter, chatCharacterRepository.findByCreatorMemberId(1L))
|
|
||||||
assertEquals(true, chatCharacterRepository.existsByCreatorMemberId(1L))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `AI 캐릭터용 Member를 생성하고 표시 정보를 복사한다`() {
|
|
||||||
val chatCharacter = createCharacter(
|
|
||||||
name = "소다",
|
|
||||||
description = "AI 캐릭터 설명",
|
|
||||||
imagePath = "characters/1/profile.png"
|
|
||||||
)
|
|
||||||
Mockito.`when`(memberRepository.save(Mockito.any(Member::class.java))).thenAnswer { invocation ->
|
|
||||||
(invocation.arguments[0] as Member).apply { id = 10L }
|
|
||||||
}
|
|
||||||
|
|
||||||
val member = creatorMemberService.ensureAiCharacterCreatorMember(chatCharacter)
|
|
||||||
|
|
||||||
assertSame(member, chatCharacter.creatorMember)
|
|
||||||
assertNull(member.email)
|
|
||||||
assertEquals("", member.password)
|
|
||||||
assertEquals(MemberRole.CREATOR, member.role)
|
|
||||||
assertEquals(MemberKind.AI_CHARACTER, member.memberKind)
|
|
||||||
assertEquals("소다", member.nickname)
|
|
||||||
assertEquals("characters/1/profile.png", member.profileImage)
|
|
||||||
assertEquals("AI 캐릭터 설명", member.introduce)
|
|
||||||
Mockito.verify(memberRepository).save(member)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `AI 캐릭터용 Member 표시 정보를 동기화한다`() {
|
|
||||||
val member = createMember(memberKind = MemberKind.AI_CHARACTER).apply {
|
|
||||||
nickname = "old-name"
|
|
||||||
profileImage = "old/profile.png"
|
|
||||||
introduce = "old-description"
|
|
||||||
}
|
|
||||||
val chatCharacter = createCharacter(
|
|
||||||
name = "new-name",
|
|
||||||
description = "new-description",
|
|
||||||
imagePath = "new/profile.png"
|
|
||||||
).apply { creatorMember = member }
|
|
||||||
|
|
||||||
creatorMemberService.syncAiCharacterCreatorMemberDisplayFields(chatCharacter)
|
|
||||||
|
|
||||||
assertEquals("new-name", member.nickname)
|
|
||||||
assertEquals("new/profile.png", member.profileImage)
|
|
||||||
assertEquals("new-description", member.introduce)
|
|
||||||
Mockito.verify(memberRepository).save(member)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `동기화 대상 creatorMember가 없으면 저장 실패를 위해 예외를 던진다`() {
|
|
||||||
val chatCharacter = createCharacter(
|
|
||||||
id = 1L,
|
|
||||||
name = "missing-creator-member",
|
|
||||||
description = "description"
|
|
||||||
)
|
|
||||||
|
|
||||||
val exception = assertThrows(SodaException::class.java) {
|
|
||||||
creatorMemberService.syncAiCharacterCreatorMemberDisplayFields(chatCharacter)
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals("common.error.invalid_request", exception.messageKey)
|
|
||||||
Mockito.verifyNoInteractions(memberRepository)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `사람 크리에이터 Member 표시 정보는 덮어쓰지 않는다`() {
|
|
||||||
val member = createMember(memberKind = MemberKind.HUMAN).apply {
|
|
||||||
nickname = "human-name"
|
|
||||||
profileImage = "human/profile.png"
|
|
||||||
introduce = "human-description"
|
|
||||||
}
|
|
||||||
val chatCharacter = createCharacter(
|
|
||||||
name = "ai-name",
|
|
||||||
description = "ai-description",
|
|
||||||
imagePath = "ai/profile.png"
|
|
||||||
).apply { creatorMember = member }
|
|
||||||
|
|
||||||
creatorMemberService.syncAiCharacterCreatorMemberDisplayFields(chatCharacter)
|
|
||||||
|
|
||||||
assertEquals("human-name", member.nickname)
|
|
||||||
assertEquals("human/profile.png", member.profileImage)
|
|
||||||
assertEquals("human-description", member.introduce)
|
|
||||||
Mockito.verifyNoInteractions(memberRepository)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -172,7 +70,6 @@ class ChatCharacterCreatorMemberServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createChatCharacterService(): ChatCharacterService {
|
private fun createChatCharacterService(): ChatCharacterService {
|
||||||
creatorMemberService = Mockito.mock(ChatCharacterCreatorMemberService::class.java)
|
|
||||||
return ChatCharacterService(
|
return ChatCharacterService(
|
||||||
chatCharacterRepository = chatCharacterRepository,
|
chatCharacterRepository = chatCharacterRepository,
|
||||||
tagRepository = Mockito.mock(ChatCharacterTagRepository::class.java),
|
tagRepository = Mockito.mock(ChatCharacterTagRepository::class.java),
|
||||||
|
|||||||
Reference in New Issue
Block a user