diff --git a/spring-security-modules/spring-security-web-boot-3/pom.xml b/spring-security-modules/spring-security-web-boot-3/pom.xml index 1fff259c16..9d09d60611 100644 --- a/spring-security-modules/spring-security-web-boot-3/pom.xml +++ b/spring-security-modules/spring-security-web-boot-3/pom.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-security-web-boot-3 0.0.1-SNAPSHOT @@ -25,6 +25,20 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-test + test + + + org.apache.commons + commons-lang3 + + + org.springframework.security + spring-security-test + test + \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java new file mode 100644 index 0000000000..e7d6d823a6 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.httpfirewall; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HttpFirewallApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(HttpFirewallApplication.class); + application.setAdditionalProfiles("httpfirewall"); + application.run(args); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java new file mode 100644 index 0000000000..3147b962a3 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/HttpFirewallConfiguration.java @@ -0,0 +1,48 @@ +package com.baeldung.httpfirewall; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.firewall.HttpFirewall; +import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler; +import org.springframework.security.web.firewall.RequestRejectedHandler; +import org.springframework.security.web.firewall.StrictHttpFirewall; + +import java.util.Arrays; + +@Configuration +public class HttpFirewallConfiguration extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + //@formatter:off + http + .csrf() + .disable() + .authorizeRequests() + .antMatchers("/error") + .permitAll() + .anyRequest() + .authenticated() + .and() + .httpBasic(); + //@formatter:on + } + + @Bean + public HttpFirewall configureFirewall() { + StrictHttpFirewall strictHttpFirewall = new StrictHttpFirewall(); + strictHttpFirewall.setAllowedHttpMethods(Arrays.asList("GET", "POST", "DELETE", "OPTIONS")); // Allow only HTTP GET, POST, DELETE and OPTIONS methods + return strictHttpFirewall; + } + + /* + Use this bean if you are using Spring Security 5.4 and above + */ + @Bean + public RequestRejectedHandler requestRejectedHandler() { + return new HttpStatusRequestRejectedHandler(); // Default status code is 400. Can be customized + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java new file mode 100644 index 0000000000..9bed81bb8f --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/api/UserApi.java @@ -0,0 +1,59 @@ +package com.baeldung.httpfirewall.api; + +import com.baeldung.httpfirewall.model.Response; +import com.baeldung.httpfirewall.model.User; +import com.baeldung.httpfirewall.service.UserServiceImpl; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/api/v1/users") +public class UserApi { + + private final UserServiceImpl userServiceImpl; + + public UserApi(UserServiceImpl userServiceImpl) { + this.userServiceImpl = userServiceImpl; + } + + @PostMapping + public ResponseEntity createUser(@RequestBody User user) { + if (StringUtils.isBlank(user.getId())) { + user.setId(UUID.randomUUID().toString()); + } + userServiceImpl.saveUser(user); + Response response = new Response(HttpStatus.CREATED.value(), "User created successfully", System.currentTimeMillis()); + URI location = URI.create("/users/" + user.getId()); + return ResponseEntity.created(location).body(response); + } + + @GetMapping("/{userId}") + public User getUser(@PathVariable("userId") String userId) { + return userServiceImpl.findById(userId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No user exists with the given Id")); + } + + @GetMapping() + public List getAllUsers() { + return userServiceImpl.findAll().orElse(new ArrayList<>()); + } + + @DeleteMapping("/{userId}") + public ResponseEntity deleteUser(@PathVariable("userId") String userId) { + userServiceImpl.deleteUser(userId); + return ResponseEntity.ok(new Response(200, "The user has been deleted successfully", System.currentTimeMillis())); + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java new file mode 100644 index 0000000000..fb89abf17d --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/dao/InMemoryUserDao.java @@ -0,0 +1,65 @@ +package com.baeldung.httpfirewall.dao; + +import com.baeldung.httpfirewall.model.User; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Repository +public class InMemoryUserDao { + private Map map = new HashMap<>(); + + /** + * Persists the user. The user is store in an In-Memory store (a HashMap) + * The default implementation is an In-Memory persistence + * @param user The user that should be persisted + */ + + public void save(User user) { + map.put(user.getId(), user); + } + + /** + * Finds the user from the in-memory data store. + * The default implementation is an In-Memory persistence + * + * @param userId The ID of the user that has to be fetched + * @return An optional of the requested user + */ + public Optional findById(String userId) { + return Optional.ofNullable(map.get(userId)); + } + + /** + * Finds all the users from the in-memory data store + * The default implementation is an In-Memory persistence + */ + + public Optional> findAll() { + return Optional.of(new ArrayList<>(map.values())); + } + + /** + * Delete the user from the data store + * The default implementation is an In-Memory persistence + * @param userId The user that has to be deleted + */ + + public void delete(String userId) { + map.remove(userId); + } + + /** + * Checks if the user exists + * The default implementation is an In-Memory persistence + * @param userId The user that has to be checked for + */ + + public boolean isExists(String userId) { + return map.containsKey(userId); + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java new file mode 100644 index 0000000000..ba1c8d5dea --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/Response.java @@ -0,0 +1,40 @@ +package com.baeldung.httpfirewall.model; + +public class Response { + private int code; + private String message; + private long timestamp; + + public Response() { + } + + public Response(int code, String message, long timestamp) { + this.code = code; + this.message = message; + this.timestamp = timestamp; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java new file mode 100644 index 0000000000..5807a990e7 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/model/User.java @@ -0,0 +1,41 @@ +package com.baeldung.httpfirewall.model; + +public class User { + private String id; + private String username; + private String email; + + public User() { + } + + public User(String id, String username, String email) { + this.id = id; + this.username = username; + this.email = email; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java new file mode 100644 index 0000000000..d3d3f20f3d --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/java/com/baeldung/httpfirewall/service/UserServiceImpl.java @@ -0,0 +1,51 @@ +package com.baeldung.httpfirewall.service; + +import com.baeldung.httpfirewall.dao.InMemoryUserDao; +import com.baeldung.httpfirewall.model.User; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class UserServiceImpl { + + private final InMemoryUserDao inMemoryUserDao; + + public UserServiceImpl(InMemoryUserDao inMemoryUserDao) { + this.inMemoryUserDao = inMemoryUserDao; + } + + /** + * Creates a user. Checks if the user already exists and then persists the user + * @param user The user that is to be persisted into the store + */ + public void saveUser(User user) { + inMemoryUserDao.save(user); + } + + /** + * Get a user. Returns a user + * + * @param userId The user that has to be fetched form the repository + */ + public Optional findById(String userId) { + return inMemoryUserDao.findById(userId); + } + + /** + * Fetch all the users in the store + * @return A list of all the users + */ + public Optional> findAll() { + return inMemoryUserDao.findAll(); + } + + /** + * Delete the user with a given id + * @param userId The identifier of the user + */ + public void deleteUser(String userId) { + inMemoryUserDao.delete(userId); + } +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties b/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties new file mode 100644 index 0000000000..cb7e159bf3 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/main/resources/application-httpfirewall.properties @@ -0,0 +1,2 @@ +spring.security.user.name=user +spring.security.user.password=password \ No newline at end of file diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java new file mode 100644 index 0000000000..4b4a9a40ce --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiLiveTest.java @@ -0,0 +1,114 @@ +package com.baeldung.httpfirewall.api; + +import com.baeldung.httpfirewall.model.User; + +import com.baeldung.httpfirewall.service.UserServiceImpl; +import com.baeldung.httpfirewall.utility.UserTestUtility; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; + +@SpringBootTest +@AutoConfigureMockMvc +@DisplayName("User API Live Tests") +class UserApiLiveTest { + + private final String userId = "1"; + + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + + @BeforeEach + void setup() throws Exception { + //@formatter:off + mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithId(userId))) + .contentType("application/json")); + //@formatter:on + } + + @Test + @WithMockUser + @DisplayName("LiveTest User Creation") + void givenCredentials_whenHttpPost_thenReturn201() throws Exception { + // @formatter:off + MvcResult result = mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithId("200"))) + .contentType("application/json")) + .andDo(print()) + .andExpect(header().exists("Location")).andReturn(); + + assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); + // @formatter:on + mockMvc.perform(delete("/api/v1/users/" + 200).contentType("application/json")); + } + + @Test + @WithMockUser + @DisplayName("LiveTest Get User") + void givenCredentials_whenHttpGetById_thenReturnUser() throws Exception { + // @formatter:off + MvcResult result=mockMvc + .perform(get("/api/v1/users/"+userId) + .contentType("application/json")).andReturn(); + // @formatter:on + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertEquals(userId, objectMapper.readValue(result.getResponse().getContentAsString(), User.class).getId()); + } + + @Test + @WithMockUser + @DisplayName("LiveTest Get All Users") + void givenCredentials_whenHttpGet_thenReturnAllUsers() throws Exception { + // @formatter:off + MvcResult result=mockMvc + .perform(get("/api/v1/users/") + .contentType("application/json")).andReturn(); + // @formatter:on + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertNotNull(result.getResponse().getContentAsString()); + + List users = objectMapper.readValue(result.getResponse().getContentAsString(), objectMapper.getTypeFactory().constructCollectionType(List.class, User.class)); + + assertEquals(1, users.size()); + } + + @Test + @WithMockUser + @DisplayName("LiveTest Delete User") + void givenCredentials_whenHttpDelete_thenDeleteUser() throws Exception { + // @formatter:off + MvcResult result=mockMvc + .perform(delete("/api/v1/users/"+userId) + .contentType("application/json")).andReturn(); + // @formatter:on + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertNotNull(result.getResponse().getContentAsString()); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java new file mode 100644 index 0000000000..4f6217ade2 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/api/UserApiUnitTest.java @@ -0,0 +1,161 @@ +package com.baeldung.httpfirewall.api; + +import com.baeldung.httpfirewall.model.User; +import com.baeldung.httpfirewall.service.UserServiceImpl; +import com.baeldung.httpfirewall.utility.UserTestUtility; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +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 org.springframework.http.HttpStatus; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; + +@WebMvcTest +@AutoConfigureMockMvc +@DisplayName("User API Unit Tests") +class UserApiUnitTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserServiceImpl userService; + + @Autowired + private ObjectMapper objectMapper; + + @Test + @DisplayName("Test to Check Authentication") + void whenNoAuthentication_thenThrow401() throws Exception { + // @formatter:off + MvcResult result = mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) + .contentType("application/json")) + .andReturn(); + assertEquals(HttpStatus.UNAUTHORIZED.value(), result.getResponse().getStatus()); + // @formatter:off + } + + @Test + @WithMockUser + @DisplayName("Test Malicious URL") + void givenCredentials_whenMaliciousUrl_thenThrowRequestRejectedException() throws Exception { + // @formatter:off + MvcResult result = mockMvc + .perform(post("/api/v1\\users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) + .contentType("application/json")) + .andDo(print()) + .andReturn(); + assertEquals(HttpStatus.BAD_REQUEST.value(), result.getResponse().getStatus()); + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test User Create") + void givenCredentials_whenHttpPost_thenReturn201() throws Exception { + // @formatter:off + doNothing().when(userService).saveUser(new User()); + + MvcResult result=mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUser())) + .contentType("application/json")) + .andDo(print()) + .andExpect(header().exists("Location")).andReturn(); + assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test User Create Without ID") + void givenCredentials_whenHttpPostWithId_thenReturn201() throws Exception { + // @formatter:off + doNothing().when(userService).saveUser(new User()); + + MvcResult result = mockMvc + .perform(post("/api/v1/users") + .content(objectMapper.writeValueAsString(UserTestUtility.createUserWithoutId())) + .contentType("application/json")) + .andDo(print()) + .andExpect(header().exists("Location")).andReturn(); + assertEquals(HttpStatus.CREATED.value(), result.getResponse().getStatus()); + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test Get User") + void givenCredentials_whenHttpGetWithId_thenReturnUser() throws Exception { + String userId = "1"; + // @formatter:off + when(userService.findById("1")).thenReturn(UserTestUtility.createUserWithId(userId)); + + MvcResult result = mockMvc + .perform(get("/api/v1/users/"+userId) + .accept("application/json")) + .andDo(print()) + .andReturn(); + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertEquals("jhondoe",objectMapper.readValue(result.getResponse().getContentAsString(), User.class).getUsername()); + + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test Get All Users") + void givenCredentials_whenHttpGetWithoutId_thenReturnAllUsers() throws Exception { + // @formatter:off + when(userService.findAll()).thenReturn(UserTestUtility.createUsers()); + + MvcResult result = mockMvc + .perform(get("/api/v1/users/") + .accept("application/json")) + .andDo(print()) + .andReturn(); + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertTrue(result.getResponse().getContentAsString().contains("jane.doe")); + // @formatter:on + } + + @Test + @WithMockUser + @DisplayName("Test Delete a User") + void givenCredentials_whenHttpDelete_thenDeleteUser() throws Exception { + String userId = "1"; + doNothing().when(userService).deleteUser(userId); + // @formatter:off + MvcResult result = mockMvc + .perform(delete("/api/v1/users/"+userId) + .accept("application/json")) + .andDo(print()) + .andReturn(); + assertEquals(HttpStatus.OK.value(), result.getResponse().getStatus()); + assertNotNull(result.getResponse()); + assertTrue(result.getResponse().getContentAsString().contains("The user has been deleted successfully")); + // @formatter:on + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java new file mode 100644 index 0000000000..4a58312c0f --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/service/UserServiceUnitTest.java @@ -0,0 +1,92 @@ +package com.baeldung.httpfirewall.service; + +import com.baeldung.httpfirewall.dao.InMemoryUserDao; + +import com.baeldung.httpfirewall.model.User; +import com.baeldung.httpfirewall.utility.UserTestUtility; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@DisplayName("UserService Unit Tests") +class UserServiceUnitTest { + + @InjectMocks + private UserServiceImpl userService; + + @Mock + private InMemoryUserDao userDao; + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + @DisplayName("Check Create User") + void whenCalledCreateUser_thenVerify() { + User user = UserTestUtility.createUser(); + doNothing().when(userDao).save(user); + + userService.saveUser(user); + verify(userDao, times(1)).save(user); + } + + + + @Test + @DisplayName("Check Get User") + void givenUserId_whenCalledFindById_thenReturnUser() { + User user = UserTestUtility.createUserWithId("1").orElse(new User("1", "jhondoe", "jhon.doe@gmail.com")); + + when(userDao.findById(user.getId())).thenReturn(Optional.of(user)); + + User actualUser = userService.findById("1").get(); + + assertNotNull(actualUser); + assertEquals("jhondoe", actualUser.getUsername()); + verify(userDao, times(1)).findById(user.getId()); + } + + @Test + @DisplayName("Check Get All Users") + void whenCalledFindAll_thenReturnAllUsers() { + List users = UserTestUtility.createUsers().orElse(new ArrayList<>()); + + when(userDao.findAll()).thenReturn(Optional.of(users)); + + Optional> actualUsers = userService.findAll(); + + assertNotNull(actualUsers); + assertEquals(2, users.size()); + verify(userDao, times(1)).findAll(); + } + + @Test + @DisplayName("Check Delete Users") + void givenId_whenCalledDeleteUser_thenDeleteUser() { + User user = UserTestUtility.createUserWithId("1").orElse(new User()); + + doNothing().when(userDao).delete(user.getId()); + userService.deleteUser(user.getId()); + verify(userDao, times(1)).delete(user.getId()); + } + +} diff --git a/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java new file mode 100644 index 0000000000..77953a5176 --- /dev/null +++ b/spring-security-modules/spring-security-web-boot-3/src/test/java/com/baeldung/httpfirewall/utility/UserTestUtility.java @@ -0,0 +1,33 @@ +package com.baeldung.httpfirewall.utility; + +import com.baeldung.httpfirewall.model.User; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public class UserTestUtility { + public static User createUser() { + return new User(UUID.randomUUID().toString(),"jhondoe", "jhondoe@gmail.com"); + } + + public static User createUserWithoutId() { + return new User("","jhondoe", "jhondoe@gmail.com"); + } + + public static Optional createUserWithId(String id) { + // @formatter:off + return Optional.of(new User(id, "jhondoe", "jhon.doe@gmail.com")); + // @formatter:on + } + + public static Optional> createUsers() { + // @formatter:off + return Optional.of(Arrays.asList( + new User(UUID.randomUUID().toString(), "jhondoe","jhon.doe@gmail.com" ), + new User(UUID.randomUUID().toString(), "janedoe","jane.doe@gmail.com" )) + ); + // @formatter:on + } +}