diff --git a/pom.xml b/pom.xml index adf3f5cda..d5de2d04f 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,11 @@ lombok true + + org.springframework.boot + spring-boot-starter-test + test + diff --git a/src/test/java/com/openisle/controller/AdminControllerTest.java b/src/test/java/com/openisle/controller/AdminControllerTest.java new file mode 100644 index 000000000..e50c82cb3 --- /dev/null +++ b/src/test/java/com/openisle/controller/AdminControllerTest.java @@ -0,0 +1,25 @@ +package com.openisle.controller; + +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.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(AdminController.class) +@AutoConfigureMockMvc(addFilters = false) +class AdminControllerTest { + @Autowired + private MockMvc mockMvc; + + @Test + void adminHelloReturnsMessage() throws Exception { + mockMvc.perform(get("/api/admin/hello")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("Hello, Admin User")); + } +} diff --git a/src/test/java/com/openisle/controller/AuthControllerTest.java b/src/test/java/com/openisle/controller/AuthControllerTest.java new file mode 100644 index 000000000..cdc73798d --- /dev/null +++ b/src/test/java/com/openisle/controller/AuthControllerTest.java @@ -0,0 +1,90 @@ +package com.openisle.controller; + +import com.openisle.model.User; +import com.openisle.service.EmailService; +import com.openisle.service.JwtService; +import com.openisle.service.UserService; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.Map; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(AuthController.class) +@AutoConfigureMockMvc(addFilters = false) +class AuthControllerTest { + @Autowired + private MockMvc mockMvc; + + @MockBean + private UserService userService; + @MockBean + private JwtService jwtService; + @MockBean + private EmailService emailService; + + @Test + void registerSendsEmail() throws Exception { + User user = new User(); + user.setEmail("a@b.com"); + user.setUsername("u"); + user.setVerificationCode("123456"); + Mockito.when(userService.register(eq("u"), eq("a@b.com"), eq("p"))).thenReturn(user); + + mockMvc.perform(post("/api/auth/register") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"username\":\"u\",\"email\":\"a@b.com\",\"password\":\"p\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + + Mockito.verify(emailService).sendEmail(eq("a@b.com"), any(), any()); + } + + @Test + void verifyCodeEndpoint() throws Exception { + Mockito.when(userService.verifyCode("u", "123")).thenReturn(true); + + mockMvc.perform(post("/api/auth/verify") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"username\":\"u\",\"code\":\"123\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("Verified")); + } + + @Test + void loginReturnsToken() throws Exception { + User user = new User(); + user.setUsername("u"); + Mockito.when(userService.authenticate("u", "p")).thenReturn(Optional.of(user)); + Mockito.when(jwtService.generateToken("u")).thenReturn("token"); + + mockMvc.perform(post("/api/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"username\":\"u\",\"password\":\"p\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.token").value("token")); + } + + @Test + void loginFails() throws Exception { + Mockito.when(userService.authenticate("u", "bad")).thenReturn(Optional.empty()); + + mockMvc.perform(post("/api/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"username\":\"u\",\"password\":\"bad\"}")) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.error").value("Invalid credentials or user not verified")); + } +} diff --git a/src/test/java/com/openisle/controller/CommentControllerTest.java b/src/test/java/com/openisle/controller/CommentControllerTest.java new file mode 100644 index 000000000..228b84543 --- /dev/null +++ b/src/test/java/com/openisle/controller/CommentControllerTest.java @@ -0,0 +1,77 @@ +package com.openisle.controller; + +import com.openisle.model.Comment; +import com.openisle.model.Post; +import com.openisle.model.User; +import com.openisle.service.CommentService; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.test.web.servlet.MockMvc; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.mockito.ArgumentMatchers.eq; +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.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(CommentController.class) +@AutoConfigureMockMvc(addFilters = false) +class CommentControllerTest { + @Autowired + private MockMvc mockMvc; + + @MockBean + private CommentService commentService; + + private Comment createComment(Long id, String content, String authorName) { + User user = new User(); + user.setUsername(authorName); + Comment c = new Comment(); + c.setId(id); + c.setContent(content); + c.setCreatedAt(LocalDateTime.now()); + c.setAuthor(user); + c.setPost(new Post()); + return c; + } + + @Test + void createAndListComments() throws Exception { + Comment comment = createComment(1L, "hi", "bob"); + Mockito.when(commentService.addComment(eq("bob"), eq(1L), eq("hi"))).thenReturn(comment); + Mockito.when(commentService.getCommentsForPost(1L)).thenReturn(List.of(comment)); + Mockito.when(commentService.getReplies(1L)).thenReturn(List.of()); + + mockMvc.perform(post("/api/posts/1/comments") + .contentType("application/json") + .content("{\"content\":\"hi\"}") + .principal(new UsernamePasswordAuthenticationToken("bob", "p"))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.content").value("hi")); + + mockMvc.perform(get("/api/posts/1/comments")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].id").value(1)); + } + + @Test + void replyComment() throws Exception { + Comment reply = createComment(2L, "re", "alice"); + Mockito.when(commentService.addReply(eq("alice"), eq(1L), eq("re"))).thenReturn(reply); + + mockMvc.perform(post("/api/comments/1/replies") + .contentType("application/json") + .content("{\"content\":\"re\"}") + .principal(new UsernamePasswordAuthenticationToken("alice", "p"))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(2)); + } +} diff --git a/src/test/java/com/openisle/controller/HelloControllerTest.java b/src/test/java/com/openisle/controller/HelloControllerTest.java new file mode 100644 index 000000000..9a9769b91 --- /dev/null +++ b/src/test/java/com/openisle/controller/HelloControllerTest.java @@ -0,0 +1,25 @@ +package com.openisle.controller; + +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.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(HelloController.class) +@AutoConfigureMockMvc(addFilters = false) +class HelloControllerTest { + @Autowired + private MockMvc mockMvc; + + @Test + void helloReturnsMessage() throws Exception { + mockMvc.perform(get("/api/hello")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").value("Hello, Authenticated User")); + } +} diff --git a/src/test/java/com/openisle/controller/PostControllerTest.java b/src/test/java/com/openisle/controller/PostControllerTest.java new file mode 100644 index 000000000..9f027216e --- /dev/null +++ b/src/test/java/com/openisle/controller/PostControllerTest.java @@ -0,0 +1,75 @@ +package com.openisle.controller; + +import com.openisle.model.Post; +import com.openisle.model.User; +import com.openisle.service.PostService; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.test.web.servlet.MockMvc; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +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.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(PostController.class) +@AutoConfigureMockMvc(addFilters = false) +class PostControllerTest { + @Autowired + private MockMvc mockMvc; + + @MockBean + private PostService postService; + + @Test + void createAndGetPost() throws Exception { + User user = new User(); + user.setUsername("alice"); + Post post = new Post(); + post.setId(1L); + post.setTitle("t"); + post.setContent("c"); + post.setCreatedAt(LocalDateTime.now()); + post.setAuthor(user); + Mockito.when(postService.createPost(eq("alice"), eq("t"), eq("c"))).thenReturn(post); + Mockito.when(postService.getPost(1L)).thenReturn(post); + + mockMvc.perform(post("/api/posts") + .contentType("application/json") + .content("{\"title\":\"t\",\"content\":\"c\"}") + .principal(new UsernamePasswordAuthenticationToken("alice", "p"))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.title").value("t")); + + mockMvc.perform(get("/api/posts/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(1)); + } + + @Test + void listPosts() throws Exception { + User user = new User(); + user.setUsername("bob"); + Post post = new Post(); + post.setId(2L); + post.setTitle("hello"); + post.setContent("world"); + post.setCreatedAt(LocalDateTime.now()); + post.setAuthor(user); + Mockito.when(postService.listPosts()).thenReturn(List.of(post)); + + mockMvc.perform(get("/api/posts")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].title").value("hello")); + } +} diff --git a/src/test/java/com/openisle/controller/ReactionControllerTest.java b/src/test/java/com/openisle/controller/ReactionControllerTest.java new file mode 100644 index 000000000..8faaef469 --- /dev/null +++ b/src/test/java/com/openisle/controller/ReactionControllerTest.java @@ -0,0 +1,73 @@ +package com.openisle.controller; + +import com.openisle.model.Comment; +import com.openisle.model.Post; +import com.openisle.model.Reaction; +import com.openisle.model.ReactionType; +import com.openisle.model.User; +import com.openisle.service.ReactionService; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +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.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.test.web.servlet.MockMvc; + +import static org.mockito.ArgumentMatchers.eq; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(ReactionController.class) +@AutoConfigureMockMvc(addFilters = false) +class ReactionControllerTest { + @Autowired + private MockMvc mockMvc; + + @MockBean + private ReactionService reactionService; + + @Test + void reactToPost() throws Exception { + User user = new User(); + user.setUsername("u1"); + Post post = new Post(); + post.setId(1L); + Reaction reaction = new Reaction(); + reaction.setId(1L); + reaction.setUser(user); + reaction.setPost(post); + reaction.setType(ReactionType.LIKE); + Mockito.when(reactionService.reactToPost(eq("u1"), eq(1L), eq(ReactionType.LIKE))).thenReturn(reaction); + + mockMvc.perform(post("/api/posts/1/reactions") + .contentType("application/json") + .content("{\"type\":\"LIKE\"}") + .principal(new UsernamePasswordAuthenticationToken("u1", "p"))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.postId").value(1)); + } + + @Test + void reactToComment() throws Exception { + User user = new User(); + user.setUsername("u2"); + Comment comment = new Comment(); + comment.setId(2L); + Reaction reaction = new Reaction(); + reaction.setId(2L); + reaction.setUser(user); + reaction.setComment(comment); + reaction.setType(ReactionType.RECOMMEND); + Mockito.when(reactionService.reactToComment(eq("u2"), eq(2L), eq(ReactionType.RECOMMEND))).thenReturn(reaction); + + mockMvc.perform(post("/api/comments/2/reactions") + .contentType("application/json") + .content("{\"type\":\"RECOMMEND\"}") + .principal(new UsernamePasswordAuthenticationToken("u2", "p"))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.commentId").value(2)); + } +}