diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 1425ea0..1bc475e 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -40,4 +40,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: Package - path: build/libs \ No newline at end of file + path: build/libs diff --git a/build.gradle b/build.gradle index 7a4365e..3e06b89 100644 --- a/build.gradle +++ b/build.gradle @@ -49,6 +49,8 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api' // https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine testImplementation 'org.junit.jupiter:junit-jupiter-engine' + // https://mvnrepository.com/artifact/com.h2database/h2 + testImplementation 'com.h2database:h2' // https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api diff --git a/src/main/java/com/booleanuk/cohorts/controllers/AuthController.java b/src/main/java/com/booleanuk/cohorts/controllers/AuthController.java index 52951fd..a1f5fdb 100644 --- a/src/main/java/com/booleanuk/cohorts/controllers/AuthController.java +++ b/src/main/java/com/booleanuk/cohorts/controllers/AuthController.java @@ -92,31 +92,7 @@ public ResponseEntity registerUser(@Valid @RequestBody SignupRequest signupRe // Create a new user add salt here if using one User user = new User(signupRequest.getEmail(), encoder.encode(signupRequest.getPassword())); - Set strRoles = signupRequest.getRole(); - Set roles = new HashSet<>(); - - if (strRoles == null) { - Role studentRole = roleRepository.findByName(ERole.ROLE_STUDENT).orElseThrow(() -> new RuntimeException("Error: Role is not found")); - roles.add(studentRole); - } else { - strRoles.forEach((role) -> { - switch (role) { - case "admin": - Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN).orElseThrow(() -> new RuntimeException("Error: Role is not found")); - roles.add(adminRole); - break; - case "teacher": - Role teacherRole = roleRepository.findByName(ERole.ROLE_TEACHER).orElseThrow(() -> new RuntimeException("Error: Role is not found")); - roles.add(teacherRole); - break; - default: - Role studentRole = roleRepository.findByName(ERole.ROLE_STUDENT).orElseThrow(() -> new RuntimeException("Error: Role is not found")); - roles.add(studentRole); - break; - } - }); - } - user.setRoles(roles); + userRepository.save(user); return ResponseEntity.ok((new MessageResponse("User registered successfully"))); } diff --git a/src/main/java/com/booleanuk/cohorts/controllers/ProfileController.java b/src/main/java/com/booleanuk/cohorts/controllers/ProfileController.java index cec73eb..501e3ca 100644 --- a/src/main/java/com/booleanuk/cohorts/controllers/ProfileController.java +++ b/src/main/java/com/booleanuk/cohorts/controllers/ProfileController.java @@ -43,7 +43,7 @@ public class ProfileController { @Autowired private UserRepository userRepository; - record PostProfile( + public record PostProfile( int userId, String first_name, String last_name, diff --git a/src/main/java/com/booleanuk/cohorts/payload/request/SignupRequest.java b/src/main/java/com/booleanuk/cohorts/payload/request/SignupRequest.java index 0fc94de..3329932 100644 --- a/src/main/java/com/booleanuk/cohorts/payload/request/SignupRequest.java +++ b/src/main/java/com/booleanuk/cohorts/payload/request/SignupRequest.java @@ -17,11 +17,14 @@ public class SignupRequest { @Email private String email; - private Set role; - @NotBlank @Size(min = 6, max = 40) private String password; private Cohort cohort; + + public SignupRequest(String email, String password) { + this.email = email; + this.password = password; + } } diff --git a/src/main/java/com/booleanuk/cohorts/repository/UserRepository.java b/src/main/java/com/booleanuk/cohorts/repository/UserRepository.java index 1bc7024..7d34f7c 100644 --- a/src/main/java/com/booleanuk/cohorts/repository/UserRepository.java +++ b/src/main/java/com/booleanuk/cohorts/repository/UserRepository.java @@ -1,5 +1,6 @@ package com.booleanuk.cohorts.repository; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; @@ -18,4 +19,6 @@ public interface UserRepository extends JpaRepository { Optional findByEmailWithProfile(@Param("email") String email); Boolean existsByEmail(String email); + + List getTopById(int id); } diff --git a/src/test/java/com/booleanuk/controllerTests/CohortControllerTest.java b/src/test/java/com/booleanuk/controllerTests/CohortControllerTest.java index 41eeea9..3f4b6f4 100644 --- a/src/test/java/com/booleanuk/controllerTests/CohortControllerTest.java +++ b/src/test/java/com/booleanuk/controllerTests/CohortControllerTest.java @@ -1,4 +1,257 @@ package com.booleanuk.controllerTests; +import com.booleanuk.cohorts.controllers.AuthController; +import com.booleanuk.cohorts.controllers.ProfileController; +import com.booleanuk.cohorts.models.Cohort; +import com.booleanuk.cohorts.models.Profile; +import com.booleanuk.cohorts.models.User; +import com.booleanuk.cohorts.models.Role; +import com.booleanuk.cohorts.models.ERole; +import com.booleanuk.cohorts.payload.request.SignupRequest; +import com.booleanuk.cohorts.repository.ProfileRepository; +import com.booleanuk.cohorts.repository.UserRepository; +import com.booleanuk.cohorts.repository.RoleRepository; +import com.booleanuk.cohorts.repository.CohortRepository; +import com.booleanuk.cohorts.security.services.UserDetailsImpl; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletContext; +import org.json.JSONArray; +import org.json.JSONObject; +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.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockServletContext; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebAppConfiguration +@SpringBootTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Transactional +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class CohortControllerTest { + @Autowired + private WebApplicationContext webApplicationContext; + + @Autowired + private UserRepository userRepository; + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private CohortRepository cohortRepository; + + @Autowired + AuthController authController; + + @Autowired + ProfileController profileController; + + @Autowired + ProfileRepository profileRepository; + + @PersistenceContext + private EntityManager entityManager; + + private MockMvc mockMvc; + + private int actualUserId; + private int testCohortId; + + private User testUser; + + @BeforeEach + public void setup() throws Exception { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); + + profileRepository.deleteAll(); + userRepository.deleteAll(); + roleRepository.deleteAll(); + cohortRepository.deleteAll(); + entityManager.flush(); + entityManager.clear(); + + + Role teacherRole = new Role(ERole.ROLE_TEACHER); + Role studentRole = new Role(ERole.ROLE_STUDENT); + roleRepository.save(teacherRole); + roleRepository.save(studentRole); + entityManager.flush(); + + + Cohort testCohort = new Cohort(); + testCohort = cohortRepository.save(testCohort); + testCohortId = testCohort.getId(); + entityManager.flush(); + + SignupRequest signupRequest = new SignupRequest("thomas@ladder.com", "@Qwerty12345"); + this.authController.registerUser(signupRequest); + entityManager.flush(); + + testUser = userRepository.findAll().get(0); + actualUserId = testUser.getId(); + + ProfileController.PostProfile postProfile = new ProfileController.PostProfile( + actualUserId, + "Thomas", + "Ladder", + "gottaStepUp", + "244783772", + "tallerThanU", + "I need a ladder, but can't afford one. So, steps will have to be taken", + "ROLE_TEACHER", + "Big moves", + testCohortId, + "1999-01-01", + "2039-01-01", + "https://media.makeameme.org/created/ladder-i.jpg" + ); + ResponseEntity profileRegisterResponse = this.profileController.createProfile(postProfile); + entityManager.flush(); + entityManager.clear(); + + // Refresh the user entity to get the updated state with profile + testUser = userRepository.findById(actualUserId).orElse(null); + } + + private void authenticateUser(User user) { + UserDetailsImpl userDetails = UserDetailsImpl.build(user); + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + @Test + public void heuristics_testClassSetup() { + ServletContext servletContext = webApplicationContext.getServletContext(); + + assertNotNull(servletContext); + assertTrue(servletContext instanceof MockServletContext); + assertNotNull(webApplicationContext.getBean("cohortController")); + } + + @Test + public void tryGetAllCohorts_testFirstNameOnFirstProfile_withSingleProfileInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/cohorts") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data"); + JSONArray cohorts = response.getJSONArray("cohorts"); + assertNotNull(cohorts); + + JSONObject firstProfile = cohorts.getJSONObject(0).getJSONArray("profiles").getJSONObject(0); + assertEquals(firstProfile.getString("firstName"), "Thomas"); + } + + @Test + public void tryGetCohortsById_testEmailOnFirstProfile_withSingleProfileInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/cohorts/" + testCohortId) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("cohort"); + assertNotNull(response); + + JSONObject firstProfile = response.getJSONArray("profiles").getJSONObject(0); + assertEquals(firstProfile.getString("firstName"), "Thomas"); + + } + + @Test + public void tryGetCohortsByUserId_testEmailOnFirstProfile_withSingleProfileInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/cohorts/teacher/" + actualUserId)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("cohort"); + assertNotNull(response); + + JSONObject firstProfile = response.getJSONArray("profiles").getJSONObject(0); + assertEquals(firstProfile.getString("firstName"), "Thomas"); + assertEquals(firstProfile.getJSONObject("user").getString("email"), "thomas@ladder.com"); + } + + @Test + public void tryAddStudentToCohort_checkProfileObjectAndResponseBody_withSingleProfileInDb() throws Exception { + Cohort secondTestCohort = new Cohort(); + secondTestCohort = cohortRepository.save(secondTestCohort); + int secondTestCohortId = secondTestCohort.getId(); + entityManager.flush(); + + SignupRequest studentSignupRequest = new SignupRequest("student@test.com", "@Student123"); + this.authController.registerUser(studentSignupRequest); + entityManager.flush(); + + User studentUser = userRepository.findByEmail("student@test.com").orElse(null); + assertNotNull(studentUser); + + ProfileController.PostProfile studentPostProfile = new ProfileController.PostProfile( + studentUser.getId(), + "Fritjof", + "Ladderson", + "BigLadderMan", + "748337483784", + "bigLadderMan", + "I invented the upside down ladder", + "ROLE_STUDENT", + "Alternative ladders", + secondTestCohortId, + "1999-01-01", + "2040-01-01", + "https://example.com/ladder.jpg" + ); + this.profileController.createProfile(studentPostProfile); + entityManager.flush(); + + Profile studentProfile = profileRepository.findById(studentUser.getId()).orElse(null); + assertNotNull(studentProfile); + + authenticateUser(testUser); + + String requestBody = "{\"profileId\":" + studentProfile.getId() + "}"; + + MvcResult result = this.mockMvc.perform(patch("/cohorts/teacher/" + testCohortId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()); + assertNotNull(response); + + assertEquals(testCohortId, response.getJSONObject("cohort").getInt("id")); + assertEquals("Fritjof", response.getString("firstName")); + assertEquals("Ladderson", response.getString("lastName")); + + Profile updatedProfile = profileRepository.findById(studentProfile.getId()).orElse(null); + assertNotNull(updatedProfile); + assertNotNull(updatedProfile.getCohort()); + assertEquals(testCohortId, updatedProfile.getCohort().getId()); + } + } diff --git a/src/test/java/com/booleanuk/controllerTests/CourseControllerTest.java b/src/test/java/com/booleanuk/controllerTests/CourseControllerTest.java index 978802e..e7ab7bf 100644 --- a/src/test/java/com/booleanuk/controllerTests/CourseControllerTest.java +++ b/src/test/java/com/booleanuk/controllerTests/CourseControllerTest.java @@ -1,4 +1,303 @@ package com.booleanuk.controllerTests; +import com.booleanuk.cohorts.controllers.AuthController; +import com.booleanuk.cohorts.controllers.ProfileController; +import com.booleanuk.cohorts.models.*; +import com.booleanuk.cohorts.payload.request.SignupRequest; +import com.booleanuk.cohorts.repository.*; +import com.booleanuk.cohorts.security.services.UserDetailsImpl; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletContext; +import org.json.JSONArray; +import org.json.JSONObject; +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.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockServletContext; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebAppConfiguration +@SpringBootTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Transactional +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class CourseControllerTest { -} + @Autowired + private WebApplicationContext webApplicationContext; + + @Autowired + private UserRepository userRepository; + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private CohortRepository cohortRepository; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + AuthController authController; + + @Autowired + ProfileController profileController; + + @Autowired + ProfileRepository profileRepository; + + @PersistenceContext + private EntityManager entityManager; + + private MockMvc mockMvc; + + private int testCourseId; + private int testCohortId; + private User testTeacherUser; + private User testStudentUser; + + @BeforeEach + public void setup() throws Exception { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); + + profileRepository.deleteAll(); + cohortRepository.deleteAll(); + courseRepository.deleteAll(); + userRepository.deleteAll(); + roleRepository.deleteAll(); + entityManager.flush(); + entityManager.clear(); + + Role teacherRole = new Role(ERole.ROLE_TEACHER); + Role studentRole = new Role(ERole.ROLE_STUDENT); + roleRepository.save(teacherRole); + roleRepository.save(studentRole); + entityManager.flush(); + + Course testCourse = new Course(); + testCourse.setName("Java Development"); + testCourse.setStartDate(LocalDate.parse("2024-01-01")); + testCourse.setEndDate(LocalDate.parse("2024-06-01")); + testCourse = courseRepository.save(testCourse); + testCourseId = testCourse.getId(); + entityManager.flush(); + + Cohort testCohort = new Cohort(); + testCohort.setName("Java Cohort 1"); + testCohort.setCourse(testCourse); + testCohort = cohortRepository.save(testCohort); + testCohortId = testCohort.getId(); + entityManager.flush(); + + SignupRequest teacherSignupRequest = new SignupRequest("teacher@test.com", "@Teacher123"); + this.authController.registerUser(teacherSignupRequest); + entityManager.flush(); + + testTeacherUser = userRepository.findByEmail("teacher@test.com").orElse(null); + + ProfileController.PostProfile teacherPostProfile = new ProfileController.PostProfile( + testTeacherUser.getId(), + "John", + "Teacher", + "johnTeacher", + "123456789", + "teacherGitHub", + "I am a teacher", + "ROLE_TEACHER", + "Teaching Java", + testCohortId, + "1980-01-01", + "2030-01-01", + "https://example.com/teacher.jpg" + ); + this.profileController.createProfile(teacherPostProfile); + entityManager.flush(); + + SignupRequest studentSignupRequest = new SignupRequest("student@test.com", "@Student123"); + this.authController.registerUser(studentSignupRequest); + entityManager.flush(); + + testStudentUser = userRepository.findByEmail("student@test.com").orElse(null); + + ProfileController.PostProfile studentPostProfile = new ProfileController.PostProfile( + testStudentUser.getId(), + "Jane", + "Student", + "janeStudent", + "987654321", + "studentGitHub", + "I am a student", + "ROLE_STUDENT", + "Learning Java", + testCohortId, + "2000-01-01", + "2040-01-01", + "https://example.com/student.jpg" + ); + this.profileController.createProfile(studentPostProfile); + entityManager.flush(); + entityManager.clear(); + + testTeacherUser = userRepository.findById(testTeacherUser.getId()).orElse(null); + testStudentUser = userRepository.findById(testStudentUser.getId()).orElse(null); + } + + private void authenticateUser(User user) { + UserDetailsImpl userDetails = UserDetailsImpl.build(user); + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + @Test + public void heuristics_testClassSetup() { + ServletContext servletContext = webApplicationContext.getServletContext(); + + assertNotNull(servletContext); + assertTrue(servletContext instanceof MockServletContext); + assertNotNull(webApplicationContext.getBean("courseController")); + } + + @Test + public void tryGetAllCourses_testCourseNameAndDates_withSingleCourseInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/courses") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data"); + JSONArray courses = response.getJSONArray("courses"); + assertNotNull(courses); + assertEquals(1, courses.length()); + + JSONObject firstCourse = courses.getJSONObject(0); + assertEquals("Java Development", firstCourse.getString("name")); + assertEquals("2024-01-01", firstCourse.getString("startDate")); + assertEquals("2024-06-01", firstCourse.getString("endDate")); + } + + @Test + public void tryGetCourseById_testCourseDetailsAndCohorts_withSingleCourseInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/courses/" + testCourseId) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("course"); + assertNotNull(response); + + assertEquals("Java Development", response.getString("name")); + assertEquals("2024-01-01", response.getString("startDate")); + assertEquals("2024-06-01", response.getString("endDate")); + + JSONArray cohorts = response.getJSONArray("cohorts"); + assertEquals(1, cohorts.length()); + assertEquals("Java Development", response.getString("name")); + } + + @Test + public void tryGetCourseById_testNotFound_withInvalidId() throws Exception { + this.mockMvc.perform(get("/courses/999") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isNotFound()) + .andReturn(); + } + + @Test + public void tryGetAllStudents_testStudentProfilesInCourse_withStudentInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/courses/students/" + testCourseId) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data"); + JSONArray profiles = response.getJSONArray("profiles"); + assertNotNull(profiles); + assertEquals(1, profiles.length()); + + JSONObject studentProfile = profiles.getJSONObject(0); + assertEquals("Jane", studentProfile.getString("firstName")); + assertEquals("Student", studentProfile.getString("lastName")); + assertEquals("janeStudent", studentProfile.getString("username")); + } + + @Test + public void tryGetAllStudents_testNotFound_withInvalidCourseId() throws Exception { + this.mockMvc.perform(get("/courses/students/999") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isNotFound()) + .andReturn(); + } + + @Test + public void tryCreateCourse_testCourseCreation_withValidData() throws Exception { + String requestBody = """ + { + "name": "Python Development", + "startDate": "2024-07-01", + "endDate": "2024-12-01" + } + """; + + MvcResult result = this.mockMvc.perform(post("/courses") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isCreated()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("course"); + assertNotNull(response); + + assertEquals("Python Development", response.getString("name")); + assertEquals("2024-07-01", response.getString("startDate")); + assertEquals("2024-12-01", response.getString("endDate")); + + Course savedCourse = courseRepository.findById(response.getInt("id")).orElse(null); + assertNotNull(savedCourse); + assertEquals("Python Development", savedCourse.getName()); + } + + @Test + public void tryCreateCourse_testBadRequest_withBlankDates() throws Exception { + String requestBody = """ + { + "name": "Invalid Course", + "startDate": "", + "endDate": "" + } + """; + + this.mockMvc.perform(post("/courses") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isBadRequest()) + .andReturn(); + } +} \ No newline at end of file diff --git a/src/test/java/com/booleanuk/controllerTests/PostControllerTest.java b/src/test/java/com/booleanuk/controllerTests/PostControllerTest.java index b6b6516..3766922 100644 --- a/src/test/java/com/booleanuk/controllerTests/PostControllerTest.java +++ b/src/test/java/com/booleanuk/controllerTests/PostControllerTest.java @@ -1,4 +1,507 @@ package com.booleanuk.controllerTests; +import com.booleanuk.cohorts.controllers.AuthController; +import com.booleanuk.cohorts.controllers.ProfileController; +import com.booleanuk.cohorts.models.*; +import com.booleanuk.cohorts.payload.request.SignupRequest; +import com.booleanuk.cohorts.repository.*; +import com.booleanuk.cohorts.security.services.UserDetailsImpl; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletContext; +import org.json.JSONArray; +import org.json.JSONObject; +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.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockServletContext; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebAppConfiguration +@SpringBootTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Transactional +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class PostControllerTest { -} + @Autowired + private WebApplicationContext webApplicationContext; + + @Autowired + private UserRepository userRepository; + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private CohortRepository cohortRepository; + + @Autowired + private CourseRepository courseRepository; + + @Autowired + private PostRepository postRepository; + + @Autowired + private CommentRepository commentRepository; + + @Autowired + AuthController authController; + + @Autowired + ProfileController profileController; + + @Autowired + ProfileRepository profileRepository; + + @PersistenceContext + private EntityManager entityManager; + + private MockMvc mockMvc; + + private int testCourseId; + private int testCohortId; + private int testPostId; + private int testCommentId; + private User testUser; + private User testUser2; + + @BeforeEach + public void setup() throws Exception { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); + + commentRepository.deleteAll(); + postRepository.deleteAll(); + profileRepository.deleteAll(); + cohortRepository.deleteAll(); + courseRepository.deleteAll(); + userRepository.deleteAll(); + roleRepository.deleteAll(); + entityManager.flush(); + entityManager.clear(); + + Role teacherRole = new Role(ERole.ROLE_TEACHER); + Role studentRole = new Role(ERole.ROLE_STUDENT); + roleRepository.save(teacherRole); + roleRepository.save(studentRole); + entityManager.flush(); + + Course testCourse = new Course(); + testCourse.setName("Java Development"); + testCourse.setStartDate(LocalDate.parse("2024-01-01")); + testCourse.setEndDate(LocalDate.parse("2024-06-01")); + testCourse = courseRepository.save(testCourse); + testCourseId = testCourse.getId(); + entityManager.flush(); + + Cohort testCohort = new Cohort(); + testCohort.setName("Java Cohort 1"); + testCohort.setCourse(testCourse); + testCohort = cohortRepository.save(testCohort); + testCohortId = testCohort.getId(); + entityManager.flush(); + + SignupRequest signupRequest = new SignupRequest("john@test.com", "@Password123"); + this.authController.registerUser(signupRequest); + entityManager.flush(); + + testUser = userRepository.findByEmail("john@test.com").orElse(null); + + ProfileController.PostProfile postProfile = new ProfileController.PostProfile( + testUser.getId(), + "John", + "Doe", + "johndoe", + "123456789", + "johnGitHub", + "I am a developer", + "ROLE_STUDENT", + "Learning Java", + testCohortId, + "1990-01-01", + "2030-01-01", + "https://example.com/john.jpg" + ); + this.profileController.createProfile(postProfile); + entityManager.flush(); + + SignupRequest signupRequest2 = new SignupRequest("jane@test.com", "@Password123"); + this.authController.registerUser(signupRequest2); + entityManager.flush(); + + testUser2 = userRepository.findByEmail("jane@test.com").orElse(null); + + ProfileController.PostProfile postProfile2 = new ProfileController.PostProfile( + testUser2.getId(), + "Jane", + "Smith", + "janesmith", + "987654321", + "janeGitHub", + "I am also a developer", + "ROLE_STUDENT", + "Learning Java too", + testCohortId, + "1992-01-01", + "2030-01-01", + "https://example.com/jane.jpg" + ); + this.profileController.createProfile(postProfile2); + entityManager.flush(); + + Post testPost = new Post("This is a test post", testUser, 0); + testPost = postRepository.save(testPost); + testPostId = testPost.getId(); + entityManager.flush(); + + Comment testComment = new Comment("This is a test comment", testUser2, testPost); + testComment = commentRepository.save(testComment); + testCommentId = testComment.getId(); + entityManager.flush(); + entityManager.clear(); + + testUser = userRepository.findById(testUser.getId()).orElse(null); + testUser2 = userRepository.findById(testUser2.getId()).orElse(null); + } + + private void authenticateUser(User user) { + UserDetailsImpl userDetails = UserDetailsImpl.build(user); + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + @Test + public void heuristics_testClassSetup() { + ServletContext servletContext = webApplicationContext.getServletContext(); + + assertNotNull(servletContext); + assertTrue(servletContext instanceof MockServletContext); + assertNotNull(webApplicationContext.getBean("postController")); + } + + @Test + public void tryGetAllPosts_testPostContentAndAuthor_withSinglePostInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/posts") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data"); + JSONArray posts = response.getJSONArray("posts"); + assertNotNull(posts); + assertEquals(1, posts.length()); + + JSONObject firstPost = posts.getJSONObject(0); + assertEquals("This is a test post", firstPost.getString("content")); + assertEquals("John", firstPost.getJSONObject("user").getJSONObject("profile").getString("firstName")); + assertEquals("Doe", firstPost.getJSONObject("user").getJSONObject("profile").getString("lastName")); + } + + @Test + public void tryCreatePost_testPostCreation_withAuthenticatedUser() throws Exception { + authenticateUser(testUser); + + String requestBody = """ + { + "content": "This is a new test post" + } + """; + + MvcResult result = this.mockMvc.perform(post("/posts") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isCreated()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("post"); + assertNotNull(response); + + assertEquals("This is a new test post", response.getString("content")); + assertEquals("John", response.getJSONObject("user").getJSONObject("profile").getString("firstName")); + assertEquals(0, response.getInt("likes")); + } + + @Test + public void tryCreatePost_testUnauthorized_withoutAuthentication() throws Exception { + String requestBody = """ + { + "content": "This should fail" + } + """; + + this.mockMvc.perform(post("/posts") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isUnauthorized()) + .andReturn(); + } + + @Test + public void tryGetPostById_testPostDetails_withValidId() throws Exception { + MvcResult result = this.mockMvc.perform(get("/posts/" + testPostId) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("post"); + assertNotNull(response); + + assertEquals("This is a test post", response.getString("content")); + assertEquals("John", response.getJSONObject("user").getJSONObject("profile").getString("firstName")); + assertEquals(testPostId, response.getInt("id")); + } + + @Test + public void tryGetPostById_testNotFound_withInvalidId() throws Exception { + this.mockMvc.perform(get("/posts/999") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isNotFound()) + .andReturn(); + } + + @Test + public void tryDeletePostById_testPostDeletion_withValidId() throws Exception { + MvcResult result = this.mockMvc.perform(delete("/posts/" + testPostId)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("post"); + assertNotNull(response); + assertEquals("This is a test post", response.getString("content")); + + Post deletedPost = postRepository.findById(testPostId).orElse(null); + assertNull(deletedPost); + } + + @Test + public void tryAddCommentToPost_testCommentCreation_withValidData() throws Exception { + String requestBody = """ + { + "body": "This is a new comment", + "userId": %d + } + """.formatted(testUser2.getId()); + + MvcResult result = this.mockMvc.perform(post("/posts/" + testPostId + "/comments") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isCreated()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("comment"); + assertNotNull(response); + + assertEquals("This is a new comment", response.getString("body")); + assertEquals(testUser2.getId(), response.getJSONObject("user").getInt("id")); + } + + @Test + public void tryGetCommentsForPost_testCommentsRetrieval_withValidPostId() throws Exception { + MvcResult result = this.mockMvc.perform(get("/posts/" + testPostId + "/comments") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("post"); + assertNotNull(response); + + JSONArray comments = response.getJSONArray("comments"); + assertEquals(1, comments.length()); + assertEquals("This is a test comment", comments.getJSONObject(0).getString("body")); + } + + @Test + public void tryGetCommentById_testCommentRetrieval_withValidIds() throws Exception { + MvcResult result = this.mockMvc.perform(get("/posts/" + testPostId + "/comments/" + testCommentId) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("comment"); + assertNotNull(response); + + assertEquals("This is a test comment", response.getString("body")); + assertEquals(testCommentId, response.getInt("id")); + } + + @Test + public void tryUpdateComment_testCommentUpdate_withOwnerAuthentication() throws Exception { + authenticateUser(testUser2); + + String requestBody = """ + { + "body": "This is an updated comment" + } + """; + + MvcResult result = this.mockMvc.perform(put("/posts/" + testPostId + "/comments/" + testCommentId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("comment"); + assertNotNull(response); + + assertEquals("This is an updated comment", response.getString("body")); + assertEquals(testCommentId, response.getInt("id")); + } + + @Test + public void tryUpdateComment_testForbidden_withNonOwnerAuthentication() throws Exception { + authenticateUser(testUser); + + String requestBody = """ + { + "body": "This should fail" + } + """; + + this.mockMvc.perform(put("/posts/" + testPostId + "/comments/" + testCommentId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isForbidden()) + .andReturn(); + } + + @Test + public void tryDeleteComment_testCommentDeletion_withOwnerAuthentication() throws Exception { + authenticateUser(testUser2); + + this.mockMvc.perform(delete("/posts/" + testPostId + "/comments/" + testCommentId)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + Comment deletedComment = commentRepository.findById(testCommentId).orElse(null); + assertNull(deletedComment); + } + + @Test + public void tryLikePost_testPostLiking_withAuthenticatedUser() throws Exception { + authenticateUser(testUser); + + MvcResult result = this.mockMvc.perform(post("/posts/" + testPostId + "/like")) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("post"); + assertNotNull(response); + + assertEquals(1, response.getInt("likes")); + assertEquals(testPostId, response.getInt("id")); + } + + @Test + public void tryUnlikePost_testPostUnliking_withAuthenticatedUser() throws Exception { + Post post = postRepository.findById(testPostId).orElse(null); + post.setLikes(1); + postRepository.save(post); + entityManager.flush(); + + authenticateUser(testUser); + + MvcResult result = this.mockMvc.perform(delete("/posts/" + testPostId + "/like")) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("post"); + assertNotNull(response); + + assertEquals(0, response.getInt("likes")); + assertEquals(testPostId, response.getInt("id")); + } + + @Test + public void tryUpdatePost_testPostUpdate_withOwnerAuthentication() throws Exception { + authenticateUser(testUser); + + String requestBody = """ + { + "content": "This is an updated post content" + } + """; + + MvcResult result = this.mockMvc.perform(put("/posts/" + testPostId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + JSONObject response = new JSONObject(result.getResponse().getContentAsString()).getJSONObject("data").getJSONObject("post"); + assertNotNull(response); + + assertEquals("This is an updated post content", response.getString("content")); + assertEquals(testPostId, response.getInt("id")); + assertNotNull(response.getString("timeUpdated")); + } + + @Test + public void tryUpdatePost_testForbidden_withNonOwnerAuthentication() throws Exception { + authenticateUser(testUser2); + + String requestBody = """ + { + "content": "This should fail" + } + """; + + this.mockMvc.perform(put("/posts/" + testPostId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isForbidden()) + .andReturn(); + } + + @Test + public void tryUpdatePost_testBadRequest_withEmptyContent() throws Exception { + authenticateUser(testUser); + + String requestBody = """ + { + "content": "" + } + """; + + this.mockMvc.perform(put("/posts/" + testPostId) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andDo(print()) + .andExpect(status().isBadRequest()) + .andReturn(); + } +} \ No newline at end of file diff --git a/src/test/java/com/booleanuk/controllerTests/ProfileControllerTest.java b/src/test/java/com/booleanuk/controllerTests/ProfileControllerTest.java index fc7a322..f37b339 100644 --- a/src/test/java/com/booleanuk/controllerTests/ProfileControllerTest.java +++ b/src/test/java/com/booleanuk/controllerTests/ProfileControllerTest.java @@ -1,4 +1,201 @@ package com.booleanuk.controllerTests; +import com.booleanuk.cohorts.controllers.AuthController; +import com.booleanuk.cohorts.controllers.ProfileController; +import com.booleanuk.cohorts.controllers.SearchController; +import com.booleanuk.cohorts.models.Cohort; +import com.booleanuk.cohorts.models.ERole; +import com.booleanuk.cohorts.models.Role; +import com.booleanuk.cohorts.models.User; +import com.booleanuk.cohorts.payload.request.SignupRequest; +import com.booleanuk.cohorts.repository.CohortRepository; +import com.booleanuk.cohorts.repository.ProfileRepository; +import com.booleanuk.cohorts.repository.RoleRepository; +import com.booleanuk.cohorts.repository.UserRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletContext; +import org.json.JSONArray; +import org.json.JSONObject; +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.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockServletContext; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +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.status; + +@WebAppConfiguration +@SpringBootTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Transactional +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class ProfileControllerTest { + @Autowired + private WebApplicationContext webApplicationContext; + + @Autowired + private UserRepository userRepository; + + @Autowired + AuthController authController; + + @Autowired + ProfileController profileController; + + @Autowired + ProfileRepository profileRepository; + + @Autowired + RoleRepository roleRepository; + + @Autowired + CohortRepository cohortRepository; + + @PersistenceContext + private EntityManager entityManager; + + private MockMvc mockMvc; + + private int actualUserId; + private int testCohortId; + + @BeforeEach + public void setup() throws Exception { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); + userRepository.deleteAll(); + roleRepository.deleteAll(); + cohortRepository.deleteAll(); + entityManager.flush(); + entityManager.clear(); + + + Role teacherRole = new Role(ERole.ROLE_TEACHER); + Role studentRole = new Role(ERole.ROLE_STUDENT); + roleRepository.save(teacherRole); + roleRepository.save(studentRole); + entityManager.flush(); + + + Cohort testCohort = new Cohort(); + testCohort = cohortRepository.save(testCohort); + testCohortId = testCohort.getId(); + entityManager.flush(); + + SignupRequest signupRequest = new SignupRequest("thomas@ladder.com", "@Qwerty12345"); + ResponseEntity registerResponse = this.authController.registerUser(signupRequest); + entityManager.flush(); + entityManager.clear(); + + + actualUserId = userRepository.findAll().get(0).getId(); + + } + + @Test + public void heuristics_testClassSetup() { + ServletContext servletContext = webApplicationContext.getServletContext(); + + assertNotNull(servletContext); + assertTrue(servletContext instanceof MockServletContext); + assertNotNull(webApplicationContext.getBean("searchController")); + } + + @Test + public void tryCreateProfile_testFirstNameOnCreatedProfile() throws Exception { + String profileJson = """ + { + "userId": %d, + "first_name": "Thomas", + "last_name": "Ladder", + "username": "gottaStepUp", + "mobile": "244783772", + "github_username": "tallerThanU", + "bio": "GI need a ladder, but can't afford one. So, steps will have to be taken", + "role": "ROLE_STUDENT", + "specialism": "Big moves", + "cohort": 1, + "start_date": "1999-01-01", + "end_date": "2039-01-01", + "photo": "https://media.makeameme.org/created/ladder-i.jpg" + } + """.formatted(actualUserId); + + MvcResult result = this.mockMvc.perform(post("/profiles") + .contentType(MediaType.APPLICATION_JSON) + .content(profileJson)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + assertNotNull(result); + + String json = result.getResponse().getContentAsString(); + JSONObject jsonObject = new JSONObject(json); + + JSONObject profile = jsonObject.getJSONObject("profile"); + String firstName = profile.getString("firstName"); + String username = profile.getString("username"); + + System.out.println("First Name: " + firstName); + assertEquals("Thomas", firstName, "Profile first name should be Thomas"); + assertEquals("gottaStepUp", username, "Profile username should be gottaStepUp"); + } + + @Test + public void tryGetProfileForId_testFirstNameOnFoundProfile_withProfilesInDB() throws Exception { + ResponseEntity profileResponse = profileController.createProfile(new ProfileController.PostProfile( + actualUserId, // Use the actual user ID + "Thomas", + "Ladder", + "gottaStepUp", + "244783772", + "tallerThanU", + "I need a ladder, but can't afford one. So, steps will have to be taken", + "ROLE_STUDENT", + "Big moves", + 1, + "1999-01-01", + "2039-01-01", + "https://media.makeameme.org/created/ladder-i.jpg" + )); + + entityManager.flush(); + entityManager.clear(); + + MvcResult result = this.mockMvc.perform(get("/profiles/"+ actualUserId)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(print()) + .andReturn(); + + assertNotNull(result); + + String json = result.getResponse().getContentAsString(); + JSONObject jsonObject = new JSONObject(json); + + JSONObject profile = jsonObject.getJSONObject("data").getJSONObject("profile"); + String firstName = profile.getString("firstName"); + String username = profile.getString("username"); + System.out.println("First Name: " + firstName); + assertEquals("Thomas", firstName, "Profile first name should be Thomas"); + assertEquals("gottaStepUp", username, "Profile first name should be Thomas"); + } + } diff --git a/src/test/java/com/booleanuk/controllerTests/SearchControllerTest.java b/src/test/java/com/booleanuk/controllerTests/SearchControllerTest.java index 94c0313..067f667 100644 --- a/src/test/java/com/booleanuk/controllerTests/SearchControllerTest.java +++ b/src/test/java/com/booleanuk/controllerTests/SearchControllerTest.java @@ -1,30 +1,56 @@ package com.booleanuk.controllerTests; +import com.booleanuk.cohorts.controllers.AuthController; +import com.booleanuk.cohorts.controllers.ProfileController; import com.booleanuk.cohorts.controllers.SearchController; +import com.booleanuk.cohorts.models.Cohort; +import com.booleanuk.cohorts.models.ERole; +import com.booleanuk.cohorts.models.Role; +import com.booleanuk.cohorts.models.User; +import com.booleanuk.cohorts.payload.request.SignupRequest; +import com.booleanuk.cohorts.repository.CohortRepository; +import com.booleanuk.cohorts.repository.ProfileRepository; +import com.booleanuk.cohorts.repository.RoleRepository; import com.booleanuk.cohorts.repository.UserRepository; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; import jakarta.servlet.ServletContext; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.jupiter.api.Assertions; 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.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.mock.web.MockServletContext; +import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.context.WebApplicationContext; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; 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.status; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @WebAppConfiguration @SpringBootTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Transactional +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) class SearchControllerTest { @Autowired @@ -34,17 +60,89 @@ class SearchControllerTest { private UserRepository userRepository; @Autowired - private SearchController searchController; + private RoleRepository roleRepository; + + @Autowired + private CohortRepository cohortRepository; + + @Autowired + AuthController authController; + + @Autowired + ProfileController profileController; + + @Autowired + ProfileRepository profileRepository; + + @PersistenceContext + private EntityManager entityManager; private MockMvc mockMvc; + private int actualUserId; + private int testCohortId; + + private User testUser; + @BeforeEach public void setup() throws Exception { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); + + profileRepository.deleteAll(); + userRepository.deleteAll(); + roleRepository.deleteAll(); + cohortRepository.deleteAll(); + entityManager.flush(); + entityManager.clear(); + + + Role teacherRole = new Role(ERole.ROLE_TEACHER); + Role studentRole = new Role(ERole.ROLE_STUDENT); + roleRepository.save(teacherRole); + roleRepository.save(studentRole); + entityManager.flush(); + + + Cohort testCohort = new Cohort(); + testCohort = cohortRepository.save(testCohort); + testCohortId = testCohort.getId(); + entityManager.flush(); + + SignupRequest signupRequest = new SignupRequest("thomas@ladder.com", "@Qwerty12345"); + ResponseEntity registerResponse = this.authController.registerUser(signupRequest); + entityManager.flush(); + entityManager.clear(); + + List users = userRepository.findAll(); + User createdUser = users.get(0); + int actualUserId = createdUser.getId(); + + System.out.println("Using user ID for profile creation: " + actualUserId); + + + ResponseEntity profileResponse = profileController.createProfile(new ProfileController.PostProfile( + actualUserId, // Use the actual user ID + "Thomas", + "Ladder", + "gottaStepUp", + "244783772", + "tallerThanU", + "I need a ladder, but can't afford one. So, steps will have to be taken", + "ROLE_STUDENT", + "Big moves", + 1, + "1999-01-01", + "2039-01-01", + "https://media.makeameme.org/created/ladder-i.jpg" + )); + + entityManager.flush(); + entityManager.clear(); + } @Test - public void heuristicsTryGettingBeanSearchController() { + public void heuristics_testClassSetup() { ServletContext servletContext = webApplicationContext.getServletContext(); assertNotNull(servletContext); @@ -53,9 +151,52 @@ public void heuristicsTryGettingBeanSearchController() { } @Test - public void tryGettingBaseURL_andGetSomeResponse() throws Exception { - this.mockMvc.perform(get("/search/profiles")) + public void trySearchProfilesDefault_withProfilesInDB() throws Exception { + MvcResult result = this.mockMvc.perform(get("/search/profiles")) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + String json = result.getResponse().getContentAsString(); + + JSONObject jsonObject = new JSONObject(json); + JSONArray jsonArray = jsonObject.getJSONObject("data").getJSONArray("profiles"); + + assertTrue(jsonArray.length() == 1, "Should return at least one profile"); + } + + @Test + public void trySearchProfilesQuery_testFirstNameOnFirstFoundProfile_withProfilesInDB() throws Exception { + MvcResult result = this.mockMvc.perform(get("/search/profiles/thomas")) + .andDo(print()) + .andExpect(status().isOk()) .andDo(print()) - .andExpect(status().isOk()); + .andReturn(); + + String json = result.getResponse().getContentAsString(); + + JSONObject jsonObject = new JSONObject(json); + JSONArray profileArray = jsonObject.getJSONObject("data").getJSONArray("profiles"); + assertTrue(profileArray.length() > 0, "Should return at least one profile"); + + JSONObject firstProfile = profileArray.getJSONObject(0); + String profileFirstName = firstProfile.getString("firstName"); + assertTrue(profileFirstName.toLowerCase().contains("thomas"), + "Profile first name should contain 'thomas'"); + } + + @Test + public void trySearchProfileQuery_testNoProfilesFound_withProfilesInDB() throws Exception { + MvcResult result = this.mockMvc.perform(get("/search/profiles/firstnamethatdoesnotexsist")) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(print()) + .andReturn(); + + String json = result.getResponse().getContentAsString(); + JSONObject jsonObject = new JSONObject(json); + + JSONArray profileArray = jsonObject.getJSONObject("data").getJSONArray("profiles"); + assertTrue(profileArray.length() == 0, "Should return no profiles"); } } diff --git a/src/test/java/com/booleanuk/controllerTests/UserControllerTest.java b/src/test/java/com/booleanuk/controllerTests/UserControllerTest.java index 45c01d1..c8eb3c5 100644 --- a/src/test/java/com/booleanuk/controllerTests/UserControllerTest.java +++ b/src/test/java/com/booleanuk/controllerTests/UserControllerTest.java @@ -1,4 +1,297 @@ package com.booleanuk.controllerTests; +import com.booleanuk.cohorts.controllers.*; +import com.booleanuk.cohorts.models.Cohort; +import com.booleanuk.cohorts.models.ERole; +import com.booleanuk.cohorts.models.Role; +import com.booleanuk.cohorts.models.User; +import com.booleanuk.cohorts.payload.request.PostRequest; +import com.booleanuk.cohorts.payload.request.SignupRequest; +import com.booleanuk.cohorts.payload.response.PostResponse; +import com.booleanuk.cohorts.repository.*; +import com.booleanuk.cohorts.security.services.UserDetailsImpl; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletContext; +import org.json.JSONArray; +import org.json.JSONObject; +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.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockServletContext; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebAppConfiguration +@SpringBootTest +@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) +@Transactional +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class UserControllerTest { + + @Autowired + private WebApplicationContext webApplicationContext; + + @Autowired + private UserRepository userRepository; + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private CohortRepository cohortRepository; + + @Autowired + AuthController authController; + + @Autowired + ProfileController profileController; + + @Autowired + ProfileRepository profileRepository; + + @Autowired + PostController postController; + + @Autowired + PostRepository postRepository; + + @PersistenceContext + private EntityManager entityManager; + + private MockMvc mockMvc; + + private int actualUserId; + private int testCohortId; + + private User testUser; + + @BeforeEach + public void setup() throws Exception { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build(); + profileRepository.deleteAll(); + userRepository.deleteAll(); + roleRepository.deleteAll(); + cohortRepository.deleteAll(); + entityManager.flush(); + entityManager.clear(); + + + Role teacherRole = new Role(ERole.ROLE_TEACHER); + Role studentRole = new Role(ERole.ROLE_STUDENT); + roleRepository.save(teacherRole); + roleRepository.save(studentRole); + entityManager.flush(); + + + Cohort testCohort = new Cohort(); + testCohort = cohortRepository.save(testCohort); + testCohortId = testCohort.getId(); + entityManager.flush(); + + SignupRequest signupRequest = new SignupRequest("thomas@ladder.com", "@Qwerty12345"); + ResponseEntity registerResponse = this.authController.registerUser(signupRequest); + entityManager.flush(); + entityManager.clear(); + + testUser = userRepository.findAll().get(0); + actualUserId = testUser.getId(); + } + + private void authenticateUser(User user) { + UserDetailsImpl userDetails = UserDetailsImpl.build(user); + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + + @Test + public void heuristics_testClassSetup() { + ServletContext servletContext = webApplicationContext.getServletContext(); + + assertNotNull(servletContext); + assertTrue(servletContext instanceof MockServletContext); + assertNotNull(webApplicationContext.getBean("userController")); + } + + @Test + public void tryGetAllUsers_testEmailOnFirstUser_withSingleUserInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/users") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + assertNotNull(result); + String json = result.getResponse().getContentAsString(); + JSONObject jsonObject = new JSONObject(json).getJSONObject("data"); + + JSONArray jsonArray = jsonObject.getJSONArray("users"); + String email = jsonArray.getJSONObject(0).getString("email"); + + assertTrue(jsonArray.length() == 1); + assertEquals("thomas@ladder.com", email, "Email should be thomas@ladder.com"); + } + + @Test + public void tryGetAllUsers_testEmailOnMultipleUsers_withMultipleUserInDb() throws Exception { + this.authController.registerUser(new SignupRequest("fredrik@ladder.com", "@Qwerty12345")); + this.authController.registerUser(new SignupRequest("sara@ladder.com", "@Qwerty12345")); + this.authController.registerUser(new SignupRequest("josefine@ladder.com", "@Qwerty12345")); + entityManager.flush(); + entityManager.clear(); + + MvcResult result = this.mockMvc.perform(get("/users") + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + assertNotNull(result); + + String json = result.getResponse().getContentAsString(); + JSONObject jsonObject = new JSONObject(json).getJSONObject("data"); + JSONArray jsonArray = jsonObject.getJSONArray("users"); + + assertTrue(jsonArray.length() == 4); + + String emailThomas = jsonArray.getJSONObject(0).getString("email"); + String emailFredrik = jsonArray.getJSONObject(1).getString("email"); + String emailSara = jsonArray.getJSONObject(2).getString("email"); + String emailJosefine = jsonArray.getJSONObject(3).getString("email"); + + assertEquals("thomas@ladder.com", emailThomas, "Email should be thomas@ladder.com"); + assertEquals("fredrik@ladder.com", emailFredrik, "Email should be fredrik@ladder.com"); + assertEquals("sara@ladder.com", emailSara, "Email should be sara@ladder.com"); + assertEquals("josefine@ladder.com", emailJosefine, "Email should be josefine@ladder.com"); + } + + @Test + public void tryGetUserById_testEmailOnFirstUser_withSingleUserInDb() throws Exception { + MvcResult result = this.mockMvc.perform(get("/users/" + actualUserId) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + assertNotNull(result); + String json = result.getResponse().getContentAsString(); + JSONObject jsonObject = new JSONObject(json).getJSONObject("data"); + + JSONObject user = jsonObject.getJSONObject("user"); + String email = user.getString("email"); + assertEquals("thomas@ladder.com", email, "Email should be thomas@ladder.com"); + } + + @Test + public void tryDeleteUserById_testReturnCodeAndIfUserIsActuallyDeleted() throws Exception { + MvcResult result = this.mockMvc.perform(delete("/users/" + actualUserId) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + assertTrue(userRepository.findById(actualUserId).isEmpty(), "User list should be empty"); + } + + @Test + public void tryUpdateLikedPosts_testAddingSingleLikedPost_checkUserObjectAndResponseBody_withSingleUserIndb() throws Exception { + authenticateUser(testUser); + + ResponseEntity postResponse = this.postController.createPost(new PostRequest("It's not DNS... There's no way it's DNS... It was DNS", actualUserId)); + + entityManager.flush(); + entityManager.clear(); + + int postId = this.postRepository.findAll().get(0).getId(); + + // Create the request body with the post_id + String requestBody = "{\"post_id\": " + postId + "}"; + + MvcResult result = this.mockMvc.perform(patch("/users/" + actualUserId + "/like") + .with(user(UserDetailsImpl.build(testUser))) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + String json = result.getResponse().getContentAsString(); + JSONObject jsonObject = new JSONObject(json).getJSONObject("data"); + JSONObject user = jsonObject.getJSONObject("user"); + JSONArray likedPosts = user.getJSONArray("likedPosts"); + + assertEquals(1, likedPosts.length(), "User should have 1 liked post in their likedPosts array"); + User userWithLike = userRepository.getReferenceById(actualUserId); + assertTrue(userWithLike.getLikedPosts().size() == 1, "User should have 2 liked posts in their likedPosts array"); + } + + @Test + public void tryUpdateLikedPosts_testAddingMultipleLikedPost_checkUserObjectAndResponseBody_withSingleUserIndb() throws Exception { + authenticateUser(testUser); + + ResponseEntity postResponse = this.postController.createPost(new PostRequest("It's not DNS... There's no way it's DNS... It was DNS", actualUserId)); + ResponseEntity postResponse2 = this.postController.createPost(new PostRequest("Sorry I forgot", actualUserId)); + entityManager.flush(); + entityManager.clear(); + + // Add first post + int postId = this.postRepository.findAll().get(0).getId(); + String requestBody = "{\"post_id\": " + postId + "}"; + + MvcResult result = this.mockMvc.perform(patch("/users/" + actualUserId + "/like") + .with(user(UserDetailsImpl.build(testUser))) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + // Add second post + postId = this.postRepository.findAll().get(1).getId(); + requestBody = "{\"post_id\": " + postId + "}"; + + result = this.mockMvc.perform(patch("/users/" + actualUserId + "/like") + .with(user(UserDetailsImpl.build(testUser))) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .accept(MediaType.APPLICATION_JSON)) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + + // Actual testing logic + String json = result.getResponse().getContentAsString(); + JSONObject jsonObject = new JSONObject(json).getJSONObject("data"); + JSONObject user = jsonObject.getJSONObject("user"); + JSONArray likedPosts = user.getJSONArray("likedPosts"); + + assertEquals(2, likedPosts.length(), "User should have 2 liked posts in their likedPosts array"); + + User userWithLike = userRepository.getReferenceById(actualUserId); + assertTrue(userWithLike.getLikedPosts().size() == 2, "User should have 2 liked posts in their likedPosts array"); + } }