268 lines
11 KiB
Java

package com.walkguide.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.walkguide.dto.request.FcmTokenRequest;
import com.walkguide.dto.request.LoginRequest;
import com.walkguide.dto.request.RefreshTokenRequest;
import com.walkguide.dto.request.RegisterRequest;
import com.walkguide.dto.response.AuthDataResponse;
import com.walkguide.security.SecurityHelper;
import com.walkguide.service.AuthService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import com.walkguide.security.JwtAuthFilter;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@AutoConfigureMockMvc(addFilters = false)
@WebMvcTest(AuthController.class)
@DisplayName("AuthController Unit Tests")
class AuthControllerTest {
@MockBean private JwtAuthFilter jwtAuthFilter;
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private AuthService authService;
private AuthDataResponse sampleAuthData;
@BeforeEach
void setUp() {
sampleAuthData = AuthDataResponse.builder()
.accessToken("access-token-xyz")
.refreshToken("refresh-token-xyz")
.role("ROLE_USER")
.userId(1L)
.displayName("Test User")
.uniqueUserId("ABC123DEF456")
.build();
}
// ===== PING =====
@Test
@DisplayName("GET /api/v1/auth/ping - harus return 200 pong")
void ping_shouldReturn200WithPong() throws Exception {
mockMvc.perform(get("/api/v1/auth/ping"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data").value("pong"))
.andExpect(jsonPath("$.message").value("Server aktif"));
}
// ===== REGISTER =====
@Test
@DisplayName("POST /api/v1/auth/register - valid request harus return 200 dengan token")
void register_validRequest_shouldReturn200() throws Exception {
RegisterRequest req = new RegisterRequest();
req.setEmail("new@test.com");
req.setPassword("password123");
req.setDisplayName("New User");
req.setRole("USER");
when(authService.register(any(RegisterRequest.class))).thenReturn(sampleAuthData);
mockMvc.perform(post("/api/v1/auth/register")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("Registrasi berhasil"))
.andExpect(jsonPath("$.data.accessToken").value("access-token-xyz"))
.andExpect(jsonPath("$.data.role").value("ROLE_USER"));
verify(authService).register(any(RegisterRequest.class));
}
@Test
@DisplayName("POST /api/v1/auth/register - email kosong harus return 400")
void register_emptyEmail_shouldReturn400() throws Exception {
RegisterRequest req = new RegisterRequest();
req.setEmail("");
req.setPassword("password123");
req.setDisplayName("New User");
req.setRole("USER");
mockMvc.perform(post("/api/v1/auth/register")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isBadRequest());
verify(authService, never()).register(any());
}
@Test
@DisplayName("POST /api/v1/auth/register - password kurang dari 6 karakter harus return 400")
void register_shortPassword_shouldReturn400() throws Exception {
RegisterRequest req = new RegisterRequest();
req.setEmail("user@test.com");
req.setPassword("abc");
req.setDisplayName("User");
req.setRole("USER");
mockMvc.perform(post("/api/v1/auth/register")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isBadRequest());
verify(authService, never()).register(any());
}
@Test
@DisplayName("POST /api/v1/auth/register - format email tidak valid harus return 400")
void register_invalidEmailFormat_shouldReturn400() throws Exception {
RegisterRequest req = new RegisterRequest();
req.setEmail("bukan-email");
req.setPassword("password123");
req.setDisplayName("User");
req.setRole("USER");
mockMvc.perform(post("/api/v1/auth/register")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isBadRequest());
verify(authService, never()).register(any());
}
// ===== LOGIN =====
@Test
@DisplayName("POST /api/v1/auth/login - valid credentials harus return 200 dengan token")
void login_validCredentials_shouldReturn200() throws Exception {
LoginRequest req = new LoginRequest();
req.setEmail("user@test.com");
req.setPassword("password123");
when(authService.login(any(LoginRequest.class))).thenReturn(sampleAuthData);
mockMvc.perform(post("/api/v1/auth/login")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("Login berhasil"))
.andExpect(jsonPath("$.data.accessToken").value("access-token-xyz"))
.andExpect(jsonPath("$.data.userId").value(1));
verify(authService).login(any(LoginRequest.class));
}
@Test
@DisplayName("POST /api/v1/auth/login - service throw RuntimeException harus return 500")
void login_serviceThrows_shouldReturn500() throws Exception {
LoginRequest req = new LoginRequest();
req.setEmail("user@test.com");
req.setPassword("wrong");
when(authService.login(any(LoginRequest.class)))
.thenThrow(new RuntimeException("Password salah"));
mockMvc.perform(post("/api/v1/auth/login")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isInternalServerError());
}
// ===== REFRESH =====
@Test
@DisplayName("POST /api/v1/auth/refresh - token valid harus return token baru")
void refresh_validToken_shouldReturn200() throws Exception {
RefreshTokenRequest req = new RefreshTokenRequest();
req.setRefreshToken("valid-refresh-token");
AuthDataResponse newData = AuthDataResponse.builder()
.accessToken("new-access-token")
.refreshToken("valid-refresh-token")
.role("ROLE_USER")
.userId(1L)
.build();
when(authService.refreshToken("valid-refresh-token")).thenReturn(newData);
mockMvc.perform(post("/api/v1/auth/refresh")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("Token diperbarui"))
.andExpect(jsonPath("$.data.accessToken").value("new-access-token"));
verify(authService).refreshToken("valid-refresh-token");
}
// ===== LOGOUT =====
@Test
@DisplayName("POST /api/v1/auth/logout - authenticated user harus return 200")
@WithMockUser(username = "1", roles = "USER")
void logout_authenticated_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> securityHelper = mockStatic(SecurityHelper.class)) {
securityHelper.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
doNothing().when(authService).logout(1L);
mockMvc.perform(post("/api/v1/auth/logout")
.with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("Logout berhasil"));
verify(authService).logout(1L);
}
}
// ===== UPDATE FCM TOKEN =====
@Test
@DisplayName("PUT /api/v1/auth/fcm-token - authenticated user harus update FCM token")
@WithMockUser(username = "1", roles = "USER")
void updateFcmToken_authenticated_shouldReturn200() throws Exception {
try (MockedStatic<SecurityHelper> securityHelper = mockStatic(SecurityHelper.class)) {
securityHelper.when(SecurityHelper::getCurrentUserId).thenReturn(1L);
FcmTokenRequest req = new FcmTokenRequest();
req.setFcmToken("fcm-token-new-value");
doNothing().when(authService).updateFcmToken(eq(1L), eq("fcm-token-new-value"));
mockMvc.perform(put("/api/v1/auth/fcm-token")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(req)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("FCM token diperbarui"));
verify(authService).updateFcmToken(1L, "fcm-token-new-value");
}
}
}