From d7f5560d7a1b7223484d1ecc81c014b267213225 Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Sat, 29 Jul 2023 15:43:17 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20ManiaDB=20API=20=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EC=97=AC=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=EB=90=98=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EB=85=B8=EB=9E=98=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - webclient 사용 --- backend/build.gradle | 9 + .../application/ManiaDBSearchService.java | 70 ++++ .../dto/UnregisteredSongSearchResponse.java | 45 ++ .../dto/maniadb/ManiaDBAPISearchResponse.java | 13 + .../dto/maniadb/SongAlbumResponse.java | 13 + .../dto/maniadb/SongArtistResponse.java | 13 + .../dto/maniadb/SongTrackArtistsResponse.java | 14 + .../dto/maniadb/UnregisteredSongResponse.java | 19 + .../maniadb/UnregisteredSongResponses.java | 14 + .../song/config/ManiaDBConfiguration.java | 30 ++ .../exception/UnregisteredSongException.java | 25 ++ .../shook/song/ui/ManiaDBApiController.java | 29 ++ .../application/ManiaDBSearchServiceTest.java | 396 ++++++++++++++++++ .../song/ui/ManiaDBApiControllerTest.java | 58 +++ 14 files changed, 748 insertions(+) create mode 100644 backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java create mode 100644 backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java create mode 100644 backend/src/main/java/shook/shook/song/application/dto/maniadb/ManiaDBAPISearchResponse.java create mode 100644 backend/src/main/java/shook/shook/song/application/dto/maniadb/SongAlbumResponse.java create mode 100644 backend/src/main/java/shook/shook/song/application/dto/maniadb/SongArtistResponse.java create mode 100644 backend/src/main/java/shook/shook/song/application/dto/maniadb/SongTrackArtistsResponse.java create mode 100644 backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponse.java create mode 100644 backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponses.java create mode 100644 backend/src/main/java/shook/shook/song/config/ManiaDBConfiguration.java create mode 100644 backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java create mode 100644 backend/src/main/java/shook/shook/song/ui/ManiaDBApiController.java create mode 100644 backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java create mode 100644 backend/src/test/java/shook/shook/song/ui/ManiaDBApiControllerTest.java diff --git a/backend/build.gradle b/backend/build.gradle index e5276e151..e10171f6b 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -27,6 +27,12 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' + // WebClient Dependency + implementation 'org.springframework.boot:spring-boot-starter-webflux' + + // XML parsing Dependency + implementation 'org.glassfish.jaxb:jaxb-runtime' + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' @@ -36,6 +42,9 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' + + // WebClient Test Dependencies + testImplementation 'com.squareup.okhttp3:mockwebserver' } tasks.named('test') { diff --git a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java new file mode 100644 index 000000000..5eaf83a58 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java @@ -0,0 +1,70 @@ +package shook.shook.song.application; + +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; +import shook.shook.song.application.dto.UnregisteredSongSearchResponse; +import shook.shook.song.application.dto.maniadb.ManiaDBAPISearchResponse; +import shook.shook.song.application.dto.maniadb.UnregisteredSongResponses; +import shook.shook.song.exception.UnregisteredSongException; +import shook.shook.song.exception.UnregisteredSongException.EmptyResultException; + +@RequiredArgsConstructor +@Service +public class ManiaDBSearchService { + + private static final String MANIA_DB_API_URI = "/%s/?sr=song&display=%d&key=example&v=0.5"; + private static final int SEARCH_SIZE = 100; + private static final String SPECIAL_MARK_REGEX = "[^ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z0-9,. ]"; + private final WebClient webClient; + + public List searchSongs(final String searchWord) { + final String parsedSearchWord = replaceSpecialMark(searchWord); + final UnregisteredSongResponses searchResult = getSearchResult(parsedSearchWord); + + if (Objects.isNull(searchResult.getSongs())) { + return Collections.emptyList(); + } + + return searchResult.getSongs().stream() + .map(UnregisteredSongSearchResponse::from) + .toList(); + } + + private String replaceSpecialMark(final String rawSearchWord) { + return rawSearchWord.replaceAll(SPECIAL_MARK_REGEX, ""); + } + + private UnregisteredSongResponses getSearchResult(final String searchWord) { + final String searchUrl = String.format(MANIA_DB_API_URI, searchWord, SEARCH_SIZE); + final ManiaDBAPISearchResponse result = getResultFromManiaDB(searchUrl); + + if (Objects.isNull(result)) { + throw new EmptyResultException(); + } + + return result.getSongs(); + } + + private ManiaDBAPISearchResponse getResultFromManiaDB(final String searchUrl) { + return webClient.get() + .uri(searchUrl) + .accept(MediaType.TEXT_XML) + .acceptCharset(StandardCharsets.UTF_8) + .retrieve() + .onStatus(HttpStatusCode::is4xxClientError, (clientResponse) -> { + throw new UnregisteredSongException.ManiaDBClientException(); + }) + .onStatus(HttpStatusCode::is5xxServerError, (clientResponse) -> { + throw new UnregisteredSongException.ManiaDBServerException(); + }) + .bodyToMono(ManiaDBAPISearchResponse.class) + .block(); + } +} diff --git a/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java b/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java new file mode 100644 index 000000000..e3d0c332c --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java @@ -0,0 +1,45 @@ +package shook.shook.song.application.dto; + +import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import lombok.Getter; +import shook.shook.song.application.dto.maniadb.SongArtistResponse; + +@AllArgsConstructor +@Getter +public class UnregisteredSongSearchResponse { + + private static final String EMPTY_SINGER = ""; + private static final String SINGER_DELIMITER = ", "; + private String title; + private String singer; + private String albumImageUrl; + + public static UnregisteredSongSearchResponse from( + final shook.shook.song.application.dto.maniadb.UnregisteredSongResponse unregisteredSongResponse) { + if (unregisteredSongResponse.getTrackArtists() == null + || unregisteredSongResponse.getTrackArtists().getArtists() == null) { + return new UnregisteredSongSearchResponse( + unregisteredSongResponse.getTitle().trim(), + EMPTY_SINGER, + unregisteredSongResponse.getAlbum().getImage().trim() + ); + } + + final String singers = collectToString(unregisteredSongResponse); + + return new UnregisteredSongSearchResponse( + unregisteredSongResponse.getTitle().trim(), + singers, + unregisteredSongResponse.getAlbum().getImage().trim() + ); + } + + private static String collectToString( + final shook.shook.song.application.dto.maniadb.UnregisteredSongResponse unregisteredSongResponse) { + return unregisteredSongResponse.getTrackArtists().getArtists().stream() + .map(SongArtistResponse::getName) + .map(String::trim) + .collect(Collectors.joining(SINGER_DELIMITER)); + } +} diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/ManiaDBAPISearchResponse.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/ManiaDBAPISearchResponse.java new file mode 100644 index 000000000..558c3d01e --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/ManiaDBAPISearchResponse.java @@ -0,0 +1,13 @@ +package shook.shook.song.application.dto.maniadb; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import lombok.Getter; + +@Getter +@XmlRootElement(name = "rss") +public class ManiaDBAPISearchResponse { + + @XmlElement(name = "channel") + private UnregisteredSongResponses songs; +} diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongAlbumResponse.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongAlbumResponse.java new file mode 100644 index 000000000..f80728210 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongAlbumResponse.java @@ -0,0 +1,13 @@ +package shook.shook.song.application.dto.maniadb; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import lombok.Getter; + +@Getter +@XmlRootElement(name = "album", namespace = "http://www.maniadb.com/api") +public class SongAlbumResponse { + + @XmlElement(name = "image") + private String image; +} diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongArtistResponse.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongArtistResponse.java new file mode 100644 index 000000000..969fe44a8 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongArtistResponse.java @@ -0,0 +1,13 @@ +package shook.shook.song.application.dto.maniadb; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import lombok.Getter; + +@Getter +@XmlRootElement(name = "artist", namespace = "http://www.maniadb.com/api") +public class SongArtistResponse { + + @XmlElement(name = "name") + private String name; +} diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongTrackArtistsResponse.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongTrackArtistsResponse.java new file mode 100644 index 000000000..34b420a26 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SongTrackArtistsResponse.java @@ -0,0 +1,14 @@ +package shook.shook.song.application.dto.maniadb; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import java.util.List; +import lombok.Getter; + +@Getter +@XmlRootElement(name = "trackartists", namespace = "http://www.maniadb.com/api") +public class SongTrackArtistsResponse { + + @XmlElement(name = "artist", namespace = "http://www.maniadb.com/api") + private List artists; +} diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponse.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponse.java new file mode 100644 index 000000000..e19d44144 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponse.java @@ -0,0 +1,19 @@ +package shook.shook.song.application.dto.maniadb; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import lombok.Getter; + +@Getter +@XmlRootElement(name = "item") +public class UnregisteredSongResponse { + + @XmlElement(name = "title") + private String title; + + @XmlElement(name = "trackartists", namespace = "http://www.maniadb.com/api") + private SongTrackArtistsResponse trackArtists; + + @XmlElement(name = "album", namespace = "http://www.maniadb.com/api") + private SongAlbumResponse album; +} diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponses.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponses.java new file mode 100644 index 000000000..36144593d --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponses.java @@ -0,0 +1,14 @@ +package shook.shook.song.application.dto.maniadb; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import java.util.List; +import lombok.Getter; + +@Getter +@XmlRootElement(name = "channel") +public class UnregisteredSongResponses { + + @XmlElement(name = "item") + private List songs; +} diff --git a/backend/src/main/java/shook/shook/song/config/ManiaDBConfiguration.java b/backend/src/main/java/shook/shook/song/config/ManiaDBConfiguration.java new file mode 100644 index 000000000..300cb9fd2 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/config/ManiaDBConfiguration.java @@ -0,0 +1,30 @@ +package shook.shook.song.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.codec.xml.Jaxb2XmlDecoder; +import org.springframework.web.reactive.function.client.ExchangeStrategies; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class ManiaDBConfiguration { + + private static final String MANIA_DB_BASE_URL = "http://www.maniadb.com/api/search"; + + @Bean + public WebClient getWebClient() { + return WebClient.builder() + .baseUrl(MANIA_DB_BASE_URL) + .exchangeStrategies( + ExchangeStrategies.builder() + .codecs(configurer -> + configurer.defaultCodecs().jaxb2Decoder(new Jaxb2XmlDecoder()) + ) + .codecs(configurer -> + configurer.defaultCodecs().maxInMemorySize(4 * 1024 * 1024) + ) + .build() + ) + .build(); + } +} diff --git a/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java b/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java new file mode 100644 index 000000000..743e8a330 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java @@ -0,0 +1,25 @@ +package shook.shook.song.exception; + +public class UnregisteredSongException extends RuntimeException { + + public static class EmptyResultException extends UnregisteredSongException { + + public EmptyResultException() { + super(); + } + } + + public static class ManiaDBServerException extends UnregisteredSongException { + + public ManiaDBServerException() { + super(); + } + } + + public static class ManiaDBClientException extends UnregisteredSongException { + + public ManiaDBClientException() { + super(); + } + } +} diff --git a/backend/src/main/java/shook/shook/song/ui/ManiaDBApiController.java b/backend/src/main/java/shook/shook/song/ui/ManiaDBApiController.java new file mode 100644 index 000000000..5b1dc6894 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/ui/ManiaDBApiController.java @@ -0,0 +1,29 @@ +package shook.shook.song.ui; + +import java.util.List; +import lombok.RequiredArgsConstructor; +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 shook.shook.song.application.ManiaDBSearchService; +import shook.shook.song.application.dto.UnregisteredSongSearchResponse; + +@RequiredArgsConstructor +@RequestMapping("/songs/unregistered/search") +@RestController +public class ManiaDBApiController { + + private final ManiaDBSearchService maniaDBSearchService; + + @GetMapping + public ResponseEntity> searchUnregisteredSong( + final @RequestParam("keyword") String searchWord + ) { + final List songs = maniaDBSearchService.searchSongs( + searchWord); + + return ResponseEntity.ok(songs); + } +} diff --git a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java new file mode 100644 index 000000000..29d231d49 --- /dev/null +++ b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java @@ -0,0 +1,396 @@ +package shook.shook.song.application; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.codec.xml.Jaxb2XmlDecoder; +import org.springframework.web.reactive.function.client.ExchangeStrategies; +import org.springframework.web.reactive.function.client.WebClient; +import shook.shook.song.application.dto.UnregisteredSongSearchResponse; +import shook.shook.song.exception.UnregisteredSongException; +import shook.shook.song.exception.UnregisteredSongException.EmptyResultException; + +@ExtendWith(MockitoExtension.class) +class ManiaDBSearchServiceTest { + + private static final String SEARCH_WORD = "흔들리는꽃속에서네샴푸향이느껴진거야"; + private static final String SPECIAL_MARK_SEARCH_WORD = "\b흔%들리는꽃*들속@에서네샴/푸향이+느껴진-거야!\t"; + private static final String SEARCH_RESULT = """ + + + + + <![CDATA[Maniadb Open API v0.5 : Search song for "흔들리는꽃속에서네샴푸향이느껴진거야"]]> + + www.maniadb.com + + + + Fri, 28 Jul 2023 12:03:53 +0900 + 1 + 1 + 100 + + + + + + <![CDATA[흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야]]> + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[멜로가 체질 by 김태성 [ost] (2019)]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """; + + private static final String EMPTY_RESULT_SEARCH_WORD = "빈값검색"; + private static final String EMPTY_RESULT = """ + + + + + <![CDATA[Maniadb Open API v0.5 : Search song for "빈값검색"]]> + + www.maniadb.com + + + + Fri, 28 Jul 2023 17:37:01 +0900 + 0 + 1 + 100 + + + + + + """; + + private static final String EMPTY_SINGER_SEARCH_RESULT = """ + + + + + <![CDATA[Maniadb Open API v0.5 : Search song for "흔들리는꽃속에서네샴푸향이느껴진거야"]]> + + www.maniadb.com + + + + Fri, 28 Jul 2023 12:03:53 +0900 + 1 + 1 + 100 + + + + + + <![CDATA[흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야]]> + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[멜로가 체질 by 김태성 [ost] (2019)]]> + + + + + + + + + + + + + + + + + + + + + + + """; + + private static final String EMPTY_STRING = ""; + + private MockWebServer mockServer; + private ManiaDBSearchService maniaDBSearchService; + + @BeforeEach + void startServer() { + mockServer = new MockWebServer(); + maniaDBSearchService = new ManiaDBSearchService( + WebClient.builder() + .baseUrl(mockServer.url("/") + .toString()) + .exchangeStrategies( + ExchangeStrategies.builder() + .codecs(configurer -> + configurer.defaultCodecs().jaxb2Decoder(new Jaxb2XmlDecoder()) + ) + .codecs(configurer -> + configurer.defaultCodecs().maxInMemorySize(4 * 1024 * 1024) + ) + .build() + ) + .build() + ); + } + + @AfterEach + void tearDown() throws IOException { + mockServer.shutdown(); + } + + @DisplayName("검색 요청을 보내면 XML 응답을 정상적으로 받고, 파싱한 데이터를 응답한다.") + @Test + void search() { + // given + mockServer.enqueue(new MockResponse() + .setResponseCode(HttpStatus.OK.value()) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML) + .addHeader(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8) + .setBody(SEARCH_RESULT) + ); + + final UnregisteredSongSearchResponse expectedResponse = new UnregisteredSongSearchResponse( + "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", + "장범준", + "http://i.maniadb.com/images/album/777/777829_1_f.jpg" + ); + + // when + final List responses = + maniaDBSearchService.searchSongs(SEARCH_WORD); + + // then + assertAll( + () -> assertThat(responses).hasSize(1), + () -> assertThat(responses.get(0)).usingRecursiveComparison() + .isEqualTo(expectedResponse) + ); + } + + @DisplayName("특수문자가 포함된 검색 단어가 입력된 경우, 특수문자를 제거하고 검색한다.") + @Test + void searchBySpecialMarkSearchWord() { + // given + mockServer.enqueue(new MockResponse() + .setResponseCode(HttpStatus.OK.value()) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML) + .addHeader(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8) + .setBody(SEARCH_RESULT) + ); + + final UnregisteredSongSearchResponse expectedResponse = new UnregisteredSongSearchResponse( + "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", + "장범준", + "http://i.maniadb.com/images/album/777/777829_1_f.jpg" + ); + + // when + final List responses = + maniaDBSearchService.searchSongs(SPECIAL_MARK_SEARCH_WORD); + + // then + assertAll( + () -> assertThat(responses).hasSize(1), + () -> assertThat(responses.get(0)).usingRecursiveComparison() + .isEqualTo(expectedResponse) + ); + } + + @DisplayName("XML 응답에 노래가 존재하지 않으면 빈 리스트를 리턴한다.") + @Test + void searchResultReturnEmptyList() { + // given + mockServer.enqueue(new MockResponse() + .setResponseCode(HttpStatus.OK.value()) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML) + .addHeader(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8) + .setBody(EMPTY_RESULT) + ); + + // when + final List responses = + maniaDBSearchService.searchSongs(EMPTY_RESULT_SEARCH_WORD); + + // then + assertThat(responses).isEmpty(); + } + + @DisplayName("XML 응답에 가수가 없으면 가수의 값으로 빈 문자열을 리턴한다.") + @Test + void searchResultReturnEmptySinger() { + // given + mockServer.enqueue(new MockResponse() + .setResponseCode(HttpStatus.OK.value()) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML) + .addHeader(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8) + .setBody(EMPTY_SINGER_SEARCH_RESULT) + ); + + final UnregisteredSongSearchResponse expectedResponse = new UnregisteredSongSearchResponse( + "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", + "", + "http://i.maniadb.com/images/album/777/777829_1_f.jpg" + ); + + // when + final List responses = + maniaDBSearchService.searchSongs(SEARCH_WORD); + + // then + assertAll( + () -> assertThat(responses).hasSize(1), + () -> assertThat(responses.get(0)).usingRecursiveComparison() + .isEqualTo(expectedResponse) + ); + } + + @DisplayName("XML 응답을 파싱한 결과값이 null 이면 예외가 발생한다.") + @Test + void nullResultThrowException() { + // given + mockServer.enqueue(new MockResponse() + .setResponseCode(HttpStatus.OK.value()) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML) + .addHeader(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8) + .setBody(EMPTY_STRING) + ); + + // when + // then + assertThatThrownBy(() -> maniaDBSearchService.searchSongs(SEARCH_WORD)) + .isInstanceOf(EmptyResultException.class); + } + + @DisplayName("ManiaDB로 보내는 요청이 잘못된 경우, 예외가 발생한다.") + @Test + void wrongRequestThrowException() { + // given + mockServer.enqueue(new MockResponse() + .setResponseCode(HttpStatus.BAD_REQUEST.value()) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML) + .addHeader(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8) + ); + + // when + // then + assertThatThrownBy(() -> maniaDBSearchService.searchSongs(SEARCH_WORD)) + .isInstanceOf(UnregisteredSongException.ManiaDBClientException.class); + } + + @DisplayName("ManiaDB API 서버에서 예외가 발생한 경우, 예외가 발생한다.") + @Test + void maniaDBServerExceptionThrowException() { + // given + mockServer.enqueue(new MockResponse() + .setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML) + .addHeader(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8) + ); + + // when + // then + assertThatThrownBy(() -> maniaDBSearchService.searchSongs(SEARCH_WORD)) + .isInstanceOf(UnregisteredSongException.ManiaDBServerException.class); + } +} diff --git a/backend/src/test/java/shook/shook/song/ui/ManiaDBApiControllerTest.java b/backend/src/test/java/shook/shook/song/ui/ManiaDBApiControllerTest.java new file mode 100644 index 000000000..199e7e555 --- /dev/null +++ b/backend/src/test/java/shook/shook/song/ui/ManiaDBApiControllerTest.java @@ -0,0 +1,58 @@ +package shook.shook.song.ui; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import io.restassured.RestAssured; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import shook.shook.song.application.dto.UnregisteredSongSearchResponse; + +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +class ManiaDBApiControllerTest { + + @LocalServerPort + public int port; + + @BeforeEach + void setUp() { + RestAssured.port = port; + } + + @DisplayName("내부 DB에 등록되지 않은 노래를 검색할 때 200 상태코드, 노래의 이름과 가수, 앨범 커버를 담은 응답을 반환한다.") + @Test + void registerPart_unique() { + //given + final String keyword = "흔들리는꽃들속에서네샴푸향이느껴진거야"; + final UnregisteredSongSearchResponse expectedFirstResponse = new UnregisteredSongSearchResponse( + "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", + "피아노 가이", + "http://i.maniadb.com/images/album/908/908953_1_f.jpg" + ); + + //when + final UnregisteredSongSearchResponse[] songResponses = RestAssured.given().log().all() + .when().log().all() + .get("/songs/unregistered/search?keyword=" + keyword) + .then().log().all() + .statusCode(HttpStatus.OK.value()) + .extract().body().as(UnregisteredSongSearchResponse[].class); + + final List responses = Arrays.stream( + songResponses).toList(); + + //then + assertAll( + () -> assertThat(responses).hasSize(19), + () -> assertThat(responses.get(0)).usingRecursiveComparison() + .isEqualTo(expectedFirstResponse) + ); + } +} From ee3e38bb4e16e34d9b88e312ca2ec2e616f67d27 Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:52:26 +0900 Subject: [PATCH 02/12] =?UTF-8?q?refactor:=20=EC=BB=A4=EC=8A=A4=ED=85=80?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ManiaDB 관련 예외를 ExternalApiException 으로 분리 --- .../song/application/ManiaDBSearchService.java | 6 +++--- .../song/exception/ExternalApiException.java | 18 ++++++++++++++++++ .../exception/UnregisteredSongException.java | 14 -------------- .../application/ManiaDBSearchServiceTest.java | 6 +++--- 4 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 backend/src/main/java/shook/shook/song/exception/ExternalApiException.java diff --git a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java index 5eaf83a58..6f4b09e2e 100644 --- a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java +++ b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java @@ -12,7 +12,7 @@ import shook.shook.song.application.dto.UnregisteredSongSearchResponse; import shook.shook.song.application.dto.maniadb.ManiaDBAPISearchResponse; import shook.shook.song.application.dto.maniadb.UnregisteredSongResponses; -import shook.shook.song.exception.UnregisteredSongException; +import shook.shook.song.exception.ExternalApiException; import shook.shook.song.exception.UnregisteredSongException.EmptyResultException; @RequiredArgsConstructor @@ -59,10 +59,10 @@ private ManiaDBAPISearchResponse getResultFromManiaDB(final String searchUrl) { .acceptCharset(StandardCharsets.UTF_8) .retrieve() .onStatus(HttpStatusCode::is4xxClientError, (clientResponse) -> { - throw new UnregisteredSongException.ManiaDBClientException(); + throw new ExternalApiException.ManiaDBClientException(); }) .onStatus(HttpStatusCode::is5xxServerError, (clientResponse) -> { - throw new UnregisteredSongException.ManiaDBServerException(); + throw new ExternalApiException.ManiaDBServerException(); }) .bodyToMono(ManiaDBAPISearchResponse.class) .block(); diff --git a/backend/src/main/java/shook/shook/song/exception/ExternalApiException.java b/backend/src/main/java/shook/shook/song/exception/ExternalApiException.java new file mode 100644 index 000000000..cf97bccb2 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/exception/ExternalApiException.java @@ -0,0 +1,18 @@ +package shook.shook.song.exception; + +public class ExternalApiException extends RuntimeException { + + public static class ManiaDBServerException extends ExternalApiException { + + public ManiaDBServerException() { + super(); + } + } + + public static class ManiaDBClientException extends ExternalApiException { + + public ManiaDBClientException() { + super(); + } + } +} diff --git a/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java b/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java index 743e8a330..4793ae4c8 100644 --- a/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java +++ b/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java @@ -8,18 +8,4 @@ public EmptyResultException() { super(); } } - - public static class ManiaDBServerException extends UnregisteredSongException { - - public ManiaDBServerException() { - super(); - } - } - - public static class ManiaDBClientException extends UnregisteredSongException { - - public ManiaDBClientException() { - super(); - } - } } diff --git a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java index 29d231d49..39c393b6a 100644 --- a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java +++ b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java @@ -22,7 +22,7 @@ import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; import shook.shook.song.application.dto.UnregisteredSongSearchResponse; -import shook.shook.song.exception.UnregisteredSongException; +import shook.shook.song.exception.ExternalApiException; import shook.shook.song.exception.UnregisteredSongException.EmptyResultException; @ExtendWith(MockitoExtension.class) @@ -375,7 +375,7 @@ void wrongRequestThrowException() { // when // then assertThatThrownBy(() -> maniaDBSearchService.searchSongs(SEARCH_WORD)) - .isInstanceOf(UnregisteredSongException.ManiaDBClientException.class); + .isInstanceOf(ExternalApiException.ManiaDBClientException.class); } @DisplayName("ManiaDB API 서버에서 예외가 발생한 경우, 예외가 발생한다.") @@ -391,6 +391,6 @@ void maniaDBServerExceptionThrowException() { // when // then assertThatThrownBy(() -> maniaDBSearchService.searchSongs(SEARCH_WORD)) - .isInstanceOf(UnregisteredSongException.ManiaDBServerException.class); + .isInstanceOf(ExternalApiException.ManiaDBServerException.class); } } From 53443bddf6cc4196c9931ccbdfcd87ab2039c16a Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:59:22 +0900 Subject: [PATCH 03/12] =?UTF-8?q?chore:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ApiController.java => UnregisteredSongSearchController.java} | 2 +- ...ollerTest.java => UnregisteredSongSearchControllerTest.java} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename backend/src/main/java/shook/shook/song/ui/{ManiaDBApiController.java => UnregisteredSongSearchController.java} (95%) rename backend/src/test/java/shook/shook/song/ui/{ManiaDBApiControllerTest.java => UnregisteredSongSearchControllerTest.java} (97%) diff --git a/backend/src/main/java/shook/shook/song/ui/ManiaDBApiController.java b/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java similarity index 95% rename from backend/src/main/java/shook/shook/song/ui/ManiaDBApiController.java rename to backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java index 5b1dc6894..9a815b912 100644 --- a/backend/src/main/java/shook/shook/song/ui/ManiaDBApiController.java +++ b/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java @@ -13,7 +13,7 @@ @RequiredArgsConstructor @RequestMapping("/songs/unregistered/search") @RestController -public class ManiaDBApiController { +public class UnregisteredSongSearchController { private final ManiaDBSearchService maniaDBSearchService; diff --git a/backend/src/test/java/shook/shook/song/ui/ManiaDBApiControllerTest.java b/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java similarity index 97% rename from backend/src/test/java/shook/shook/song/ui/ManiaDBApiControllerTest.java rename to backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java index 199e7e555..4301f0519 100644 --- a/backend/src/test/java/shook/shook/song/ui/ManiaDBApiControllerTest.java +++ b/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java @@ -16,7 +16,7 @@ import shook.shook.song.application.dto.UnregisteredSongSearchResponse; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -class ManiaDBApiControllerTest { +class UnregisteredSongSearchControllerTest { @LocalServerPort public int port; From 6a7bf4e952739925154b35919614ffdc483ab24f Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Mon, 31 Jul 2023 22:47:10 +0900 Subject: [PATCH 04/12] =?UTF-8?q?config:=20prod=20group=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/main/resources/application.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 9bc54f71d..97ee468e9 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -1,4 +1,7 @@ spring: + profiles: + group: + prod: oauth, jwt config: import: classpath:shook-security/application.yml From 89fd82836f1726404f8944c332aed91779349921 Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Mon, 31 Jul 2023 22:48:29 +0900 Subject: [PATCH 05/12] =?UTF-8?q?refactor:=20UnregisteredSongException=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - EmptyResultException 클래스를 ExternalApiException 클래스 내부로 이동 --- .../shook/song/application/ManiaDBSearchService.java | 3 +-- .../shook/song/exception/ExternalApiException.java | 7 +++++++ .../song/exception/UnregisteredSongException.java | 11 ----------- .../song/application/ManiaDBSearchServiceTest.java | 2 +- 4 files changed, 9 insertions(+), 14 deletions(-) delete mode 100644 backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java diff --git a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java index 6f4b09e2e..1d82c14f1 100644 --- a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java +++ b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java @@ -13,7 +13,6 @@ import shook.shook.song.application.dto.maniadb.ManiaDBAPISearchResponse; import shook.shook.song.application.dto.maniadb.UnregisteredSongResponses; import shook.shook.song.exception.ExternalApiException; -import shook.shook.song.exception.UnregisteredSongException.EmptyResultException; @RequiredArgsConstructor @Service @@ -46,7 +45,7 @@ private UnregisteredSongResponses getSearchResult(final String searchWord) { final ManiaDBAPISearchResponse result = getResultFromManiaDB(searchUrl); if (Objects.isNull(result)) { - throw new EmptyResultException(); + throw new ExternalApiException.EmptyResultException(); } return result.getSongs(); diff --git a/backend/src/main/java/shook/shook/song/exception/ExternalApiException.java b/backend/src/main/java/shook/shook/song/exception/ExternalApiException.java index cf97bccb2..203059da5 100644 --- a/backend/src/main/java/shook/shook/song/exception/ExternalApiException.java +++ b/backend/src/main/java/shook/shook/song/exception/ExternalApiException.java @@ -2,6 +2,13 @@ public class ExternalApiException extends RuntimeException { + public static class EmptyResultException extends ExternalApiException { + + public EmptyResultException() { + super(); + } + } + public static class ManiaDBServerException extends ExternalApiException { public ManiaDBServerException() { diff --git a/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java b/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java deleted file mode 100644 index 4793ae4c8..000000000 --- a/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java +++ /dev/null @@ -1,11 +0,0 @@ -package shook.shook.song.exception; - -public class UnregisteredSongException extends RuntimeException { - - public static class EmptyResultException extends UnregisteredSongException { - - public EmptyResultException() { - super(); - } - } -} diff --git a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java index 39c393b6a..2946e693a 100644 --- a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java +++ b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java @@ -23,7 +23,7 @@ import org.springframework.web.reactive.function.client.WebClient; import shook.shook.song.application.dto.UnregisteredSongSearchResponse; import shook.shook.song.exception.ExternalApiException; -import shook.shook.song.exception.UnregisteredSongException.EmptyResultException; +import shook.shook.song.exception.ExternalApiException.EmptyResultException; @ExtendWith(MockitoExtension.class) class ManiaDBSearchServiceTest { From 238346817fa59f92c494edaae6ab217a58cfd811 Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Mon, 31 Jul 2023 23:13:21 +0900 Subject: [PATCH 06/12] =?UTF-8?q?feat:=20=EA=B2=80=EC=83=89=EC=96=B4?= =?UTF-8?q?=EA=B0=80=20=EB=B9=88=20=EB=AC=B8=EC=9E=90=EC=97=B4=EC=9D=B4?= =?UTF-8?q?=EB=82=98=20null=20=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../song/application/ManiaDBSearchService.java | 10 ++++++++++ .../song/exception/UnregisteredSongException.java | 12 ++++++++++++ .../song/application/ManiaDBSearchServiceTest.java | 14 ++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java diff --git a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java index 1d82c14f1..b19ab7af2 100644 --- a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java +++ b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java @@ -13,6 +13,8 @@ import shook.shook.song.application.dto.maniadb.ManiaDBAPISearchResponse; import shook.shook.song.application.dto.maniadb.UnregisteredSongResponses; import shook.shook.song.exception.ExternalApiException; +import shook.shook.song.exception.UnregisteredSongException; +import shook.shook.util.StringChecker; @RequiredArgsConstructor @Service @@ -24,6 +26,8 @@ public class ManiaDBSearchService { private final WebClient webClient; public List searchSongs(final String searchWord) { + validateSearchWord(searchWord); + final String parsedSearchWord = replaceSpecialMark(searchWord); final UnregisteredSongResponses searchResult = getSearchResult(parsedSearchWord); @@ -36,6 +40,12 @@ public List searchSongs(final String searchWord) .toList(); } + private void validateSearchWord(final String searchWord) { + if (StringChecker.isNullOrBlank(searchWord)) { + throw new UnregisteredSongException.NullOrBlankSearchWordException(); + } + } + private String replaceSpecialMark(final String rawSearchWord) { return rawSearchWord.replaceAll(SPECIAL_MARK_REGEX, ""); } diff --git a/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java b/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java new file mode 100644 index 000000000..2e83be56d --- /dev/null +++ b/backend/src/main/java/shook/shook/song/exception/UnregisteredSongException.java @@ -0,0 +1,12 @@ +package shook.shook.song.exception; + +public class UnregisteredSongException extends RuntimeException { + + public static class NullOrBlankSearchWordException extends UnregisteredSongException { + + public NullOrBlankSearchWordException() { + super(); + } + } + +} diff --git a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java index 2946e693a..986ffce62 100644 --- a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java +++ b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java @@ -14,6 +14,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -24,6 +26,7 @@ import shook.shook.song.application.dto.UnregisteredSongSearchResponse; import shook.shook.song.exception.ExternalApiException; import shook.shook.song.exception.ExternalApiException.EmptyResultException; +import shook.shook.song.exception.UnregisteredSongException; @ExtendWith(MockitoExtension.class) class ManiaDBSearchServiceTest { @@ -268,6 +271,17 @@ void search() { ); } + @DisplayName("검색 단어가 null 이거나 빈 문자열인 경우, 예외가 발생한다.") + @NullAndEmptySource + @ParameterizedTest(name = "검색 단어가 \"{0}\" 인 경우") + void nullOrBlankSearchWord(final String searchWord) { + // given + // when + // then + assertThatThrownBy(() -> maniaDBSearchService.searchSongs(searchWord)) + .isInstanceOf(UnregisteredSongException.NullOrBlankSearchWordException.class); + } + @DisplayName("특수문자가 포함된 검색 단어가 입력된 경우, 특수문자를 제거하고 검색한다.") @Test void searchBySpecialMarkSearchWord() { From 0577695f2b72bb555101f60b3a44b122cadcd154 Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Mon, 31 Jul 2023 23:14:17 +0900 Subject: [PATCH 07/12] =?UTF-8?q?style:=20=EA=B0=9C=ED=96=89=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 --- .../java/shook/shook/song/application/ManiaDBSearchService.java | 1 + .../song/application/dto/UnregisteredSongSearchResponse.java | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java index b19ab7af2..1c22d3d70 100644 --- a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java +++ b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java @@ -23,6 +23,7 @@ public class ManiaDBSearchService { private static final String MANIA_DB_API_URI = "/%s/?sr=song&display=%d&key=example&v=0.5"; private static final int SEARCH_SIZE = 100; private static final String SPECIAL_MARK_REGEX = "[^ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z0-9,. ]"; + private final WebClient webClient; public List searchSongs(final String searchWord) { diff --git a/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java b/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java index e3d0c332c..e0543d720 100644 --- a/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java +++ b/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java @@ -11,6 +11,7 @@ public class UnregisteredSongSearchResponse { private static final String EMPTY_SINGER = ""; private static final String SINGER_DELIMITER = ", "; + private String title; private String singer; private String albumImageUrl; From 237d01e080dfa6efda52fa040ef9939c2c296556 Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Thu, 3 Aug 2023 21:00:02 +0900 Subject: [PATCH 08/12] =?UTF-8?q?feat:=20=EB=B9=88=20=EA=B0=92=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../song/application/ManiaDBSearchServiceTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java index 986ffce62..d6d3f57f0 100644 --- a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java +++ b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -311,6 +312,17 @@ void searchBySpecialMarkSearchWord() { ); } + @DisplayName("검색할 단어로 빈 값이 입력된 경우, 예외가 발생한다.") + @ValueSource(strings = {" ", "\t", "\n", ""}) + @ParameterizedTest(name = "검색 단어가 \"{0}\" 인 경우") + void searchWithBlankWord(final String blankSearchWord) { + // given + // when + // then + assertThatThrownBy(() -> maniaDBSearchService.searchSongs(blankSearchWord)) + .isInstanceOf(UnregisteredSongException.NullOrBlankSearchWordException.class); + } + @DisplayName("XML 응답에 노래가 존재하지 않으면 빈 리스트를 리턴한다.") @Test void searchResultReturnEmptyList() { From 4d2ab0cbad71abd8e8fec276e7bde28c3fe5aafa Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Wed, 9 Aug 2023 10:58:40 +0900 Subject: [PATCH 09/12] =?UTF-8?q?chore:=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../song/application/ManiaDBSearchService.java | 6 +++--- ...a => SearchedSongFromManiaDBApiResponse.java} | 8 ++++---- .../ui/UnregisteredSongSearchController.java | 6 +++--- .../application/ManiaDBSearchServiceTest.java | 16 ++++++++-------- .../ui/UnregisteredSongSearchControllerTest.java | 10 +++++----- 5 files changed, 23 insertions(+), 23 deletions(-) rename backend/src/main/java/shook/shook/song/application/dto/{UnregisteredSongSearchResponse.java => SearchedSongFromManiaDBApiResponse.java} (86%) diff --git a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java index 1c22d3d70..84420adf5 100644 --- a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java +++ b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java @@ -9,7 +9,7 @@ import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; -import shook.shook.song.application.dto.UnregisteredSongSearchResponse; +import shook.shook.song.application.dto.SearchedSongFromManiaDBApiResponse; import shook.shook.song.application.dto.maniadb.ManiaDBAPISearchResponse; import shook.shook.song.application.dto.maniadb.UnregisteredSongResponses; import shook.shook.song.exception.ExternalApiException; @@ -26,7 +26,7 @@ public class ManiaDBSearchService { private final WebClient webClient; - public List searchSongs(final String searchWord) { + public List searchSongs(final String searchWord) { validateSearchWord(searchWord); final String parsedSearchWord = replaceSpecialMark(searchWord); @@ -37,7 +37,7 @@ public List searchSongs(final String searchWord) } return searchResult.getSongs().stream() - .map(UnregisteredSongSearchResponse::from) + .map(SearchedSongFromManiaDBApiResponse::from) .toList(); } diff --git a/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java b/backend/src/main/java/shook/shook/song/application/dto/SearchedSongFromManiaDBApiResponse.java similarity index 86% rename from backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java rename to backend/src/main/java/shook/shook/song/application/dto/SearchedSongFromManiaDBApiResponse.java index e0543d720..0049829c6 100644 --- a/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongSearchResponse.java +++ b/backend/src/main/java/shook/shook/song/application/dto/SearchedSongFromManiaDBApiResponse.java @@ -7,7 +7,7 @@ @AllArgsConstructor @Getter -public class UnregisteredSongSearchResponse { +public class SearchedSongFromManiaDBApiResponse { private static final String EMPTY_SINGER = ""; private static final String SINGER_DELIMITER = ", "; @@ -16,11 +16,11 @@ public class UnregisteredSongSearchResponse { private String singer; private String albumImageUrl; - public static UnregisteredSongSearchResponse from( + public static SearchedSongFromManiaDBApiResponse from( final shook.shook.song.application.dto.maniadb.UnregisteredSongResponse unregisteredSongResponse) { if (unregisteredSongResponse.getTrackArtists() == null || unregisteredSongResponse.getTrackArtists().getArtists() == null) { - return new UnregisteredSongSearchResponse( + return new SearchedSongFromManiaDBApiResponse( unregisteredSongResponse.getTitle().trim(), EMPTY_SINGER, unregisteredSongResponse.getAlbum().getImage().trim() @@ -29,7 +29,7 @@ public static UnregisteredSongSearchResponse from( final String singers = collectToString(unregisteredSongResponse); - return new UnregisteredSongSearchResponse( + return new SearchedSongFromManiaDBApiResponse( unregisteredSongResponse.getTitle().trim(), singers, unregisteredSongResponse.getAlbum().getImage().trim() diff --git a/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java b/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java index 9a815b912..b242176be 100644 --- a/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java +++ b/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java @@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import shook.shook.song.application.ManiaDBSearchService; -import shook.shook.song.application.dto.UnregisteredSongSearchResponse; +import shook.shook.song.application.dto.SearchedSongFromManiaDBApiResponse; @RequiredArgsConstructor @RequestMapping("/songs/unregistered/search") @@ -18,10 +18,10 @@ public class UnregisteredSongSearchController { private final ManiaDBSearchService maniaDBSearchService; @GetMapping - public ResponseEntity> searchUnregisteredSong( + public ResponseEntity> searchUnregisteredSong( final @RequestParam("keyword") String searchWord ) { - final List songs = maniaDBSearchService.searchSongs( + final List songs = maniaDBSearchService.searchSongs( searchWord); return ResponseEntity.ok(songs); diff --git a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java index d6d3f57f0..6cbfdcb53 100644 --- a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java +++ b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java @@ -24,7 +24,7 @@ import org.springframework.http.codec.xml.Jaxb2XmlDecoder; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; -import shook.shook.song.application.dto.UnregisteredSongSearchResponse; +import shook.shook.song.application.dto.SearchedSongFromManiaDBApiResponse; import shook.shook.song.exception.ExternalApiException; import shook.shook.song.exception.ExternalApiException.EmptyResultException; import shook.shook.song.exception.UnregisteredSongException; @@ -254,14 +254,14 @@ void search() { .setBody(SEARCH_RESULT) ); - final UnregisteredSongSearchResponse expectedResponse = new UnregisteredSongSearchResponse( + final SearchedSongFromManiaDBApiResponse expectedResponse = new SearchedSongFromManiaDBApiResponse( "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", "장범준", "http://i.maniadb.com/images/album/777/777829_1_f.jpg" ); // when - final List responses = + final List responses = maniaDBSearchService.searchSongs(SEARCH_WORD); // then @@ -294,14 +294,14 @@ void searchBySpecialMarkSearchWord() { .setBody(SEARCH_RESULT) ); - final UnregisteredSongSearchResponse expectedResponse = new UnregisteredSongSearchResponse( + final SearchedSongFromManiaDBApiResponse expectedResponse = new SearchedSongFromManiaDBApiResponse( "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", "장범준", "http://i.maniadb.com/images/album/777/777829_1_f.jpg" ); // when - final List responses = + final List responses = maniaDBSearchService.searchSongs(SPECIAL_MARK_SEARCH_WORD); // then @@ -335,7 +335,7 @@ void searchResultReturnEmptyList() { ); // when - final List responses = + final List responses = maniaDBSearchService.searchSongs(EMPTY_RESULT_SEARCH_WORD); // then @@ -353,14 +353,14 @@ void searchResultReturnEmptySinger() { .setBody(EMPTY_SINGER_SEARCH_RESULT) ); - final UnregisteredSongSearchResponse expectedResponse = new UnregisteredSongSearchResponse( + final SearchedSongFromManiaDBApiResponse expectedResponse = new SearchedSongFromManiaDBApiResponse( "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", "", "http://i.maniadb.com/images/album/777/777829_1_f.jpg" ); // when - final List responses = + final List responses = maniaDBSearchService.searchSongs(SEARCH_WORD); // then diff --git a/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java b/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java index 4301f0519..0a95df7ce 100644 --- a/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java +++ b/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java @@ -13,7 +13,7 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; -import shook.shook.song.application.dto.UnregisteredSongSearchResponse; +import shook.shook.song.application.dto.SearchedSongFromManiaDBApiResponse; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) class UnregisteredSongSearchControllerTest { @@ -31,21 +31,21 @@ void setUp() { void registerPart_unique() { //given final String keyword = "흔들리는꽃들속에서네샴푸향이느껴진거야"; - final UnregisteredSongSearchResponse expectedFirstResponse = new UnregisteredSongSearchResponse( + final SearchedSongFromManiaDBApiResponse expectedFirstResponse = new SearchedSongFromManiaDBApiResponse( "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", "피아노 가이", "http://i.maniadb.com/images/album/908/908953_1_f.jpg" ); //when - final UnregisteredSongSearchResponse[] songResponses = RestAssured.given().log().all() + final SearchedSongFromManiaDBApiResponse[] songResponses = RestAssured.given().log().all() .when().log().all() .get("/songs/unregistered/search?keyword=" + keyword) .then().log().all() .statusCode(HttpStatus.OK.value()) - .extract().body().as(UnregisteredSongSearchResponse[].class); + .extract().body().as(SearchedSongFromManiaDBApiResponse[].class); - final List responses = Arrays.stream( + final List responses = Arrays.stream( songResponses).toList(); //then From e8eb4152b06f42820ae807d3c1960aaca0e73dd0 Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:00:34 +0900 Subject: [PATCH 10/12] =?UTF-8?q?fix:=20=ED=86=B5=ED=95=A9=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 외부 API 에 직접 의존하는 통합 테스트 삭제 --- .../shook/song/ui/SongControllerTest.java | 6 +- .../UnregisteredSongSearchControllerTest.java | 58 ------------------- 2 files changed, 3 insertions(+), 61 deletions(-) delete mode 100644 backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java diff --git a/backend/src/test/java/shook/shook/song/ui/SongControllerTest.java b/backend/src/test/java/shook/shook/song/ui/SongControllerTest.java index 26e89cb86..595c0458c 100644 --- a/backend/src/test/java/shook/shook/song/ui/SongControllerTest.java +++ b/backend/src/test/java/shook/shook/song/ui/SongControllerTest.java @@ -22,14 +22,14 @@ class SongControllerTest { @LocalServerPort public int port; + @Autowired + private SongRepository songRepository; + @BeforeEach void setUp() { RestAssured.port = port; } - @Autowired - private SongRepository songRepository; - @DisplayName("노래 정보를 조회시 제목, 가수, 길이, URL, 킬링파트를 담은 응답을 반환한다.") @Test void showSongById() { diff --git a/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java b/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java deleted file mode 100644 index 0a95df7ce..000000000 --- a/backend/src/test/java/shook/shook/song/ui/UnregisteredSongSearchControllerTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package shook.shook.song.ui; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; - -import io.restassured.RestAssured; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.http.HttpStatus; -import shook.shook.song.application.dto.SearchedSongFromManiaDBApiResponse; - -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -class UnregisteredSongSearchControllerTest { - - @LocalServerPort - public int port; - - @BeforeEach - void setUp() { - RestAssured.port = port; - } - - @DisplayName("내부 DB에 등록되지 않은 노래를 검색할 때 200 상태코드, 노래의 이름과 가수, 앨범 커버를 담은 응답을 반환한다.") - @Test - void registerPart_unique() { - //given - final String keyword = "흔들리는꽃들속에서네샴푸향이느껴진거야"; - final SearchedSongFromManiaDBApiResponse expectedFirstResponse = new SearchedSongFromManiaDBApiResponse( - "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", - "피아노 가이", - "http://i.maniadb.com/images/album/908/908953_1_f.jpg" - ); - - //when - final SearchedSongFromManiaDBApiResponse[] songResponses = RestAssured.given().log().all() - .when().log().all() - .get("/songs/unregistered/search?keyword=" + keyword) - .then().log().all() - .statusCode(HttpStatus.OK.value()) - .extract().body().as(SearchedSongFromManiaDBApiResponse[].class); - - final List responses = Arrays.stream( - songResponses).toList(); - - //then - assertAll( - () -> assertThat(responses).hasSize(19), - () -> assertThat(responses.get(0)).usingRecursiveComparison() - .isEqualTo(expectedFirstResponse) - ); - } -} From 2c5c53ba6a3afd254ef9fe33bc724c0a6653188f Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:10:06 +0900 Subject: [PATCH 11/12] =?UTF-8?q?chore:=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/ManiaDBSearchService.java | 12 ++--- .../SearchedSongFromManiaDBApiResponse.java | 46 ------------------ .../dto/UnregisteredSongResponse.java | 47 +++++++++++++++++++ .../dto/maniadb/ManiaDBAPISearchResponse.java | 2 +- ...> SearchedSongFromManiaDBApiResponse.java} | 2 +- ... SearchedSongFromManiaDBApiResponses.java} | 4 +- .../ui/UnregisteredSongSearchController.java | 6 +-- .../application/ManiaDBSearchServiceTest.java | 16 +++---- 8 files changed, 68 insertions(+), 67 deletions(-) delete mode 100644 backend/src/main/java/shook/shook/song/application/dto/SearchedSongFromManiaDBApiResponse.java create mode 100644 backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongResponse.java rename backend/src/main/java/shook/shook/song/application/dto/maniadb/{UnregisteredSongResponse.java => SearchedSongFromManiaDBApiResponse.java} (91%) rename backend/src/main/java/shook/shook/song/application/dto/maniadb/{UnregisteredSongResponses.java => SearchedSongFromManiaDBApiResponses.java} (70%) diff --git a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java index 84420adf5..02108ff14 100644 --- a/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java +++ b/backend/src/main/java/shook/shook/song/application/ManiaDBSearchService.java @@ -9,9 +9,9 @@ import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; -import shook.shook.song.application.dto.SearchedSongFromManiaDBApiResponse; +import shook.shook.song.application.dto.UnregisteredSongResponse; import shook.shook.song.application.dto.maniadb.ManiaDBAPISearchResponse; -import shook.shook.song.application.dto.maniadb.UnregisteredSongResponses; +import shook.shook.song.application.dto.maniadb.SearchedSongFromManiaDBApiResponses; import shook.shook.song.exception.ExternalApiException; import shook.shook.song.exception.UnregisteredSongException; import shook.shook.util.StringChecker; @@ -26,18 +26,18 @@ public class ManiaDBSearchService { private final WebClient webClient; - public List searchSongs(final String searchWord) { + public List searchSongs(final String searchWord) { validateSearchWord(searchWord); final String parsedSearchWord = replaceSpecialMark(searchWord); - final UnregisteredSongResponses searchResult = getSearchResult(parsedSearchWord); + final SearchedSongFromManiaDBApiResponses searchResult = getSearchResult(parsedSearchWord); if (Objects.isNull(searchResult.getSongs())) { return Collections.emptyList(); } return searchResult.getSongs().stream() - .map(SearchedSongFromManiaDBApiResponse::from) + .map(UnregisteredSongResponse::from) .toList(); } @@ -51,7 +51,7 @@ private String replaceSpecialMark(final String rawSearchWord) { return rawSearchWord.replaceAll(SPECIAL_MARK_REGEX, ""); } - private UnregisteredSongResponses getSearchResult(final String searchWord) { + private SearchedSongFromManiaDBApiResponses getSearchResult(final String searchWord) { final String searchUrl = String.format(MANIA_DB_API_URI, searchWord, SEARCH_SIZE); final ManiaDBAPISearchResponse result = getResultFromManiaDB(searchUrl); diff --git a/backend/src/main/java/shook/shook/song/application/dto/SearchedSongFromManiaDBApiResponse.java b/backend/src/main/java/shook/shook/song/application/dto/SearchedSongFromManiaDBApiResponse.java deleted file mode 100644 index 0049829c6..000000000 --- a/backend/src/main/java/shook/shook/song/application/dto/SearchedSongFromManiaDBApiResponse.java +++ /dev/null @@ -1,46 +0,0 @@ -package shook.shook.song.application.dto; - -import java.util.stream.Collectors; -import lombok.AllArgsConstructor; -import lombok.Getter; -import shook.shook.song.application.dto.maniadb.SongArtistResponse; - -@AllArgsConstructor -@Getter -public class SearchedSongFromManiaDBApiResponse { - - private static final String EMPTY_SINGER = ""; - private static final String SINGER_DELIMITER = ", "; - - private String title; - private String singer; - private String albumImageUrl; - - public static SearchedSongFromManiaDBApiResponse from( - final shook.shook.song.application.dto.maniadb.UnregisteredSongResponse unregisteredSongResponse) { - if (unregisteredSongResponse.getTrackArtists() == null - || unregisteredSongResponse.getTrackArtists().getArtists() == null) { - return new SearchedSongFromManiaDBApiResponse( - unregisteredSongResponse.getTitle().trim(), - EMPTY_SINGER, - unregisteredSongResponse.getAlbum().getImage().trim() - ); - } - - final String singers = collectToString(unregisteredSongResponse); - - return new SearchedSongFromManiaDBApiResponse( - unregisteredSongResponse.getTitle().trim(), - singers, - unregisteredSongResponse.getAlbum().getImage().trim() - ); - } - - private static String collectToString( - final shook.shook.song.application.dto.maniadb.UnregisteredSongResponse unregisteredSongResponse) { - return unregisteredSongResponse.getTrackArtists().getArtists().stream() - .map(SongArtistResponse::getName) - .map(String::trim) - .collect(Collectors.joining(SINGER_DELIMITER)); - } -} diff --git a/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongResponse.java b/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongResponse.java new file mode 100644 index 000000000..bc3db2944 --- /dev/null +++ b/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongResponse.java @@ -0,0 +1,47 @@ +package shook.shook.song.application.dto; + +import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import lombok.Getter; +import shook.shook.song.application.dto.maniadb.SearchedSongFromManiaDBApiResponse; +import shook.shook.song.application.dto.maniadb.SongArtistResponse; + +@AllArgsConstructor +@Getter +public class UnregisteredSongResponse { + + private static final String EMPTY_SINGER = ""; + private static final String SINGER_DELIMITER = ", "; + + private String title; + private String singer; + private String albumImageUrl; + + public static UnregisteredSongResponse from( + final SearchedSongFromManiaDBApiResponse searchedSongFromManiaDBApiResponse) { + if (searchedSongFromManiaDBApiResponse.getTrackArtists() == null + || searchedSongFromManiaDBApiResponse.getTrackArtists().getArtists() == null) { + return new UnregisteredSongResponse( + searchedSongFromManiaDBApiResponse.getTitle().trim(), + EMPTY_SINGER, + searchedSongFromManiaDBApiResponse.getAlbum().getImage().trim() + ); + } + + final String singers = collectToString(searchedSongFromManiaDBApiResponse); + + return new UnregisteredSongResponse( + searchedSongFromManiaDBApiResponse.getTitle().trim(), + singers, + searchedSongFromManiaDBApiResponse.getAlbum().getImage().trim() + ); + } + + private static String collectToString( + final SearchedSongFromManiaDBApiResponse searchedSongFromManiaDBApiResponse) { + return searchedSongFromManiaDBApiResponse.getTrackArtists().getArtists().stream() + .map(SongArtistResponse::getName) + .map(String::trim) + .collect(Collectors.joining(SINGER_DELIMITER)); + } +} diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/ManiaDBAPISearchResponse.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/ManiaDBAPISearchResponse.java index 558c3d01e..12b4acab4 100644 --- a/backend/src/main/java/shook/shook/song/application/dto/maniadb/ManiaDBAPISearchResponse.java +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/ManiaDBAPISearchResponse.java @@ -9,5 +9,5 @@ public class ManiaDBAPISearchResponse { @XmlElement(name = "channel") - private UnregisteredSongResponses songs; + private SearchedSongFromManiaDBApiResponses songs; } diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponse.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SearchedSongFromManiaDBApiResponse.java similarity index 91% rename from backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponse.java rename to backend/src/main/java/shook/shook/song/application/dto/maniadb/SearchedSongFromManiaDBApiResponse.java index e19d44144..655ac3041 100644 --- a/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponse.java +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SearchedSongFromManiaDBApiResponse.java @@ -6,7 +6,7 @@ @Getter @XmlRootElement(name = "item") -public class UnregisteredSongResponse { +public class SearchedSongFromManiaDBApiResponse { @XmlElement(name = "title") private String title; diff --git a/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponses.java b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SearchedSongFromManiaDBApiResponses.java similarity index 70% rename from backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponses.java rename to backend/src/main/java/shook/shook/song/application/dto/maniadb/SearchedSongFromManiaDBApiResponses.java index 36144593d..77f5abede 100644 --- a/backend/src/main/java/shook/shook/song/application/dto/maniadb/UnregisteredSongResponses.java +++ b/backend/src/main/java/shook/shook/song/application/dto/maniadb/SearchedSongFromManiaDBApiResponses.java @@ -7,8 +7,8 @@ @Getter @XmlRootElement(name = "channel") -public class UnregisteredSongResponses { +public class SearchedSongFromManiaDBApiResponses { @XmlElement(name = "item") - private List songs; + private List songs; } diff --git a/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java b/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java index b242176be..acf1ca560 100644 --- a/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java +++ b/backend/src/main/java/shook/shook/song/ui/UnregisteredSongSearchController.java @@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import shook.shook.song.application.ManiaDBSearchService; -import shook.shook.song.application.dto.SearchedSongFromManiaDBApiResponse; +import shook.shook.song.application.dto.UnregisteredSongResponse; @RequiredArgsConstructor @RequestMapping("/songs/unregistered/search") @@ -18,10 +18,10 @@ public class UnregisteredSongSearchController { private final ManiaDBSearchService maniaDBSearchService; @GetMapping - public ResponseEntity> searchUnregisteredSong( + public ResponseEntity> searchUnregisteredSong( final @RequestParam("keyword") String searchWord ) { - final List songs = maniaDBSearchService.searchSongs( + final List songs = maniaDBSearchService.searchSongs( searchWord); return ResponseEntity.ok(songs); diff --git a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java index 6cbfdcb53..2f406ea5b 100644 --- a/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java +++ b/backend/src/test/java/shook/shook/song/application/ManiaDBSearchServiceTest.java @@ -24,7 +24,7 @@ import org.springframework.http.codec.xml.Jaxb2XmlDecoder; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; -import shook.shook.song.application.dto.SearchedSongFromManiaDBApiResponse; +import shook.shook.song.application.dto.UnregisteredSongResponse; import shook.shook.song.exception.ExternalApiException; import shook.shook.song.exception.ExternalApiException.EmptyResultException; import shook.shook.song.exception.UnregisteredSongException; @@ -254,14 +254,14 @@ void search() { .setBody(SEARCH_RESULT) ); - final SearchedSongFromManiaDBApiResponse expectedResponse = new SearchedSongFromManiaDBApiResponse( + final UnregisteredSongResponse expectedResponse = new UnregisteredSongResponse( "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", "장범준", "http://i.maniadb.com/images/album/777/777829_1_f.jpg" ); // when - final List responses = + final List responses = maniaDBSearchService.searchSongs(SEARCH_WORD); // then @@ -294,14 +294,14 @@ void searchBySpecialMarkSearchWord() { .setBody(SEARCH_RESULT) ); - final SearchedSongFromManiaDBApiResponse expectedResponse = new SearchedSongFromManiaDBApiResponse( + final UnregisteredSongResponse expectedResponse = new UnregisteredSongResponse( "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", "장범준", "http://i.maniadb.com/images/album/777/777829_1_f.jpg" ); // when - final List responses = + final List responses = maniaDBSearchService.searchSongs(SPECIAL_MARK_SEARCH_WORD); // then @@ -335,7 +335,7 @@ void searchResultReturnEmptyList() { ); // when - final List responses = + final List responses = maniaDBSearchService.searchSongs(EMPTY_RESULT_SEARCH_WORD); // then @@ -353,14 +353,14 @@ void searchResultReturnEmptySinger() { .setBody(EMPTY_SINGER_SEARCH_RESULT) ); - final SearchedSongFromManiaDBApiResponse expectedResponse = new SearchedSongFromManiaDBApiResponse( + final UnregisteredSongResponse expectedResponse = new UnregisteredSongResponse( "흔들리는 꽃들 속에서 네 샴푸향이 느껴진거야", "", "http://i.maniadb.com/images/album/777/777829_1_f.jpg" ); // when - final List responses = + final List responses = maniaDBSearchService.searchSongs(SEARCH_WORD); // then From 7bd679aa588bd8ca4546984b9309e73256769c70 Mon Sep 17 00:00:00 2001 From: Eunsol Kim <61370551+Cyma-s@users.noreply.github.com> Date: Wed, 9 Aug 2023 11:16:43 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:=20if=20=EB=AC=B8=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../song/application/dto/UnregisteredSongResponse.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongResponse.java b/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongResponse.java index bc3db2944..20da84abb 100644 --- a/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongResponse.java +++ b/backend/src/main/java/shook/shook/song/application/dto/UnregisteredSongResponse.java @@ -19,8 +19,7 @@ public class UnregisteredSongResponse { public static UnregisteredSongResponse from( final SearchedSongFromManiaDBApiResponse searchedSongFromManiaDBApiResponse) { - if (searchedSongFromManiaDBApiResponse.getTrackArtists() == null - || searchedSongFromManiaDBApiResponse.getTrackArtists().getArtists() == null) { + if (isEmptyArtists(searchedSongFromManiaDBApiResponse)) { return new UnregisteredSongResponse( searchedSongFromManiaDBApiResponse.getTitle().trim(), EMPTY_SINGER, @@ -37,6 +36,12 @@ public static UnregisteredSongResponse from( ); } + private static boolean isEmptyArtists( + final SearchedSongFromManiaDBApiResponse searchedSongFromManiaDBApiResponse) { + return searchedSongFromManiaDBApiResponse.getTrackArtists() == null + || searchedSongFromManiaDBApiResponse.getTrackArtists().getArtists() == null; + } + private static String collectToString( final SearchedSongFromManiaDBApiResponse searchedSongFromManiaDBApiResponse) { return searchedSongFromManiaDBApiResponse.getTrackArtists().getArtists().stream()