Skip to content

Commit

Permalink
대기열 관련 설정 waiting 서버와 align
Browse files Browse the repository at this point in the history
- zset key
  - 변경 전 : ticketing_id
  - 변경 후 : "queue::{ticketing_id}"
- purchase token pattern
  - 변경 전 : {email}:{ticketing_id}:{entry_time}
  - 변경 후 : {email}:{ticketing_id}
  • Loading branch information
dla0510 committed May 27, 2024
1 parent 4c83408 commit f333bed
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class CheckWaitingQueueAndTokenAop {

private final SecurityContextHelper securityContextHelper;
private final RedisService redisService;
private final String tokenPattern = "^[\\w\\.-]+@[\\w\\.-]+:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}+:\\d+$";
private final String tokenPattern = "^[\\w\\.-]+@[\\w\\.-]+:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}+$";

@Around("@annotation(com.tiketeer.Tiketeer.domain.purchase.annotation.CheckWaitingQueueAndToken)")
public Object check(final ProceedingJoinPoint joinPoint) throws Throwable {
Expand All @@ -47,17 +47,16 @@ public Object check(final ProceedingJoinPoint joinPoint) throws Throwable {
String[] args = purchaseToken.split(":");
var email = args[0];
var ticketingId = args[1];
var entryTime = Long.parseLong(args[2]);

validateUser(email);
validateTokenWithRedis(ticketingId, email, entryTime);
validateTokenWithRedis(ticketingId, email);

try {
return joinPoint.proceed();
} catch (Throwable e) {
throw e;
} finally {
redisService.removeZset(ticketingId, email);
redisService.removeZset("queue::" + ticketingId, email);
}
}

Expand All @@ -77,22 +76,13 @@ private void validateUser(String email) {
}
}

private void validateTokenWithRedis(String ticketingId, String email, Long entryTime) {
var results = redisService.getZSetRankAndScore(ticketingId, email).orElseThrow(() -> {
log.error("User does not enter queue (email: " + email + ", ticketing_id: " + ticketingId + ")");
private void validateTokenWithRedis(String ticketingId, String email) {
var results = redisService.getZSetRankAndScore("queue::" + ticketingId, email).orElseThrow(() -> {
log.error("User does not enter queue (email: {}, ticketing_id: {})", email, ticketingId);
return new UserNotExistInQueueException();
});
var rank = results.getFirst();
var entryTimeInRedis = results.getSecond();

if (entryTime != entryTimeInRedis.longValue()) {
log.error(
"Entry time(" + entryTime + ") in token does not match with entry time("
+ entryTimeInRedis.longValue()
+ ") in redis (email: " + email
+ ", ticketing_id: " + ticketingId + ")");
throw new PurchaseTokenNotValidException();
}
if (rank >= 10) {
log.error(
"User is not in purchasing order. (email: \" + email + \", ticketing_id: \" + ticketingId + \")\"");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ void postPurchaseSuccess() throws Exception {
String content = objectMapper.writeValueAsString(req);

var unixTime = System.currentTimeMillis();
redisService.addZSet(ticketing.getId().toString(), buyerEmail, (double)unixTime);
List<String> tokenValues = Arrays.asList(buyerEmail, ticketing.getId().toString(), String.valueOf(unixTime));
redisService.addZSet("queue::" + ticketing.getId().toString(), buyerEmail, (double)unixTime);
List<String> tokenValues = Arrays.asList(buyerEmail, ticketing.getId().toString());
var purchaseToken = Encoders.BASE64.encode(String.join(":", tokenValues).getBytes());

// when
Expand All @@ -128,7 +128,7 @@ void postPurchaseSuccess() throws Exception {
.andExpect(status().isCreated())
.andExpect(jsonPath("$.data.purchaseId").value(purchaseRepository.findAll().getFirst().getId().toString()
));
var rankOpt = redisService.getZSetRank(ticketing.getId().toString(), buyerEmail);
var rankOpt = redisService.getZSetRank("queue::" + ticketing.getId().toString(), buyerEmail);
Assertions.assertThat(rankOpt).isNotPresent();

}
Expand Down Expand Up @@ -187,7 +187,7 @@ void postPurchaseFailPurchaseTokenNotValid() throws Exception {
.build();
String content = objectMapper.writeValueAsString(req);

List<String> tokenValues = Arrays.asList(buyerEmail, ticketingId.toString());
List<String> tokenValues = Arrays.asList(buyerEmail, "");
var purchaseToken = Encoders.BASE64.encode(String.join(":", tokenValues).getBytes());

// when
Expand Down Expand Up @@ -224,8 +224,7 @@ void postPurchaseFailPurchaseTokenOfOtherUser() throws Exception {
.build();
String content = objectMapper.writeValueAsString(req);

var unixTime = System.currentTimeMillis();
List<String> tokenValues = Arrays.asList(otherEmail, ticketingId.toString(), String.valueOf(unixTime));
List<String> tokenValues = Arrays.asList(otherEmail, ticketingId.toString());
var purchaseToken = Encoders.BASE64.encode(String.join(":", tokenValues).getBytes());

// when
Expand Down Expand Up @@ -279,45 +278,6 @@ void postPurchaseFailUserNotExistInQueue() throws Exception {
.andExpect(status().isUnauthorized());
}

@Test
@DisplayName("일치하지 않는 entry time > 구매 생성 요청 > 실패")
@Transactional
void postPurchaseFailEntryTimeNotValid() throws Exception {
// given
var ticketingId = UUID.randomUUID();
var buyerEmail = "buyer@test.com";
String token = testHelper.registerAndLoginAndReturnAccessToken(buyerEmail, RoleEnum.BUYER);
var buyer = memberRepository.findByEmail(buyerEmail).orElseThrow();
buyer.setPoint(10000);
Cookie cookie = new Cookie(JwtMetadata.ACCESS_TOKEN, token);

var count = 2;
PostPurchaseRequestDto req = PostPurchaseRequestDto.builder()
.ticketingId(ticketingId)
.count(count)
.build();
String content = objectMapper.writeValueAsString(req);

var unixTime = System.currentTimeMillis();
var otherUnixTime = unixTime + 100;
redisService.addZSet(ticketingId.toString(), buyerEmail, (double)unixTime);
List<String> tokenValues = Arrays.asList(buyerEmail, ticketingId.toString(), String.valueOf(otherUnixTime));
var purchaseToken = Encoders.BASE64.encode(String.join(":", tokenValues).getBytes());

// when
mockMvc
.perform(post("/api/purchases")
.contextPath("/api")
.contentType(MediaType.APPLICATION_JSON)
.characterEncoding("utf-8")
.content(content)
.cookie(cookie)
.header("Purchase-Token", purchaseToken)
)
//then
.andExpect(status().isUnauthorized());
}

@Test
@DisplayName("구매 가능한 대기열 순위에 들지 않음 > 구매 생성 요청 > 실패")
@Transactional
Expand All @@ -338,11 +298,11 @@ void postPurchaseFailNotInOrder() throws Exception {
String content = objectMapper.writeValueAsString(req);

var unixTime = System.currentTimeMillis();
redisService.addZSet(ticketingId.toString(), buyerEmail, (double)unixTime);
redisService.addZSet("queue::" + ticketingId, buyerEmail, (double)unixTime);
for (int i = 1; i < 11; i++) {
redisService.addZSet(ticketingId.toString(), i + "@test.com", (double)(unixTime - 100 * i));
redisService.addZSet("queue::" + ticketingId, i + "@test.com", (double)(unixTime - 100 * i));
}
List<String> tokenValues = Arrays.asList(buyerEmail, ticketingId.toString(), String.valueOf(unixTime));
List<String> tokenValues = Arrays.asList(buyerEmail, ticketingId.toString());
var purchaseToken = Encoders.BASE64.encode(String.join(":", tokenValues).getBytes());

// when
Expand Down

0 comments on commit f333bed

Please sign in to comment.