Skip to content

Commit

Permalink
refactor: 쿠폰, 알림 테스트 접근 제어자, 메서드명, 클래스명 변경 (#148)
Browse files Browse the repository at this point in the history
* style : Schedule 어노테이션 위치 변경

* refactor: 쿠폰 발행 기간 하루로 통일 및 쿠폰 정보 오픈 날짜 추가

* feat: 쿠폰 발행 가능 날짜 중복 체크 기능 추가

* refactor: Builder 삭제

* test: 쿠폰 관련 테스트 수정

* feat: 쿠폰 발행 관련 레포지토리 기능 구현 및 테스트

* test: 쿠폰 발행 관련 문자열 레디스 기능 구현 및 테스트

* feat: 쿠폰 발행 관련 ZSET 레디스 기능 구현 및 테스트

* test: 쿠폰 발행 컨트롤러 기능 테스트

* test: RestDoc 업데이트

* test: Github Actions 시, Redis ZSET 명령어 못찾는 테스트 Disable

* refactor: 알림 및 쿠폰 테스트 코드 메서드명 변경 및 알림 콕 알림 키 변경

* refactor: LocalDate 코드 리뷰 반영
  • Loading branch information
hongdosan authored Nov 26, 2023
1 parent 0756c4d commit 5e6f7d2
Show file tree
Hide file tree
Showing 27 changed files with 269 additions and 223 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class CouponManageService {

@Scheduled(fixedDelay = 1000)
public void issue() {
LocalDate now = LocalDate.from(clockHolder.times());
LocalDate now = clockHolder.date();
Optional<Coupon> isCoupon = couponRepository.findByStartAt(now);

if (!canIssue(isCoupon)) {
Expand Down Expand Up @@ -69,7 +69,7 @@ public void deleteCouponManage(String couponName) {
}

private void validateRegister(String couponName) {
LocalDate now = LocalDate.from(clockHolder.times());
LocalDate now = clockHolder.date();
Optional<Coupon> coupon = couponRepository.findByStartAt(now);

if (coupon.isEmpty() || !coupon.get().getName().equals(couponName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public Coupon getByWalletIdAndMemberId(Long couponWalletId, Long memberId) {
}

public List<CouponResponse> getAllByStatus(CouponStatusRequest request) {
LocalDate now = LocalDate.from(clockHolder.times());
LocalDate now = clockHolder.date();
List<Coupon> coupons = couponSearchRepository.findAllByStatus(now, request);

return coupons.stream()
Expand All @@ -78,7 +78,7 @@ public List<CouponResponse> getAllByStatus(CouponStatusRequest request) {
}

private void validatePeriod(LocalDate startAt, LocalDate openAt) {
LocalDate now = LocalDate.from(clockHolder.times());
LocalDate now = clockHolder.date();

if (!now.isBefore(startAt)) {
throw new BadRequestException(ErrorMessage.INVALID_COUPON_START_AT_PERIOD);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public class NotificationService {

private static final String KNOCK_BODY = "%s님이 콕 찔렀습니다.";
private static final String CERTIFY_TIME_BODY = "%s방 인증 시간입니다.";
private static final String KNOCK_KEY = "room_%s_member_%s_knocks_%s";

private final FcmService fcmService;
private final RoomService roomService;
Expand All @@ -41,13 +40,11 @@ public class NotificationService {
@Transactional
public void sendKnock(AuthMember member, Long targetId, Long roomId) {
roomService.validateRoomById(roomId);

String knockKey = generateKnockKey(member.id(), targetId, roomId);
validateConflictKnock(knockKey);
validateConflictKnock(member.id(), targetId, roomId);

String fcmToken = fcmService.findTokenByMemberId(targetId);
fcmService.sendAsync(fcmToken, String.format(KNOCK_BODY, member.nickname()));
notificationRepository.saveKnock(knockKey);
notificationRepository.saveKnock(member.id(), targetId, roomId);
}

@Scheduled(cron = "0 50 * * * *")
Expand All @@ -68,8 +65,8 @@ public List<Long> getMyKnockStatusInRoom(Long memberId, Long roomId, List<Partic
.filter(participant -> !participant.getMemberId().equals(memberId))
.toList();

Predicate<Long> knockPredicate = targetId
-> notificationRepository.existsKnockByKey(generateKnockKey(memberId, targetId, roomId));
Predicate<Long> knockPredicate = targetId ->
notificationRepository.existsKnockByKey(memberId, targetId, roomId);

Map<Boolean, List<Long>> knockStatus = filteredParticipants.stream()
.map(Participant::getMemberId)
Expand All @@ -78,13 +75,9 @@ public List<Long> getMyKnockStatusInRoom(Long memberId, Long roomId, List<Partic
return knockStatus.get(true);
}

private void validateConflictKnock(String knockKey) {
if (notificationRepository.existsKnockByKey(knockKey)) {
private void validateConflictKnock(Long memberId, Long targetId, Long roomId) {
if (notificationRepository.existsKnockByKey(memberId, targetId, roomId)) {
throw new ConflictException(ErrorMessage.CONFLICT_KNOCK);
}
}

private String generateKnockKey(Long memberId, Long targetId, Long roomId) {
return String.format(KNOCK_KEY, roomId, memberId, targetId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import org.springframework.stereotype.Repository;

import com.moabam.api.infrastructure.redis.StringRedisRepository;
import com.moabam.api.infrastructure.redis.ValueRedisRepository;
import com.moabam.api.infrastructure.redis.ZSetRedisRepository;

import lombok.RequiredArgsConstructor;
Expand All @@ -19,7 +19,7 @@ public class CouponManageRepository {
private static final String STOCK_KEY = "%s_INCR";

private final ZSetRedisRepository zSetRedisRepository;
private final StringRedisRepository stringRedisRepository;
private final ValueRedisRepository valueRedisRepository;

public void addIfAbsentQueue(String couponName, Long memberId, double registerTime) {
zSetRedisRepository.addIfAbsent(requireNonNull(couponName), requireNonNull(memberId), registerTime);
Expand All @@ -34,20 +34,20 @@ public Set<Long> popMinQueue(String couponName, long count) {
}

public void deleteQueue(String couponName) {
stringRedisRepository.delete(requireNonNull(couponName));
valueRedisRepository.delete(requireNonNull(couponName));
}

public int increaseIssuedStock(String couponName) {
String stockKey = String.format(STOCK_KEY, requireNonNull(couponName));

return stringRedisRepository
return valueRedisRepository
.increment(requireNonNull(stockKey))
.intValue();
}

public int getIssuedStock(String couponName) {
String stockKey = String.format(STOCK_KEY, requireNonNull(couponName));
String stockValue = stringRedisRepository.get(requireNonNull(stockKey));
String stockValue = valueRedisRepository.get(requireNonNull(stockKey));

if (stockValue == null) {
return 0;
Expand All @@ -58,6 +58,6 @@ public int getIssuedStock(String couponName) {

public void deleteIssuedStock(String couponName) {
String stockKey = String.format(STOCK_KEY, requireNonNull(couponName));
stringRedisRepository.delete(requireNonNull(stockKey));
valueRedisRepository.delete(requireNonNull(stockKey));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,30 @@

import org.springframework.stereotype.Repository;

import com.moabam.api.infrastructure.redis.StringRedisRepository;
import com.moabam.api.infrastructure.redis.ValueRedisRepository;

import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
public class NotificationRepository {

private static final String KNOCK_KEY = "room_%s_member_%s_knocks_%s";
private static final long EXPIRE_KNOCK = 12;

private final StringRedisRepository stringRedisRepository;
private final ValueRedisRepository valueRedisRepository;

public void saveKnock(String key) {
stringRedisRepository.save(
requireNonNull(key),
BLANK,
Duration.ofHours(EXPIRE_KNOCK)
);
public void saveKnock(Long memberId, Long targetId, Long roomId) {
String knockKey =
String.format(KNOCK_KEY, requireNonNull(roomId), requireNonNull(memberId), requireNonNull(targetId));

valueRedisRepository.save(knockKey, BLANK, Duration.ofHours(EXPIRE_KNOCK));
}

public boolean existsKnockByKey(String key) {
return stringRedisRepository.hasKey(requireNonNull(key));
public boolean existsKnockByKey(Long memberId, Long targetId, Long roomId) {
String knockKey =
String.format(KNOCK_KEY, requireNonNull(roomId), requireNonNull(memberId), requireNonNull(targetId));

return valueRedisRepository.hasKey(requireNonNull(knockKey));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import org.springframework.stereotype.Repository;

import com.moabam.api.infrastructure.redis.StringRedisRepository;
import com.moabam.api.infrastructure.redis.ValueRedisRepository;

import lombok.RequiredArgsConstructor;

Expand All @@ -16,25 +16,25 @@ public class FcmRepository {

private static final long EXPIRE_FCM_TOKEN = 60;

private final StringRedisRepository stringRedisRepository;
private final ValueRedisRepository valueRedisRepository;

public void saveToken(Long memberId, String fcmToken) {
stringRedisRepository.save(
valueRedisRepository.save(
String.valueOf(requireNonNull(memberId)),
requireNonNull(fcmToken),
Duration.ofDays(EXPIRE_FCM_TOKEN)
);
}

public void deleteTokenByMemberId(Long memberId) {
stringRedisRepository.delete(String.valueOf(requireNonNull(memberId)));
valueRedisRepository.delete(String.valueOf(requireNonNull(memberId)));
}

public String findTokenByMemberId(Long memberId) {
return stringRedisRepository.get(String.valueOf(requireNonNull(memberId)));
return valueRedisRepository.get(String.valueOf(requireNonNull(memberId)));
}

public boolean existsTokenByMemberId(Long memberId) {
return stringRedisRepository.hasKey(String.valueOf(requireNonNull(memberId)));
return valueRedisRepository.hasKey(String.valueOf(requireNonNull(memberId)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@Repository
@RequiredArgsConstructor
public class StringRedisRepository {
public class ValueRedisRepository {

private final RedisTemplate<String, Object> redisTemplate;

Expand Down
54 changes: 32 additions & 22 deletions src/main/resources/static/docs/coupon.html
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ <h4 id="_요청" class="discrete">요청</h4>
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">POST /admins/coupons HTTP/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 183
Content-Length: 175
Host: localhost:8080

{
Expand All @@ -479,9 +479,11 @@ <h4 id="_응답" class="discrete">응답</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">HTTP/1.1 201 Created
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers</code></pre>
Access-Control-Allow-Origin:
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Access-Control-Allow-Headers: Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, X-Requested-With,Content-Type, Referer
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600</code></pre>
</div>
</div>
<hr>
Expand All @@ -496,17 +498,19 @@ <h3 id="_쿠폰_삭제">쿠폰 삭제</h3>
<h4 id="_요청_2" class="discrete">요청</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">DELETE /admins/coupons/1 HTTP/1.1
<pre class="highlight nowrap"><code class="language-http" data-lang="http">DELETE /admins/coupons/27 HTTP/1.1
Host: localhost:8080</code></pre>
</div>
</div>
<h4 id="_응답_2" class="discrete">응답</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers</code></pre>
Access-Control-Allow-Origin:
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Access-Control-Allow-Headers: Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, X-Requested-With,Content-Type, Referer
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600</code></pre>
</div>
</div>
<hr>
Expand All @@ -522,19 +526,21 @@ <h3 id="_특정_쿠폰_조회">특정 쿠폰 조회</h3>
<h4 id="_요청_3">요청</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">GET /coupons/26 HTTP/1.1
<pre class="highlight nowrap"><code class="language-http" data-lang="http">GET /coupons/16 HTTP/1.1
Host: localhost:8080</code></pre>
</div>
</div>
<h4 id="_응답_3" class="discrete">응답</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin:
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Access-Control-Allow-Headers: Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, X-Requested-With,Content-Type, Referer
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600
Content-Type: application/json
Content-Length: 215
Content-Length: 205

{
"id" : 16,
Expand Down Expand Up @@ -565,7 +571,7 @@ <h4 id="_요청_4">요청</h4>
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">POST /coupons/search HTTP/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 44
Content-Length: 41
Host: localhost:8080

{
Expand All @@ -578,11 +584,13 @@ <h4 id="_응답_4" class="discrete">응답</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin:
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Access-Control-Allow-Headers: Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, X-Requested-With,Content-Type, Referer
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600
Content-Type: application/json
Content-Length: 216
Content-Length: 206

[ {
"id" : 17,
Expand Down Expand Up @@ -623,9 +631,11 @@ <h4 id="_응답_5" class="discrete">응답</h4>
<div class="listingblock">
<div class="content">
<pre class="highlight nowrap"><code class="language-http" data-lang="http">HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin:
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Access-Control-Allow-Headers: Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, X-Requested-With,Content-Type, Referer
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600
Content-Type: application/json
Content-Length: 64

Expand Down Expand Up @@ -660,7 +670,7 @@ <h3 id="_쿠폰_사용_진행_중">쿠폰 사용 (진행 중)</h3>
<div id="footer">
<div id="footer-text">
Version 0.0.1-SNAPSHOT<br>
Last updated 2023-11-23 17:01:22 +0900
Last updated 2023-11-26 13:14:53 +0900
</div>
</div>
</body>
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/static/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ <h4 id="_상태코드httpstatus"><a class="link" href="#_상태코드httpstatus"
<div id="footer">
<div id="footer-text">
Version 0.0.1-SNAPSHOT<br>
Last updated 2023-11-23 17:01:22 +0900
Last updated 2023-11-06 23:30:09 +0900
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.3/highlight.min.js"></script>
Expand Down
Loading

0 comments on commit 5e6f7d2

Please sign in to comment.