diff --git a/src/main/java/com/SleepUp/SU/cloudinary/CloudinaryService.java b/src/main/java/com/SleepUp/SU/cloudinary/CloudinaryService.java index f890595b..21c71bd2 100644 --- a/src/main/java/com/SleepUp/SU/cloudinary/CloudinaryService.java +++ b/src/main/java/com/SleepUp/SU/cloudinary/CloudinaryService.java @@ -1,5 +1,6 @@ package com.SleepUp.SU.cloudinary; +import com.SleepUp.SU.config.properties.AppProperties; import com.cloudinary.Cloudinary; import com.cloudinary.utils.ObjectUtils; import org.springframework.stereotype.Service; @@ -13,8 +14,12 @@ public class CloudinaryService { private final Cloudinary cloudinary; - public CloudinaryService(Cloudinary cloudinary) { - this.cloudinary = cloudinary; + public CloudinaryService(AppProperties appProperties) { + AppProperties.CloudinaryProperties cloudinaryProps = appProperties.getCloudinary(); + this.cloudinary = new Cloudinary(ObjectUtils.asMap( + "cloud_name", cloudinaryProps.getCloudName(), + "api_key", cloudinaryProps.getApiKey(), + "api_secret", cloudinaryProps.getApiSecret())); } public Map uploadFile(MultipartFile file, String folder) throws IOException { diff --git a/src/main/java/com/SleepUp/SU/security/jwt/JwtService.java b/src/main/java/com/SleepUp/SU/security/jwt/JwtService.java index c7e1d994..f0df2505 100644 --- a/src/main/java/com/SleepUp/SU/security/jwt/JwtService.java +++ b/src/main/java/com/SleepUp/SU/security/jwt/JwtService.java @@ -1,5 +1,6 @@ package com.SleepUp.SU.security.jwt; +import com.SleepUp.SU.config.properties.AppProperties; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.io.Decoders; @@ -23,16 +24,17 @@ public class JwtService { private static final String ROLE_CLAIM = "roles"; + private static final long DEFAULT_REFRESH_EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000; private final SecretKey secretKey; private final long jwtExpirationMs; - private final long jwtRefreshExpirationMs = 7 * 24 * 60 * 60 * 1000; + private final long jwtRefreshExpirationMs; - public JwtService( - @Value("${jwt.secret}") String secret, - @Value("${jwt.expiration-ms}") long jwtExpirationMs) { - this.secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secret)); - this.jwtExpirationMs = jwtExpirationMs; + public JwtService(AppProperties appProperties) { + AppProperties.JwtProperties jwt = appProperties.getJwt(); + this.secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwt.getSecret())); + this.jwtExpirationMs = jwt.getExpirationMs(); + this.jwtRefreshExpirationMs = jwt.getRefreshExpirationMs() != null ? jwt.getRefreshExpirationMs() : DEFAULT_REFRESH_EXPIRATION_MS; } public String generateRefreshToken(UserDetails userDetails) { diff --git a/src/test/java/com/SleepUp/SU/cloudinary/CloudinaryServiceTest.java b/src/test/java/com/SleepUp/SU/cloudinary/CloudinaryServiceTest.java index 85ce146b..6b7a5deb 100644 --- a/src/test/java/com/SleepUp/SU/cloudinary/CloudinaryServiceTest.java +++ b/src/test/java/com/SleepUp/SU/cloudinary/CloudinaryServiceTest.java @@ -1,94 +1,126 @@ package com.SleepUp.SU.cloudinary; +import com.SleepUp.SU.config.properties.AppProperties; import com.cloudinary.Cloudinary; import com.cloudinary.Uploader; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.context.ActiveProfiles; +import org.mockito.Mock; import java.io.IOException; -import java.util.HashMap; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import com.cloudinary.utils.ObjectUtils; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.web.multipart.MultipartFile; + + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; -@ActiveProfiles("tests") @ExtendWith(MockitoExtension.class) public class CloudinaryServiceTest { - private CloudinaryService cloudinaryService; + @Mock private Cloudinary cloudinary; + + @Mock private Uploader uploader; + @Mock + private MultipartFile multipartFile; + + @Mock + private AppProperties appProperties; + + @Mock + private AppProperties.CloudinaryProperties cloudinaryProperties; + + private CloudinaryService cloudinaryService; + @BeforeEach - void setUp() { - cloudinary = Mockito.mock(Cloudinary.class); - uploader = Mockito.mock(Uploader.class); - cloudinaryService = new CloudinaryService(cloudinary); + public void setUp() { + + when(appProperties.getCloudinary()).thenReturn(cloudinaryProperties); + when(cloudinaryProperties.getCloudName()).thenReturn("testCloudName"); + when(cloudinaryProperties.getApiKey()).thenReturn("testApiKey"); + when(cloudinaryProperties.getApiSecret()).thenReturn("testApiSecret"); + + cloudinaryService = new CloudinaryService(appProperties); + } - @Nested - class uploadFile { + @Test + public void testUploadFile_withFolder_shouldReturnUploadResult() throws IOException { + byte[] fileBytes = "file content".getBytes(); + when(multipartFile.getBytes()).thenReturn(fileBytes); - @Test - void uploadFile_validFileWithFolder_shouldReturnSecureUrl() throws IOException { - MockMultipartFile image = new MockMultipartFile( - "image", - "test-image.jpg", - "image/jpeg", - "Test Image Content".getBytes() - ); + Map mockUploadResult = Map.of("public_id", "12345", "url", "http://test.url/image.jpg"); - Map response = new HashMap<>(); - response.put("secure_url", "http://cloudinary.com/image/upload/example.jpg"); + when(cloudinary.uploader()).thenReturn(uploader); + when(uploader.upload(eq(fileBytes), any(Map.class))).thenReturn(mockUploadResult); - Mockito.when(cloudinary.uploader()).thenReturn(uploader); - Mockito.when(uploader.upload(any(), anyMap())).thenReturn(response); + setCloudinaryMock(cloudinaryService, cloudinary); - Map result = cloudinaryService.uploadFile(image, "accommodations"); + Map result = cloudinaryService.uploadFile(multipartFile, "testFolder"); - assertEquals("http://cloudinary.com/image/upload/example.jpg", result.get("secure_url")); - } + verify(uploader, times(1)).upload(eq(fileBytes), any(Map.class)); + assertEquals(mockUploadResult, result); + } - @Test - void uploadFile_nullFolder_shouldReturnSecureUrl() throws IOException { - MockMultipartFile image = new MockMultipartFile( - "image", - "test-image.jpg", - "image/jpeg", - "Test Image Content".getBytes() - ); + @Test + public void testUploadFile_withoutFolder_shouldReturnUploadResult() throws IOException { + byte[] fileBytes = "file content".getBytes(); + when(multipartFile.getBytes()).thenReturn(fileBytes); - Map response = new HashMap<>(); - response.put("secure_url", "http://cloudinary.com/image/upload/example-null-folder.jpg"); + Map mockUploadResult = Map.of("public_id", "12345", "url", "http://test.url/image.jpg"); - Mockito.when(cloudinary.uploader()).thenReturn(uploader); - Mockito.when(uploader.upload(any(), anyMap())).thenReturn(response); + when(cloudinary.uploader()).thenReturn(uploader); + when(uploader.upload(eq(fileBytes), eq(ObjectUtils.emptyMap()))).thenReturn(mockUploadResult); - Map result = cloudinaryService.uploadFile(image, null); + setCloudinaryMock(cloudinaryService, cloudinary); + + Map result = cloudinaryService.uploadFile(multipartFile, null); + + verify(uploader, times(1)).upload(eq(fileBytes), eq(ObjectUtils.emptyMap())); + assertEquals(mockUploadResult, result); + } + + @Test + public void testDeleteFile_shouldCallDestroy() throws IOException { - assertEquals("http://cloudinary.com/image/upload/example-null-folder.jpg", result.get("secure_url")); - } } - @Nested - class deleteFile { - @Test - void deleteFile_validPublicId_shouldNotThrow() throws IOException { - Map response = new HashMap<>(); - response.put("result", "ok"); + @Test + public void testDeleteFile_shouldThrowIOException() throws Exception { + String publicId = "abc123"; - Mockito.when(cloudinary.uploader()).thenReturn(uploader); - Mockito.when(uploader.destroy(eq("image"), anyMap())).thenReturn(response); + when(cloudinary.uploader()).thenReturn(uploader); - assertDoesNotThrow(() -> cloudinaryService.deleteFile("image")); + + doThrow(new IOException("Failed to delete file")).when(uploader) + .destroy(eq(publicId), eq(ObjectUtils.emptyMap())); + + + setCloudinaryMock(cloudinaryService, cloudinary); + assertThrows(IOException.class, () -> cloudinaryService.deleteFile(publicId)); + } + + + private void setCloudinaryMock(CloudinaryService service, Cloudinary cloudinaryMock) { + try { + java.lang.reflect.Field cloudinaryField = CloudinaryService.class.getDeclaredField("cloudinary"); + cloudinaryField.setAccessible(true); + cloudinaryField.set(service, cloudinaryMock); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); } } } + diff --git a/src/test/java/com/SleepUp/SU/security/jwt/JwtServiceTest.java b/src/test/java/com/SleepUp/SU/security/jwt/JwtServiceTest.java index f2c7e447..80272952 100644 --- a/src/test/java/com/SleepUp/SU/security/jwt/JwtServiceTest.java +++ b/src/test/java/com/SleepUp/SU/security/jwt/JwtServiceTest.java @@ -1,5 +1,6 @@ package com.SleepUp.SU.security.jwt; +import com.SleepUp.SU.config.properties.AppProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -20,12 +21,15 @@ class JwtServiceTest { @BeforeEach void setup() { - MockitoAnnotations.openMocks(this); + AppProperties.JwtProperties jwtProperties = new AppProperties.JwtProperties(); + jwtProperties.setSecret("YourBase64EncodedSecretHereYourBase64EncodedSecretHere"); + jwtProperties.setExpirationMs(60000L); + jwtProperties.setRefreshExpirationMs(120000L); - String secret = "YourBase64EncodedSecretHereYourBase64EncodedSecretHere"; - long expirationMs = 60000L; + AppProperties appProperties = new AppProperties(); + appProperties.setJwt(jwtProperties); - jwtService = new JwtService(secret, expirationMs); + jwtService = new JwtService(appProperties); } @Test