diff --git a/src/test/java/teammates/sqlui/webapi/DeleteFeedbackSessionActionTest.java b/src/test/java/teammates/sqlui/webapi/DeleteFeedbackSessionActionTest.java new file mode 100644 index 00000000000..cf919002c87 --- /dev/null +++ b/src/test/java/teammates/sqlui/webapi/DeleteFeedbackSessionActionTest.java @@ -0,0 +1,166 @@ +package teammates.sqlui.webapi; + +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.Instant; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import teammates.common.datatransfer.InstructorPrivileges; +import teammates.common.util.Const; +import teammates.storage.sqlentity.Course; +import teammates.storage.sqlentity.FeedbackSession; +import teammates.storage.sqlentity.Instructor; +import teammates.ui.output.MessageOutput; +import teammates.ui.webapi.DeleteFeedbackSessionAction; + +/** + * SUT: {@link DeleteFeedbackSessionAction}. + */ +public class DeleteFeedbackSessionActionTest extends BaseActionTest { + private String googleId = "user-googleId"; + private Course course; + private FeedbackSession session; + + @Override + protected String getActionUri() { + return Const.ResourceURIs.SESSION; + } + + @Override + protected String getRequestMethod() { + return DELETE; + } + + @BeforeMethod + void setUp() { + course = new Course("course-id", "name", Const.DEFAULT_TIME_ZONE, "institute"); + session = new FeedbackSession( + "session-name", + course, + "creater_email@tm.tmt", + null, + Instant.parse("2020-01-01T00:00:00.000Z"), + Instant.parse("2020-10-01T00:00:00.000Z"), + Instant.parse("2020-01-01T00:00:00.000Z"), + Instant.parse("2020-11-01T00:00:00.000Z"), + null, + false, + false, + false); + loginAsInstructor(googleId); + } + + @Test + public void testExecute_sessionDoesNotExist_failSilently() { + String sessionName = "incorrect-name"; + String[] params = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, sessionName, + Const.ParamsNames.COURSE_ID, course.getId(), + }; + DeleteFeedbackSessionAction action = getAction(params); + MessageOutput actionOutput = (MessageOutput) getJsonResult(action).getOutput(); + assertEquals("The feedback session is deleted.", actionOutput.getMessage()); + verify(mockLogic, times(1)) + .deleteFeedbackSessionCascade(sessionName, course.getId()); + } + + @Test + public void testExecute_sessionExists_success() { + String[] params = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, session.getName(), + Const.ParamsNames.COURSE_ID, session.getCourseId(), + }; + + DeleteFeedbackSessionAction action = getAction(params); + MessageOutput actionOutput = (MessageOutput) getJsonResult(action).getOutput(); + assertEquals("The feedback session is deleted.", actionOutput.getMessage()); + verify(mockLogic, times(1)) + .deleteFeedbackSessionCascade(session.getName(), session.getCourseId()); + } + + @Test + public void testExecute_missingParameters_throwsInvalidHttpParameterException() { + String[] params = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, "session-name", + }; + + verifyHttpParameterFailure(params); + + String[] params2 = { + Const.ParamsNames.COURSE_ID, "course-id", + }; + + verifyHttpParameterFailure(params2); + + String[] params3 = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, null, + Const.ParamsNames.COURSE_ID, course.getId(), + }; + + verifyHttpParameterFailure(params3); + + String[] params4 = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, session.getName(), + Const.ParamsNames.COURSE_ID, null, + }; + + verifyHttpParameterFailure(params4); + + String[] params5 = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, null, + Const.ParamsNames.COURSE_ID, null, + }; + + verifyHttpParameterFailure(params5); + } + + @Test + public void testSpecificAccessControl_notInstructor_cannotAccess() { + String[] params = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, session.getName(), + Const.ParamsNames.COURSE_ID, session.getCourseId(), + }; + loginAsStudent(googleId); + verifyCannotAccess(params); + logoutUser(); + verifyCannotAccess(params); + } + + @Test + public void testSpecificAccessControl_instructorWithPermission_canAccess() { + InstructorPrivileges instructorPrivileges = new InstructorPrivileges(); + instructorPrivileges.updatePrivilege(Const.InstructorPermissions.CAN_MODIFY_SESSION, true); + Instructor instructor = new Instructor(course, "name", "instructoremail@tm.tmt", + false, "", null, instructorPrivileges); + loginAsInstructor(googleId); + when(mockLogic.getInstructorByGoogleId(course.getId(), googleId)).thenReturn(instructor); + when(mockLogic.getFeedbackSessionFromRecycleBin(session.getName(), course.getId())).thenReturn(session); + + String[] params = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, session.getName(), + Const.ParamsNames.COURSE_ID, session.getCourseId(), + }; + verifyCanAccess(params); + + } + + @Test + public void testSpecificAccessControl_instructorWithoutPermission_cannotAccess() { + InstructorPrivileges instructorPrivileges = new InstructorPrivileges(); + Instructor instructor = new Instructor(course, "name", "instructoremail@tm.tmt", + false, "", null, instructorPrivileges); + loginAsInstructor(googleId); + when(mockLogic.getInstructorByGoogleId(course.getId(), googleId)).thenReturn(instructor); + when(mockLogic.getFeedbackSessionFromRecycleBin(session.getName(), course.getId())).thenReturn(session); + + String[] params = { + Const.ParamsNames.FEEDBACK_SESSION_NAME, session.getName(), + Const.ParamsNames.COURSE_ID, session.getCourseId(), + }; + verifyCannotAccess(params); + } +} diff --git a/src/test/java/teammates/sqlui/webapi/EnrollStudentsActionTest.java b/src/test/java/teammates/sqlui/webapi/EnrollStudentsActionTest.java new file mode 100644 index 00000000000..a0d51fcd762 --- /dev/null +++ b/src/test/java/teammates/sqlui/webapi/EnrollStudentsActionTest.java @@ -0,0 +1,226 @@ +package teammates.sqlui.webapi; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import teammates.common.datatransfer.InstructorPrivileges; +import teammates.common.exception.EntityAlreadyExistsException; +import teammates.common.exception.EntityDoesNotExistException; +import teammates.common.exception.InvalidParametersException; +import teammates.common.util.Const; +import teammates.storage.sqlentity.Course; +import teammates.storage.sqlentity.Instructor; +import teammates.storage.sqlentity.Section; +import teammates.storage.sqlentity.Student; +import teammates.storage.sqlentity.Team; +import teammates.ui.output.EnrollStudentsData; +import teammates.ui.output.StudentData; +import teammates.ui.request.StudentsEnrollRequest; +import teammates.ui.webapi.EnrollStudentsAction; +import teammates.ui.webapi.JsonResult; + +/** + * Test cases for the {@link EnrollStudentsAction} class. + */ +public class EnrollStudentsActionTest extends BaseActionTest { + private Course course; + private Team team; + private Section section; + + @Override + protected String getActionUri() { + return Const.ResourceURIs.STUDENTS; + } + + @Override + protected String getRequestMethod() { + return PUT; + } + + @BeforeMethod + void setUp() { + course = new Course("course-id", "name", Const.DEFAULT_TIME_ZONE, "institute"); + section = new Section(course, "section"); + team = new Team(section, course.getId()); + } + + @Test + public void testExecute_withNewStudent_shouldBeAdded() throws Exception { + Instructor instructor = getTypicalInstructor(); + loginAsInstructor(instructor.getGoogleId()); + Student newStudent = new Student(course, "name", "email.com", "", team); + when(mockLogic.getCourse(course.getId())).thenReturn(course); + when(mockLogic.getStudentsForCourse(course.getId())).thenReturn(new ArrayList<>()); + when(mockLogic.createStudent( + argThat(argument -> Objects.equals(argument.getName(), newStudent.getName()) + && Objects.equals(argument.getEmail(), newStudent.getEmail()) + && Objects.equals(argument.getTeam(), newStudent.getTeam()) + && Objects.equals(argument.getSection(), newStudent.getSection())))).thenReturn(newStudent); + when(mockLogic.getTeamOrCreate(section, "team")).thenReturn(team); + when(mockLogic.getSectionOrCreate(course.getId(), "section")).thenReturn(section); + + StudentsEnrollRequest req = prepareRequest(newStudent); + String[] params = new String[] { + Const.ParamsNames.COURSE_ID, course.getId(), + }; + EnrollStudentsAction action = getAction(req, params); + JsonResult result = getJsonResult(action); + + List enrolledStudents = ((EnrollStudentsData) result.getOutput()).getStudentsData().getStudents(); + assertEquals(1, enrolledStudents.size()); + assertEquals(enrolledStudents.get(0).getEmail(), newStudent.getEmail()); + verifySpecifiedTasksAdded(Const.TaskQueue.SEARCH_INDEXING_QUEUE_NAME, 1); + } + + @Test + public void testExecute_studentAlreadyEnrolled_updateStudent() throws Exception { + Instructor instructor = getTypicalInstructor(); + loginAsInstructor(instructor.getGoogleId()); + Student newStudent = new Student(course, "name", "email.com", "", team); + Student existingStudent = new Student(course, "oldName", "email.com", "", team); + when(mockLogic.getStudentsForCourse(course.getId())).thenReturn(new ArrayList<>(List.of(existingStudent))); + when(mockLogic.getCourse(course.getId())).thenReturn(course); + when(mockLogic.getStudentForEmail(course.getId(), newStudent.getEmail())).thenReturn(existingStudent); + when(mockLogic.getTeamOrCreate(section, "team")).thenReturn(team); + when(mockLogic.getSectionOrCreate(course.getId(), "section")).thenReturn(section); + when(mockLogic.updateStudentCascade( + argThat(argument -> Objects.equals(argument.getName(), newStudent.getName()) + && Objects.equals(argument.getEmail(), newStudent.getEmail()) + && Objects.equals(argument.getTeam(), newStudent.getTeam()) + && Objects.equals(argument.getSection(), newStudent.getSection())))).thenReturn(newStudent); + StudentsEnrollRequest req = prepareRequest(newStudent); + String[] params = new String[] { + Const.ParamsNames.COURSE_ID, course.getId(), + }; + EnrollStudentsAction action = getAction(req, params); + JsonResult result = getJsonResult(action); + + List enrolledStudents = ((EnrollStudentsData) result.getOutput()).getStudentsData().getStudents(); + assertEquals(enrolledStudents.size(), 1); + assertEquals(enrolledStudents.get(0).getName(), newStudent.getName()); + verifySpecifiedTasksAdded(Const.TaskQueue.SEARCH_INDEXING_QUEUE_NAME, 1); + } + + @Test + public void testExecute_invalidParamsAndNotAlreadyEnrolled_studentAddedToErrorList() throws + EntityAlreadyExistsException, InvalidParametersException { + doThrow(new InvalidParametersException("")).when(mockLogic).createStudent(any(Student.class)); + + Instructor instructor = getTypicalInstructor(); + loginAsInstructor(instructor.getGoogleId()); + Student newStudent = new Student(course, "name", "email.com", "", team); + when(mockLogic.getStudentsForCourse(course.getId())).thenReturn(new ArrayList<>()); + when(mockLogic.getCourse(course.getId())).thenReturn(course); + when(mockLogic.getTeamOrCreate(section, "team")).thenReturn(team); + when(mockLogic.getSectionOrCreate(course.getId(), "section")).thenReturn(section); + + StudentsEnrollRequest req = prepareRequest(newStudent); + String[] params = new String[] { + Const.ParamsNames.COURSE_ID, course.getId(), + }; + EnrollStudentsAction action = getAction(req, params); + JsonResult result = getJsonResult(action); + List enrolledStudents = ((EnrollStudentsData) result.getOutput()).getStudentsData().getStudents(); + List errors = + ((EnrollStudentsData) result.getOutput()).getUnsuccessfulEnrolls(); + assertEquals(errors.size(), 1); + assertEquals(enrolledStudents.size(), 0); + } + + @Test + public void testExecute_invalidParamsAndAlreadyEnrolled_studentAddedToErrorList() + throws InvalidParametersException, EntityDoesNotExistException, EntityAlreadyExistsException { + Instructor instructor = getTypicalInstructor(); + loginAsInstructor(instructor.getGoogleId()); + + doThrow(new InvalidParametersException("")).when(mockLogic).updateStudentCascade(any(Student.class)); + + Student newStudent = new Student(course, "name", "email.com", "", team); + when(mockLogic.getCourse(course.getId())).thenReturn(course); + when(mockLogic.getStudentsForCourse(course.getId())).thenReturn(new ArrayList<>(List.of(newStudent))); + when(mockLogic.getStudentForEmail(course.getId(), newStudent.getEmail())).thenReturn(newStudent); + when(mockLogic.getTeamOrCreate(section, "team")).thenReturn(team); + when(mockLogic.getSectionOrCreate(course.getId(), "section")).thenReturn(section); + + StudentsEnrollRequest req = prepareRequest(newStudent); + String[] params = new String[] { + Const.ParamsNames.COURSE_ID, course.getId(), + }; + EnrollStudentsAction action = getAction(req, params); + JsonResult result = getJsonResult(action); + List enrolledStudents = ((EnrollStudentsData) result.getOutput()).getStudentsData().getStudents(); + List errors = + ((EnrollStudentsData) result.getOutput()).getUnsuccessfulEnrolls(); + assertEquals(errors.size(), 1); + assertEquals(enrolledStudents.size(), 0); + } + + @Test + public void testExecute_invalidCourseId_invalidHttpRequestBodyException() { + Instructor instructor = getTypicalInstructor(); + loginAsInstructor(instructor.getGoogleId()); + String[] params = new String[] { + Const.ParamsNames.COURSE_ID, null, + }; + + verifyHttpParameterFailure(params); + } + + @Test + public void testSpecificAccessControl_instructorWithInvalidPermission_cannotAccess() { + Instructor instructor = new Instructor(course, "name", "instructoremail@tm.tmt", + false, "", null, new InstructorPrivileges()); + loginAsInstructor(instructor.getGoogleId()); + String[] params = new String[] { + Const.ParamsNames.COURSE_ID, course.getId(), + }; + + verifyCannotAccess(params); + } + + @Test + public void testSpecificAccessControl_instructorWithValidPermission_canAccess() { + InstructorPrivileges instructorPrivileges = new InstructorPrivileges(); + instructorPrivileges.updatePrivilege(Const.InstructorPermissions.CAN_MODIFY_STUDENT, true); + Instructor instructor = new Instructor(course, "name", "instructoremail@tm.tmt", + false, "", null, instructorPrivileges); + loginAsInstructor(instructor.getGoogleId()); + when(mockLogic.getInstructorByGoogleId(course.getId(), instructor.getGoogleId())).thenReturn(instructor); + when(mockLogic.getCourse(course.getId())).thenReturn(course); + String[] params = new String[] { + Const.ParamsNames.COURSE_ID, course.getId(), + }; + verifyCanAccess(params); + } + + @Test + public void testSpecificAccessControl_notInstructor_cannotAccess() { + String[] params = { + Const.ParamsNames.COURSE_ID, course.getId(), + }; + loginAsStudent("random-id"); + verifyCannotAccess(params); + + logoutUser(); + verifyCannotAccess(params); + } + + private StudentsEnrollRequest prepareRequest(Student... studentsToEnroll) { + List requestList = new ArrayList<>(); + Arrays.stream(studentsToEnroll).forEach(student -> requestList.add( + new StudentsEnrollRequest.StudentEnrollRequest(student.getName(), student.getEmail(), + "team", "section", student.getComments()))); + return new StudentsEnrollRequest(requestList); + } + +}