Riot은 인게임에서 게임 ID를 복사하면 "게임아이디" 이런식으로 복사되게 해놓고는 게임 아이디로 검색을 호출할 때는 "KR_게임아이디" 이런식으로 받는다.
그래서 이 KR이라는 것을 다음과 같이 LolSearchAdapter에 넣어주고 한동안 Controller를 생성하지 않았다.
public MatchRecord searchMatch(String matchId) {
try {
matchId = "KR_" + matchId;
MatchRecord result = restTemplate.getForObject(
"https://asia.api.riotgames.com/lol/match/v5/matches/" + matchId + "?api_key=" + apiKey,
MatchRecord.class
);
return result;
} catch (Exception e) {
throw new ApiException(SearchStatus.SEARCH_RESULT_NOT_FOUND);
}
}
그리고 BoardApiController를 개발하고 BoardService를 개발하면서 LolSearchAdapter를 사용할 일이 생기고
public MatchGameResponse searchMatch(String gameId) {
Optional<MatchGame> savedEntity = matchGameService.findByGameId(gameId);
MatchGame matchGame;
if (savedEntity != null && savedEntity.isPresent()) {
matchGame = savedEntity.get();
} else {
MatchRecord vo = lolSearchAdapter.searchMatch(gameId);
matchGame = matchGameService.save(vo);
matchUserService.saveAll(vo.info().participants(), matchGame);
}
MatchGameResponse response = MatchGameResponse.toResponse(matchGame);
return response;
}
BoardService에 위와 같이 전적을 검색하는 코드를 작성하고
@Test
@DisplayName("이미 저장된 게임이 있을 때 lolSearchAdapter를 통해서 검색하지 않는다")
void searchAlreadySavedGame() {
// given
MatchRecord vo = MatchDummy.create();
MatchGame game = matchGameService.save(vo);
boardService = new BoardService(matchGameService, matchUserService, mockLolSearch);
List<ParticipantRecord> participantVO = vo.info().participants();
matchUserService.saveAll(participantVO, game);
// when
boardService.searchMatch(game.getGameId());
// then
verify(mockLolSearch, never()).searchMatch(anyString());
}
다음과 같이 중복 검사 테스트도 작성하고 실제 API 호출을 해보다가 Bug가 터졌다.
2024-03-19T23:25:40.020Z ERROR 835114 --- [nio-8080-exec-5] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry 'KR_6862565824' for key 'MATCH_GAME.gameId'
????? 분명히 중복 검사 해주고 있는데????????
원인은 BoardService의
Optional<MatchGame> savedEntity = matchGameService.findByGameId(gameId);
이 코드에 있었다. BoardApiController에서 "KR_" 문구를 추가해주는 것이 아니기 때문에 유저는 게임에서 복사한 "KR_"이 빠진 코드를 그대로 넣게 되고 "KR_"이 빠진 gameId로 데이터베이스에서 정보를 찾는다. 하지만 이에 해당하는 정보는 없고 LolSearchAdapter로 넘어가서 "KR_"을 붙인 후 데이터베이스에서 그 정보를 그대로 저장하다가 먼저 전적을 검색해서 저장된 정보가 있으면 에러가 발생하게 되는 것이다.
이 코드를 수정하면서 제일 먼저 들었던 생각이 '아... 통합 테스트를 했더라면' 이었다.
Riot은 인게임에서 게임 ID를 복사하면 "게임아이디" 이런식으로 복사되게 해놓고는 게임 아이디로 검색을 호출할 때는 "KR_게임아이디" 이런식으로 받는다.
그래서 이 KR이라는 것을 다음과 같이 LolSearchAdapter에 넣어주고 한동안 Controller를 생성하지 않았다.
public MatchRecord searchMatch(String matchId) {
try {
matchId = "KR_" + matchId;
MatchRecord result = restTemplate.getForObject(
"https://asia.api.riotgames.com/lol/match/v5/matches/" + matchId + "?api_key=" + apiKey,
MatchRecord.class
);
return result;
} catch (Exception e) {
throw new ApiException(SearchStatus.SEARCH_RESULT_NOT_FOUND);
}
}
그리고 BoardApiController를 개발하고 BoardService를 개발하면서 LolSearchAdapter를 사용할 일이 생기고
public MatchGameResponse searchMatch(String gameId) {
Optional<MatchGame> savedEntity = matchGameService.findByGameId(gameId);
MatchGame matchGame;
if (savedEntity != null && savedEntity.isPresent()) {
matchGame = savedEntity.get();
} else {
MatchRecord vo = lolSearchAdapter.searchMatch(gameId);
matchGame = matchGameService.save(vo);
matchUserService.saveAll(vo.info().participants(), matchGame);
}
MatchGameResponse response = MatchGameResponse.toResponse(matchGame);
return response;
}
BoardService에 위와 같이 전적을 검색하는 코드를 작성하고
@Test
@DisplayName("이미 저장된 게임이 있을 때 lolSearchAdapter를 통해서 검색하지 않는다")
void searchAlreadySavedGame() {
// given
MatchRecord vo = MatchDummy.create();
MatchGame game = matchGameService.save(vo);
boardService = new BoardService(matchGameService, matchUserService, mockLolSearch);
List<ParticipantRecord> participantVO = vo.info().participants();
matchUserService.saveAll(participantVO, game);
// when
boardService.searchMatch(game.getGameId());
// then
verify(mockLolSearch, never()).searchMatch(anyString());
}
다음과 같이 중복 검사 테스트도 작성하고 실제 API 호출을 해보다가 Bug가 터졌다.
2024-03-19T23:25:40.020Z ERROR 835114 --- [nio-8080-exec-5] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry 'KR_6862565824' for key 'MATCH_GAME.gameId'
????? 분명히 중복 검사 해주고 있는데????????
원인은 BoardService의
Optional<MatchGame> savedEntity = matchGameService.findByGameId(gameId);
이 코드에 있었다. BoardApiController에서 "KR_" 문구를 추가해주는 것이 아니기 때문에 유저는 게임에서 복사한 "KR_"이 빠진 코드를 그대로 넣게 되고 "KR_"이 빠진 gameId로 데이터베이스에서 정보를 찾는다. 하지만 이에 해당하는 정보는 없고 LolSearchAdapter로 넘어가서 "KR_"을 붙인 후 데이터베이스에서 그 정보를 그대로 저장하다가 먼저 전적을 검색해서 저장된 정보가 있으면 에러가 발생하게 되는 것이다.
이 코드를 수정하면서 제일 먼저 들었던 생각이 '아... 통합 테스트를 했더라면' 이었다.