package de.asideas.crowdsource.service; import de.asideas.crowdsource.domain.exception.InvalidRequestException; import de.asideas.crowdsource.domain.exception.NotAuthorizedException; import de.asideas.crowdsource.domain.exception.ResourceNotFoundException; import de.asideas.crowdsource.domain.model.*; import de.asideas.crowdsource.domain.service.user.UserNotificationService; import de.asideas.crowdsource.domain.shared.ProjectStatus; import de.asideas.crowdsource.presentation.FinancingRound; import de.asideas.crowdsource.presentation.Pledge; import de.asideas.crowdsource.presentation.project.Attachment; import de.asideas.crowdsource.presentation.project.Project; import de.asideas.crowdsource.repository.*; import de.asideas.crowdsource.security.Roles; import org.hamcrest.core.Is; import org.joda.time.DateTime; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.test.util.ReflectionTestUtils; import java.io.InputStream; import java.util.*; import static de.asideas.crowdsource.domain.shared.LikeStatus.LIKE; import static de.asideas.crowdsource.domain.shared.LikeStatus.UNLIKE; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; import static org.mockito.internal.verification.VerificationModeFactory.atLeastOnce; import static org.mockito.internal.verification.VerificationModeFactory.times; @RunWith(MockitoJUnitRunner.class) @SuppressWarnings("Duplicates") public class ProjectServiceTest { private static final String USER_EMAIL = "user@some.host"; private static final String ADMIN1_EMAIL = "admin1@some.host"; private static final String ADMIN2_EMAIL = "admin2@some.host"; public static final int USER_BUDGED = 4000; public static final int FINANCING_ROUND_BUDGET = 10000; @InjectMocks private ProjectService projectService; @Mock private ProjectRepository projectRepository; @Mock private UserNotificationService userNotificationService; @Mock private PledgeRepository pledgeRepository; @Mock private UserRepository userRepository; @Mock private LikeRepository likeRepository; @Mock private UserService userService; @Mock private FinancingRoundRepository financingRoundRepository; @Mock private FinancingRoundService financingRoundService; @Mock private ProjectService thisInstance; @Mock private ProjectAttachmentRepository projectAttachmentRepository; @Before public void init() { ReflectionTestUtils.setField(projectService, "thisInstance", thisInstance); reset(projectRepository, pledgeRepository, userRepository, financingRoundRepository, thisInstance, likeRepository, projectAttachmentRepository); when(pledgeRepository.findByProjectAndFinancingRound(any(ProjectEntity.class), any(FinancingRoundEntity.class))).thenReturn(new ArrayList<>()); when(userRepository.findAllAdminUsers()).thenReturn(Arrays.asList(admin(ADMIN1_EMAIL), admin(ADMIN2_EMAIL))); when(projectRepository.save(any(ProjectEntity.class))).thenAnswer(invocation -> invocation.getArguments()[0]); when(likeRepository.countByProjectAndStatus(any(ProjectEntity.class), eq(LIKE))).thenReturn(0L); when(likeRepository.findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class))).thenReturn(Optional.of(new LikeEntity())); } @Test public void addProject() throws Exception { final Project project = project("myTitle", "theFullDescription", "theShortDescription", 50, ProjectStatus.PROPOSED); final ArgumentCaptor<ProjectEntity> projectEntity = ArgumentCaptor.forClass(ProjectEntity.class); when(projectRepository.save(projectEntity.capture())).thenAnswer(a -> a.getArgumentAt(0, ProjectEntity.class)); prepareActiveFinanzingRound(null); Project res = projectService.addProject(project, user(USER_EMAIL)); assertThat(res, is(new Project(projectEntity.getValue(), new ArrayList<>(), null, 0, LIKE))); verify(userNotificationService, atLeastOnce()).notifyAdminOnProjectCreation(eq(projectEntity.getValue()), anyString()); } @Test public void addProject_shouldWorkIfNoFinancingRoundIsCurrentlyActive() throws Exception { final Project project = project("myTitle", "theFullDescription", "theShortDescription", 50, ProjectStatus.PROPOSED); final ArgumentCaptor<ProjectEntity> projectEntity = ArgumentCaptor.forClass(ProjectEntity.class); when(financingRoundRepository.findActive(any())).thenReturn(null); when(projectRepository.save(projectEntity.capture())).thenAnswer(a -> a.getArgumentAt(0, ProjectEntity.class)); Project res = projectService.addProject(project, user(USER_EMAIL)); assertThat(res, is(new Project(projectEntity.getValue(), new ArrayList<>(), null, 0, LIKE))); verify(userNotificationService, atLeastOnce()).notifyAdminOnProjectCreation(eq(projectEntity.getValue()), anyString()); } @Test public void createProjectTriggersAdminNotification() throws Exception { final Project newProject = new Project(); projectService.addProject(newProject, user("some@mail.com")); verify(userNotificationService).notifyAdminOnProjectCreation(any(ProjectEntity.class), eq(ADMIN1_EMAIL)); verify(userNotificationService).notifyAdminOnProjectCreation(any(ProjectEntity.class), eq(ADMIN2_EMAIL)); verify(userNotificationService, times(2)).notifyAdminOnProjectCreation(any(ProjectEntity.class), anyString()); } @Test public void pledge_shouldThrowIllegalArgumentExceptionWhenCurrentRoundAllowsPostPledgesButDoesntEqualsProjectsRound() throws Exception { final UserEntity user = admin(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final Pledge pledge = new Pledge(4); FinancingRoundEntity mostRecentRound = prepareInactiveFinancingRound(project); when(financingRoundService.mostRecentRoundEntity()).thenReturn(mostRecentRound); project.getFinancingRound().setTerminationPostProcessingDone(true); projectService.pledge(projectId, user, pledge); verify(thisInstance).pledgeProjectUsingPostRoundBudget(eq(project), eq(user), eq(pledge)); } @Test public void pledge_shouldDispatchToPledgeProjectInRoundIfMostRecentRoundIsNullOrNotTerminatedOrNotPostProcessed() throws Exception { final UserEntity user = user(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final Pledge pledge = new Pledge(4); project.setFinancingRound(null); projectService.pledge(projectId, user, pledge); verify(thisInstance).pledgeProjectInFinancingRound(eq(project), eq(user), eq(pledge)); reset(thisInstance); prepareActiveFinanzingRound(project); projectService.pledge(projectId, user, pledge); verify(thisInstance).pledgeProjectInFinancingRound(eq(project), eq(user), eq(pledge)); reset(thisInstance); prepareInactiveFinancingRound(project); projectService.pledge(projectId, user, pledge); verify(thisInstance).pledgeProjectInFinancingRound(eq(project), eq(user), eq(pledge)); } @Test public void pledge_shouldDispatchToPledgeProjectInRoundIfRoundTerminatedAndPostProcessedButUserIsNoAdmin() throws Exception { final UserEntity user = user(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final Pledge pledge = new Pledge(4); prepareInactiveFinancingRound(project); project.getFinancingRound().setTerminationPostProcessingDone(true); projectService.pledge(projectId, user, pledge); verify(thisInstance).pledgeProjectInFinancingRound(eq(project), eq(user), eq(pledge)); } @Test public void pledge_shouldDispatchToPledgeProjectUsingPostRoundBudgetOnTerminatedPostProcessedRoundAndAdminUser() throws Exception { final UserEntity user = admin(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final Pledge pledge = new Pledge(4); prepareInactiveFinancingRound(project); FinancingRoundEntity mostRecentRound = prepareInactiveFinancingRound(null); mostRecentRound.setTerminationPostProcessingDone(true); mostRecentRound.setId("test_roundId_another"); when(financingRoundService.mostRecentRoundEntity()).thenReturn(mostRecentRound); project.getFinancingRound().setTerminationPostProcessingDone(true); try { projectService.pledge(projectId, user, pledge); fail("Exception expected to be thrown"); } catch (InvalidRequestException e) { assertThat(e.getMessage(), is(InvalidRequestException.projectTookNotPartInLastFinancingRond().getMessage())); } } @Test public void pledge_throwsResourceNotFoundExOnNotExistingProject() { final UserEntity user = user(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final Pledge pledge = new Pledge(4); final int budgetBeforePledge = user.getBudget(); pledgedAssertionProject(project, user, project.getPledgeGoal() - 4); when(projectRepository.findOne(anyString())).thenReturn(null); ResourceNotFoundException res = null; try { projectService.pledge(projectId, user, pledge); fail("InvalidRequestException expected!"); } catch (ResourceNotFoundException e) { res = e; } assertPledgeNotExecuted(res, new ResourceNotFoundException(), project, user, budgetBeforePledge, ProjectStatus.PUBLISHED); } @Test public void pledgeProjectInFinancingRound() throws Exception { final UserEntity user = user(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final int budgetBeforePledge = user.getBudget(); final Pledge pledge = new Pledge(project.getPledgeGoal() - 4); FinancingRoundEntity financingRound = prepareActiveFinanzingRound(project); projectService.pledgeProjectInFinancingRound(project, user, pledge); PledgeEntity pledgeEntity = new PledgeEntity(project, user, pledge, financingRound); assertThat(user.getBudget(), is(budgetBeforePledge - pledge.getAmount())); assertThat(project.getStatus(), is(not(ProjectStatus.FULLY_PLEDGED))); verify(pledgeRepository).save(pledgeEntity); verify(userRepository).save(user); verify(projectRepository, never()).save(any(ProjectEntity.class)); } @Test public void pledgeProjectInFinancingRound_reverse() throws Exception { final UserEntity user = user(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final int budgetBeforePledge = user.getBudget(); final Pledge pledge = new Pledge(-4); pledgedAssertionProject(project, user, 4); FinancingRoundEntity financingRound = prepareActiveFinanzingRound(project); projectService.pledgeProjectInFinancingRound(project, user, pledge); PledgeEntity pledgeEntity = new PledgeEntity(project, user, pledge, financingRound); assertThat(user.getBudget(), is(budgetBeforePledge + 4)); assertThat(project.getStatus(), is(not(ProjectStatus.FULLY_PLEDGED))); verify(pledgeRepository).save(pledgeEntity); verify(userRepository).save(user); verify(projectRepository, never()).save(any(ProjectEntity.class)); } @Test public void pledgeProjectInFinancingRound_settingStatusToFullyPledgedShouldPersistProjectToo() throws Exception { final UserEntity user = user(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final Pledge pledge = new Pledge(4); final int budgetBeforePledge = user.getBudget(); pledgedAssertionProject(project, user, project.getPledgeGoal() - 4); FinancingRoundEntity finanzingRound = prepareActiveFinanzingRound(project); projectService.pledgeProjectInFinancingRound(project, user, pledge); PledgeEntity pledgeEntity = new PledgeEntity(project, user, pledge, finanzingRound); assertThat(user.getBudget(), is(budgetBeforePledge - pledge.getAmount())); assertThat(project.getStatus(), is(ProjectStatus.FULLY_PLEDGED)); verify(pledgeRepository).save(pledgeEntity); verify(userRepository).save(user); verify(projectRepository).save(project); } @Test public void pledgeProjectInFinancingRound_errorOnPledgingShouldNotCauseAnyPersistenceActions() throws Exception { final UserEntity user = user(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final int budgetBeforePledge = user.getBudget(); final Pledge pledge = new Pledge(45); prepareActiveFinanzingRound(project); pledgedAssertionProject(project, user, 4); InvalidRequestException res = null; try { projectService.pledgeProjectInFinancingRound(project, user, pledge); fail("InvalidRequestException expected!"); } catch (InvalidRequestException e) { res = e; } assertPledgeNotExecuted(res, InvalidRequestException.pledgeGoalExceeded(), project, user, budgetBeforePledge, ProjectStatus.PUBLISHED); } @Test public void pledgeProjectUsingPostRoundBudget() throws Exception { final UserEntity user = admin(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final Pledge pledge = new Pledge(3); final int budgetBeforePledge = user.getBudget(); pledgedAssertionProject(project, user, project.getPledgeGoal() - 4); FinancingRoundEntity finanzingRound = prepareInactiveFinancingRound(project); finanzingRound.initPostRoundBudget(6000); finanzingRound.setTerminationPostProcessingDone(true); when(pledgeRepository.findByFinancingRoundAndCreatedDateGreaterThan(finanzingRound, finanzingRound.getEndDate())).thenReturn(Collections.emptyList()); projectService.pledgeProjectUsingPostRoundBudget(project, user, pledge); PledgeEntity pledgeEntity = new PledgeEntity(project, user, pledge, finanzingRound); assertThat(user.getBudget(), is(budgetBeforePledge)); assertThat(project.getStatus(), is(ProjectStatus.PUBLISHED)); verify(pledgeRepository).save(pledgeEntity); verify(userRepository).save(user); verify(projectRepository, never()).save(project); } @Test public void pledgeProjectUsingPostRoundBudget_settingStatusToFullyPledgedShouldPersistProjectToo() throws Exception { final UserEntity user = admin(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final Pledge pledge = new Pledge(4); final int budgetBeforePledge = user.getBudget(); pledgedAssertionProject(project, user, project.getPledgeGoal() - 4); FinancingRoundEntity finanzingRound = prepareInactiveFinancingRound(project); finanzingRound.initPostRoundBudget(6000); finanzingRound.setTerminationPostProcessingDone(true); when(pledgeRepository.findByFinancingRoundAndCreatedDateGreaterThan(finanzingRound, finanzingRound.getEndDate())).thenReturn(Collections.emptyList()); projectService.pledgeProjectUsingPostRoundBudget(project, user, pledge); PledgeEntity pledgeEntity = new PledgeEntity(project, user, pledge, finanzingRound); assertThat(user.getBudget(), is(budgetBeforePledge)); assertThat(project.getStatus(), is(ProjectStatus.FULLY_PLEDGED)); verify(pledgeRepository).save(pledgeEntity); verify(userRepository).save(user); verify(projectRepository).save(project); } @Test public void pledgeProjectUsingPostRoundBudget_errorOnPledgingShouldNotCauseAnyPersistenceActions() throws Exception { final UserEntity user = admin(USER_EMAIL); final String projectId = "some_id"; final ProjectEntity project = projectEntity(user, projectId, "title", 44, "short description", "description", ProjectStatus.PUBLISHED, null); final int budgetBeforePledge = user.getBudget(); final Pledge pledge = new Pledge(45); pledgedAssertionProject(project, user, project.getPledgeGoal() - 4); FinancingRoundEntity finanzingRound = prepareInactiveFinancingRound(project); finanzingRound.initPostRoundBudget(6000); finanzingRound.setTerminationPostProcessingDone(true); when(pledgeRepository.findByFinancingRoundAndCreatedDateGreaterThan(finanzingRound, finanzingRound.getEndDate())).thenReturn(Collections.emptyList()); InvalidRequestException res = null; try { projectService.pledgeProjectUsingPostRoundBudget(project, user, pledge); fail("InvalidRequestException expected!"); } catch (InvalidRequestException e) { res = e; } assertPledgeNotExecuted(res, InvalidRequestException.pledgeGoalExceeded(), project, user, budgetBeforePledge, ProjectStatus.PUBLISHED); } @Test public void modifyProjectStatus_updatedStateTriggersUserNotificationAndPeristence() throws Exception { final UserEntity user = user(USER_EMAIL); final ProjectEntity projectEntity = projectEntity("some_id", ProjectStatus.PROPOSED, user); projectService.modifyProjectStatus("some_id", ProjectStatus.PUBLISHED, user); verify(projectRepository).save(projectEntity); verify(userNotificationService).notifyCreatorOnProjectStatusUpdate(any(ProjectEntity.class)); } @Test public void modifyProjectStatus_nonUpdatedStateDoesNotTriggerUserNotificationAndNoPersistence() throws Exception { UserEntity user = user(USER_EMAIL); projectEntity("some_id", ProjectStatus.PROPOSED, user); projectService.modifyProjectStatus("some_id", ProjectStatus.PROPOSED, user); verify(projectRepository, never()).save(any(ProjectEntity.class)); verify(userNotificationService, never()).notifyCreatorOnProjectStatusUpdate(any(ProjectEntity.class)); } @Test public void modifyProjectMasterdata_notifiesAndSavesOnSuccessfulModification() throws Exception { final String projectId = "test_ID"; final UserEntity user = user(USER_EMAIL); final ProjectEntity project = projectEntity(projectId, ProjectStatus.PROPOSED, user); final Project projectCmd = project("title", "descr", "descrShort", 17, ProjectStatus.FULLY_PLEDGED); projectService.modifyProjectMasterdata(projectId, projectCmd, user); ArgumentCaptor<ProjectEntity> captProject = ArgumentCaptor.forClass(ProjectEntity.class); verify(projectRepository).save(captProject.capture()); verify(userNotificationService).notifyCreatorAndAdminOnProjectModification(project, user); assertThat(captProject.getValue().getDescription(), is(projectCmd.getDescription())); assertThat(captProject.getValue().getStatus(), not(equalTo(projectCmd.getStatus()))); } @Test public void modifyProjectMasterdata_doesNotNotifyAndSaveOnNoModification() throws Exception { final String projectId = "test_ID"; final UserEntity user = user(USER_EMAIL); final Project projectCmd = project("title", "descr", "descrShort", 17, ProjectStatus.PROPOSED); final ProjectEntity project = new ProjectEntity(user, projectCmd, null); when(projectRepository.findOne(projectId)).thenReturn(project); projectService.modifyProjectMasterdata(projectId, projectCmd, user); verify(projectRepository, never()).save(any(ProjectEntity.class)); verify(userNotificationService, never()).notifyCreatorAndAdminOnProjectModification(any(ProjectEntity.class), any(UserEntity.class)); } @Test(expected = ResourceNotFoundException.class) public void modifyProjectMasterdata_ThrowsResourceNotFoundExOnNotExistingProject() throws Exception { final String projectId = "test_ID"; when(projectRepository.findOne(projectId)).thenReturn(null); projectService.modifyProjectMasterdata(projectId, project(null, null, null, 17, null), user("blub")); verify(projectRepository, never()).save(any(ProjectEntity.class)); verify(userNotificationService, never()).notifyCreatorAndAdminOnProjectModification(any(ProjectEntity.class), any(UserEntity.class)); } @Test public void addAttachment_ShouldStoreAttachmentAndProject() throws Exception { final String projectId = "test_ID"; final UserEntity projectCreator = user(USER_EMAIL); final Project projectCmd = project("title", "descr", "descrShort", 17, ProjectStatus.PROPOSED); final ProjectEntity project = new ProjectEntity(projectCreator, projectCmd, null); final Attachment attachmentSaveCmd = aStoringRequestAttachment(); final AttachmentValue expAttachmentValue = aPersitedAttachment("fileRef"); ArgumentCaptor<AttachmentValue> writeAttachmentCaptor = ArgumentCaptor.forClass(AttachmentValue.class); when(projectRepository.findOne(projectId)).thenReturn(project); when(projectAttachmentRepository.storeAttachment(writeAttachmentCaptor.capture(), any(InputStream.class))).thenReturn(expAttachmentValue); Attachment res = projectService.addProjectAttachment(projectId, attachmentSaveCmd, projectCreator); ArgumentCaptor<ProjectEntity> projectCaptor = ArgumentCaptor.forClass(ProjectEntity.class); assertThat(writeAttachmentCaptor.getValue().getContentType(), is(attachmentSaveCmd.getType())); assertThat(writeAttachmentCaptor.getValue().getFilename(), is(attachmentSaveCmd.getName())); verify(projectRepository).save(projectCaptor.capture()); assertThat("Project should contain new attachment", projectCaptor.getValue().getAttachments().contains(expAttachmentValue)); assertPresentationAttachmentConformsPersited(res, expAttachmentValue); } @Test(expected = ResourceNotFoundException.class) public void addAttachment_ThrowsResourceNotFoundExOnNotExistingProject() throws Exception { final String projectId = "test_ID"; when(projectRepository.findOne(projectId)).thenReturn(null); projectService.addProjectAttachment(projectId, aStoringRequestAttachment(), user("blub")); } @Test public void addAttachment_shouldThrowExceptionWhenChangesNotAllowedDueToProjectStatus() throws Exception { final String projectId = "test_ID"; final UserEntity projectCreator = user(USER_EMAIL); final Project projectCmd = project("title", "descr", "descrShort", 17, ProjectStatus.PROPOSED); final ProjectEntity project = new ProjectEntity(projectCreator, projectCmd, null); project.setStatus(ProjectStatus.FULLY_PLEDGED); when(projectRepository.findOne(projectId)).thenReturn(project); try { projectService.addProjectAttachment(projectId, aStoringRequestAttachment(), projectCreator); fail("InvalidRequestException expected!"); } catch (InvalidRequestException e) { assertThat(e.getMessage(), is(InvalidRequestException.masterdataChangeNotAllowed().getMessage())); } } @Test public void loadProjectAttachment_shouldCallProjectAttachmentRepository() throws Exception { final String fileRef = "attachId_0"; final ProjectEntity projectEntity = givenAProjectEntityWithAttachments(fileRef, "anotherFileRef"); final InputStream expInputStream = mockedInputStream(); final ArgumentCaptor<AttachmentValue> repoReqCapture = ArgumentCaptor.forClass(AttachmentValue.class); when(projectAttachmentRepository.loadAttachment(repoReqCapture.capture())).thenReturn(expInputStream); final Attachment res = projectService.loadProjectAttachment(projectEntity.getId(), Attachment.asLookupByIdCommand(fileRef)); assertThat(repoReqCapture.getValue().getFileReference(), is(fileRef)); assertThat("Expected specific input stream in result", res.getPayload() == expInputStream); assertPresentationAttachmentConformsPersited(res, projectEntity.findAttachmentByReference(Attachment.asLookupByIdCommand(fileRef))); } @Test(expected = ResourceNotFoundException.class) public void loadProjectAttachment_shouldThrowResourceNotFoundExceptionOnNullPayload() throws Exception { final String fileRef = "attachId_0"; final ProjectEntity projectEntity = givenAProjectEntityWithAttachments(fileRef, "anotherFileRef"); when(projectAttachmentRepository.loadAttachment(any(AttachmentValue.class))).thenReturn(null); projectService.loadProjectAttachment(projectEntity.getId(), Attachment.asLookupByIdCommand(fileRef)); } @Test(expected = ResourceNotFoundException.class) public void loadProjectAttachment_shouldThrowResourceNotFoundExceptionOnProjectNotExisting() throws Exception { projectService.loadProjectAttachment("notExistingProjectId", Attachment.asLookupByIdCommand("aFileRef")); } @Test public void deleteAttachment_shouldCallProjectAttachmentRepositoryAndPersistProject() throws Exception { final String fileRef = "attachId_0"; final ProjectEntity project = givenAProjectEntityWithAttachments(fileRef, "anotherFileRef"); final int attachmentSizeBeforeDel = project.getAttachments().size(); project.setStatus(ProjectStatus.PROPOSED); when(projectRepository.findOne(project.getId())).thenReturn(project); projectService.deleteProjectAttachment(project.getId(), Attachment.asLookupByIdCommand(fileRef), admin("anAdmin")); final ArgumentCaptor<AttachmentValue> fileRepoCapture = ArgumentCaptor.forClass(AttachmentValue.class); final ArgumentCaptor<ProjectEntity> projectEntityRepCapture = ArgumentCaptor.forClass(ProjectEntity.class); verify(projectAttachmentRepository).deleteAttachment(fileRepoCapture.capture()); verify(projectRepository).save(projectEntityRepCapture.capture()); assertThat(fileRepoCapture.getValue().getFileReference(), is(fileRef)); assertThat(projectEntityRepCapture.getValue().getAttachments().size(), is(attachmentSizeBeforeDel - 1)); assertThat("Should have removed AttachmentValue from project", !projectEntityRepCapture.getValue().getAttachments().contains(new AttachmentValue(fileRef, null, null, 17, null))); } @Test(expected = ResourceNotFoundException.class) public void deleteAttachment_shouldThrowResourceNotFoundExceptionOnNotExistingProject() throws Exception { final String fileRef = "attachId_0"; final ProjectEntity project = givenAProjectEntityWithAttachments(fileRef, "anotherFileRef"); project.setStatus(ProjectStatus.PROPOSED); when(projectRepository.findOne(project.getId())).thenReturn(null); projectService.deleteProjectAttachment(project.getId(), Attachment.asLookupByIdCommand(fileRef), admin("anAdmin")); } @Test(expected = ResourceNotFoundException.class) public void deleteAttachment_shouldThrowResourceNotFoundOnNotExistingAttachmentValue() throws Exception { final String fileRef = "attachId_0"; final UserEntity projectCreator = user(USER_EMAIL); final ProjectEntity project = projectEntity("projectId", ProjectStatus.PROPOSED, projectCreator); projectService.deleteProjectAttachment(project.getId(), Attachment.asLookupByIdCommand(fileRef), admin("anAdmin")); } @Test(expected = NotAuthorizedException.class) public void deleteAttachment_shouldThrowNotAllowedExceptionOnDeletionByNonAdminAndNonCreator() throws Exception { final String fileRef = "attachId_0"; final ProjectEntity project = givenAProjectEntityWithAttachments(fileRef, "anotherFileRef"); project.setStatus(ProjectStatus.PROPOSED); when(projectRepository.findOne(project.getId())).thenReturn(project); when(projectAttachmentRepository.loadAttachment(any(AttachmentValue.class))).thenReturn(null); projectService.deleteProjectAttachment(project.getId(), Attachment.asLookupByIdCommand(fileRef), user("aUser")); } @Test public void deleteAttachment_shouldThrowExceptionWhenChangesNotAllowedDueToProjectStatus() throws Exception { final String fileRef = "attachId_0"; final ProjectEntity project = givenAProjectEntityWithCreatorAndAttachments(user("aCreator@asideas.de"), fileRef, "anotherFileRef"); project.setStatus(ProjectStatus.PUBLISHED); project.setFinancingRound(prepareActiveFinanzingRound(project)); when(projectRepository.findOne(project.getId())).thenReturn(project); when(projectAttachmentRepository.loadAttachment(any(AttachmentValue.class))).thenReturn(null); try { projectService.deleteProjectAttachment(project.getId(), Attachment.asLookupByIdCommand(fileRef), project.getCreator()); fail("InvalidRequestException expected!"); } catch (InvalidRequestException e) { assertThat(e.getMessage(), is(InvalidRequestException.masterdataChangeNotAllowed().getMessage())); } } @Test public void getProject_shouldReturnDefaultLikeCountAndLikeStatus() throws Exception { final UserEntity projectCreator = user(USER_EMAIL); final ProjectEntity projectEntity = projectEntity("projectId", ProjectStatus.PROPOSED, projectCreator); when(projectRepository.findOne(anyString())).thenReturn(projectEntity); when(likeRepository.findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class))).thenReturn(Optional.empty()); final Project project = projectService.getProject("projectId", projectCreator); assertThat(project, hasProperty("likeCount", equalTo(0L))); assertThat(project, hasProperty("likeStatusOfRequestUser", equalTo(UNLIKE))); } private ProjectEntity givenAProjectEntityWithCreatorAndAttachments(UserEntity creator, String... attachmentFileReferences) { final ProjectEntity projectEntity = projectEntity("test_id", ProjectStatus.PROPOSED, creator); if(attachmentFileReferences != null){ Arrays.asList(attachmentFileReferences).stream().forEach( r -> projectEntity.addAttachment(aPersitedAttachment(r)) ); } return projectEntity; } private ProjectEntity givenAProjectEntityWithAttachments(String... attachmentFileReferences) { return givenAProjectEntityWithCreatorAndAttachments(user("a_user@asideas.de"), attachmentFileReferences); } @Test public void likeProject_shouldCreateLikeEntityIfNotExists() throws Exception { when(likeRepository.findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class))).thenReturn(Optional.empty()); projectService.likeProject("projectId", any(UserEntity.class)); final ArgumentCaptor<LikeEntity> captor = ArgumentCaptor.forClass(LikeEntity.class); verify(likeRepository, times(1)).findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class)); verify(likeRepository, times(1)).save(captor.capture()); assertThat(captor.getValue().getStatus(), is(LIKE)); } @Test public void likeProject_shouldCreateLikeEntityIfExists() throws Exception { when(likeRepository.findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class))).thenReturn(Optional.of(new LikeEntity())); projectService.likeProject("projectId", any(UserEntity.class)); final ArgumentCaptor<LikeEntity> captor = ArgumentCaptor.forClass(LikeEntity.class); verify(likeRepository, times(1)).findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class)); verify(likeRepository, times(1)).save(captor.capture()); assertThat(captor.getValue().getStatus(), is(LIKE)); } @Test public void unlikeProject_shouldCreateLikeEntityIfNotExists() throws Exception { when(likeRepository.findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class))).thenReturn(Optional.empty()); projectService.unlikeProject("projectId", any(UserEntity.class)); final ArgumentCaptor<LikeEntity> captor = ArgumentCaptor.forClass(LikeEntity.class); verify(likeRepository, times(1)).findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class)); verify(likeRepository, times(1)).save(captor.capture()); assertThat(captor.getValue().getStatus(), is(UNLIKE)); } @Test public void unlikeProject_shouldCreateLikeEntityIfExists() throws Exception { when(likeRepository.findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class))).thenReturn(Optional.of(new LikeEntity())); projectService.unlikeProject("projectId", any(UserEntity.class)); final ArgumentCaptor<LikeEntity> captor = ArgumentCaptor.forClass(LikeEntity.class); verify(likeRepository, times(1)).findOneByProjectAndUser(any(ProjectEntity.class), any(UserEntity.class)); verify(likeRepository, times(1)).save(captor.capture()); assertThat(captor.getValue().getStatus(), is(UNLIKE)); } private void assertPledgeNotExecuted(RuntimeException actualEx, RuntimeException expEx, ProjectEntity project, UserEntity user, int userBudgetBeforePledge, ProjectStatus expStatus) { assertThat(actualEx.getMessage(), is(expEx.getMessage())); assertThat(user.getBudget(), is(userBudgetBeforePledge)); assertThat(project.getStatus(), is(expStatus)); verify(pledgeRepository, never()).save(any(PledgeEntity.class)); verify(userRepository, never()).save(any(UserEntity.class)); verify(projectRepository, never()).save(any(ProjectEntity.class)); } private void assertPresentationAttachmentConformsPersited(Attachment presentationAttachment, AttachmentValue persisted) throws Exception { assertThat(presentationAttachment.getCreated(), is(persisted.getCreated())); assertThat(presentationAttachment.getId(), is(persisted.getFileReference())); assertThat(presentationAttachment.getName(), is(persisted.getFilename())); assertThat(presentationAttachment.getSize(), is(persisted.getSize())); assertThat(presentationAttachment.getType(), is(persisted.getContentType())); } private void pledgedAssertionProject(ProjectEntity project, UserEntity user, int amount) { when(pledgeRepository.findByProjectAndFinancingRound(eq(project), any())) .thenReturn(Collections.singletonList(new PledgeEntity(project, user, new Pledge(amount), new FinancingRoundEntity()))); if (project.getPledgeGoal() == amount) { project.setStatus(ProjectStatus.FULLY_PLEDGED); } } private ProjectEntity projectEntity(UserEntity userEntity, String id, String title, int pledgeGoal, String shortDescription, String description, ProjectStatus status, DateTime lastModifiedDate) { ProjectEntity projectEntity = new ProjectEntity(); projectEntity.setId(id); projectEntity.setTitle(title); projectEntity.setPledgeGoal(pledgeGoal); projectEntity.setShortDescription(shortDescription); projectEntity.setDescription(description); projectEntity.setCreator(userEntity); projectEntity.setStatus(status); projectEntity.setLastModifiedDate(lastModifiedDate); when(projectRepository.findOne(id)).thenReturn(projectEntity); return projectEntity; } private ProjectEntity projectEntity(String id, ProjectStatus status, UserEntity creator) { final ProjectEntity project = new ProjectEntity(); project.setId(id); project.setCreator(creator); project.setStatus(status); when(projectRepository.findOne(id)).thenReturn(project); return project; } private Project project(String title, String description, String shortDescription, int pledgeGoal, ProjectStatus projectStatus) { final Project project = new Project(); project.setTitle(title); project.setDescription(description); project.setShortDescription(shortDescription); project.setPledgeGoal(pledgeGoal); project.setStatus(projectStatus); return project; } private UserEntity admin(String email) { final UserEntity userEntity = user(email); userEntity.setRoles(Collections.singletonList(Roles.ROLE_ADMIN)); return userEntity; } private UserEntity user(String email) { UserEntity userEntity = new UserEntity(email); userEntity.setId("id_" + email); userEntity.setBudget(USER_BUDGED); return userEntity; } private FinancingRoundEntity prepareActiveFinanzingRound(ProjectEntity project) { FinancingRoundEntity res = aFinancingRound(new DateTime().plusDays(1)); res.setId(UUID.randomUUID().toString()); if (project != null) { project.setFinancingRound(res); } when(financingRoundRepository.findActive(any())).thenReturn(res); Assert.assertThat(res.active(), Is.is(true)); return res; } private FinancingRoundEntity prepareInactiveFinancingRound(ProjectEntity project) { FinancingRoundEntity res = aFinancingRound(new DateTime().minusDays(1)); res.setId("test_roundId"); if (project != null) { project.setFinancingRound(res); } when(financingRoundRepository.findActive(any())).thenReturn(res); Assert.assertThat(res.active(), Is.is(false)); return res; } private FinancingRoundEntity aFinancingRound(DateTime endDate) { FinancingRound creationCmd = new FinancingRound(); creationCmd.setEndDate(endDate); creationCmd.setBudget(FINANCING_ROUND_BUDGET); FinancingRoundEntity res = FinancingRoundEntity.newFinancingRound(creationCmd, 7); res.setStartDate(new DateTime().minusDays(2)); return res; } private AttachmentValue aPersitedAttachment(String fileRef) { return new AttachmentValue(fileRef, "text/plain", "a_filename", 17, DateTime.now()); } private Attachment aStoringRequestAttachment() { return Attachment.asCreationCommand("test_filename", "text/plain", mockedInputStream()); } private InputStream mockedInputStream() { return mock(InputStream.class); } }