Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/com/SleepUp/SU/security/jwt/JwtService.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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) {
Expand Down
142 changes: 87 additions & 55 deletions src/test/java/com/SleepUp/SU/cloudinary/CloudinaryServiceTest.java
Original file line number Diff line number Diff line change
@@ -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<String, Object> mockUploadResult = Map.of("public_id", "12345", "url", "http://test.url/image.jpg");

Map<String, String> 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<String, String> response = new HashMap<>();
response.put("secure_url", "http://cloudinary.com/image/upload/example-null-folder.jpg");
Map<String, Object> 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<String, String> 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);
}
}
}

12 changes: 8 additions & 4 deletions src/test/java/com/SleepUp/SU/security/jwt/JwtServiceTest.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand Down
Loading