fix(recommendation): 응원 크리에이터 후속 보완을 반영한다

This commit is contained in:
2026-07-31 14:22:59 +09:00
parent 5123494e0e
commit ed54483cab
8 changed files with 427 additions and 19 deletions
@@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
import kr.co.vividnext.sodalive.v2.api.home.application.HomeRecommendationFacade
import kr.co.vividnext.sodalive.v2.recommendation.adapter.out.persistence.RecommendationSnapshot
import kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryService
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendationSnapshotWindowPolicy
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
@@ -38,6 +39,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPat
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime
import java.time.ZoneOffset
import javax.persistence.EntityManager
@SpringBootTest
@@ -524,6 +526,28 @@ class HomeRecommendationControllerTest @Autowired constructor(
.andExpect(jsonPath("$.data.items[0].creatorId").value(character.creatorMember!!.id))
}
@Test
@DisplayName("메인 홈 통합 조회는 응원 크리에이터 item의 기존 3개 필드만 노출한다")
fun shouldKeepCheerCreatorItemSchemaOnHomeRecommendations() {
val creator = saveMember("cheer-api-creator", MemberRole.CREATOR).apply {
profileImage = "cheer-api-profile.png"
}
val snapshotAt = RecommendationSnapshotWindowPolicy()
.previousKstDayUtcWindow(LocalDateTime.now(ZoneOffset.UTC))
.snapshotAt
saveCheerCreatorRecommendationSnapshot(creator.id!!, snapshotAt)
saveCheerCreatorRecommendationSnapshot(creator.id!!, snapshotAt.plusDays(1))
entityManager.flush()
entityManager.clear()
mockMvc.perform(get("/api/v2/home/recommendations"))
.andExpect(status().isOk)
.andExpect(jsonPath("$.data.cheerCreators[0].creatorId").value(creator.id))
.andExpect(jsonPath("$.data.cheerCreators[0].creatorNickname").value("cheer-api-creator"))
.andExpect(jsonPath("$.data.cheerCreators[0].creatorProfileImage").value("/cheer-api-profile.png"))
.andExpect(jsonPath("$.data.cheerCreators[0].length()").value(3))
}
@Test
@DisplayName("최근 활동 라이브 크리에이터는 creatorId와 라이브 상태별 targetId를 노출한다")
fun shouldExposeNavigationIdsForRecentlyActiveLiveCreators() {
@@ -619,4 +643,16 @@ class HomeRecommendationControllerTest @Autowired constructor(
)
)
}
private fun saveCheerCreatorRecommendationSnapshot(creatorId: Long, snapshotAt: LocalDateTime) {
entityManager.persist(
RecommendationSnapshot(
sectionType = RecommendedSectionType.CHEER_CREATOR,
targetId = creatorId,
score = 100.0,
snapshotAt = snapshotAt,
randomTieBreaker = 0.1
)
)
}
}
@@ -58,7 +58,13 @@ class HomeRecommendationResponseTest {
)
),
genreCreators = emptyList(),
cheerCreators = emptyList(),
cheerCreators = listOf(
HomeCreatorItem(
creatorId = 15L,
creatorNickname = "cheer-creator",
creatorProfileImage = "https://cdn.test/profile/cheer.png"
)
),
popularCommunityPosts = listOf(
HomePopularCommunityPostItem(
postId = 5L,
@@ -108,6 +114,13 @@ class HomeRecommendationResponseTest {
assertEquals("https://cdn.test/profile/character.png", json["aiCharacters"][0]["profileImage"].asText())
assertEquals(13L, json["aiCharacters"][0]["creatorId"].asLong())
assertEquals(true, json["aiCharacters"][1]["profileImage"].isNull)
assertEquals(15L, json["cheerCreators"][0]["creatorId"].asLong())
assertEquals("cheer-creator", json["cheerCreators"][0]["creatorNickname"].asText())
assertEquals("https://cdn.test/profile/cheer.png", json["cheerCreators"][0]["creatorProfileImage"].asText())
assertEquals(
setOf("creatorId", "creatorNickname", "creatorProfileImage"),
json["cheerCreators"][0].fieldNames().asSequence().toSet()
)
assertEquals(5L, json["popularCommunityPosts"][0]["postId"].asLong())
assertEquals("https://cdn.test/community/image.png", json["popularCommunityPosts"][0]["imageUrl"].asText())
assertEquals("https://cdn.test/community/audio.mp3", json["popularCommunityPosts"][0]["audioUrl"].asText())