Skip to content

Commit

Permalink
Merge pull request #148 from softeerbootcamp4th/fix/#147-shorten-url-…
Browse files Browse the repository at this point in the history
…encoding

Fix/#147 shorten url encoding
  • Loading branch information
wjddn2165 authored Aug 16, 2024
2 parents 0c23e13 + 7771093 commit 672595b
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 222 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@ public LotteryEventController(LotteryEventService lotteryEventService, RedisServ
this.lotteryEventService = lotteryEventService;
this.redisService = redisService;
}
// 추첨 이벤트 조회 API -> 가짜 API

// 추첨 이벤트 조회 API
@GetMapping
public ResponseEntity<LotteryEventResponseDto> getLotteryEvent(){
return ResponseEntity
.status(HttpStatus.OK)
.body(lotteryEventService.getLotteryEvent());
}

// 캐스퍼 봇 생성 API
@PostMapping("/casperBot")
public ResponseEntity<CasperBotResponseDto> postCasperBot(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public static String encrypt(String plainText, SecretKey key) throws NoSuchPaddi
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
return Base62Utils.encode(encryptedBytes);
}

public static String decrypt(String encryptedText, SecretKey key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
byte[] decryptedBytes = cipher.doFinal(Base62Utils.decodeToBytes(encryptedText));
return new String(decryptedBytes);
}

Expand Down
19 changes: 19 additions & 0 deletions Server/src/main/java/JGS/CasperEvent/global/util/Base62Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,23 @@ public static long decode(String str){
}
return result;
}

public static String encode(byte[] data) {
StringBuilder sb = new StringBuilder();
for (byte b : data) {
int value = b & 0xFF;
sb.append(encode(value));
}
return sb.toString();
}

public static byte[] decodeToBytes(String str) {
int length = str.length() / 2;
byte[] data = new byte[length];
for (int i = 0; i < length; i++) {
String part = str.substring(i * 2, i * 2 + 2);
data[i] = (byte) decode(part);
}
return data;
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,74 @@
package JGS.CasperEvent.domain.event.controller.eventController;

import JGS.CasperEvent.domain.event.dto.ResponseDto.lotteryEventResponseDto.LotteryEventResponseDto;
import JGS.CasperEvent.domain.event.service.adminService.AdminService;
import JGS.CasperEvent.domain.event.service.eventService.LotteryEventService;
import JGS.CasperEvent.domain.event.service.redisService.RedisService;
import JGS.CasperEvent.global.entity.BaseUser;
import JGS.CasperEvent.global.enums.Role;
import JGS.CasperEvent.global.jwt.service.UserService;
import JGS.CasperEvent.global.jwt.util.JwtProvider;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
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.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("local")
@WebMvcTest(LotteryEventController.class)
@Import(JwtProvider.class)
public class LotteryEventControllerTest {
@Autowired
private MockMvc mockMvc;

@MockBean
private LotteryEventService lotteryEventService;
@MockBean
private UserService userService;
@MockBean
private AdminService adminService;
@MockBean
private RedisService redisService;

public String phoneNumber;
public String accessToken;

@BeforeEach
void setUp() throws Exception {
this.phoneNumber = "010-0000-0000";

// userService 모킹
given(userService.verifyUser(any())).willReturn(new BaseUser(this.phoneNumber, Role.USER));

// 엑세스 토큰 설정
this.accessToken = getToken(this.phoneNumber);

// 추첨 이벤트 조회
LotteryEventResponseDto lotteryEventResponseDto = new LotteryEventResponseDto(
LocalDateTime.of(2024, 8, 15, 0, 0, 0),
LocalDateTime.of(2024, 8, 1, 0, 0, 0),
LocalDateTime.of(2024, 8, 31, 0, 0, 0),
ChronoUnit.DAYS.between(LocalDateTime.of(2024, 8, 1, 0, 0, 0), LocalDateTime.of(2024, 8, 31, 0, 0, 0))
);
given(lotteryEventService.getLotteryEvent()).willReturn(lotteryEventResponseDto);
}

String getToken(String phoneNumber) throws Exception {
String requestBody = String.format("""
{
Expand All @@ -43,221 +88,22 @@ String getToken(String phoneNumber) throws Exception {
return "Bearer " + jsonString.substring(start, end);
}

@Test
@DisplayName("추첨 이벤트 조회 API 성공 테스트")
void getLotteryEventAndServerTime() throws Exception {
//given
String token = this.accessToken;

@Nested
@DisplayName("캐스퍼 봇 생성 테스트")
class CasperBotTest {
//TODO: Expecation이 없을때, 있을때 값 증가 테스트
//TODO: DB에 없는 사용자 테스트 작성
@Test
@DisplayName("캐스퍼 봇 생성 성공 테스트")
public void createCasperBotSuccessTest() throws Exception {
//given
String accessToken = getToken("010-0000-0000");

String casperBotRequest = """
{
"eyeShape": "2",
"eyePosition": "1",
"mouthShape": "4",
"color": "2",
"sticker": "4",
"name": "myCasperBot",
"expectation": "myExpectation"
}
""";

//when
ResultActions perform = mockMvc.perform(post("/event/lottery/casperBot")
.contentType(MediaType.APPLICATION_JSON)
.content(casperBotRequest)
.header("Authorization", accessToken));

//then
perform
.andExpect(status().isCreated())
.andExpect(jsonPath("$.eyeShape").value(2))
.andExpect(jsonPath("$.eyePosition").value(1))
.andExpect(jsonPath("$.mouthShape").value(4))
.andExpect(jsonPath("$.color").value(2))
.andExpect(jsonPath("$.sticker").value(4))
.andExpect(jsonPath("$.name").value("myCasperBot"))
.andExpect(jsonPath("$.expectation").value("myExpectation"))
.andDo(print());
}

@Test
@DisplayName("캐스퍼 봇 생성 실패 테스트 - 필수 필드 없음")
void createCasperBotFailureTest_RequiredFieldNotExist() throws Exception {
String accessToken = getToken("010-0000-0000");
//given
String casperBotRequest = """
{
"eye_shape": "2",
"eye_position": "1",
"mouth_shape": "4",
"color": "2",
"sticker": "4",
"expectation": "myExpectation"
}
""";


//when
ResultActions perform = mockMvc.perform(post("/event/lottery/casperBot")
.contentType(MediaType.APPLICATION_JSON)
.content(casperBotRequest)
.header("Authorization", accessToken));

//then
perform.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode").value("INVALID_PARAMETER"))
.andDo(print());

}

@Test
@DisplayName("캐스퍼 봇 생성 실패 테스트 - 잘못된 값")
void createCasperBotSuccessTest_WrongValue() throws Exception {
//given
String accessToken = getToken("010-0000-0000");
String casperBotRequest = """
{
"eyeShape": "15",
"eyePosition": "1",
"mouthShape": "4",
"color": "2",
"sticker": "4",
"name": "myCasperBot",
"expectation": "myExpectation"
}""";

//when
ResultActions perform = mockMvc.perform(post("/event/lottery/casperBot")
.contentType(MediaType.APPLICATION_JSON)
.content(casperBotRequest)
.header("Authorization", accessToken));

//then
perform.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode").value("INVALID_PARAMETER"))
.andDo(print());
}

@Test
@DisplayName("캐스퍼 봇 생성 실패 테스트 - 인증 토큰 없음")
void createCasperBotSuccessTest_CookieNotPresent() throws Exception {
//given
String casperBotRequest = """
{
"eyeShape": "1",
"eyePosition": "1",
"mouthShape": "4",
"color": "2",
"sticker": "4",
"name": "myCasperBot",
"expectation": "myExpectation"
}
""";

//when
ResultActions perform = mockMvc.perform(post("/event/lottery/casperBot")
.contentType(MediaType.APPLICATION_JSON)
.content(casperBotRequest));

//then
perform.andExpect(status().isUnauthorized())
.andDo(print());

}
}

@Nested
@DisplayName("캐스퍼 봇 응모 조회")
class CasperBotAppliedTest {
@Test
@DisplayName("캐스퍼 봇 응모 여부 조회 성공 - 유저가 존재할 경우")
void userHasAppliedCasperBotSuccessTest_PresentUser() throws Exception {
String accessToken = getToken("010-0000-0000");

String casperBotRequest = """
{
"eyeShape": "2",
"eyePosition": "1",
"mouthShape": "4",
"color": "2",
"sticker": "4",
"name": "myCasperBot",
"expectation": "myExpectation"
}
""";
//when
mockMvc.perform(post("/event/lottery/casperBot")
.contentType(MediaType.APPLICATION_JSON)
.content(casperBotRequest)
.header("Authorization", accessToken));

//when
ResultActions perform = mockMvc.perform(get("/event/lottery/applied")
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", accessToken));

//then
perform.andExpect(status().isOk())
.andDo(print());

}

@Test
@DisplayName("캐스퍼 봇 응모 여부 조회 성공 - 유저가 존재하지 않는 경우")
void userHasAppliedCasperBotSuccessTest_NotPresentUser() throws Exception {
//given
String accessToken = getToken("010-1234-1234");

//when
ResultActions perform = mockMvc.perform(get("/event/lottery/applied")
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", accessToken));
//then
perform.andExpect(status().isNotFound())
.andExpect(jsonPath("$.errorCode").value("USER_NOT_FOUND"))
.andExpect(jsonPath("$.message").value("응모하지 않은 사용자입니다."))
.andDo(print());

}

@Test
@DisplayName("캐스퍼 봇 응모 여부 조회 실패 - 토큰이 없는 경우")
void userHasAppliedCasperBotFailureTest_NotPresentCookie() throws Exception {
//when
ResultActions perform = mockMvc.perform(get("/event/lottery/applied")
.contentType(MediaType.APPLICATION_JSON));
//then
perform.andExpect(status().isUnauthorized())
.andExpect(jsonPath("$.errorCode").value("JWT_MISSING"))
.andExpect(jsonPath("$.message").value("인증 토큰이 존재하지 않습니다."))
.andDo(print());

}
}

@Nested
@DisplayName("캐스퍼 봇 조회 테스트")
class CasperBotResponseDtoTest {
@Test
@DisplayName("캐스퍼 봇 조회 테스트 성공 - Redis")
void GetCasperBotSuccessTest_redis() throws Exception {
for (int i = 0; i < 100; i++) {
ResultActions perform = mockMvc.perform(get("/event/lottery/caspers"));
//when
ResultActions perform = mockMvc.perform(get("/event/lottery")
.contentType(MediaType.APPLICATION_JSON));

//then
perform.andExpect(status().isOk())
.andExpect(result -> {
String responseBody = result.getResponse().getContentAsString();
assertFalse(responseBody.isEmpty(), "Response body should not be empty");
});
//then
perform.andExpect(status().isOk())
.andExpect(jsonPath("$.serverDateTime").value("2024-08-15T00:00:00"))
.andExpect(jsonPath("$.eventStartDate").value("2024-08-01T00:00:00"))
.andExpect(jsonPath("$.eventEndDate").value("2024-08-31T00:00:00"))
.andDo(print());

}
}
}
}

0 comments on commit 672595b

Please sign in to comment.