diff --git a/backend/src/test/java/com/csed/knowtopia/controller/CourseCrudControllerTest.java b/backend/src/test/java/com/csed/knowtopia/controller/CourseCrudControllerTest.java new file mode 100644 index 0000000..343e948 --- /dev/null +++ b/backend/src/test/java/com/csed/knowtopia/controller/CourseCrudControllerTest.java @@ -0,0 +1,299 @@ +package com.csed.knowtopia.controller; + +import com.csed.knowtopia.dto.CourseDTO; +import com.csed.knowtopia.entity.Course; +import com.csed.knowtopia.entity.User; +import com.csed.knowtopia.repository.CourseRepository; +import com.csed.knowtopia.repository.ModuleRepository; +import com.csed.knowtopia.repository.LessonRepository; +import com.csed.knowtopia.repository.UserRepository; +import com.csed.knowtopia.service.JwtUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +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.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.time.LocalDate; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@SpringBootTest +@AutoConfigureMockMvc +public class CourseCrudControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + private ModuleRepository moduleRepository; + + @Autowired + private LessonRepository lessonRepository; + + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserRepository userRepository; + + @BeforeEach + public void prepareForTest() { + courseRepository.deleteAll(); + moduleRepository.deleteAll(); + lessonRepository.deleteAll(); + + Course course = new Course(); + course.setTitle("Test Course"); + course.setDescription("Description of test course"); + course.setCategory("Test Category"); + course.setRating(3.0f); + course.setCreationDate(LocalDate.now()); + courseRepository.save(course); + } + + @AfterEach + void cleanUp() { + courseRepository.deleteAll(); + userRepository.deleteAll(); + } + + private String mockTokenGenerate() { + userRepository.deleteAll(); + User user = new User(); + user.setUsername("Test User"); + user.setPassword("password"); + user.setEmail("testuser@example.com"); + user.setRole("USER"); + userRepository.save(user); + + return jwtUtil.generateToken(user.getUsername()); + } + + private String mockToken_2() { + User user = new User(); + user.setUsername("Test User 2"); + user.setPassword("password"); + user.setEmail("test12user@example.com"); + user.setRole("USER"); + userRepository.save(user); + + return jwtUtil.generateToken(user.getUsername()); + } + + private Long mockCourse(String token) { + Optional instructor = userRepository.findByUsername(jwtUtil.extractUsername(token)); + Course course = new Course(); + course.setTitle("Test Course"); + course.setDescription("Description of test course"); + course.setCategory("Test Category"); + course.setRating(3.0f); + course.setInstructor(instructor.get()); + course.setCreationDate(LocalDate.now()); + + courseRepository.save(course); + + return course.getId(); + } + + @Test + public void testCreateCourseSuccess() throws Exception { + CourseDTO courseDTO = new CourseDTO(); + courseDTO.setTitle("Spring Boot Basics"); + courseDTO.setCategory("Programming"); + String mockToken = mockTokenGenerate(); + courseDTO.setDescription("Learn Spring Boot step by step"); + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/create") + .header("Authorization", "Bearer " + mockToken) // Add the mock token + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(courseDTO))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Spring Boot Basics")) + .andExpect(MockMvcResultMatchers.jsonPath("$.description").value("Learn Spring Boot step by step")) + .andExpect(MockMvcResultMatchers.jsonPath("$.category").value("Programming")) + .andExpect(MockMvcResultMatchers.jsonPath("$.instructor.username").value("Test User")); + } + + @Test + public void testCreateCourseUnauthorized() throws Exception { + CourseDTO courseDTO = new CourseDTO(); + courseDTO.setTitle("Spring Boot Basics"); + courseDTO.setDescription("Learn Spring Boot step by step"); + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(courseDTO))) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testUpdateCourseDetailsSuccess() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + + CourseDTO updatedCourseDTO = new CourseDTO(); + updatedCourseDTO.setTitle("Updated Course Title"); + updatedCourseDTO.setDescription("Updated course description"); + updatedCourseDTO.setCategory("Updated Category"); + updatedCourseDTO.setRating(4.5f); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/" + courseId) + .header("Authorization", "Bearer " + mockToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updatedCourseDTO))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Updated Course Title")) + .andExpect(MockMvcResultMatchers.jsonPath("$.description").value("Updated course description")) + .andExpect(MockMvcResultMatchers.jsonPath("$.category").value("Updated Category")) + .andExpect(MockMvcResultMatchers.jsonPath("$.rating").value(3.0)); + } + + @Test + public void testUpdateCourseDetailsUnauthorized() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + + CourseDTO updatedCourseDTO = new CourseDTO(); + updatedCourseDTO.setTitle("Updated Course Title"); + updatedCourseDTO.setDescription("Updated course description"); + updatedCourseDTO.setCategory("Updated Category"); + updatedCourseDTO.setRating(4.5f); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/" + courseId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updatedCourseDTO))) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testUpdateCourseDetailsNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + + CourseDTO updatedCourseDTO = new CourseDTO(); + updatedCourseDTO.setTitle("Updated Course Title"); + updatedCourseDTO.setDescription("Updated course description"); + updatedCourseDTO.setCategory("Updated Category"); + updatedCourseDTO.setRating(4.5f); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/100000") + .header("Authorization", "Bearer " + mockToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updatedCourseDTO))) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + public void testUpdateCourseDetailsNotInstructor() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + + String mockToken2 = mockToken_2(); + CourseDTO updatedCourseDTO = new CourseDTO(); + updatedCourseDTO.setTitle("Updated Course Title"); + updatedCourseDTO.setDescription("Updated course description"); + updatedCourseDTO.setCategory("Updated Category"); + updatedCourseDTO.setRating(4.5f); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/" + courseId) + .header("Authorization", "Bearer " + mockToken2) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updatedCourseDTO))) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testDeleteCourseSuccess() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/" + courseId) // Assuming course ID 1 exists + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isOk()); + + // Verify the course is deleted + assertFalse(courseRepository.findById(1L).isPresent()); + + // Verify cascading deletion for associated modules and lessons + assertTrue(moduleRepository.findByCourseId(1L).isEmpty()); + } + + @Test + public void testDeleteCourseUnauthorized() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/" + courseId)) // Assuming course ID 1 exists + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testDeleteCourseNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/100000") + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + public void testDeleteNotInstructor() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + + String mockToken2 = mockToken_2(); + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/" + courseId) + .header("Authorization", "Bearer " + mockToken2)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testFetchCoursesByInstructorSuccess() throws Exception { + // Mocking token and user + String mockToken = mockTokenGenerate(); + + // Creating and assigning courses to the instructor + Long courseId1 = mockCourse(mockToken); + Long courseId2 = mockCourse(mockToken); + + mockMvc.perform(MockMvcRequestBuilders.get("/api/courses/instructor/fetch") + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(courseId1)) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].id").value(courseId2)) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].instructor.username").value("Test User")) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].instructor.username").value("Test User")); + } + + @Test + public void testFetchCoursesByInstructorUnauthorized() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/api/courses/instructor/fetch")) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testFetchCoursesByInstructorNoCourses() throws Exception { + // Mocking token and user + String mockToken = mockTokenGenerate(); + + mockMvc.perform(MockMvcRequestBuilders.get("/api/courses/instructor/fetch") + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isEmpty()); + } + +} \ No newline at end of file diff --git a/backend/src/test/java/com/csed/knowtopia/controller/LessonControllerTest.java b/backend/src/test/java/com/csed/knowtopia/controller/LessonControllerTest.java new file mode 100644 index 0000000..fdace5f --- /dev/null +++ b/backend/src/test/java/com/csed/knowtopia/controller/LessonControllerTest.java @@ -0,0 +1,345 @@ +package com.csed.knowtopia.controller; + +import com.csed.knowtopia.dto.LessonDTO; +import com.csed.knowtopia.entity.Lesson; +import com.csed.knowtopia.entity.Module; +import com.csed.knowtopia.entity.Course; +import com.csed.knowtopia.entity.User; +import com.csed.knowtopia.repository.LessonRepository; +import com.csed.knowtopia.repository.ModuleRepository; +import com.csed.knowtopia.repository.CourseRepository; +import com.csed.knowtopia.repository.UserRepository; +import com.csed.knowtopia.service.JwtUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +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.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +@SpringBootTest +@AutoConfigureMockMvc +public class LessonControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private UserRepository userRepository; + + @Autowired + private ModuleRepository moduleRepository; + + @Autowired + private LessonRepository lessonRepository; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private JwtUtil jwtUtil; + + @BeforeEach + public void prepareForTest() { + lessonRepository.deleteAll(); + moduleRepository.deleteAll(); + courseRepository.deleteAll(); + + Course course = new Course(); + course.setTitle("Test Course"); + course.setDescription("Description of test course"); + courseRepository.save(course); + + Module module = new Module(); + module.setTitle("Test Module"); + module.setCourse(course); + moduleRepository.save(module); + } + + @AfterEach + void cleanUp() { + courseRepository.deleteAll(); + userRepository.deleteAll(); + } + + private String mockTokenGenerate() { + userRepository.deleteAll(); + User user = new User(); + user.setUsername("Test User"); + user.setPassword("password"); + user.setEmail("testuser@example.com"); + user.setRole("USER"); + userRepository.save(user); + + return jwtUtil.generateToken(user.getUsername()); + } + + private String mockToken_2() { + User user = new User(); + user.setUsername("Test User 2"); + user.setPassword("password"); + user.setEmail("test12user@example.com"); + user.setRole("USER"); + userRepository.save(user); + + return jwtUtil.generateToken(user.getUsername()); + } + + private Long mockModule(String token) { + Optional instructor = userRepository.findByUsername(jwtUtil.extractUsername(token)); + Course course = new Course(); + course.setTitle("Test Course"); + course.setDescription("Description of test course"); + course.setInstructor(instructor.get()); + courseRepository.save(course); + + Module module = new Module(); + module.setTitle("Mock Module"); + module.setCourse(course); + moduleRepository.save(module); + return module.getId(); + } + + private Long mockLesson(Long moduleId) { + Optional module = moduleRepository.findById(moduleId); + Lesson lesson = new Lesson(); + lesson.setTitle("Mock Lesson"); + lesson.setOrderIndex(1); + lesson.setModule(module.get()); + lessonRepository.save(lesson); + return lesson.getId(); + } + + @Test + public void testCreateLessonSuccess() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("New Lesson"); + lessonDTO.setOrderIndex(1); + lessonDTO.setModuleId(moduleId); + + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/lessons/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("New Lesson")); + } + + @Test + public void testCreateLessonUnauthorized() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("New Lesson"); + lessonDTO.setOrderIndex(1); + lessonDTO.setModuleId(moduleId); + + String unauthorizedToken = mockToken_2(); + + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/lessons/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + unauthorizedToken)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testCreateLessonModuleNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("New Lesson"); + lessonDTO.setOrderIndex(1); + lessonDTO.setModuleId(moduleId + 1); + + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/lessons/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + public void testCreateLessonNotInstructor() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("New Lesson"); + lessonDTO.setOrderIndex(1); + lessonDTO.setModuleId(moduleId); + + String unauthorizedToken = mockToken_2(); + + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/lessons/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + unauthorizedToken)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testUpdateLessonSuccess() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("Updated Lesson"); + lessonDTO.setOrderIndex(2); + lessonDTO.setDescription("Updated description"); + lessonDTO.setModuleId(moduleId); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/lessons/" + lessonId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Updated Lesson")); + } + + @Test + public void testUpdateLessonInvalid() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("Updated Lesson"); + lessonDTO.setOrderIndex(-1); + lessonDTO.setDescription("Updated description"); + lessonDTO.setModuleId(moduleId); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/lessons/" + lessonId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("Validation failed")); + } + + @Test + public void testUpdateLessonUnauthorized() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("Updated Lesson"); + lessonDTO.setOrderIndex(2); + lessonDTO.setModuleId(moduleId); + + String unauthorizedToken = mockToken_2(); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/lessons/" + lessonId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + unauthorizedToken)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testUpdateLessonNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("Updated Lesson"); + lessonDTO.setOrderIndex(2); + lessonDTO.setModuleId(moduleId); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/lessons/" + (lessonId + 1)) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + public void testUpdateLessonNotInstructor() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + LessonDTO lessonDTO = new LessonDTO(); + lessonDTO.setTitle("Updated Lesson"); + lessonDTO.setOrderIndex(2); + lessonDTO.setModuleId(moduleId); + + String unauthorizedToken = mockToken_2(); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/lessons/" + lessonId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(lessonDTO)) + .header("Authorization", "Bearer " + unauthorizedToken)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testDeleteLessonSuccess() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/lessons/" + lessonId) + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isOk()); + + assertFalse(lessonRepository.findById(lessonId).isPresent()); + } + + @Test + public void testDeleteLessonUnauthorized() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + String unauthorizedToken = mockToken_2(); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/lessons/" + lessonId) + .header("Authorization", "Bearer " + unauthorizedToken)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testDeleteLessonNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/lessons/" + (lessonId + 1)) + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + public void testDeleteLessonNotInstructor() throws Exception { + String mockToken = mockTokenGenerate(); + Long moduleId = mockModule(mockToken); + Long lessonId = mockLesson(moduleId); + + String unauthorizedToken = mockToken_2(); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/lessons/" + lessonId) + .header("Authorization", "Bearer " + unauthorizedToken)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } +} \ No newline at end of file diff --git a/backend/src/test/java/com/csed/knowtopia/controller/ModuleControllerTest.java b/backend/src/test/java/com/csed/knowtopia/controller/ModuleControllerTest.java new file mode 100644 index 0000000..34b706f --- /dev/null +++ b/backend/src/test/java/com/csed/knowtopia/controller/ModuleControllerTest.java @@ -0,0 +1,345 @@ +package com.csed.knowtopia.controller; + +import com.csed.knowtopia.dto.ModuleDTO; +import com.csed.knowtopia.entity.Module; +import com.csed.knowtopia.entity.Course; +import com.csed.knowtopia.entity.User; +import com.csed.knowtopia.repository.ModuleRepository; +import com.csed.knowtopia.repository.CourseRepository; +import com.csed.knowtopia.repository.UserRepository; +import com.csed.knowtopia.service.JwtUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +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.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.time.LocalDate; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +@SpringBootTest +@AutoConfigureMockMvc +public class ModuleControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private UserRepository userRepository; + + @Autowired + private ModuleRepository moduleRepository; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private JwtUtil jwtUtil; + + @BeforeEach + public void prepareForTest() { + moduleRepository.deleteAll(); + courseRepository.deleteAll(); + + Course course = new Course(); + course.setTitle("Test Course"); + course.setDescription("Description of test course"); + courseRepository.save(course); + + Module module = new Module(); + module.setTitle("Test Module"); + module.setCourse(course); + moduleRepository.save(module); + } + + @AfterEach + void cleanUp() { + courseRepository.deleteAll(); + userRepository.deleteAll(); + } + + private String mockTokenGenerate() { + userRepository.deleteAll(); + User user = new User(); + user.setUsername("Test User"); + user.setPassword("password"); + user.setEmail("testuser@example.com"); + user.setRole("USER"); + userRepository.save(user); + + return jwtUtil.generateToken(user.getUsername()); + } + + private String mockToken_2() { + User user = new User(); + user.setUsername("Test User 2"); + user.setPassword("password"); + user.setEmail("test12user@example.com"); + user.setRole("USER"); + userRepository.save(user); + + return jwtUtil.generateToken(user.getUsername()); + } + + private Long mockCourse(String token) { + Optional instructor = userRepository.findByUsername(jwtUtil.extractUsername(token)); + Course course = new Course(); + course.setTitle("Test Course"); + course.setDescription("Description of test course"); + course.setCategory("Test Category"); + course.setRating(3.0f); + course.setInstructor(instructor.get()); + course.setCreationDate(LocalDate.now()); + + courseRepository.save(course); + + return course.getId(); + } + + private Long mockModule(Long courseId) { + Optional course = courseRepository.findById(courseId); + Module module = new Module(); + module.setTitle("Mock Module"); + module.setCourse(course.get()); + moduleRepository.save(module); + return module.getId(); + } + + @Test + public void testCreateModuleSuccess() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + ModuleDTO moduleDTO = new ModuleDTO(); + moduleDTO.setTitle("New Module"); + moduleDTO.setCourseId(courseId); + + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/modules/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(moduleDTO)) + .header("Authorization", "Bearer " + jwtUtil.generateToken("Test User"))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("New Module")); + } + + @Test + public void testCreateModuleUnauthorized(){ + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + ModuleDTO moduleDTO = new ModuleDTO(); + moduleDTO.setTitle("New Module"); + moduleDTO.setCourseId(courseId); + String mockToken2 = mockToken_2(); + try { + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/modules/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(moduleDTO)) + .header("Authorization", "Bearer " + mockToken2)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void testCreateModuleCourseNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + ModuleDTO moduleDTO = new ModuleDTO(); + moduleDTO.setTitle("New Module"); + moduleDTO.setCourseId(1L); + + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/modules/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(moduleDTO)) + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + public void testCreateModuleNotInstructor() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + ModuleDTO moduleDTO = new ModuleDTO(); + moduleDTO.setTitle("New Module"); + moduleDTO.setCourseId(courseId); + String mockToken2 = mockToken_2(); + mockMvc.perform(MockMvcRequestBuilders.post("/api/courses/modules/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(moduleDTO)) + .header("Authorization", "Bearer " + mockToken2)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testUpdateModuleSuccess() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + Long moduleId = mockModule(courseId); + + ModuleDTO updatedModuleDTO = new ModuleDTO(); + updatedModuleDTO.setTitle("Updated Module Title"); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/modules/" + moduleId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updatedModuleDTO)) + .header("Authorization", "Bearer " + jwtUtil.generateToken("Test User"))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Updated Module Title")); + } + + @Test + public void testUpdateModuleUnauthorized() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + Long moduleId = mockModule(courseId); + + ModuleDTO updatedModuleDTO = new ModuleDTO(); + updatedModuleDTO.setTitle("Updated Module Title"); + + String mockToken2 = mockToken_2(); + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/modules/" + moduleId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updatedModuleDTO)) + .header("Authorization", "Bearer " + mockToken2)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testUpdateModuleNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + mockModule(courseId); + + ModuleDTO updatedModuleDTO = new ModuleDTO(); + updatedModuleDTO.setTitle("Updated Module Title"); + + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/modules/" + 100) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updatedModuleDTO)) + .header("Authorization", "Bearer " + jwtUtil.generateToken("Test User"))) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + public void testUpdateModuleNotInstructor() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + Long moduleId = mockModule(courseId); + + ModuleDTO updatedModuleDTO = new ModuleDTO(); + updatedModuleDTO.setTitle("Updated Module Title"); + + String mockToken2 = mockToken_2(); + mockMvc.perform(MockMvcRequestBuilders.put("/api/courses/modules/" + moduleId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(updatedModuleDTO)) + .header("Authorization", "Bearer " + mockToken2)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testDeleteModuleSuccess() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + Long moduleId = mockModule(courseId); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/modules/" + moduleId) + .header("Authorization", "Bearer " + jwtUtil.generateToken("Test User"))) + .andExpect(MockMvcResultMatchers.status().isOk()); + + assertFalse(moduleRepository.findById(moduleId).isPresent()); + } + + @Test + public void testDeleteModuleUnauthorized() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + Long moduleId = mockModule(courseId); + + String mockToken2 = mockToken_2(); + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/modules/" + moduleId) + .header("Authorization", "Bearer " + mockToken2)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testDeleteModuleNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + mockModule(courseId); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/modules/" + 100) + .header("Authorization", "Bearer " + jwtUtil.generateToken("Test User"))) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + public void testDeleteModuleCourseNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + Long moduleId = mockModule(courseId); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/modules/" + moduleId) + .header("Authorization", "Bearer " + jwtUtil.generateToken("Test User"))) + .andExpect(MockMvcResultMatchers.status().isOk()); + + assertFalse(moduleRepository.findById(moduleId).isPresent()); + } + + @Test + public void testDeleteModuleNotInstructor() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + Long moduleId = mockModule(courseId); + + String mockToken2 = mockToken_2(); + mockMvc.perform(MockMvcRequestBuilders.delete("/api/courses/modules/" + moduleId) + .header("Authorization", "Bearer " + mockToken2)) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testGetCourseModulesSuccess() throws Exception { + // Mocking a course and modules + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + mockModule(courseId); + + mockMvc.perform(MockMvcRequestBuilders.get("/api/courses/modules/" + courseId + "/all") + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.courseId").value(courseId)) + .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Test Course")) + .andExpect(MockMvcResultMatchers.jsonPath("$.modules").isArray()) + .andExpect(MockMvcResultMatchers.jsonPath("$.modules[0].title").value("Mock Module")); + } + + @Test + public void testGetCourseModulesUnauthorized() throws Exception { + String mockToken = mockTokenGenerate(); + Long courseId = mockCourse(mockToken); + + mockMvc.perform(MockMvcRequestBuilders.get("/api/courses/modules/" + courseId + "/all")) + .andExpect(MockMvcResultMatchers.status().isUnauthorized()); + } + + @Test + public void testGetCourseModulesNotFound() throws Exception { + String mockToken = mockTokenGenerate(); + + mockMvc.perform(MockMvcRequestBuilders.get("/api/courses/modules/9999/all") + .header("Authorization", "Bearer " + mockToken)) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } +} \ No newline at end of file