package com.qprogramming.tasq.agile; import com.qprogramming.tasq.account.Account; import com.qprogramming.tasq.account.AccountService; import com.qprogramming.tasq.account.Roles; import com.qprogramming.tasq.error.TasqAuthException; import com.qprogramming.tasq.projects.Project; import com.qprogramming.tasq.projects.ProjectService; import com.qprogramming.tasq.support.PeriodHelper; import com.qprogramming.tasq.support.ResultData; import com.qprogramming.tasq.support.web.Message; import com.qprogramming.tasq.task.Task; import com.qprogramming.tasq.task.TaskService; import com.qprogramming.tasq.task.TaskState; import com.qprogramming.tasq.task.worklog.LogType; import com.qprogramming.tasq.task.worklog.WorkLog; import com.qprogramming.tasq.task.worklog.WorkLogService; import com.qprogramming.tasq.test.MockSecurityContext; import com.qprogramming.tasq.test.TestUtils; import org.joda.time.LocalDate; import org.joda.time.Period; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.annotation.PropertySource; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.ui.Model; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.persistence.EntityManager; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.*; import static com.qprogramming.tasq.test.TestUtils.*; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) @PropertySource("classpath:/project.properties") public class SprintControllerTest { @Rule public ExpectedException thrown = ExpectedException.none(); @Autowired PeriodHelper periodHelper; @Mock private AccountService accSrvMock; @Mock private MockSecurityContext securityMock; @Mock private RedirectAttributes raMock; @Mock private ProjectService projSrvMock; @Mock private TaskService taskSrvMock; @Mock private SprintRepository sprintRepoMock; @Mock private ReleaseRepository releaseRepoMock; @Mock private WorkLogService wrkLogSrvMock; @Mock private Authentication authMock; @Mock private Model modelMock; @Mock private MessageSource msgMock; @Mock private HttpServletResponse responseMock; @Mock private HttpServletRequest requestMock; @Mock private EntityManager entityManagerMock; private Account testAccount; private Project project; private SprintController sprintCtrl; private AgileService sprintSrv; @Before public void setUp() { // ReflectionTestUtils.setField(PeriodHelper.class, "hours", 8); testAccount = TestUtils.createAccount(); project = TestUtils.createProject(); Set<Account> participants = new HashSet<>(createAccountList()); project.setParticipants(participants); sprintSrv = spy(new AgileService(sprintRepoMock, releaseRepoMock, taskSrvMock)); sprintCtrl = new SprintController(projSrvMock, taskSrvMock, sprintSrv, wrkLogSrvMock, msgMock); when(securityMock.getAuthentication()).thenReturn(authMock); when(authMock.getPrincipal()).thenReturn(testAccount); SecurityContextHolder.setContext(securityMock); } @Test public void showNotParticipantTest() { boolean catched = false; when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); try { sprintCtrl.showBoard(PROJECT_ID, modelMock, requestMock, raMock); } catch (TasqAuthException e) { catched = true; } Assert.assertTrue("TasqAuthException not thrown", catched); catched = false; try { sprintCtrl.showBacklog(PROJECT_ID, modelMock, requestMock); } catch (TasqAuthException e) { catched = true; } Assert.assertTrue("TasqAuthException not thrown", catched); } @Test public void showNoActiveSprintTest() { project.addParticipant(testAccount); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(projSrvMock.canEdit(project)).thenReturn(true); when(sprintRepoMock.findByProjectIdAndActiveTrue(project.getId())).thenReturn(null); when(msgMock.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("PROJECT_ID"); Assert.assertEquals("redirect:/" + project.getProjectId() + "/scrum/backlog", sprintCtrl.showBoard(PROJECT_ID, modelMock, requestMock, raMock)); verify(modelMock, times(1)).addAttribute(anyString(), anyObject()); } @Test public void showBoardTest() { project.addParticipant(testAccount); Sprint sprint = new Sprint(); sprint.setProject(project); sprint.setId(1L); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(projSrvMock.canEdit(project)).thenReturn(true); when(sprintRepoMock.findByProjectIdAndActiveTrue(project.getId())).thenReturn(sprint); when(taskSrvMock.findAllBySprint(sprint)).thenReturn(createTaskList(project)); when(msgMock.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("TEST"); Assert.assertEquals("/scrum/board", sprintCtrl.showBoard(PROJECT_ID, modelMock, requestMock, raMock)); verify(modelMock, times(4)).addAttribute(anyString(), anyObject()); } @Test public void showBacklogTest() { project.addParticipant(testAccount); List<Sprint> sprintList = createSprints(); List<Task> taskList = createTaskList(project); taskList.get(0).addSprint(sprintList.get(1)); taskList.get(1).addSprint(sprintList.get(1)); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(projSrvMock.canEdit(project)).thenReturn(true); when(sprintRepoMock.findByProjectIdAndFinished(project.getId(), false)).thenReturn(sprintList); when(taskSrvMock.findByProjectAndOpen(project)).thenReturn(taskList); when(msgMock.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("TEST"); Assert.assertEquals("/scrum/backlog", sprintCtrl.showBacklog(PROJECT_ID, modelMock, requestMock)); verify(modelMock, times(5)).addAttribute(anyString(), anyObject()); } @Test public void createSprintNotAdminAuthTest() { boolean catched = false; project.setAdministrators(new HashSet<Account>()); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); testAccount.setRole(Roles.ROLE_VIEWER); try { sprintCtrl.createSprint(PROJECT_ID, modelMock, requestMock, raMock); } catch (TasqAuthException e) { catched = true; } Assert.assertTrue(catched); } @Test public void createSprintTest() { project.setAdministrators(new HashSet<Account>()); testAccount.setRole(Roles.ROLE_ADMIN); List<Sprint> sprintList = createSprints(); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(sprintRepoMock.findByProjectId(1L)).thenReturn(sprintList); when(projSrvMock.canAdminister(project)).thenReturn(true); sprintCtrl.createSprint(PROJECT_ID, modelMock, requestMock, raMock); verify(sprintRepoMock, times(1)).save(any(Sprint.class)); } @Test public void assignToSprintBadAuthTest() { boolean catched = false; project.setAdministrators(new HashSet<Account>()); testAccount.setRole(Roles.ROLE_POWERUSER); when(sprintRepoMock.findById(1L)).thenReturn(null); Task task = createTask(PROJECT_ID, 1, project); when(taskSrvMock.findById(PROJECT_ID)).thenReturn(task); try { sprintCtrl.assignSprint(PROJECT_ID, 1L, requestMock, raMock); } catch (TasqAuthException e) { catched = true; } Assert.assertTrue(catched); } @Test public void assignToSprintTest() { Sprint sprint = new Sprint(); sprint.setProject(project); testAccount.setRole(Roles.ROLE_ADMIN); project.setAdministrators(new HashSet<>()); when(projSrvMock.canAdminister(project)).thenReturn(true); when(sprintRepoMock.findById(1L)).thenReturn(sprint); when(msgMock.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("TEST"); Task task = createTask(PROJECT_ID, 1, project); task.setStory_points(1); Task resultTask = task; resultTask.addSprint(sprint); when(taskSrvMock.findById(PROJECT_ID)).thenReturn(task); ResultData result = sprintCtrl.assignSprint(PROJECT_ID, 1L, requestMock, raMock).getBody(); Assert.assertEquals(ResultData.Code.OK, result.code); verify(taskSrvMock, times(1)).save(resultTask); // Add to active sprint sprint.setActive(true); sprintCtrl.assignSprint(PROJECT_ID, 1L, requestMock, raMock); verify(wrkLogSrvMock, times(1)).addActivityLog(task, "", LogType.TASKSPRINTADD); // Task not esstimated when adding to active task.setEstimated(true); task.setStory_points(0); result = sprintCtrl.assignSprint(PROJECT_ID, 1L, requestMock, raMock).getBody(); Assert.assertEquals(ResultData.Code.WARNING, result.code); } @Test public void deleteSprintBadAuthTest() { boolean catched = false; project.setAdministrators(new HashSet<>()); testAccount.setRole(Roles.ROLE_POWERUSER); Sprint sprint = new Sprint(); sprint.setProject(project); when(sprintRepoMock.findById(1L)).thenReturn(sprint); try { sprintCtrl.deleteSprint(1L, modelMock, requestMock, raMock); } catch (TasqAuthException e) { catched = true; } Assert.assertTrue(catched); } @Test public void deleteSprintTest() { project.setAdministrators(new HashSet<>()); testAccount.setRole(Roles.ROLE_ADMIN); project.addParticipant(testAccount); List<Sprint> sprintList = createSprints(); List<Task> taskList = createTaskList(project); Sprint removedSprint = sprintList.get(1); taskList.get(0).addSprint(removedSprint); taskList.get(1).addSprint(removedSprint); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(projSrvMock.findById(1L)).thenReturn(project); when(projSrvMock.canAdminister(project)).thenReturn(true); when(sprintRepoMock.findById(1l)).thenReturn(sprintList.get(1)); when(taskSrvMock.findAllBySprint(removedSprint)).thenReturn(taskList); sprintCtrl.deleteSprint(1L, modelMock, requestMock, raMock); verify(taskSrvMock, times(2)).save(any(Task.class)); } @Test public void removeSprintBadAuthTest() { boolean catched = false; project.setAdministrators(new HashSet<Account>()); testAccount.setRole(Roles.ROLE_POWERUSER); Task task = createTask(PROJECT_ID, 1, project); when(taskSrvMock.findById(PROJECT_ID)).thenReturn(task); try { sprintCtrl.removeFromSprint(PROJECT_ID, 1L, modelMock, requestMock, raMock); } catch (TasqAuthException e) { catched = true; } Assert.assertTrue(catched); } @Test public void removeSprintTest() { Sprint sprint = new Sprint(); sprint.setProject(project); testAccount.setRole(Roles.ROLE_ADMIN); project.setAdministrators(new HashSet<Account>()); when(sprintRepoMock.findById(1L)).thenReturn(sprint); when(msgMock.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("PROJECT_ID"); Task task = createTask(PROJECT_ID, 1, project); task.setStory_points(1); Task resultTask = task; task.addSprint(sprint); when(taskSrvMock.findById(PROJECT_ID)).thenReturn(task); when(projSrvMock.canAdminister(project)).thenReturn(true); ResultData result = sprintCtrl.removeFromSprint(PROJECT_ID, 1L, modelMock, requestMock, raMock).getBody(); Assert.assertEquals(ResultData.Code.OK, result.code); verify(taskSrvMock, times(1)).save(resultTask); // remove from active sprint sprint.setActive(true); sprintCtrl.removeFromSprint(PROJECT_ID, 1L, modelMock, requestMock, raMock); verify(wrkLogSrvMock, times(1)).addActivityLog(task, null, LogType.TASKSPRINTREMOVE); } @Test public void startSprintEndDateOverlapsTest() { Sprint sprint = createSingleSprint(); LocalDate startDate = new LocalDate(2015, 1, 1); LocalDate endDate = startDate.plusDays(7); sprint.setStart_date(startDate.toDate()); sprint.setEnd_date(endDate.toDate()); sprint.setSprint_no(1L); List<Sprint> list = new LinkedList<Sprint>(); list.add(sprint); when(sprintRepoMock.findByProjectId(1L)).thenReturn(list); when(projSrvMock.canAdminister(any(Project.class))).thenReturn(true); ResultData result = sprintCtrl.startSprint(2L, 1L, "06-01-2015", "12-01-2015", "12:25", "23:15"); Assert.assertEquals(ResultData.Code.WARNING, result.code); } @Test public void startSprintTest() { project.setAdministrators(new HashSet<Account>()); Sprint sprint = createSingleSprint(); Sprint sprint2 = new Sprint(); sprint2.setProject(project); sprint2.setId(2L); LocalDate startDate = new LocalDate(2015, 1, 10); LocalDate endDate = startDate.plusDays(7); sprint2.setStart_date(startDate.toDate()); sprint2.setEnd_date(endDate.toDate()); sprint2.setSprint_no(2L); List<Sprint> list = new LinkedList<Sprint>(); list.add(sprint); list.add(sprint2); List<Task> taskList = createTaskList(project); for (Task task : taskList) { task.addSprint(sprint2); } taskList.get(0).setState(TaskState.ONGOING); when(sprintRepoMock.findByProjectId(1L)).thenReturn(list); when(sprintRepoMock.findById(2L)).thenReturn(sprint2); when(projSrvMock.findById(1L)).thenReturn(project); when(projSrvMock.canAdminister(project)).thenReturn(true); when(sprintRepoMock.findByProjectIdAndActiveTrue(1L)).thenReturn(null); when(taskSrvMock.findAllBySprint(sprint2)).thenReturn(taskList); testAccount.setRole(Roles.ROLE_POWERUSER); ResultData result = sprintCtrl.startSprint(2L, 1L, "06-02-2015", "12-02-2015", "12:25", "23:15"); Assert.assertEquals(ResultData.Code.ERROR, result.code); testAccount.setRole(Roles.ROLE_ADMIN); result = sprintCtrl.startSprint(2L, 1L, "06-02-2015", "12-02-2015", "12:25", "23:15"); Assert.assertEquals(ResultData.Code.OK, result.code); verify(sprintRepoMock, times(1)).save(any(Sprint.class)); verify(wrkLogSrvMock, times(1)).addWorkLogNoTask(null, project, LogType.SPRINT_START); taskList.get(1).setStory_points(0); result = sprintCtrl.startSprint(2L, 1L, "06-02-2015", "12-02-2015", "12:25", "23:15"); Assert.assertEquals(ResultData.Code.WARNING, result.code); } @Test public void finishSprint() { project.setAdministrators(new HashSet<Account>()); testAccount.setRole(Roles.ROLE_ADMIN); Sprint sprint = createSingleSprint(); List<Task> taskList = createTaskList(project); for (Task task : taskList) { task.addSprint(sprint); } taskList.get(0).setState(TaskState.CLOSED); taskList.get(1).setState(TaskState.ONGOING); taskList.get(2).setState(TaskState.BLOCKED); when(sprintRepoMock.findById(1L)).thenReturn(sprint); when(projSrvMock.findById(1L)).thenReturn(project); when(projSrvMock.canAdminister(project)).thenReturn(true); when(taskSrvMock.findAllBySprint(sprint)).thenReturn(taskList); when(msgMock.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("TEST"); sprintCtrl.finishSprint(1L, requestMock, raMock); verify(taskSrvMock, times(5)).save(any(Task.class)); verify(wrkLogSrvMock, times(1)).addWorkLogNoTask(null, project, LogType.SPRINT_STOP); verify(sprintRepoMock, times(1)).save(sprint); } @Test public void showBurnDownNoActiveTest() { Sprint sprint = createSingleSprint(); when(sprintRepoMock.findByProjectIdAndSprintNo(1L, 1L)).thenReturn(sprint); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); sprintCtrl.showBurndown(PROJECT_ID, 1L, modelMock, raMock); sprint.setEnd_date(null); sprint.setActive(false); sprintCtrl.showBurndown(PROJECT_ID, 1L, modelMock, raMock); verify(raMock, times(2)).addFlashAttribute(anyString(), new Message(anyString(), Message.Type.WARNING, new Object[]{})); } @Test public void showBurnDownNotStartedTest() { Sprint sprint = createSingleSprint(); sprint.setStart_date(null); List<Sprint> list = new LinkedList<Sprint>(); list.add(sprint); when(sprintRepoMock.findByProjectIdAndSprintNo(1L, 1L)).thenReturn(sprint); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(sprintRepoMock.findByProjectId(1L)).thenReturn(list); sprintCtrl.showBurndown(PROJECT_ID, 1L, modelMock, raMock); } @Test public void showBurnDownTest() { Sprint sprint = createSingleSprint(); List<Sprint> list = new LinkedList<Sprint>(); list.add(sprint); when(sprintRepoMock.findByProjectIdAndSprintNo(1L, 1L)).thenReturn(sprint); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(sprintRepoMock.findByProjectId(1L)).thenReturn(list); sprintCtrl.showBurndown(PROJECT_ID, 1L, modelMock, raMock); } @Test public void checkIfActiveTest() { when(sprintRepoMock.findById(1L)).thenReturn(createSingleSprint()); Assert.assertTrue(sprintCtrl.checkIfActive(1L, responseMock)); } @Test public void getSprintsTest() { Sprint sprint = createSingleSprint(); sprint.setActive(false); List<Sprint> list = new LinkedList<Sprint>(); list.add(sprint); when(sprintRepoMock.findByProjectProjectIdAndFinished(TestUtils.PROJECT_ID, false)).thenReturn(list); List<DisplaySprint> result = sprintCtrl.showProjectSprints(TestUtils.PROJECT_ID, responseMock); Assert.assertEquals(1, result.size()); } @Test public void showBurdownChartNotStartedTest() { when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(sprintRepoMock.findByProjectIdAndSprintNo(project.getId(), 1L)).thenReturn(null); when(msgMock.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("TEST"); SprintData result = sprintCtrl.showBurndownChart(PROJECT_ID, 1L); Assert.assertNotNull(result.getMessage()); } @Test public void showBurdownChartTest() { Sprint sprint = createSingleSprint(); sprint.setStart_date(new LocalDate().minusDays(5).toDate()); sprint.setEnd_date(new LocalDate().plusDays(5).toDate()); sprint.setTotalStoryPoints(4); Task task = createTask(PROJECT_ID, 1, project); task.setEstimate(new Period(10, 0, 0, 0)); task.setState(TaskState.CLOSED); WorkLog wrk = new WorkLog(); wrk.setActivity(new Period(1, 0, 0, 0)); wrk.setTask(task); wrk.setTime(new LocalDate().minusDays(2).toDate()); wrk.setTimeLogged(wrk.getRawTime()); wrk.setAccount(testAccount); WorkLog wl = new WorkLog(); wl.setTask(task); wl.setAccount(testAccount); wl.setTime(new LocalDate().minusDays(1).toDate()); wl.setTimeLogged(wl.getRawTime()); wl.setType(LogType.CLOSED); Task task2 = createTask(PROJECT_ID, 2, project); WorkLog wl2 = new WorkLog(); wl2.setTask(task2); wl2.setAccount(testAccount); wl2.setTime(new LocalDate().minusDays(1).toDate()); wl2.setTimeLogged(wl2.getRawTime()); wl2.setType(LogType.TASKSPRINTADD); List<WorkLog> workLogs = new LinkedList<WorkLog>(); workLogs.add(wrk); workLogs.add(wl); workLogs.add(wl2); when(projSrvMock.findByProjectId(PROJECT_ID)).thenReturn(project); when(sprintRepoMock.findByProjectIdAndSprintNo(project.getId(), 1L)).thenReturn(sprint); when(msgMock.getMessage(anyString(), any(Object[].class), any(Locale.class))).thenReturn("TEST"); when(wrkLogSrvMock.getAllSprintEvents(sprint)).thenReturn(workLogs); SprintData result = sprintCtrl.showBurndownChart(PROJECT_ID, 1L); Assert.assertNull(result.getMessage()); } @Test public void equalsSprintTest() { Sprint sprint = createSingleSprint(); Sprint sprint2 = createSingleSprint(); DisplaySprint ds = new DisplaySprint(sprint); DisplaySprint ds2 = new DisplaySprint(sprint2); Assert.assertEquals(ds, ds2); Assert.assertEquals(ds.hashCode(), ds2.hashCode()); Assert.assertEquals(ds.getName(), ds2.getName()); Assert.assertEquals(sprint, sprint2); ds.setSprintNo(2L); Assert.assertEquals(1, ds.compareTo(ds2)); } @Test public void validateSprintTest() { String start = "20-20-20"; String end = ""; ResultData resultData = sprintCtrl.validateSprint(start, end, responseMock); Assert.assertEquals(ResultData.Code.WARNING, resultData.code); } @Test public void validateSprintValidTest() { String start = "20-12-2016 11:15"; String end = "27-12-2016 11:15"; ResultData resultData = sprintCtrl.validateSprint(start, end, responseMock); Assert.assertEquals(ResultData.Code.OK, resultData.code); } @Test public void validateSprintTooLongTest() { String start = "20-11-2016 11:15"; String end = "27-12-2016 11:15"; ResultData resultData = sprintCtrl.validateSprint(start, end, responseMock); Assert.assertEquals(ResultData.Code.WARNING, resultData.code); } private Sprint createSingleSprint() { Sprint sprint = new Sprint(); sprint.setProject(project); sprint.setId(1L); sprint.setSprint_no(1L); LocalDate startDate = new LocalDate(2015, 1, 1); LocalDate endDate = startDate.plusDays(7); sprint.setStart_date(startDate.toDate()); sprint.setEnd_date(endDate.toDate()); sprint.setSprint_no(1L); sprint.setActive(true); return sprint; } private List<Task> createTaskList(Project project) { List<Task> taskList = new LinkedList<Task>(); for (int i = 0; i < 5; i++) { taskList.add(TestUtils.createTask("TASK" + i, i, project)); } return taskList; } private List<Sprint> createSprints() { Sprint sprint = new Sprint(); sprint.setProject(project); sprint.setId(1L); LocalDate startDate = new LocalDate(); startDate = startDate.minusDays(7); LocalDate endDate = new LocalDate(); endDate = endDate.minusDays(3); sprint.setStart_date(startDate.toDate()); sprint.setEnd_date(endDate.toDate()); sprint.setSprint_no(1L); Sprint sprint2 = new Sprint(); sprint2.setProject(project); sprint2.setId(2L); sprint2.setStart_date(endDate.plusDays(1).toDate()); sprint2.setSprint_no(2L); sprint2.setActive(true); List<Sprint> sprintList = new LinkedList<Sprint>(); sprintList.add(sprint); sprintList.add(sprint2); return sprintList; } }