From 4730b6ea21c20953ded3af6685e0d1ca4d8c37de Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 11:52:20 +0900 Subject: [PATCH 01/13] =?UTF-8?q?refactor:=20BaseTimeEntity=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=9D=BC=EC=9E=90=20=EC=B1=85=EC=9E=84=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../evaluatepost/domain/EvaluatePost.java | 4 ---- .../suwiki/domain/exampost/domain/ExamPost.java | 17 +++++++++-------- .../suwiki/domain/lecture/domain/Lecture.java | 4 ---- .../usw/suwiki/domain/notice/domain/Notice.java | 14 ++++---------- .../java/usw/suwiki/global/BaseTimeEntity.java | 17 ++++++++++------- 5 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/main/java/usw/suwiki/domain/evaluatepost/domain/EvaluatePost.java b/src/main/java/usw/suwiki/domain/evaluatepost/domain/EvaluatePost.java index 7f52e9dc..ee7c16b2 100644 --- a/src/main/java/usw/suwiki/domain/evaluatepost/domain/EvaluatePost.java +++ b/src/main/java/usw/suwiki/domain/evaluatepost/domain/EvaluatePost.java @@ -1,6 +1,5 @@ package usw.suwiki.domain.evaluatepost.domain; -import java.time.LocalDateTime; import java.util.Objects; import javax.persistence.Column; import javax.persistence.Entity; @@ -13,7 +12,6 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.data.annotation.LastModifiedDate; import usw.suwiki.domain.evaluatepost.controller.dto.EvaluatePostSaveDto; import usw.suwiki.domain.evaluatepost.controller.dto.EvaluatePostUpdateDto; import usw.suwiki.domain.lecture.domain.Lecture; @@ -50,8 +48,6 @@ public class EvaluatePost extends BaseTimeEntity { @JoinColumn(name = "user_idx") private User user; - @LastModifiedDate - private LocalDateTime modifiedDate; @Column(columnDefinition = "TEXT", nullable = false) private String content; //주관적인 강의평가 입력내용 diff --git a/src/main/java/usw/suwiki/domain/exampost/domain/ExamPost.java b/src/main/java/usw/suwiki/domain/exampost/domain/ExamPost.java index 08afb50b..4b2b8354 100644 --- a/src/main/java/usw/suwiki/domain/exampost/domain/ExamPost.java +++ b/src/main/java/usw/suwiki/domain/exampost/domain/ExamPost.java @@ -1,19 +1,23 @@ package usw.suwiki.domain.exampost.domain; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.data.annotation.LastModifiedDate; -import usw.suwiki.domain.exampost.controller.dto.ExamPostsSaveDto; import usw.suwiki.domain.exampost.controller.dto.ExamPostUpdateDto; +import usw.suwiki.domain.exampost.controller.dto.ExamPostsSaveDto; import usw.suwiki.domain.lecture.domain.Lecture; import usw.suwiki.domain.user.user.User; import usw.suwiki.global.BaseTimeEntity; -import javax.persistence.*; -import java.time.LocalDateTime; - @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity @@ -30,9 +34,6 @@ public class ExamPost extends BaseTimeEntity { private String examInfo; //시험방식 private String examDifficulty; //난이도 - @LastModifiedDate - private LocalDateTime modifiedDate; - @Column(columnDefinition = "TEXT", nullable = false) private String content; diff --git a/src/main/java/usw/suwiki/domain/lecture/domain/Lecture.java b/src/main/java/usw/suwiki/domain/lecture/domain/Lecture.java index b8e668a0..a93121c9 100644 --- a/src/main/java/usw/suwiki/domain/lecture/domain/Lecture.java +++ b/src/main/java/usw/suwiki/domain/lecture/domain/Lecture.java @@ -1,6 +1,5 @@ package usw.suwiki.domain.lecture.domain; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; @@ -16,7 +15,6 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.data.annotation.LastModifiedDate; import usw.suwiki.domain.evaluatepost.domain.EvaluatePost; import usw.suwiki.domain.evaluatepost.service.dto.EvaluatePostsToLecture; import usw.suwiki.global.BaseTimeEntity; @@ -52,8 +50,6 @@ public class Lecture extends BaseTimeEntity { private int postsCount = 0; - @LastModifiedDate - private LocalDateTime modifiedDate; @OneToMany(mappedBy = "lecture", cascade = CascadeType.ALL, orphanRemoval = true) private List evaluatePostList = new ArrayList<>(); diff --git a/src/main/java/usw/suwiki/domain/notice/domain/Notice.java b/src/main/java/usw/suwiki/domain/notice/domain/Notice.java index 9b12161c..1b8417c3 100644 --- a/src/main/java/usw/suwiki/domain/notice/domain/Notice.java +++ b/src/main/java/usw/suwiki/domain/notice/domain/Notice.java @@ -1,16 +1,13 @@ package usw.suwiki.domain.notice.domain; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.springframework.data.annotation.LastModifiedDate; -import usw.suwiki.domain.notice.controller.dto.NoticeSaveOrUpdateDto; -import usw.suwiki.global.BaseTimeEntity; - import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; -import java.time.LocalDateTime; +import lombok.Getter; +import lombok.NoArgsConstructor; +import usw.suwiki.domain.notice.controller.dto.NoticeSaveOrUpdateDto; +import usw.suwiki.global.BaseTimeEntity; @Getter @NoArgsConstructor @@ -20,9 +17,6 @@ public class Notice extends BaseTimeEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @LastModifiedDate - private LocalDateTime modifiedDate; - private String title; private String content; diff --git a/src/main/java/usw/suwiki/global/BaseTimeEntity.java b/src/main/java/usw/suwiki/global/BaseTimeEntity.java index ff07fd16..8ea81023 100644 --- a/src/main/java/usw/suwiki/global/BaseTimeEntity.java +++ b/src/main/java/usw/suwiki/global/BaseTimeEntity.java @@ -1,19 +1,22 @@ package usw.suwiki.global; +import java.time.LocalDateTime; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; import lombok.Getter; import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import javax.persistence.EntityListeners; -import javax.persistence.MappedSuperclass; -import java.time.LocalDateTime; - @Getter -@MappedSuperclass //Jpa Entity 클래스들이 BastTimeEntity 를 상속할 경우, 필드들도 칼럼으로 인식된다. -@EntityListeners(AuditingEntityListener.class) //Auditing 기능을 포함시킨다. +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) public abstract class BaseTimeEntity { - @CreatedDate // Entity가 생성되어 저장할 때 시간이 자동 저장된다. + @CreatedDate private LocalDateTime createDate; + + @LastModifiedDate + private LocalDateTime modifiedDate; } From 82e5fee022ef095e6a90158ccd4b9fa4a5617a04 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 13:02:22 +0900 Subject: [PATCH 02/13] =?UTF-8?q?feat:=20ClientAppVersion=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../version/entity/ClientAppVersion.java | 51 +++++++++++++++++++ .../domain/version/entity/ClientOS.java | 31 +++++++++++ .../global/exception/ExceptionType.java | 7 +++ .../exception/errortype/VersionException.java | 10 ++++ 4 files changed, 99 insertions(+) create mode 100644 src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java create mode 100644 src/main/java/usw/suwiki/domain/version/entity/ClientOS.java create mode 100644 src/main/java/usw/suwiki/global/exception/errortype/VersionException.java diff --git a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java new file mode 100644 index 00000000..7d0c7d1b --- /dev/null +++ b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java @@ -0,0 +1,51 @@ +package usw.suwiki.domain.version.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import usw.suwiki.global.BaseTimeEntity; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class ClientAppVersion extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "client_version_id") + private Long id; + + @Enumerated(EnumType.STRING) + @NotNull + private ClientOS os; + + @NotNull + @Min(value = 0) + private Integer versionCode; + + @NotNull + private Boolean isUpdateRequired; + + @Size(max = 2000) + private String description; + + + @Builder + public ClientAppVersion(ClientOS os, Integer versionCode, Boolean isUpdateRequired, String description) { + this.os = os; + this.versionCode = versionCode; + this.isUpdateRequired = isUpdateRequired; + this.description = description; + } +} diff --git a/src/main/java/usw/suwiki/domain/version/entity/ClientOS.java b/src/main/java/usw/suwiki/domain/version/entity/ClientOS.java new file mode 100644 index 00000000..58ff0703 --- /dev/null +++ b/src/main/java/usw/suwiki/domain/version/entity/ClientOS.java @@ -0,0 +1,31 @@ +package usw.suwiki.domain.version.entity; + +import java.util.Arrays; +import lombok.RequiredArgsConstructor; +import usw.suwiki.global.exception.ExceptionType; +import usw.suwiki.global.exception.errortype.VersionException; +import usw.suwiki.global.util.enums.KeyValueEnumModel; + +@RequiredArgsConstructor +public enum ClientOS implements KeyValueEnumModel { + ANDROID("ANDROID"), IOS("IOS"), WEB("WEB"); + + private final String value; + + public static ClientOS ofString(String param) { + return Arrays.stream(ClientOS.values()) + .filter(v -> v.getValue().equals(param.toUpperCase())) + .findFirst() + .orElseThrow(() -> new VersionException(ExceptionType.INVALID_CLIENT_OS)); + } + + @Override + public String getKey() { + return name(); + } + + @Override + public String getValue() { + return value; + } +} diff --git a/src/main/java/usw/suwiki/global/exception/ExceptionType.java b/src/main/java/usw/suwiki/global/exception/ExceptionType.java index 0f0f74c5..3428252a 100644 --- a/src/main/java/usw/suwiki/global/exception/ExceptionType.java +++ b/src/main/java/usw/suwiki/global/exception/ExceptionType.java @@ -114,6 +114,13 @@ public enum ExceptionType { INVALID_TIMETABLE_CELL_SCHEDULE("TIMETABLE210", "유효하지 않은 셀 스케줄입니다.", BAD_REQUEST), OVERLAPPED_TIMETABLE_CELL_SCHEDULE("TIMETABLE211", "시간표에 중복되는 요일-교시입니다.", CONFLICT), + + /** + * Domain : Version + */ + INVALID_CLIENT_OS("VERSION110", "유효하지 않은 클라이언트 OS 입니다.", BAD_REQUEST), + + /** * 공통 */ diff --git a/src/main/java/usw/suwiki/global/exception/errortype/VersionException.java b/src/main/java/usw/suwiki/global/exception/errortype/VersionException.java new file mode 100644 index 00000000..0cbed338 --- /dev/null +++ b/src/main/java/usw/suwiki/global/exception/errortype/VersionException.java @@ -0,0 +1,10 @@ +package usw.suwiki.global.exception.errortype; + +import usw.suwiki.global.exception.ExceptionType; + +public class VersionException extends BaseException { + public VersionException(ExceptionType exceptionType) { + super(exceptionType); + } + +} From 4aac4fb71aed61ecade0d19d28a6132502ebeda0 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 13:27:44 +0900 Subject: [PATCH 03/13] =?UTF-8?q?refactor:=20ClientAppVersion=20=ED=95=84?= =?UTF-8?q?=EC=88=98=20=EC=97=AC=EB=B6=80=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usw/suwiki/domain/version/entity/ClientAppVersion.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java index 7d0c7d1b..6d9b389e 100644 --- a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java +++ b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java @@ -35,17 +35,17 @@ public class ClientAppVersion extends BaseTimeEntity { private Integer versionCode; @NotNull - private Boolean isUpdateRequired; + private Boolean isVital; @Size(max = 2000) private String description; @Builder - public ClientAppVersion(ClientOS os, Integer versionCode, Boolean isUpdateRequired, String description) { + public ClientAppVersion(ClientOS os, Integer versionCode, Boolean isVital, String description) { this.os = os; this.versionCode = versionCode; - this.isUpdateRequired = isUpdateRequired; + this.isVital = isVital; this.description = description; } } From 040912ebf01e81f1b3518e94be87046f53332c16 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 13:29:43 +0900 Subject: [PATCH 04/13] =?UTF-8?q?refactor:=20JPA=20Test=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/annotation/SuwikiJpaTest.java | 23 +++++++++++++++++++ .../timetable/TimetableRepositoryTest.java | 13 ++--------- 2 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 src/test/java/usw/suwiki/global/annotation/SuwikiJpaTest.java diff --git a/src/test/java/usw/suwiki/global/annotation/SuwikiJpaTest.java b/src/test/java/usw/suwiki/global/annotation/SuwikiJpaTest.java new file mode 100644 index 00000000..0d09d09f --- /dev/null +++ b/src/test/java/usw/suwiki/global/annotation/SuwikiJpaTest.java @@ -0,0 +1,23 @@ +package usw.suwiki.global.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.TestMethodOrder; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import usw.suwiki.config.TestJpaConfig; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) + +@DataJpaTest +@Import(TestJpaConfig.class) +@TestMethodOrder(MethodOrderer.DisplayName.class) +@AutoConfigureTestDatabase(replace = Replace.NONE) +public @interface SuwikiJpaTest { +} diff --git a/src/test/java/usw/suwiki/repository/timetable/TimetableRepositoryTest.java b/src/test/java/usw/suwiki/repository/timetable/TimetableRepositoryTest.java index c85530be..c6b27b15 100644 --- a/src/test/java/usw/suwiki/repository/timetable/TimetableRepositoryTest.java +++ b/src/test/java/usw/suwiki/repository/timetable/TimetableRepositoryTest.java @@ -13,15 +13,8 @@ import javax.validation.ConstraintViolationException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.context.annotation.Import; -import usw.suwiki.config.TestJpaConfig; import usw.suwiki.domain.timetable.entity.Semester; import usw.suwiki.domain.timetable.entity.Timetable; import usw.suwiki.domain.timetable.entity.TimetableCell; @@ -32,16 +25,14 @@ import usw.suwiki.domain.timetable.repository.TimetableRepository; import usw.suwiki.domain.user.user.User; import usw.suwiki.domain.user.user.repository.UserRepository; +import usw.suwiki.global.annotation.SuwikiJpaTest; import usw.suwiki.global.exception.ExceptionType; import usw.suwiki.global.exception.errortype.TimetableException; import usw.suwiki.template.timetable.TimetableTemplate; import usw.suwiki.template.timetablecell.TimetableCellTemplate; import usw.suwiki.template.user.UserTemplate; -@DataJpaTest -@Import(TestJpaConfig.class) -@TestMethodOrder(MethodOrderer.DisplayName.class) -@AutoConfigureTestDatabase(replace = Replace.NONE) +@SuwikiJpaTest public class TimetableRepositoryTest { @Autowired From 2c7bff24131f04b62999f7a6dd867209b3332d1a Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 13:30:15 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=82=BD=EC=9E=85=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClientAppVersionRepository.java | 8 ++ .../ClientAppVersionRepositoryTest.java | 102 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/main/java/usw/suwiki/domain/version/repository/ClientAppVersionRepository.java create mode 100644 src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java diff --git a/src/main/java/usw/suwiki/domain/version/repository/ClientAppVersionRepository.java b/src/main/java/usw/suwiki/domain/version/repository/ClientAppVersionRepository.java new file mode 100644 index 00000000..f8f8a8d5 --- /dev/null +++ b/src/main/java/usw/suwiki/domain/version/repository/ClientAppVersionRepository.java @@ -0,0 +1,8 @@ +package usw.suwiki.domain.version.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import usw.suwiki.domain.version.entity.ClientAppVersion; + +public interface ClientAppVersionRepository extends JpaRepository { + +} diff --git a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java new file mode 100644 index 00000000..c6152bdd --- /dev/null +++ b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java @@ -0,0 +1,102 @@ +package usw.suwiki.repository.clientappversion; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.Optional; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.validation.ConstraintViolationException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import usw.suwiki.domain.version.entity.ClientAppVersion; +import usw.suwiki.domain.version.entity.ClientOS; +import usw.suwiki.domain.version.repository.ClientAppVersionRepository; +import usw.suwiki.global.annotation.SuwikiJpaTest; + +@SuwikiJpaTest +public class ClientAppVersionRepositoryTest { + @Autowired + ClientAppVersionRepository clientAppVersionRepository; + + @PersistenceContext + private EntityManager entityManager; + + private ClientAppVersion dummyClientAppVersion; + + @BeforeEach + public void setUp() { + ClientAppVersion androidVersion1 = ClientAppVersion.builder() + .os(ClientOS.ANDROID) + .versionCode(1) + .isVital(true) + .build(); + ClientAppVersion androidVersion2 = ClientAppVersion.builder() + .os(ClientOS.ANDROID) + .versionCode(2) + .isVital(true) + .build(); + ClientAppVersion androidVersion3 = ClientAppVersion.builder() + .os(ClientOS.ANDROID) + .versionCode(3) + .isVital(true) + .build(); + + clientAppVersionRepository.save(androidVersion1); + clientAppVersionRepository.save(androidVersion2); + clientAppVersionRepository.save(androidVersion3); + + entityManager.clear(); + } + + + @Test + @DisplayName("클라이언트 앱 버전 생성") + public void CLIENT_APP_VERSION_CREATE() { + // given + ClientAppVersion iosAppVersion = ClientAppVersion.builder() + .os(ClientOS.IOS) + .versionCode(1) + .isVital(true) + .build(); + + // when + ClientAppVersion saved = clientAppVersionRepository.save(iosAppVersion); + entityManager.clear(); + Optional found = clientAppVersionRepository.findById(saved.getId()); + + // then + assertThat(found).isPresent(); + assertThat(found.get().getOs()).isEqualTo(ClientOS.IOS); + assertThat(found.get().getVersionCode()).isEqualTo(1); + assertThat(found.get().getIsVital()).isTrue(); + } + + @Test + @DisplayName("클라이언트 앱 버전 생성 실패 - NOT NULL 제약 조건을 준수해야 한다.") + public void CLIENT_APP_VERSION_CREATE_FAIL_NOT_NULL_CONSTRAINT() { + // given + ClientAppVersion nullOsVersion = ClientAppVersion.builder() + .versionCode(1) + .isVital(true) + .build(); + ClientAppVersion nullCodeVersion = ClientAppVersion.builder() + .os(ClientOS.IOS) + .isVital(true) + .build(); + ClientAppVersion nullIsVitalVersion = ClientAppVersion.builder() + .os(ClientOS.IOS) + .versionCode(1) + .build(); + + // when & then + assertThatThrownBy(()->clientAppVersionRepository.save(nullOsVersion)) + .isExactlyInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(()->clientAppVersionRepository.save(nullCodeVersion)) + .isExactlyInstanceOf(ConstraintViolationException.class); + assertThatThrownBy(()->clientAppVersionRepository.save(nullIsVitalVersion)) + .isExactlyInstanceOf(ConstraintViolationException.class); + } +} From 742d1887b52b917ef995532945d2a3b9255ee2d1 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 13:43:32 +0900 Subject: [PATCH 06/13] =?UTF-8?q?feat:=20OS=EC=97=90=20=EB=94=B0=EB=A5=B8?= =?UTF-8?q?=20=EA=B0=80=EC=9E=A5=20=EC=B5=9C=EA=B7=BC=EC=9D=98=20=ED=95=84?= =?UTF-8?q?=EC=88=98=20=EB=B2=84=EC=A0=84=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClientAppVersionRepository.java | 3 +++ .../ClientAppVersionRepositoryTest.java | 26 +++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/main/java/usw/suwiki/domain/version/repository/ClientAppVersionRepository.java b/src/main/java/usw/suwiki/domain/version/repository/ClientAppVersionRepository.java index f8f8a8d5..d0c864f8 100644 --- a/src/main/java/usw/suwiki/domain/version/repository/ClientAppVersionRepository.java +++ b/src/main/java/usw/suwiki/domain/version/repository/ClientAppVersionRepository.java @@ -1,8 +1,11 @@ package usw.suwiki.domain.version.repository; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import usw.suwiki.domain.version.entity.ClientAppVersion; +import usw.suwiki.domain.version.entity.ClientOS; public interface ClientAppVersionRepository extends JpaRepository { + Optional findFirstByOsAndIsVitalTrueOrderByVersionCodeDesc(ClientOS os); } diff --git a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java index c6152bdd..f4f1a07a 100644 --- a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java +++ b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java @@ -24,7 +24,10 @@ public class ClientAppVersionRepositoryTest { @PersistenceContext private EntityManager entityManager; - private ClientAppVersion dummyClientAppVersion; + private ClientAppVersion dummyClientAppVersionFirst; + private ClientAppVersion dummyClientAppVersionSecond; + private ClientAppVersion dummyClientAppVersionThird; + @BeforeEach public void setUp() { @@ -41,12 +44,12 @@ public void setUp() { ClientAppVersion androidVersion3 = ClientAppVersion.builder() .os(ClientOS.ANDROID) .versionCode(3) - .isVital(true) + .isVital(false) .build(); - clientAppVersionRepository.save(androidVersion1); - clientAppVersionRepository.save(androidVersion2); - clientAppVersionRepository.save(androidVersion3); + this.dummyClientAppVersionFirst = clientAppVersionRepository.save(androidVersion1); + this.dummyClientAppVersionSecond = clientAppVersionRepository.save(androidVersion2); + this.dummyClientAppVersionThird = clientAppVersionRepository.save(androidVersion3); entityManager.clear(); } @@ -99,4 +102,17 @@ public void CLIENT_APP_VERSION_CREATE_FAIL_NOT_NULL_CONSTRAINT() { assertThatThrownBy(()->clientAppVersionRepository.save(nullIsVitalVersion)) .isExactlyInstanceOf(ConstraintViolationException.class); } + + @Test + @DisplayName("클라이언트 앱 버전 조회 - 특정 OS에 대한 가장 최신의 필수 버전 조회") + public void CLIENT_APP_VERSION_FIND_MOST_RECENT_VITAL_VERSION() { + // given + Optional optionalClientAppVersion = clientAppVersionRepository + .findFirstByOsAndIsVitalTrueOrderByVersionCodeDesc(ClientOS.ANDROID); + + // when & then + assertThat(optionalClientAppVersion).isPresent(); + assertThat(optionalClientAppVersion.get().getVersionCode()).isEqualTo(2); + } + } From fde5b7fb4fe941e31e8d3724832242c12b65d9cb Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 14:03:58 +0900 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20ClientAppVersion=20=EC=9C=A0?= =?UTF-8?q?=EB=8B=88=ED=81=AC=20=ED=82=A4=20=EC=A0=9C=EC=95=BD=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../version/entity/ClientAppVersion.java | 10 +++++++- .../ClientAppVersionRepositoryTest.java | 23 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java index 6d9b389e..94832575 100644 --- a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java +++ b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java @@ -19,19 +19,27 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(uniqueConstraints = { + @UniqueConstraint( + name = "UNIQUE_OS_AND_VERSION_CODE", + columnNames = {"os", "version_code"} + ) +}) public class ClientAppVersion extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "client_version_id") + @Column(name = "client_app_version_id") private Long id; @Enumerated(EnumType.STRING) @NotNull + @Column(name = "os") private ClientOS os; @NotNull @Min(value = 0) + @Column(name = "version_code") private Integer versionCode; @NotNull diff --git a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java index f4f1a07a..ac0aa756 100644 --- a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java +++ b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java @@ -1,6 +1,7 @@ package usw.suwiki.repository.clientappversion; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.Optional; @@ -11,6 +12,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; import usw.suwiki.domain.version.entity.ClientAppVersion; import usw.suwiki.domain.version.entity.ClientOS; import usw.suwiki.domain.version.repository.ClientAppVersionRepository; @@ -103,6 +105,27 @@ public void CLIENT_APP_VERSION_CREATE_FAIL_NOT_NULL_CONSTRAINT() { .isExactlyInstanceOf(ConstraintViolationException.class); } + @Test + @DisplayName("클라이언트 앱 버전 생성 실패 - UNIQUE 제약 조건 (os, versionCode)을 준수해야 한다.") + public void CLIENT_APP_VERSION_CREATE_FAIL_UNIQUE_CONSTRAINT() { + // given + ClientAppVersion first = ClientAppVersion.builder() + .os(ClientOS.IOS) + .versionCode(1) + .isVital(false) + .build(); + ClientAppVersion second = ClientAppVersion.builder() + .os(ClientOS.IOS) + .versionCode(1) + .isVital(false) + .build(); + + // when & then + assertThatNoException().isThrownBy(() -> clientAppVersionRepository.save(first)); + assertThatThrownBy(() -> clientAppVersionRepository.save(second)) + .isExactlyInstanceOf(DataIntegrityViolationException.class); + } + @Test @DisplayName("클라이언트 앱 버전 조회 - 특정 OS에 대한 가장 최신의 필수 버전 조회") public void CLIENT_APP_VERSION_FIND_MOST_RECENT_VITAL_VERSION() { From 3b4c1dba4bb2dc03399120431804c1091c0ba432 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 14:40:58 +0900 Subject: [PATCH 08/13] =?UTF-8?q?feat:=20ClientAppVersion=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=ED=95=84=EC=88=98=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=20=ED=99=95=EC=9D=B8=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../version/entity/ClientAppVersion.java | 11 +++++++++ .../ClientAppVersionRepositoryTest.java | 23 ++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java index 94832575..ffa6582d 100644 --- a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java +++ b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java @@ -7,6 +7,8 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; @@ -15,6 +17,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import usw.suwiki.global.BaseTimeEntity; +import usw.suwiki.global.exception.ExceptionType; +import usw.suwiki.global.exception.errortype.VersionException; @Entity @Getter @@ -56,4 +60,11 @@ public ClientAppVersion(ClientOS os, Integer versionCode, Boolean isVital, Strin this.isVital = isVital; this.description = description; } + + public boolean judgeIsUpdateRequired(ClientOS os, Integer otherVersionCode) { + if (!this.os.equals(os)) { + throw new VersionException(ExceptionType.SERVER_ERROR); + } + return this.isVital && this.versionCode > otherVersionCode; + } } diff --git a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java index ac0aa756..3bb9f83a 100644 --- a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java +++ b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java @@ -17,6 +17,7 @@ import usw.suwiki.domain.version.entity.ClientOS; import usw.suwiki.domain.version.repository.ClientAppVersionRepository; import usw.suwiki.global.annotation.SuwikiJpaTest; +import usw.suwiki.global.exception.errortype.VersionException; @SuwikiJpaTest public class ClientAppVersionRepositoryTest { @@ -97,11 +98,11 @@ public void CLIENT_APP_VERSION_CREATE_FAIL_NOT_NULL_CONSTRAINT() { .build(); // when & then - assertThatThrownBy(()->clientAppVersionRepository.save(nullOsVersion)) + assertThatThrownBy(() -> clientAppVersionRepository.save(nullOsVersion)) .isExactlyInstanceOf(ConstraintViolationException.class); - assertThatThrownBy(()->clientAppVersionRepository.save(nullCodeVersion)) + assertThatThrownBy(() -> clientAppVersionRepository.save(nullCodeVersion)) .isExactlyInstanceOf(ConstraintViolationException.class); - assertThatThrownBy(()->clientAppVersionRepository.save(nullIsVitalVersion)) + assertThatThrownBy(() -> clientAppVersionRepository.save(nullIsVitalVersion)) .isExactlyInstanceOf(ConstraintViolationException.class); } @@ -138,4 +139,20 @@ public void CLIENT_APP_VERSION_FIND_MOST_RECENT_VITAL_VERSION() { assertThat(optionalClientAppVersion.get().getVersionCode()).isEqualTo(2); } + @Test + @DisplayName("클라이언트 앱 버전 조회 - 업데이트 필수 여부 확인") + public void CLIENT_APP_VERSION_CHECK_IS_UPDATE_REQUIRED() { + // given + Optional optionalClientAppVersion = clientAppVersionRepository + .findFirstByOsAndIsVitalTrueOrderByVersionCodeDesc(ClientOS.ANDROID); + + // when & then + assertThat(optionalClientAppVersion).isPresent(); + assertThat(optionalClientAppVersion.get().judgeIsUpdateRequired(ClientOS.ANDROID, 1)) + .isTrue(); + assertThatThrownBy(() -> optionalClientAppVersion.get().judgeIsUpdateRequired(ClientOS.IOS, 1)) + .isExactlyInstanceOf(VersionException.class); + } + + } From 60e5db0f1e123be3f8f3bc5f26fd9cec087d35bd Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 15:08:24 +0900 Subject: [PATCH 09/13] =?UTF-8?q?refactor:=20ClientAppVersion=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=ED=95=84=EC=88=98=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=20=ED=99=95=EC=9D=B8=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usw/suwiki/domain/version/entity/ClientAppVersion.java | 2 +- .../clientappversion/ClientAppVersionRepositoryTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java index ffa6582d..560e8877 100644 --- a/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java +++ b/src/main/java/usw/suwiki/domain/version/entity/ClientAppVersion.java @@ -61,7 +61,7 @@ public ClientAppVersion(ClientOS os, Integer versionCode, Boolean isVital, Strin this.description = description; } - public boolean judgeIsUpdateRequired(ClientOS os, Integer otherVersionCode) { + public boolean judgeIsUpdateMandatory(ClientOS os, Integer otherVersionCode) { if (!this.os.equals(os)) { throw new VersionException(ExceptionType.SERVER_ERROR); } diff --git a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java index 3bb9f83a..35e4ca5e 100644 --- a/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java +++ b/src/test/java/usw/suwiki/repository/clientappversion/ClientAppVersionRepositoryTest.java @@ -148,9 +148,9 @@ public void CLIENT_APP_VERSION_CHECK_IS_UPDATE_REQUIRED() { // when & then assertThat(optionalClientAppVersion).isPresent(); - assertThat(optionalClientAppVersion.get().judgeIsUpdateRequired(ClientOS.ANDROID, 1)) + assertThat(optionalClientAppVersion.get().judgeIsUpdateMandatory(ClientOS.ANDROID, 1)) .isTrue(); - assertThatThrownBy(() -> optionalClientAppVersion.get().judgeIsUpdateRequired(ClientOS.IOS, 1)) + assertThatThrownBy(() -> optionalClientAppVersion.get().judgeIsUpdateMandatory(ClientOS.IOS, 1)) .isExactlyInstanceOf(VersionException.class); } From f8c7dc27ea9ae49b62901975a15dc5c316ed5965 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 15:19:36 +0900 Subject: [PATCH 10/13] =?UTF-8?q?refactor:=20Mockito=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B3=B5=ED=86=B5=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/annotation/SuwikiMockitoTest.java | 18 ++++++++++++++++++ .../service/lecture/LectureServiceTest.java | 8 ++------ .../timetable/TimetableServiceTest.java | 8 ++------ 3 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 src/test/java/usw/suwiki/global/annotation/SuwikiMockitoTest.java diff --git a/src/test/java/usw/suwiki/global/annotation/SuwikiMockitoTest.java b/src/test/java/usw/suwiki/global/annotation/SuwikiMockitoTest.java new file mode 100644 index 00000000..a52384a7 --- /dev/null +++ b/src/test/java/usw/suwiki/global/annotation/SuwikiMockitoTest.java @@ -0,0 +1,18 @@ +package usw.suwiki.global.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) + +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.DisplayName.class) +public @interface SuwikiMockitoTest { +} diff --git a/src/test/java/usw/suwiki/service/lecture/LectureServiceTest.java b/src/test/java/usw/suwiki/service/lecture/LectureServiceTest.java index 1c05ad73..9da02b77 100644 --- a/src/test/java/usw/suwiki/service/lecture/LectureServiceTest.java +++ b/src/test/java/usw/suwiki/service/lecture/LectureServiceTest.java @@ -10,13 +10,9 @@ import java.util.List; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Slice; import org.springframework.data.domain.SliceImpl; @@ -24,12 +20,12 @@ import usw.suwiki.domain.lecture.domain.Lecture; import usw.suwiki.domain.lecture.domain.repository.LectureRepository; import usw.suwiki.domain.lecture.service.LectureService; +import usw.suwiki.global.annotation.SuwikiMockitoTest; import usw.suwiki.global.dto.NoOffsetPaginationResponse; import usw.suwiki.template.lecture.LectureDetailTemplate; import usw.suwiki.template.lecture.LectureTemplate; -@ExtendWith(MockitoExtension.class) -@TestMethodOrder(MethodOrderer.DisplayName.class) +@SuwikiMockitoTest public class LectureServiceTest { @InjectMocks LectureService lectureService; diff --git a/src/test/java/usw/suwiki/service/timetable/TimetableServiceTest.java b/src/test/java/usw/suwiki/service/timetable/TimetableServiceTest.java index 011f513d..f921b38b 100644 --- a/src/test/java/usw/suwiki/service/timetable/TimetableServiceTest.java +++ b/src/test/java/usw/suwiki/service/timetable/TimetableServiceTest.java @@ -16,13 +16,9 @@ import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import usw.suwiki.domain.timetable.dto.request.CreateTimetableCellRequest; import usw.suwiki.domain.timetable.dto.request.CreateTimetableRequest; import usw.suwiki.domain.timetable.dto.request.CreateWholeTimetableRequest; @@ -40,14 +36,14 @@ import usw.suwiki.domain.timetable.service.TimetableService; import usw.suwiki.domain.user.user.User; import usw.suwiki.domain.user.user.service.UserCRUDService; +import usw.suwiki.global.annotation.SuwikiMockitoTest; import usw.suwiki.global.exception.ExceptionType; import usw.suwiki.global.exception.errortype.TimetableException; import usw.suwiki.template.timetable.TimetableTemplate; import usw.suwiki.template.timetablecell.TimetableCellTemplate; import usw.suwiki.template.user.UserTemplate; -@ExtendWith(MockitoExtension.class) -@TestMethodOrder(MethodOrderer.DisplayName.class) +@SuwikiMockitoTest public class TimetableServiceTest { @InjectMocks TimetableService timetableService; From 6092897470f0d5d3b7c661cee06abbcccab2c201 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 15:43:43 +0900 Subject: [PATCH 11/13] =?UTF-8?q?fix:=20ClientOS=20=EC=9D=B8=EC=9E=90?= =?UTF-8?q?=EA=B0=92=20null=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/usw/suwiki/domain/version/entity/ClientOS.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/usw/suwiki/domain/version/entity/ClientOS.java b/src/main/java/usw/suwiki/domain/version/entity/ClientOS.java index 58ff0703..f6cd908d 100644 --- a/src/main/java/usw/suwiki/domain/version/entity/ClientOS.java +++ b/src/main/java/usw/suwiki/domain/version/entity/ClientOS.java @@ -1,6 +1,7 @@ package usw.suwiki.domain.version.entity; import java.util.Arrays; +import java.util.Objects; import lombok.RequiredArgsConstructor; import usw.suwiki.global.exception.ExceptionType; import usw.suwiki.global.exception.errortype.VersionException; @@ -13,10 +14,13 @@ public enum ClientOS implements KeyValueEnumModel { private final String value; public static ClientOS ofString(String param) { + if (Objects.isNull(param)) { + throw new VersionException(ExceptionType.INVALID_CLIENT_OS); + } return Arrays.stream(ClientOS.values()) .filter(v -> v.getValue().equals(param.toUpperCase())) .findFirst() - .orElseThrow(() -> new VersionException(ExceptionType.INVALID_CLIENT_OS)); + .orElseThrow(() -> new VersionException(ExceptionType.COMMON_CLIENT_ERROR)); } @Override From 0a7bb0c502960cfcbd6e2166eb3089932d8190a6 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 15:50:52 +0900 Subject: [PATCH 12/13] =?UTF-8?q?feat=20:=20ClientAppVersionService=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=ED=95=84=EC=88=98=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=ED=99=95=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CheckUpdateMandatoryResponse.java | 19 +++++ .../service/ClientAppVersionService.java | 31 +++++++ .../global/exception/ExceptionType.java | 3 +- .../ClientAppVersionServiceTest.java | 85 +++++++++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/main/java/usw/suwiki/domain/version/dto/response/CheckUpdateMandatoryResponse.java create mode 100644 src/main/java/usw/suwiki/domain/version/service/ClientAppVersionService.java create mode 100644 src/test/java/usw/suwiki/service/clientappversion/ClientAppVersionServiceTest.java diff --git a/src/main/java/usw/suwiki/domain/version/dto/response/CheckUpdateMandatoryResponse.java b/src/main/java/usw/suwiki/domain/version/dto/response/CheckUpdateMandatoryResponse.java new file mode 100644 index 00000000..ac1162b4 --- /dev/null +++ b/src/main/java/usw/suwiki/domain/version/dto/response/CheckUpdateMandatoryResponse.java @@ -0,0 +1,19 @@ +package usw.suwiki.domain.version.dto.response; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class CheckUpdateMandatoryResponse { + private final Boolean isUpdateMandatory; + + public static CheckUpdateMandatoryResponse from(boolean isUpdateMandatory) { + return CheckUpdateMandatoryResponse.builder() + .isUpdateMandatory(isUpdateMandatory) + .build(); + } +} diff --git a/src/main/java/usw/suwiki/domain/version/service/ClientAppVersionService.java b/src/main/java/usw/suwiki/domain/version/service/ClientAppVersionService.java new file mode 100644 index 00000000..a6503c74 --- /dev/null +++ b/src/main/java/usw/suwiki/domain/version/service/ClientAppVersionService.java @@ -0,0 +1,31 @@ +package usw.suwiki.domain.version.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import usw.suwiki.domain.version.dto.response.CheckUpdateMandatoryResponse; +import usw.suwiki.domain.version.entity.ClientAppVersion; +import usw.suwiki.domain.version.entity.ClientOS; +import usw.suwiki.domain.version.repository.ClientAppVersionRepository; +import usw.suwiki.global.exception.ExceptionType; +import usw.suwiki.global.exception.errortype.VersionException; + + +@Slf4j +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class ClientAppVersionService { + private final ClientAppVersionRepository clientAppVersionRepository; + + public CheckUpdateMandatoryResponse checkIsUpdateMandatory(String os, int versionCode) { + ClientOS clientOS = ClientOS.ofString(os); + ClientAppVersion clientAppVersion = clientAppVersionRepository + .findFirstByOsAndIsVitalTrueOrderByVersionCodeDesc(clientOS) + .orElseThrow(() -> new VersionException(ExceptionType.SERVER_ERROR)); + + boolean isUpdateMandatory = clientAppVersion.judgeIsUpdateMandatory(clientOS, versionCode); + return CheckUpdateMandatoryResponse.from(isUpdateMandatory); + } +} diff --git a/src/main/java/usw/suwiki/global/exception/ExceptionType.java b/src/main/java/usw/suwiki/global/exception/ExceptionType.java index 3428252a..e565e230 100644 --- a/src/main/java/usw/suwiki/global/exception/ExceptionType.java +++ b/src/main/java/usw/suwiki/global/exception/ExceptionType.java @@ -116,8 +116,9 @@ public enum ExceptionType { OVERLAPPED_TIMETABLE_CELL_SCHEDULE("TIMETABLE211", "시간표에 중복되는 요일-교시입니다.", CONFLICT), /** - * Domain : Version + * Domain : Client Version */ + CLIENT_VERSION_NOT_FOUND("VERSION001", "존재하지 않는 클라이언트 버전입니다.", NOT_FOUND), INVALID_CLIENT_OS("VERSION110", "유효하지 않은 클라이언트 OS 입니다.", BAD_REQUEST), diff --git a/src/test/java/usw/suwiki/service/clientappversion/ClientAppVersionServiceTest.java b/src/test/java/usw/suwiki/service/clientappversion/ClientAppVersionServiceTest.java new file mode 100644 index 00000000..c451c438 --- /dev/null +++ b/src/test/java/usw/suwiki/service/clientappversion/ClientAppVersionServiceTest.java @@ -0,0 +1,85 @@ +package usw.suwiki.service.clientappversion; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.when; +import static org.mockito.Mockito.verify; + +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import usw.suwiki.domain.version.entity.ClientAppVersion; +import usw.suwiki.domain.version.entity.ClientOS; +import usw.suwiki.domain.version.repository.ClientAppVersionRepository; +import usw.suwiki.domain.version.service.ClientAppVersionService; +import usw.suwiki.global.annotation.SuwikiMockitoTest; +import usw.suwiki.global.exception.ExceptionType; +import usw.suwiki.global.exception.errortype.VersionException; + +@SuwikiMockitoTest +public class ClientAppVersionServiceTest { + @InjectMocks + ClientAppVersionService clientAppVersionService; + + @Mock + ClientAppVersionRepository clientAppVersionRepository; + + + @Test + @DisplayName("클라이언트 앱 필수 업데이트 여부 확인") + public void CLIENT_APP_CHECK_IS_UPDATE_MANDATORY() { + // given + ClientAppVersion clientAppVersion = ClientAppVersion.builder() + .os(ClientOS.ANDROID) + .versionCode(30) + .isVital(true) + .build(); + + when(clientAppVersionRepository.findFirstByOsAndIsVitalTrueOrderByVersionCodeDesc(any(ClientOS.class))) + .thenReturn(Optional.of(clientAppVersion)); + + // when & then + assertThatNoException() + .isThrownBy(() -> clientAppVersionService.checkIsUpdateMandatory("ANDROID", 20)); + verify(clientAppVersionRepository) + .findFirstByOsAndIsVitalTrueOrderByVersionCodeDesc(any(ClientOS.class)); + } + + @Test + @DisplayName("클라이언트 앱 필수 업데이트 여부 확인 실패 - 파라미터는 모두 NOT NULL 이어야 한다.") + public void CLIENT_APP_CHECK_IS_UPDATE_MANDATORY_FAIL_NULL_PARAMETER() { + // given + + // when & then + assertThatThrownBy(() -> clientAppVersionService.checkIsUpdateMandatory(null, 20)) + .isExactlyInstanceOf(VersionException.class) + .hasMessage(ExceptionType.INVALID_CLIENT_OS.getMessage()); + } + + @Test + @DisplayName("클라이언트 앱 필수 업데이트 여부 확인 실패 - OS 마다 DB에 최소 하나의 is_vital = true인 레코드가 존재해야 한다.") + public void CLIENT_APP_CHECK_IS_UPDATE_MANDATORY_FAIL_RECORD_NOT_EXIST() { + // given + when(clientAppVersionRepository.findFirstByOsAndIsVitalTrueOrderByVersionCodeDesc(any(ClientOS.class))) + .thenReturn(Optional.empty()); + + // when & then + assertThatThrownBy(() -> clientAppVersionService.checkIsUpdateMandatory("ANDROID", 30)) + .isExactlyInstanceOf(VersionException.class); + verify(clientAppVersionRepository) + .findFirstByOsAndIsVitalTrueOrderByVersionCodeDesc(any(ClientOS.class)); + } + + @Test + @DisplayName("클라이언트 앱 필수 업데이트 여부 확인 실패 - ClientOS ENUM에 있지 않은 os는 조회될 수 없다.") + public void CLIENT_APP_CHECK_IS_UPDATE_MANDATORY_FAIL_INVALID_OS() { + // given + + // when & then + assertThatThrownBy(() -> clientAppVersionService.checkIsUpdateMandatory("linux_ubuntu", 22)) + .isExactlyInstanceOf(VersionException.class); + } +} From 884cf89b1af95c44a074c6f7202d1fac2ad53291 Mon Sep 17 00:00:00 2001 From: wonseok2877 Date: Wed, 24 Jan 2024 15:51:24 +0900 Subject: [PATCH 13/13] =?UTF-8?q?feat=20:=20ClientAppVersionController=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=ED=95=84=EC=88=98=20?= =?UTF-8?q?=EC=97=AC=EB=B6=80=20=ED=99=95=EC=9D=B8=20API=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ClientAppVersionController.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/usw/suwiki/domain/version/controller/ClientAppVersionController.java diff --git a/src/main/java/usw/suwiki/domain/version/controller/ClientAppVersionController.java b/src/main/java/usw/suwiki/domain/version/controller/ClientAppVersionController.java new file mode 100644 index 00000000..a1675a8c --- /dev/null +++ b/src/main/java/usw/suwiki/domain/version/controller/ClientAppVersionController.java @@ -0,0 +1,27 @@ +package usw.suwiki.domain.version.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import usw.suwiki.domain.version.dto.response.CheckUpdateMandatoryResponse; +import usw.suwiki.domain.version.service.ClientAppVersionService; + +@Slf4j +@RestController +@RequestMapping("/client/version") +@RequiredArgsConstructor +public class ClientAppVersionController { + private final ClientAppVersionService clientAppVersionService; + + @GetMapping("/update-mandatory") + public ResponseEntity checkIsUpdateMandatory( + @RequestParam String os, + @RequestParam Integer versionCode + ) { + return ResponseEntity.ok(clientAppVersionService.checkIsUpdateMandatory(os, versionCode)); + } +}