Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@
@Slf4j
public class RankingTierUpdateService {

private static final int AURA_EXP_THRESHOLD = 100_000;
private static final int MASTER_EXP_THRESHOLD = 75_000;
private static final int AURA_EXP_THRESHOLD = 200_000;
private static final int MASTER_EXP_THRESHOLD = 150_000;

private final UserRepositoryPort userRepositoryPort;
private final UserRankHistoryRepositoryPort userRankHistoryRepositoryPort;
private final SeasonRepositoryPort seasonRepositoryPort;

/**
* 랭킹 기반 티어(Master, Aura) 업데이트
* - Aura : 1위 && exp >= 100,000
* - Master: 2~3위 && exp >= 75,000 (상위 3등 2명)
* - Aura : 1위 && exp >= 200,000
* - Master: 2~3위 && exp >= 150,000 (상위 3등 2명)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Master 티어의 조건 설명이 실제 코드 로직과 차이가 있습니다. 코드(93라인)에서는 rank <= 3을 확인하므로, 1위 유저가 AURA 점수 기준(200,000)을 충족하지 못하더라도 MASTER 점수 기준(150,000)을 충족하면 MASTER 티어를 부여받게 됩니다. 주석의 2~3위(상위 3등 2명) 문구를 1~3위 또는 상위 3위로 수정하여 실제 동작과 일치시키는 것이 좋습니다.

Suggested change
* - Master: 2~3 && exp >= 150,000 (상위 3 2)
* - Master: 1~3 && exp >= 150,000

* - 그 외 : NONE
*/
@Transactional
Expand Down Expand Up @@ -93,4 +93,4 @@ private RankTier computeRankTier(int exp, int rank) {
if (rank <= 3 && exp >= MASTER_EXP_THRESHOLD) return RankTier.MASTER;
return RankTier.NONE;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ public enum ExpTier {
UNRANKED, // 0 ~ 999
BRONZE, // 1,000 ~ 9,999
SILVER, // 10,000 ~ 29,999
GOLD, // 30,000 ~ 49,999
DIAMOND; // 50,000+
GOLD, // 30,000 ~ 99,999
DIAMOND; // 100,000+

public static ExpTier fromExp(int exp) {
if (exp >= 50_000) return DIAMOND;
if (exp >= 100_000) return DIAMOND;
if (exp >= 30_000) return GOLD;
if (exp >= 10_000) return SILVER;
if (exp >= 1_000) return BRONZE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ void updateRankTiers_noUsers_doesNothing() {
}

@Test
@DisplayName("1위이고 exp >= 100000이면 AURA를 부여한다")
void computeRankTier_rank1_expOver100k_returnsAura() {
User user = createUser(1L, 100_000, RankTier.NONE);
@DisplayName("1위이고 exp >= 200000이면 AURA를 부여한다")
void computeRankTier_rank1_expOver200k_returnsAura() {
User user = createUser(1L, 200_000, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -74,10 +74,10 @@ void computeRankTier_rank1_expOver100k_returnsAura() {
}

@Test
@DisplayName("2위이고 exp >= 75000이면 MASTER를 부여한다")
void computeRankTier_rank2_expOver75k_returnsMaster() {
User rank1 = createUser(1L, 200_000, RankTier.NONE);
User rank2 = createUser(2L, 75_000, RankTier.NONE);
@DisplayName("2위이고 exp >= 150000이면 MASTER를 부여한다")
void computeRankTier_rank2_expOver150k_returnsMaster() {
User rank1 = createUser(1L, 250_000, RankTier.NONE);
User rank2 = createUser(2L, 150_000, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -91,11 +91,11 @@ void computeRankTier_rank2_expOver75k_returnsMaster() {
}

@Test
@DisplayName("3위이고 exp >= 75000이면 MASTER를 부여한다")
void computeRankTier_rank3_expOver75k_returnsMaster() {
User rank1 = createUser(1L, 200_000, RankTier.NONE);
User rank2 = createUser(2L, 150_000, RankTier.NONE);
User rank3 = createUser(3L, 75_000, RankTier.NONE);
@DisplayName("3위이고 exp >= 150000이면 MASTER를 부여한다")
void computeRankTier_rank3_expOver150k_returnsMaster() {
User rank1 = createUser(1L, 250_000, RankTier.NONE);
User rank2 = createUser(2L, 200_000, RankTier.NONE);
User rank3 = createUser(3L, 150_000, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2, rank3));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -111,9 +111,9 @@ void computeRankTier_rank3_expOver75k_returnsMaster() {
@DisplayName("4위이면 exp에 관계없이 NONE을 부여한다")
void computeRankTier_rank4_returnsNone() {
User rank1 = createUser(1L, 200_000, RankTier.AURA);
User rank2 = createUser(2L, 150_000, RankTier.MASTER);
User rank3 = createUser(3L, 100_000, RankTier.MASTER);
User rank4 = createUser(4L, 90_000, RankTier.NONE);
User rank2 = createUser(2L, 180_000, RankTier.MASTER);
User rank3 = createUser(3L, 150_000, RankTier.MASTER);
User rank4 = createUser(4L, 140_000, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2, rank3, rank4));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -123,9 +123,9 @@ void computeRankTier_rank4_returnsNone() {
}

@Test
@DisplayName("1위이지만 exp < 75000이면 NONE을 부여한다")
void computeRankTier_rank1_expUnder75k_returnsNone() {
User user = createUser(1L, 74_999, RankTier.AURA);
@DisplayName("1위이지만 exp < 150000이면 NONE을 부여한다")
void computeRankTier_rank1_expUnder150k_returnsNone() {
User user = createUser(1L, 149_999, RankTier.AURA);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -137,9 +137,9 @@ void computeRankTier_rank1_expUnder75k_returnsNone() {
}

@Test
@DisplayName("1위이고 exp가 75000~99999이면 MASTER를 부여한다")
void computeRankTier_rank1_expBetween75kAnd100k_returnsMaster() {
User user = createUser(1L, 99_999, RankTier.NONE);
@DisplayName("1위이고 exp가 150000~199999이면 MASTER를 부여한다")
void computeRankTier_rank1_expBetween150kAnd200k_returnsMaster() {
User user = createUser(1L, 199_999, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -151,10 +151,10 @@ void computeRankTier_rank1_expBetween75kAnd100k_returnsMaster() {
}

@Test
@DisplayName("2위이지만 exp < 75000이면 NONE을 부여한다")
void computeRankTier_rank2_expUnder75k_returnsNone() {
User rank1 = createUser(1L, 200_000, RankTier.NONE);
User rank2 = createUser(2L, 74_999, RankTier.NONE);
@DisplayName("2위이지만 exp < 150000이면 NONE을 부여한다")
void computeRankTier_rank2_expUnder150k_returnsNone() {
User rank1 = createUser(1L, 250_000, RankTier.NONE);
User rank2 = createUser(2L, 149_999, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -169,7 +169,7 @@ void computeRankTier_rank2_expUnder75k_returnsNone() {
@Test
@DisplayName("티어가 변경되지 않은 유저는 saveAll을 호출하지 않는다")
void updateRankTiers_unchangedTier_doesNotSaveUser() {
User user = createUser(1L, 100_000, RankTier.AURA);
User user = createUser(1L, 200_000, RankTier.AURA);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -183,8 +183,8 @@ void updateRankTiers_unchangedTier_doesNotSaveUser() {
@Test
@DisplayName("활성 시즌이 있을 때 모든 유저의 RankHistory를 저장한다")
void updateRankTiers_withActiveSeason_savesAllHistories() {
User rank1 = createUser(1L, 100_000, RankTier.NONE);
User rank2 = createUser(2L, 75_000, RankTier.NONE);
User rank1 = createUser(1L, 200_000, RankTier.NONE);
User rank2 = createUser(2L, 150_000, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.of(createSeason(10L)));

Expand All @@ -198,7 +198,7 @@ void updateRankTiers_withActiveSeason_savesAllHistories() {
@Test
@DisplayName("활성 시즌이 없을 때 RankHistory를 저장하지 않는다")
void updateRankTiers_withoutActiveSeason_doesNotSaveHistory() {
User user = createUser(1L, 100_000, RankTier.NONE);
User user = createUser(1L, 200_000, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.empty());

Expand All @@ -210,7 +210,7 @@ void updateRankTiers_withoutActiveSeason_doesNotSaveHistory() {
@Test
@DisplayName("저장되는 RankHistory의 날짜는 오늘이다")
void updateRankTiers_historyDate_isToday() {
User user = createUser(1L, 100_000, RankTier.NONE);
User user = createUser(1L, 200_000, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.of(createSeason(10L)));

Expand Down Expand Up @@ -238,8 +238,8 @@ void updateRankTiers_expTier_isComputedFromTotalExp() {
@Test
@DisplayName("RankHistory에 순위와 rankTier가 올바르게 저장된다")
void updateRankTiers_historyContainsCorrectRankAndTier() {
User rank1 = createUser(1L, 100_000, RankTier.NONE);
User rank2 = createUser(2L, 75_000, RankTier.NONE);
User rank1 = createUser(1L, 200_000, RankTier.NONE);
User rank2 = createUser(2L, 150_000, RankTier.NONE);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(rank1, rank2));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.of(createSeason(10L)));

Expand All @@ -258,7 +258,7 @@ void updateRankTiers_historyContainsCorrectRankAndTier() {
@Test
@DisplayName("RankHistory의 seasonId는 현재 시즌 id로 저장된다")
void updateRankTiers_historySeasonId_matchesCurrentSeason() {
User user = createUser(1L, 100_000, RankTier.NONE);
User user = createUser(1L, 200_000, RankTier.NONE);
Season season = createSeason(42L);
when(userRepositoryPort.findAllOrderByTotalExpDesc()).thenReturn(List.of(user));
when(seasonRepositoryPort.findCurrentSeason()).thenReturn(Optional.of(season));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.process.clash.domain.user.userrankhistory.enums;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class ExpTierTest {

@Test
@DisplayName("exp가 100000 이상이면 DIAMOND다")
void fromExp_overOrEqual100k_returnsDiamond() {
assertThat(ExpTier.fromExp(100_000)).isEqualTo(ExpTier.DIAMOND);
}

@Test
@DisplayName("exp가 99999 이하이면 GOLD다")
void fromExp_under100k_returnsGold() {
assertThat(ExpTier.fromExp(99_999)).isEqualTo(ExpTier.GOLD);
}
}
Loading