diff --git a/src/test/java/com/safetypin/authentication/service/GoogleAuthServiceTest.java b/src/test/java/com/safetypin/authentication/service/GoogleAuthServiceTest.java index eb14a0e62b9a50ca34aab36283c5e8277fdd0a93..15987087068ce1ba1adf8ecdb3ff0d0ec74ae660 100644 --- a/src/test/java/com/safetypin/authentication/service/GoogleAuthServiceTest.java +++ b/src/test/java/com/safetypin/authentication/service/GoogleAuthServiceTest.java @@ -1,5 +1,23 @@ package com.safetypin.authentication.service; +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; +import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse; +import com.safetypin.authentication.dto.GoogleAuthDTO; +import com.safetypin.authentication.exception.ApiException; +import com.safetypin.authentication.exception.InvalidCredentialsException; +import com.safetypin.authentication.exception.UserAlreadyExistsException; +import com.safetypin.authentication.model.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -7,99 +25,61 @@ import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.time.LocalDate; -import java.time.Year; -import java.util.*; - -import com.google.api.client.auth.oauth2.TokenResponseException; -import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.*; -import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.security.crypto.password.PasswordEncoder; +import java.util.Optional; +import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -import com.google.api.client.auth.oauth2.TokenResponse; -import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest; -import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; -import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; - -import com.safetypin.authentication.dto.GoogleAuthDTO; -import com.safetypin.authentication.exception.ApiException; -import com.safetypin.authentication.exception.UserAlreadyExistsException; -import com.safetypin.authentication.model.User; -import com.safetypin.authentication.repository.UserRepository; - @ExtendWith(MockitoExtension.class) public class GoogleAuthServiceTest { @Mock - private UserRepository userRepository; + private UserService userService; @Mock - private PasswordEncoder passwordEncoder; + private JwtService jwtService; @Mock - private OTPService otpService; + private GoogleIdToken idToken; @Mock - private GoogleIdTokenVerifier mockVerifier; + private GoogleIdToken.Payload payload; @Mock - private GoogleIdToken mockIdToken; + private GoogleIdTokenVerifier verifier; @Mock - private GoogleIdToken.Payload mockPayload; + private GoogleAuthorizationCodeTokenRequest tokenRequest; @Mock - private GoogleAuthorizationCodeTokenRequest mockTokenRequest; + private GoogleTokenResponse tokenResponse; - @Mock - private TokenResponse mockTokenResponse; + @Spy + @InjectMocks + private GoogleAuthService googleAuthService; - @Mock - private HttpURLConnection mockConnection; + private GoogleAuthDTO googleAuthDTO; + private UUID testUserId; - @Mock - private URL mockUrl; - - private GoogleAuthService googleAuthService; + private final String TEST_ACCESS_TOKEN = "test-access-token"; - @BeforeEach - void setUp() throws Exception { - MockitoAnnotations.openMocks(this); - googleAuthService = new GoogleAuthService(userRepository, passwordEncoder, otpService) { - @Override - protected GoogleIdTokenVerifier createIdTokenVerifier() { - return mockVerifier; - } + private final String TEST_GOOGLE_CLIENT_ID = "test-client-id"; - @Override - protected GoogleAuthorizationCodeTokenRequest createTokenRequest( - String tokenUrl, String clientId, String clientSecret) { - return mockTokenRequest; - } + private final String TEST_ID_TOKEN = "test-id-token"; - @Override - protected URL createURL(String urlString) throws IOException { - return mockUrl; - } - }; + @BeforeEach + void setup() { + ReflectionTestUtils.setField(googleAuthService, "googleClientId", TEST_GOOGLE_CLIENT_ID); + String TEST_GOOGLE_CLIENT_SECRET = "test-client-secret"; + ReflectionTestUtils.setField(googleAuthService, "googleClientSecret", TEST_GOOGLE_CLIENT_SECRET); - // Use reflection to set private fields for testing - setPrivateField("googleClientId", "test-client-id"); - setPrivateField("googleClientSecret", "test-client-secret"); - } + googleAuthDTO = new GoogleAuthDTO(); + googleAuthDTO.setIdToken(TEST_ID_TOKEN); + googleAuthDTO.setServerAuthCode("test-auth-code"); - private void setPrivateField(String fieldName, Object value) throws Exception { - java.lang.reflect.Field field = GoogleAuthService.class.getDeclaredField(fieldName); - field.setAccessible(true); - field.set(googleAuthService, value); + testUserId = UUID.randomUUID(); } private void setPrivateField(Object instance, String fieldName, Object value) throws Exception { @@ -108,388 +88,257 @@ public class GoogleAuthServiceTest { field.set(instance, value); } - - @Test - public void testVerifyIdToken_NullToken() { - assertThrows(IllegalArgumentException.class, () -> { - googleAuthService.verifyIdToken(null); - }); - } - @Test - void testVerifyIdToken_ValidToken() throws Exception { - // Prepare mock GoogleIdToken - GoogleIdToken mockIdToken = mock(GoogleIdToken.class); - GoogleIdToken.Payload mockPayload = new GoogleIdToken.Payload(); - mockPayload.setEmail("test@example.com"); + void authenticate_NewUser_Success() throws Exception { + // Mock verify ID token + doReturn(payload).when(googleAuthService).verifyIdToken(anyString()); + when(payload.getEmail()).thenReturn("test@example.com"); + when(payload.get("name")).thenReturn("Test User"); - // Prepare a spy to inject mock verifier - GoogleAuthService spyService = spy(googleAuthService); - doReturn(mockVerifier).when(spyService).createIdTokenVerifier(); + // Mock user service + when(userService.findByEmail(anyString())).thenReturn(Optional.empty()); - when(mockVerifier.verify(anyString())).thenReturn(mockIdToken); - when(mockIdToken.getPayload()).thenReturn(mockPayload); + // Mock getAccessToken + doReturn(TEST_ACCESS_TOKEN).when(googleAuthService).getAccessToken(anyString()); - GoogleIdToken.Payload result = spyService.verifyIdToken("valid-token"); + // Mock getUserBirthdate to return a specific date + LocalDate birthdate = LocalDate.of(1990, 1, 1); + doReturn(birthdate).when(googleAuthService).getUserBirthdate(anyString()); - assertNotNull(result); - assertEquals("test@example.com", result.getEmail()); - } - - @Test - void testVerifyIdToken_invalidIdToken() throws Exception { - // Prepare a spy for GoogleAuthService - GoogleAuthService spyService = spy(googleAuthService); - - // Mock the GoogleIdTokenVerifier and GoogleIdToken - GoogleIdTokenVerifier mockVerifier = mock(GoogleIdTokenVerifier.class); - GoogleIdToken mockIdToken = mock(GoogleIdToken.class); + // Mock user save + User savedUser = new User(); + savedUser.setId(testUserId); + when(userService.save(any(User.class))).thenReturn(savedUser); - // Set up the behavior for the mockVerifier to return null when verify is called - when(mockVerifier.verify(anyString())).thenReturn(null); // Simulating invalid ID token + // Mock JWT generation + when(jwtService.generateToken(any(UUID.class))).thenReturn("test-jwt-token"); - // Mock createIdTokenVerifier to return the mockVerifier - doReturn(mockVerifier).when(spyService).createIdTokenVerifier(); + // Execute + String result = googleAuthService.authenticate(googleAuthDTO); - // Call the method and verify that the exception is thrown - assertThrows(Exception.class, () -> spyService.verifyIdToken("invalid-token")); + // Verify + assertEquals("test-jwt-token", result); + verify(userService).findByEmail("test@example.com"); + verify(userService).save(any(User.class)); + verify(jwtService).generateToken(testUserId); } @Test - void testFetchUserData_Successful() throws Exception { - // Create a test GoogleAuthService with a protected method for URL creation - GoogleAuthService spyService = spy(new GoogleAuthService(userRepository, passwordEncoder, otpService) { - @Override - protected URL createURL(String urlString) throws IOException { - URL mockUrl = mock(URL.class); - HttpURLConnection mockConn = mock(HttpURLConnection.class); + void authenticate_ExistingGoogleUser_Success() throws Exception { + // Mock verify ID token + doReturn(payload).when(googleAuthService).verifyIdToken(anyString()); + when(payload.getEmail()).thenReturn("test@example.com"); - // Prepare input stream - String testResponse = "test response data"; - InputStream inputStream = new ByteArrayInputStream(testResponse.getBytes()); + // Mock existing user + User existingUser = new User(); + existingUser.setId(testUserId); + existingUser.setProvider("GOOGLE"); + when(userService.findByEmail("test@example.com")).thenReturn(Optional.of(existingUser)); - // Mock URL and connection behaviors - when(mockUrl.openConnection()).thenReturn(mockConn); - when(mockConn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); - when(mockConn.getInputStream()).thenReturn(inputStream); + // Mock JWT generation + when(jwtService.generateToken(any(UUID.class))).thenReturn("test-jwt-token"); - return mockUrl; - } - }); + // Execute + String result = googleAuthService.authenticate(googleAuthDTO); - // Execute and verify - String response = spyService.fetchUserData("access-token", "birthdays"); - assertEquals("test response data", response); + // Verify + assertEquals("test-jwt-token", result); + verify(userService).findByEmail("test@example.com"); + verify(userService, never()).save(any(User.class)); + verify(jwtService).generateToken(testUserId); } @Test - void testFetchUserData_ErrorResponse() throws Exception { - // Create a test GoogleAuthService with a protected method for URL creation - GoogleAuthService spyService = spy(new GoogleAuthService(userRepository, passwordEncoder, otpService) { - @Override - protected URL createURL(String urlString) throws IOException { - URL mockUrl = mock(URL.class); - HttpURLConnection mockConn = mock(HttpURLConnection.class); - - // Mock URL and connection behaviors - when(mockUrl.openConnection()).thenReturn(mockConn); - when(mockConn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_UNAUTHORIZED); + void authenticate_ExistingUserWithDifferentProvider_ThrowsException() throws Exception { + // Mock verify ID token + doReturn(payload).when(googleAuthService).verifyIdToken(anyString()); + when(payload.getEmail()).thenReturn("test@example.com"); - return mockUrl; - } - }); + // Mock existing user with different provider + User existingUser = new User(); + existingUser.setProvider("EMAIL"); + when(userService.findByEmail("test@example.com")).thenReturn(Optional.of(existingUser)); - // Verify that an ApiException is thrown - ApiException thrown = assertThrows(ApiException.class, () -> - spyService.fetchUserData("access-token", "birthdays") + // Execute and verify + UserAlreadyExistsException exception = assertThrows( + UserAlreadyExistsException.class, + () -> googleAuthService.authenticate(googleAuthDTO) ); - assertEquals("Error fetching data from Google API", thrown.getMessage()); + assertTrue(exception.getMessage().contains("Please sign in using EMAIL")); } @Test - public void testFetchUserData_ApiError() throws IOException { - when(mockUrl.openConnection()).thenReturn(mockConnection); - when(mockConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_UNAUTHORIZED); + void verifyIdToken_NullToken_ThrowsException() { + // Execute and verify + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> googleAuthService.verifyIdToken(null) + ); - assertThrows(Exception.class, () -> { - googleAuthService.fetchUserData("access-token", "fields"); - }); + assertEquals("ID Token cannot be null", exception.getMessage()); } @Test - void testGetAccessToken_Successful() throws Exception { - // Create a spy for the service - GoogleAuthService spyService = spy(googleAuthService); - - // Mock the GoogleTokenResponse creation - GoogleTokenResponse mockTokenResponse = mock(GoogleTokenResponse.class); - when(mockTokenResponse.getAccessToken()).thenReturn("test-access-token"); - - // Mock the GoogleAuthorizationCodeTokenRequest creation - GoogleAuthorizationCodeTokenRequest mockRequest = mock(GoogleAuthorizationCodeTokenRequest.class); - - // Mock the behavior of the request - doReturn(mockRequest).when(spyService).createTokenRequest(anyString(), anyString(), anyString()); + void verifyIdToken_ValidToken_ReturnsPayload() throws Exception { + // Mock the verifier creation + doReturn(verifier).when(googleAuthService).createIdTokenVerifier(); - // Mock setCode() to return the mockRequest to simulate method chaining - when(mockRequest.setCode(anyString())).thenReturn(mockRequest); // Return mockRequest itself for chaining + // Set up the verifier to return our mock ID token + when(verifier.verify(TEST_ID_TOKEN)).thenReturn(idToken); + when(idToken.getPayload()).thenReturn(payload); - // Mock the execute() method to return the mocked token response - when(mockRequest.execute()).thenReturn(mockTokenResponse); + // Execute + GoogleIdToken.Payload result = googleAuthService.verifyIdToken(TEST_ID_TOKEN); - // Execute and verify - String accessToken = spyService.getAccessToken("test-server-auth-code"); - assertEquals("test-access-token", accessToken); + // Verify + assertSame(payload, result); + verify(verifier).verify(TEST_ID_TOKEN); } @Test - void testAuthenticate_NewUser() throws Exception { - // Prepare test scenario - GoogleIdToken.Payload payload = createMockPayload(); - GoogleAuthDTO authDTO = createMockAuthDTO(); - - // Mock dependencies - GoogleAuthService spyService = spy(googleAuthService); + void verifyIdToken_InvalidToken_ThrowsException() throws Exception { + // Create a spy on the service to override the verifier creation - // Prepare mocking chain - doReturn(payload).when(spyService).verifyIdToken(anyString()); - when(userRepository.findByEmail(anyString())).thenReturn(null); - doReturn("access-token").when(spyService).getAccessToken(anyString()); - doReturn(LocalDate.now()).when(spyService).getUserBirthdate(anyString()); + // Mock the verifier creation + doReturn(verifier).when(googleAuthService).createIdTokenVerifier(); - // Prepare saved user - User savedUser = new User(); - savedUser.setId(UUID.randomUUID()); - when(userRepository.save(any(User.class))).thenReturn(savedUser); - doReturn("jwt-token").when(spyService).generateJwtToken(any(UUID.class)); + // Set up the verifier to return null (invalid token) + when(verifier.verify(anyString())).thenReturn(null); // Execute and verify - String token = spyService.authenticate(authDTO); - assertEquals("jwt-token", token); - } - - @Test - public void testAuthenticate_ExistingUserSameProvider() throws Exception { - // Prepare mock data - GoogleAuthDTO authDTO = new GoogleAuthDTO(); - authDTO.setIdToken("test-id-token"); - authDTO.setServerAuthCode("test-server-auth-code"); - - // Setup existing user with ID - User existingUser = new User(); - existingUser.setId(UUID.randomUUID()); - existingUser.setProvider("GMAIL"); - existingUser.setEmail("test@example.com"); - - // Setup ID token verification - lenient().when(mockVerifier.verify(anyString())).thenReturn(mockIdToken); - lenient().when(mockIdToken.getPayload()).thenReturn(mockPayload); - when(mockPayload.getEmail()).thenReturn("test@example.com"); - when(mockPayload.get("name")).thenReturn("Test User"); - - // Mock user repository - when(userRepository.findByEmail(anyString())).thenReturn(existingUser); - - // Prepare token response - GoogleTokenResponse mockTokenResponse = mock(GoogleTokenResponse.class); - - // Authenticate - String token = googleAuthService.authenticate(authDTO); + InvalidCredentialsException exception = assertThrows( + InvalidCredentialsException.class, + () -> googleAuthService.verifyIdToken(TEST_ID_TOKEN) + ); - // Verify - assertNotNull(token); - verify(userRepository, never()).save(any(User.class)); + assertEquals("Invalid ID Token", exception.getMessage()); + verify(verifier).verify(TEST_ID_TOKEN); } - @Test - public void testAuthenticate_ExistingUserDifferentProvider() throws Exception { - // Prepare mock data - GoogleAuthDTO authDTO = new GoogleAuthDTO(); - authDTO.setIdToken("test-id-token"); - authDTO.setServerAuthCode("test-server-auth-code"); + void getAccessToken_Success() throws Exception { - // Setup existing user - User existingUser = new User(); - existingUser.setProvider("FACEBOOK"); + // Mock the token request creation + doReturn(tokenRequest).when(googleAuthService).createAuthorizationCodeTokenRequest("test-auth-code"); - // Setup ID token verification - when(mockVerifier.verify(anyString())).thenReturn(mockIdToken); - when(mockIdToken.getPayload()).thenReturn(mockPayload); - when(mockPayload.getEmail()).thenReturn("test@example.com"); - when(mockPayload.get("name")).thenReturn("Test User"); + // Set up the token request to return our mock token response + when(tokenRequest.execute()).thenReturn((tokenResponse)); + when(tokenResponse.getAccessToken()).thenReturn(TEST_ACCESS_TOKEN); - // Mock user repository - when(userRepository.findByEmail(anyString())).thenReturn(existingUser); + // Execute + String result = googleAuthService.getAccessToken("test-auth-code"); - // Verify exception - assertThrows(UserAlreadyExistsException.class, () -> { - googleAuthService.authenticate(authDTO); - }); + // Verify + assertEquals(TEST_ACCESS_TOKEN, result); + verify(tokenRequest).execute(); } @Test - void testExtractBirthday_FullBirthdayInfo() { - String fullBirthdayJson = "{\"birthdays\":[{\"date\":{\"year\":1990,\"month\":1,\"day\":15}}]}"; - LocalDate birthday = googleAuthService.extractBirthday(fullBirthdayJson); - assertEquals(LocalDate.of(1990, 1, 15), birthday); + void extractBirthday_ValidResponse_ReturnsBirthdate() { + String jsonResponse = "{" + + "\"birthdays\": [" + + " {" + + " \"date\": {" + + " \"year\": 1990," + + " \"month\": 1," + + " \"day\": 15" + + " }" + + " }" + + "]" + + "}"; + + LocalDate result = googleAuthService.extractBirthday(jsonResponse); + + assertEquals(LocalDate.of(1990, 1, 15), result); } @Test - void testExtractBirthday_NoYear() { - String noYearJson = "{\"birthdays\":[{\"date\":{\"month\":1,\"day\":15}}]}"; - LocalDate birthday = googleAuthService.extractBirthday(noYearJson); - assertEquals(LocalDate.of(Year.now().getValue(), 1, 15), birthday); + void extractBirthday_NoYearProvided_ReturnsCurrentYear() { + String jsonResponse = "{" + + "\"birthdays\": [" + + " {" + + " \"date\": {" + + " \"month\": 1," + + " \"day\": 15" + + " }" + + " }" + + "]" + + "}"; + + LocalDate result = googleAuthService.extractBirthday(jsonResponse); + + assertEquals(LocalDate.of(LocalDate.now().getYear(), 1, 15), result); } @Test - void testExtractBirthday_EmptyBirthdays() { - String emptyBirthdaysJson = "{\"birthdays\":[]}"; - assertNull(googleAuthService.extractBirthday(emptyBirthdaysJson)); - } + void extractBirthday_NoBirthdayField_ReturnsNull() { + String jsonResponse = "{}"; - @Test - public void testExtractBirthday_NoBirthdays() { - String jsonResponse = "{\"key\":\"value\"}"; - LocalDate birthday = googleAuthService.extractBirthday(jsonResponse); + LocalDate result = googleAuthService.extractBirthday(jsonResponse); - assertNull(birthday); + assertNull(result); } @Test - public void testExtractBirthday_EmptyBirthdaysArray() { - String jsonResponse = "{\"birthdays\":[]}"; - LocalDate birthday = googleAuthService.extractBirthday(jsonResponse); + void extractBirthday_EmptyBirthdaysArray_ReturnsNull() { + String jsonResponse = "{\"birthdays\": []}"; - assertNull(birthday); - } + LocalDate result = googleAuthService.extractBirthday(jsonResponse); - @Test - public void testExtractBirthday_NoBirthdayDateField() { - // JSON response where the first birthday object doesn't have a "date" field - String jsonResponse = "{\"birthdays\":[{\"someOtherField\":\"value\"}]}"; - - LocalDate birthday = googleAuthService.extractBirthday(jsonResponse); - - assertNull(birthday); + assertNull(result); } @Test - void testCreateURL_Successful() throws Exception { - GoogleAuthService realService = new GoogleAuthService(userRepository, passwordEncoder, otpService); - setPrivateField(realService, "googleClientId", "test-client-id"); - setPrivateField(realService, "googleClientSecret", "test-client-secret"); - - String testUrlString = "https://example.com"; - URL createdUrl = realService.createURL(testUrlString); - - assertNotNull(createdUrl); - assertEquals(testUrlString, createdUrl.toString()); - } + void extractBirthday_NoDateField_ReturnsNull() { + String jsonResponse = "{" + + "\"birthdays\": [" + + " {}" + + "]" + + "}"; - @Test - void testCreateURL_InvalidURL() throws Exception { - GoogleAuthService realService = new GoogleAuthService(userRepository, passwordEncoder, otpService); - setPrivateField(realService, "googleClientId", "test-client-id"); - setPrivateField(realService, "googleClientSecret", "test-client-secret"); + LocalDate result = googleAuthService.extractBirthday(jsonResponse); - assertThrows(MalformedURLException.class, () -> { - realService.createURL("not a valid url"); - }); + assertNull(result); } @Test - void testGetUserBirthdate_Successful() throws IOException { - // Create a spy of GoogleAuthService to mock the fetchUserData method - GoogleAuthService spyService = spy(googleAuthService); - - // Prepare a mock JSON response with a birthday - String mockBirthdayResponse = "{\"birthdays\":[{\"date\":{\"year\":1990,\"month\":1,\"day\":15}}]}"; + void getUserBirthdate_Success() throws Exception { + // Setup private method mocking + doReturn("test-json-response").when(googleAuthService).fetchUserData(anyString()); - // Mock the fetchUserData method to return the prepared response - doReturn(mockBirthdayResponse).when(spyService).fetchUserData(anyString(), eq("birthdays")); + // Mock extract birthday + LocalDate birthdate = LocalDate.of(1990, 1, 15); + doReturn(birthdate).when(googleAuthService).extractBirthday(anyString()); - // Execute the method - LocalDate birthday = spyService.getUserBirthdate("test-access-token"); + // Execute + LocalDate result = googleAuthService.getUserBirthdate(TEST_ACCESS_TOKEN); - // Verify the result - assertEquals(LocalDate.of(1990, 1, 15), birthday); - - // Verify that fetchUserData was called with correct parameters - verify(spyService).fetchUserData("test-access-token", "birthdays"); + // Verify + assertEquals(birthdate, result); } @Test - void testGetUserBirthdate_NoBirthdayData() throws IOException { - // Create a spy of GoogleAuthService to mock the fetchUserData method - GoogleAuthService spyService = spy(googleAuthService); - - // Prepare a mock JSON response without birthdays - String mockEmptyResponse = "{\"key\":\"value\"}"; - - // Mock the fetchUserData method to return the prepared response - doReturn(mockEmptyResponse).when(spyService).fetchUserData(anyString(), eq("birthdays")); - - // Execute the method - LocalDate birthday = spyService.getUserBirthdate("test-access-token"); - - // Verify the result is null - assertNull(birthday); - - // Verify that fetchUserData was called with correct parameters - verify(spyService).fetchUserData("test-access-token", "birthdays"); - } + void authenticate_Exception_ThrowsApiException() throws Exception { + // Mock verify ID token to throw exception + doThrow(new IOException("Test exception")).when(googleAuthService).verifyIdToken(anyString()); - // Helper methods for creating mock objects - private GoogleIdToken.Payload createMockPayload() { - GoogleIdToken.Payload payload = new GoogleIdToken.Payload(); - payload.setEmail("test@example.com"); - payload.put("name", "Test User"); - return payload; - } - - private GoogleAuthDTO createMockAuthDTO() { - GoogleAuthDTO authDTO = new GoogleAuthDTO(); - authDTO.setIdToken("valid-token"); - authDTO.setServerAuthCode("server-code"); - return authDTO; - } - - @Test - void testGetAccessToken_WithOverriddenCreateTokenRequest() throws Exception { - // Override method createTokenRequest untuk mengembalikan stub yang sudah dikonfigurasi - GoogleAuthService spyService = spy(new GoogleAuthService(userRepository, passwordEncoder, otpService) { - @Override - protected GoogleAuthorizationCodeTokenRequest createTokenRequest(String tokenUrl, String clientId, String clientSecret) { - GoogleAuthorizationCodeTokenRequest mockRequest = mock(GoogleAuthorizationCodeTokenRequest.class); - // Gunakan GoogleTokenResponse agar sesuai dengan tipe kembalian execute() - GoogleTokenResponse tokenResponse = new GoogleTokenResponse(); - tokenResponse.setAccessToken("test-access-token"); - - try { - // Pastikan pemanggilan setCode() dan execute() mengembalikan nilai yang sesuai - when(mockRequest.setCode(anyString())).thenReturn(mockRequest); - when(mockRequest.execute()).thenReturn(tokenResponse); - } catch (IOException e) { - // Tidak diharapkan terjadi exception - fail("IOException tidak diharapkan: " + e.getMessage()); - } - return mockRequest; - } - }); + // Execute and verify + ApiException exception = assertThrows( + ApiException.class, + () -> googleAuthService.authenticate(googleAuthDTO) + ); - String accessToken = spyService.getAccessToken("dummy-code"); - assertEquals("test-access-token", accessToken); + assertEquals("Authentication failed", exception.getMessage()); } @Test void testCreateIdTokenVerifier_Configurations() throws Exception { // Create a real instance of GoogleAuthService for this test - GoogleAuthService realService = new GoogleAuthService(userRepository, passwordEncoder, otpService); + GoogleAuthService realService = new GoogleAuthService(userService, jwtService); // Use reflection to set the client ID for testing - setPrivateField(realService, "googleClientId", "test-client-id"); + setPrivateField(realService, "googleClientId", TEST_GOOGLE_CLIENT_ID); // Call the createIdTokenVerifier method GoogleIdTokenVerifier verifier = realService.createIdTokenVerifier(); @@ -501,15 +350,63 @@ public class GoogleAuthServiceTest { @Test void testCreateTokenRequests_Configurations() throws Exception { // Create a real instance of GoogleAuthService for this test - GoogleAuthService realService = new GoogleAuthService(userRepository, passwordEncoder, otpService); + GoogleAuthService realService = new GoogleAuthService(userService, jwtService); // Use reflection to set the client ID for testing - setPrivateField(realService, "googleClientId", "test-client-id"); + setPrivateField(realService, "googleClientId", TEST_GOOGLE_CLIENT_ID); - // Call the createIdTokenVerifier method - assertThrows(TokenResponseException.class, () -> { - realService.createTokenRequest("https://oauth2.googleapis.com/token", "test-client-id", "test-client-secret").setCode("sadf").execute(); + assertNotNull(realService.createAuthorizationCodeTokenRequest("dumb-bunny")); + } + + @Test + void testFetchUserData_Successful() throws Exception { + // Create a test GoogleAuthService with a protected method for URL creation + GoogleAuthService spyService = spy(new GoogleAuthService(userService, jwtService) { + @Override + protected URL createURL(String urlString) throws IOException { + URL mockUrl = mock(URL.class); + HttpURLConnection mockConn = mock(HttpURLConnection.class); + + // Prepare input stream + String testResponse = "test response data"; + InputStream inputStream = new ByteArrayInputStream(testResponse.getBytes()); + + // Mock URL and connection behaviors + when(mockUrl.openConnection()).thenReturn(mockConn); + when(mockConn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK); + when(mockConn.getInputStream()).thenReturn(inputStream); + + return mockUrl; + } + }); + + // Execute and verify + String response = spyService.fetchUserData(TEST_ACCESS_TOKEN); + assertEquals("test response data", response); + } + + @Test + void testFetchUserData_ApiError() { + + assertThrows(ApiException.class, () -> { + googleAuthService.fetchUserData(TEST_ACCESS_TOKEN); }); } + @Test + void testFetchUserData_InvalidAPIFormat() throws IOException { + // Arrange + doThrow(new MalformedURLException("Invalid URL format")) + .when(googleAuthService).createURL(anyString()); + + // Act & Assert + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> googleAuthService.fetchUserData(TEST_ACCESS_TOKEN) + ); + + // Verify the exception contains the expected message + assert(exception.getMessage().contains("Invalid API URL")); + assert(exception.getCause() instanceof MalformedURLException); + } } \ No newline at end of file