Skip to content

Commit 83bbdb2

Browse files
authored
Merge pull request #225 from Runnect/tests/banner-s3-service-prod
test: BannerService/S3Service λ‹¨μœ„ ν…ŒμŠ€νŠΈ μΆ”κ°€ + 이미지 μ—…λ‘œλ“œ ν¬λž˜μ‹œ 버그 μˆ˜μ • (prod)
2 parents ce8328d + 6d314d1 commit 83bbdb2

3 files changed

Lines changed: 187 additions & 3 deletions

File tree

β€Žsrc/main/java/org/runnect/server/external/aws/S3Service.javaβ€Ž

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,27 @@ private String createFileName(String fileName) {
7070

7171
// 파일 μœ νš¨μ„± 검사
7272
private String getFileExtension(String fileName) {
73-
if (fileName.length() == 0) {
73+
if (fileName == null || fileName.isEmpty()) {
7474
throw new NotFoundException(ErrorStatus.NOT_FOUND_IMAGE_EXCEPTION, ErrorStatus.NOT_FOUND_IMAGE_EXCEPTION.getMessage());
7575
}
76+
int dotIndex = fileName.lastIndexOf(".");
77+
// 파일λͺ…에 "."κ°€ μ•„μ˜ˆ μ—†μœΌλ©΄(lastIndexOfκ°€ -1) substring(-1)μ—μ„œ κ·ΈλŒ€λ‘œ
78+
// StringIndexOutOfBoundsException(500)이 λ‚˜λ˜ λΆ€λΆ„ β€” ν™•μž₯자 μ—†λŠ” 파일둜 λͺ…ν™•νžˆ μ²˜λ¦¬ν•œλ‹€.
79+
if (dotIndex == -1) {
80+
throw new BadRequestException(ErrorStatus.NOT_FOUND_IMAGE_EXCEPTION, ErrorStatus.NOT_FOUND_IMAGE_EXCEPTION.getMessage());
81+
}
7682
ArrayList<String> fileValidate = new ArrayList<>();
7783
fileValidate.add(".jpg");
7884
fileValidate.add(".jpeg");
7985
fileValidate.add(".png");
8086
fileValidate.add(".JPG");
8187
fileValidate.add(".JPEG");
8288
fileValidate.add(".PNG");
83-
String idxFileName = fileName.substring(fileName.lastIndexOf("."));
89+
String idxFileName = fileName.substring(dotIndex);
8490
if (!fileValidate.contains(idxFileName)) {
8591
throw new BadRequestException(ErrorStatus.NOT_FOUND_IMAGE_EXCEPTION, ErrorStatus.NOT_FOUND_IMAGE_EXCEPTION.getMessage());
8692
}
87-
return fileName.substring(fileName.lastIndexOf("."));
93+
return idxFileName;
8894
}
8995

9096
// 이미지 μ‚­μ œ
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.runnect.server.banner.service;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.mockito.Mockito.when;
5+
6+
import java.util.Arrays;
7+
import java.util.Collections;
8+
import org.junit.jupiter.api.Test;
9+
import org.junit.jupiter.api.extension.ExtendWith;
10+
import org.mockito.Mock;
11+
import org.mockito.junit.jupiter.MockitoExtension;
12+
import org.runnect.server.banner.dto.response.GetBannerResponseDto;
13+
import org.runnect.server.banner.entity.Banner;
14+
import org.runnect.server.banner.repository.BannerRepository;
15+
import org.springframework.test.util.ReflectionTestUtils;
16+
17+
@ExtendWith(MockitoExtension.class)
18+
class BannerServiceTest {
19+
20+
@Mock
21+
private BannerRepository bannerRepository;
22+
23+
private BannerService bannerService;
24+
25+
private Banner buildBanner(Long id, String imageUrl, String linkUrl, int sortOrder) {
26+
Banner banner = Banner.builder().imageUrl(imageUrl).linkUrl(linkUrl).sortOrder(sortOrder).build();
27+
ReflectionTestUtils.setField(banner, "id", id);
28+
return banner;
29+
}
30+
31+
@Test
32+
void ν™œμ„±_λ°°λ„ˆλ₯Ό_μ •λ ¬λœ_μˆœμ„œ_κ·ΈλŒ€λ‘œ_0λΆ€ν„°_μΈλ±μ‹±ν•΄μ„œ_λ°˜ν™˜ν•œλ‹€() {
33+
bannerService = new BannerService(bannerRepository);
34+
Banner first = buildBanner(1L, "image1.png", "https://a.com", 0);
35+
Banner second = buildBanner(2L, "image2.png", "https://b.com", 1);
36+
when(bannerRepository.findByIsActiveTrueOrderBySortOrderAscIdAsc())
37+
.thenReturn(Arrays.asList(first, second));
38+
39+
GetBannerResponseDto response = bannerService.getBanners();
40+
41+
assertThat(response.getBanners()).hasSize(2);
42+
assertThat(response.getBanners().get(0).getIndex()).isEqualTo(0);
43+
assertThat(response.getBanners().get(0).getImageUrl()).isEqualTo("image1.png");
44+
assertThat(response.getBanners().get(1).getIndex()).isEqualTo(1);
45+
assertThat(response.getBanners().get(1).getLinkUrl()).isEqualTo("https://b.com");
46+
}
47+
48+
@Test
49+
void ν™œμ„±_λ°°λ„ˆκ°€_μ—†μœΌλ©΄_빈_λͺ©λ‘μ„_λ°˜ν™˜ν•œλ‹€() {
50+
bannerService = new BannerService(bannerRepository);
51+
when(bannerRepository.findByIsActiveTrueOrderBySortOrderAscIdAsc())
52+
.thenReturn(Collections.emptyList());
53+
54+
GetBannerResponseDto response = bannerService.getBanners();
55+
56+
assertThat(response.getBanners()).isEmpty();
57+
}
58+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package org.runnect.server.external.aws;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5+
import static org.mockito.ArgumentMatchers.any;
6+
import static org.mockito.Mockito.mock;
7+
import static org.mockito.Mockito.when;
8+
9+
import com.amazonaws.services.s3.AmazonS3;
10+
import com.amazonaws.services.s3.model.PutObjectRequest;
11+
import java.io.ByteArrayInputStream;
12+
import java.io.IOException;
13+
import java.io.InputStream;
14+
import java.net.URL;
15+
import org.junit.jupiter.api.BeforeEach;
16+
import org.junit.jupiter.api.DisplayName;
17+
import org.junit.jupiter.api.Nested;
18+
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.api.extension.ExtendWith;
20+
import org.mockito.Mock;
21+
import org.mockito.junit.jupiter.MockitoExtension;
22+
import org.runnect.server.common.exception.BadRequestException;
23+
import org.runnect.server.common.exception.NotFoundException;
24+
import org.springframework.mock.web.MockMultipartFile;
25+
import org.springframework.test.util.ReflectionTestUtils;
26+
import org.springframework.web.multipart.MultipartFile;
27+
28+
@ExtendWith(MockitoExtension.class)
29+
class S3ServiceTest {
30+
31+
@Mock
32+
private AmazonS3 amazonS3;
33+
34+
private S3Service s3Service;
35+
36+
@BeforeEach
37+
void setUp() {
38+
s3Service = new S3Service(amazonS3);
39+
ReflectionTestUtils.setField(s3Service, "bucket", "runnect-test-bucket");
40+
}
41+
42+
private void stubUploadedUrl() throws Exception {
43+
when(amazonS3.getUrl(any(), any())).thenReturn(
44+
new URL("https://runnect-test-bucket.s3.ap-northeast-2.amazonaws.com/course/image/test.jpg"));
45+
}
46+
47+
@Nested
48+
@DisplayName("uploadImage")
49+
class UploadImage {
50+
51+
@Test
52+
@DisplayName("정상적인 이미지 파일이면 μ—…λ‘œλ“œν•˜κ³  URL을 λ°˜ν™˜ν•œλ‹€")
53+
void 정상_μ—…λ‘œλ“œ() throws Exception {
54+
stubUploadedUrl();
55+
MultipartFile file = new MockMultipartFile("image", "photo.jpg", "image/jpeg", "content".getBytes());
56+
57+
String url = s3Service.uploadImage(file, "course");
58+
59+
assertThat(url).isEqualTo(
60+
"https://runnect-test-bucket.s3.ap-northeast-2.amazonaws.com/course/image/test.jpg");
61+
}
62+
63+
@Test
64+
@DisplayName("λŒ€λ¬Έμž ν™•μž₯자(.PNG)도 정상 μ—…λ‘œλ“œλœλ‹€")
65+
void λŒ€λ¬Έμž_ν™•μž₯자() throws Exception {
66+
stubUploadedUrl();
67+
MultipartFile file = new MockMultipartFile("image", "photo.PNG", "image/png", "content".getBytes());
68+
69+
assertThat(s3Service.uploadImage(file, "course")).isNotNull();
70+
}
71+
72+
@Test
73+
@DisplayName("μ§€μ›ν•˜μ§€ μ•ŠλŠ” ν™•μž₯자면 BadRequestException")
74+
void μ§€μ›ν•˜μ§€_μ•ŠλŠ”_ν™•μž₯자() {
75+
MultipartFile file = new MockMultipartFile("image", "photo.gif", "image/gif", "content".getBytes());
76+
77+
assertThatThrownBy(() -> s3Service.uploadImage(file, "course"))
78+
.isInstanceOf(BadRequestException.class);
79+
}
80+
81+
@Test
82+
@DisplayName("[버그 μˆ˜μ • 검증] 파일λͺ…이 null이면 500(NPE) λŒ€μ‹  NotFoundException")
83+
void 파일λͺ…이_null() {
84+
MultipartFile file = new MockMultipartFile("image", null, "image/jpeg", "content".getBytes());
85+
86+
assertThatThrownBy(() -> s3Service.uploadImage(file, "course"))
87+
.isInstanceOf(NotFoundException.class);
88+
}
89+
90+
@Test
91+
@DisplayName("파일λͺ…이 빈 λ¬Έμžμ—΄μ΄λ©΄ NotFoundException")
92+
void 파일λͺ…이_λΉˆλ¬Έμžμ—΄() {
93+
MultipartFile file = new MockMultipartFile("image", "", "image/jpeg", "content".getBytes());
94+
95+
assertThatThrownBy(() -> s3Service.uploadImage(file, "course"))
96+
.isInstanceOf(NotFoundException.class);
97+
}
98+
99+
@Test
100+
@DisplayName("[버그 μˆ˜μ • 검증] ν™•μž₯자(.)κ°€ μ—†λŠ” 파일λͺ…이면 500(StringIndexOutOfBoundsException) λŒ€μ‹  BadRequestException")
101+
void ν™•μž₯μžκ°€_μ—†λŠ”_파일λͺ…() {
102+
MultipartFile file = new MockMultipartFile("image", "photo_without_extension", "image/jpeg",
103+
"content".getBytes());
104+
105+
assertThatThrownBy(() -> s3Service.uploadImage(file, "course"))
106+
.isInstanceOf(BadRequestException.class);
107+
}
108+
109+
@Test
110+
@DisplayName("파일 μŠ€νŠΈλ¦Όμ„ μ½λŠ” 쀑 였λ₯˜κ°€ λ‚˜λ©΄ NotFoundException")
111+
void 슀트림_읽기_μ‹€νŒ¨() throws IOException {
112+
MultipartFile file = mock(MultipartFile.class);
113+
when(file.getOriginalFilename()).thenReturn("photo.jpg");
114+
when(file.getInputStream()).thenThrow(new IOException("disk error"));
115+
116+
assertThatThrownBy(() -> s3Service.uploadImage(file, "course"))
117+
.isInstanceOf(NotFoundException.class);
118+
}
119+
}
120+
}

0 commit comments

Comments
Β (0)