Skip to content

Commit

Permalink
[OING-326] feat: 일일 미션 배치 구현 및 테스트코드 추가 (#249)
Browse files Browse the repository at this point in the history
* chore: Add mission module path in the targets of cicd modification checking

* feat: Add DailyMissionRegistrationJob in DailyMissionJob with Spring scheduler and table lock

* feat: Impl the methods of MissionService and DailyMissionHistyoryService those api responses was mocked

* feat: Add exceptions handling at DailyMissionRegistrationJob

* feat: Add DailyMissionHistoryRepositoryTest

* feat: Add MissionRepositoryTest for getRandomMissionExcludingIds

* feat: Add DailyMissionJobTest for registerDailyMission

* feat: Add error handling code for duplicated attempting to create daily mission history and catch exception code

* feat: Add tests for newly added error handling and exception catching code

* refactor: Refactor method and parameter name according to naming convention

* refactor: Delete unnecessary Repository annocation from DailyMissionHistoryRepositoryCustomImpl

* fix: Make Nested test class lower case
  • Loading branch information
Kwon770 authored May 7, 2024
1 parent 8ab18d4 commit 2cc26d9
Show file tree
Hide file tree
Showing 15 changed files with 617 additions and 22 deletions.
1 change: 1 addition & 0 deletions .github/workflows/dev-cicd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- 'common/**' # Common 모듈 변경
- 'family/**' # Family 모듈 변경
- 'post/**' # Post 모듈 변경
- 'mission/**' # Mission 모듈 변경
- '.github/workflows/**' # 워크플로우와 관련된 파일이 변경된 경우
- 'build.gradle' # Parent Gradle 모듈 설정이 변경된 경우
- 'settings.gradle' # Parent Gradle 설정이 변경된 경우
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/prod-cicd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- 'common/**' # Common 모듈 변경
- 'family/**' # Family 모듈 변경
- 'post/**' # Post 모듈 변경
- 'mission/**' # Mission 모듈 변경
- '.github/workflows/**' # 워크플로우와 관련된 파일이 변경된 경우
- 'build.gradle' # Parent Gradle 모듈 설정이 변경된 경우
- 'settings.gradle' # Parent Gradle 설정이 변경된 경우
Expand Down
1 change: 1 addition & 0 deletions common/src/main/java/com/oing/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public enum ErrorCode {
*/
MISSION_NOT_FOUND("MI0001", "존재하지 않는 미션입니다."),
DAILY_MISSION_HISTORY_NOT_FOUND("MI0002", "존재하지 않는 미션 히스토리입니다."),
DUPLICATED_DAILY_MISSION_HISTORY("MI0003", "이미 존재하는 미션 히스토리입니다."),

/**
* Deep Link Related Errors
Expand Down
183 changes: 183 additions & 0 deletions gateway/src/test/java/com/oing/job/DailyMissionJobTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package com.oing.job;

import com.oing.domain.DailyMissionHistory;
import com.oing.domain.Mission;
import com.oing.repository.DailyMissionHistoryRepository;
import com.oing.repository.MissionRepository;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ActiveProfiles;

import java.time.LocalDate;
import java.util.Optional;

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

@SpringBootTest
@ActiveProfiles("test")
@Transactional
public class DailyMissionJobTest {

@Autowired
private JdbcTemplate jdbcTemplate;

@Autowired
private DailyMissionJob dailyMissionJob;
@Autowired
private MissionRepository missionRepository;
@Autowired
private DailyMissionHistoryRepository dailyMissionHistoryRepository;


private Mission testMission1;
private Mission testMission2;
private Mission testMission3;
private Mission testMission4;
private Mission testMission5;
private Mission testMission6;
private Mission testMission7;


@BeforeEach
void setUp() {
testMission1 = missionRepository.save(Mission.builder()
.id("testMission1")
.content("testMission1")
.build());

testMission2 = missionRepository.save(Mission.builder()
.id("testMission2")
.content("testMission2")
.build());

testMission3 = missionRepository.save(Mission.builder()
.id("testMission3")
.content("testMission3")
.build());

testMission4 = missionRepository.save(Mission.builder()
.id("testMission4")
.content("testMission4")
.build());

testMission5 = missionRepository.save(Mission.builder()
.id("testMission5")
.content("testMission5")
.build());

testMission6 = missionRepository.save(Mission.builder()
.id("testMission6")
.content("testMission6")
.build());

testMission7 = missionRepository.save(Mission.builder()
.id("testMission7")
.content("testMission7")
.build());

// Table Lock 용 테이블 생성
jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS shedlock\n" +
"(\n" +
" name VARCHAR(64) NOT NULL,\n" +
" lock_until TIMESTAMP(3) NOT NULL,\n" +
" locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n" +
" locked_by VARCHAR(255) NOT NULL,\n" +
" PRIMARY KEY (name)\n" +
") DEFAULT CHARSET = utf8mb4\n" +
" COLLATE = utf8mb4_unicode_ci COMMENT 'ShedLock 테이블';");
// Table Lock 비활성화
jdbcTemplate.update("UPDATE shedlock SET lock_until = locked_at WHERE name = 'DailyMissionRegistrationJob'");
}


@Nested
class registerDailyMission {
@Test
void 정상_등록_테스트() {
// given
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(1))
.mission(testMission1)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(2))
.mission(testMission2)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(3))
.mission(testMission3)
.build());

// when
dailyMissionJob.registerDailyMission();

// then
Optional<DailyMissionHistory> dailyMissionHistory = dailyMissionHistoryRepository.findById(LocalDate.now());
assertThat(dailyMissionHistory).isPresent();
assertThat(dailyMissionHistory.get().getMission().getId())
.isNotIn(testMission1.getId(), testMission2.getId(), testMission3.getId())
.isIn(testMission4.getId(), testMission5.getId(), testMission6.getId(), testMission7.getId());
}

@Test
void 제외된_미션_외_미션이_없는경우_가장_오래된_미션을_선출한다() {
// given
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(1))
.mission(testMission1)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(2))
.mission(testMission2)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(3))
.mission(testMission3)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(4))
.mission(testMission4)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(5))
.mission(testMission5)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(6))
.mission(testMission6)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.now().minusDays(7))
.mission(testMission7)
.build());

// when
dailyMissionJob.registerDailyMission();

// then
Optional<DailyMissionHistory> dailyMissionHistory = dailyMissionHistoryRepository.findById(LocalDate.now());
assertThat(dailyMissionHistory).isPresent();
assertThat(dailyMissionHistory.get().getMission().getId()).isEqualTo(testMission7.getId());
}

@Test
void 등록된_미션이_없는경우_예외핸들링을_한다() {
// when
assertThatNoException().isThrownBy(() -> dailyMissionJob.registerDailyMission());
}

@Test
void 중복된_미션이_생성시도경우_예외핸들링을_한다() {
// when
assertThatNoException().isThrownBy(() -> dailyMissionJob.registerDailyMission());
jdbcTemplate.update("UPDATE shedlock SET lock_until = locked_at WHERE name = 'DailyMissionRegistrationJob'");
assertThatNoException().isThrownBy(() -> dailyMissionJob.registerDailyMission());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.oing.repository;

import com.oing.config.QuerydslConfig;
import com.oing.domain.DailyMissionHistory;
import com.oing.domain.Mission;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;

import java.time.LocalDate;
import java.util.List;

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

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // application-test.yaml의 데이터베이스 설정을 적용하기 위해서 필수
@ActiveProfiles("test")
@Import(QuerydslConfig.class)
public class DailyMissionHistoryRepositoryTest {

@Autowired
private MissionRepository missionRepository;
@Autowired
private DailyMissionHistoryRepository dailyMissionHistoryRepository;

private Mission testMission1;
private Mission testMission2;
private Mission testMission3;
private Mission testMission4;
private Mission testMission5;
private Mission testMission6;
private Mission testMission7;


@BeforeEach
void setUp() {
testMission1 = missionRepository.save(Mission.builder()
.id("testMission1")
.content("testMission1")
.build());

testMission2 = missionRepository.save(Mission.builder()
.id("testMission2")
.content("testMission2")
.build());

testMission3 = missionRepository.save(Mission.builder()
.id("testMission3")
.content("testMission3")
.build());

testMission4 = missionRepository.save(Mission.builder()
.id("testMission4")
.content("testMission4")
.build());

testMission5 = missionRepository.save(Mission.builder()
.id("testMission5")
.content("testMission5")
.build());

testMission6 = missionRepository.save(Mission.builder()
.id("testMission6")
.content("testMission6")
.build());

testMission7 = missionRepository.save(Mission.builder()
.id("testMission7")
.content("testMission7")
.build());
}


@Nested
class findRecentDailyMissionIdsOrderByDateAsc {
@Test
void 정상_조회_테스트() {
// given
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.of(2021, 10, 1))
.mission(testMission5)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.of(2021, 10, 2))
.mission(testMission6)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.of(2021, 10, 3))
.mission(testMission7)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.of(2021, 10, 4))
.mission(testMission1)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.of(2021, 10, 5))
.mission(testMission2)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.of(2021, 10, 6))
.mission(testMission3)
.build());
dailyMissionHistoryRepository.save(DailyMissionHistory.builder()
.date(LocalDate.of(2021, 10, 7))
.mission(testMission4)
.build());

// when
List<String> recentDailyMissionIds = dailyMissionHistoryRepository.findRecentDailyMissionIdsOrderByDateAsc(7);

// then
assertThat(recentDailyMissionIds)
.containsExactly(
testMission5.getId(),
testMission6.getId(),
testMission7.getId(),
testMission1.getId(),
testMission2.getId(),
testMission3.getId(),
testMission4.getId()
);
}
}
}
Loading

0 comments on commit 2cc26d9

Please sign in to comment.