package de.asideas.crowdsource.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import de.asideas.crowdsource.domain.exception.InvalidRequestException;
import de.asideas.crowdsource.domain.exception.ResourceNotFoundException;
import de.asideas.crowdsource.domain.model.AttachmentValue;
import de.asideas.crowdsource.domain.model.ProjectEntity;
import de.asideas.crowdsource.domain.model.UserEntity;
import de.asideas.crowdsource.domain.shared.ProjectStatus;
import de.asideas.crowdsource.presentation.ErrorResponse;
import de.asideas.crowdsource.presentation.Pledge;
import de.asideas.crowdsource.presentation.project.Attachment;
import de.asideas.crowdsource.presentation.project.Project;
import de.asideas.crowdsource.presentation.project.ProjectStatusUpdate;
import de.asideas.crowdsource.presentation.user.ProjectCreator;
import de.asideas.crowdsource.repository.LikeRepository;
import de.asideas.crowdsource.repository.ProjectRepository;
import de.asideas.crowdsource.repository.UserRepository;
import de.asideas.crowdsource.security.Roles;
import de.asideas.crowdsource.service.ProjectService;
import de.asideas.crowdsource.service.UserService;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.util.ReflectionTestUtils;
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.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Principal;
import java.util.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
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.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = ProjectControllerTest.Config.class)
@SuppressWarnings("Duplicates")
public class ProjectControllerTest {
@Autowired
private UserRepository userRepository;
@Autowired
private ProjectService projectService;
@Autowired
private ProjectController projectController;
@Resource
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private ObjectMapper mapper = new ObjectMapper();
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
reset(projectService, userRepository);
mapper.registerModule(new JodaModule());
givenControllerSupportsMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN));
}
@Test
public void addProject_shouldReturnSuccessfully() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER);
final Project project = project("myTitle", "theFullDescription", "theShortDescription", 50, ProjectStatus.PROPOSED);
final Project expFullProjcet = toCreatedProject(project, user);
when(projectService.addProject(project, user)).thenReturn(expFullProjcet);
MvcResult mvcResult = mockMvc.perform(post("/project")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(project)))
.andExpect(status().isCreated())
.andReturn();
assertThat(expFullProjcet, is(equalTo(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project.class))));
}
@Test
public void addProject_shouldRespondWith401IfUserWasNotFound() throws Exception {
final Project project = project("myTitle", "theFullDescription", "theShortDescription", 50, ProjectStatus.PROPOSED);
mockMvc.perform(post("/project")
.principal(new UsernamePasswordAuthenticationToken("foo@bar.de", "somepassword"))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(project)))
.andExpect(status().isUnauthorized());
}
@Test
public void addProject_shouldRespondWith400IfRequestWasInvalid() throws Exception {
final Project project = new Project();
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER);
mockMvc.perform(post("/project")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(project)))
.andExpect(status().isBadRequest());
}
@Test
public void addProject_shouldRespondWith400IfProjectWasMissing() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER);
mockMvc.perform(post("/project")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest());
}
@Test
public void getProject_shouldRespondWith404OnInvalidProjectId() throws Exception {
when(projectService.getProject(anyString(), any(UserEntity.class))).thenThrow(new ResourceNotFoundException());
mockMvc.perform(get("/project/{projectId}", "foo bah bah"))
.andExpect(status().isNotFound());
}
@Test
public void getProject_shouldRespondWith403IfTheUserMayNotSeeThisProject() throws Exception {
final UserEntity userEntity = userEntity("some@mail.com", Roles.ROLE_USER);
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
when(projectService.getProject(eq(projectId), eq(userEntity)))
.thenReturn(toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PROPOSED), creator));
mockMvc.perform(get("/project/{projectId}", projectId)
.principal(authentication(userEntity))
).andExpect(status().isForbidden());
}
@Test
public void getProject_shouldReturnSingleProjectSuccessfullyWhenProjectIsPublished() throws Exception {
final UserEntity userEntity = userEntity("some@mail.com", Roles.ROLE_USER);
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
final Project expProjcet = toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PUBLISHED), creator);
when(projectService.getProject(eq(projectId), eq(userEntity))).thenReturn(expProjcet);
MvcResult mvcResult = mockMvc.perform(get("/project/{projectId}", projectId)
.principal(authentication(userEntity)))
.andExpect(status().isOk())
.andReturn();
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project.class), is(equalTo(expProjcet)));
}
@Test
public void getProject_shouldReturnSingleProjectSuccessfullyWhenProjectIsPublishedForAnonymousToo() throws Exception {
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
final Project expProjcet = toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PUBLISHED), creator);
when(projectService.getProject(eq(projectId), eq(null))).thenReturn(expProjcet);
MvcResult mvcResult = mockMvc.perform(get("/project/{projectId}", projectId)
.principal(anonymousAuthentication()))
.andExpect(status().isOk())
.andReturn();
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project.class), is(equalTo(expProjcet)));
}
@Test
public void getProject_shouldReturnProjectLikeCountAndUserLikeStatus() throws Exception {
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
final Project expProjcet = toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PUBLISHED), creator);
when(projectService.getProject(eq(projectId), eq(null))).thenReturn(expProjcet);
mockMvc.perform(get("/project/{projectId}", projectId)
.principal(anonymousAuthentication()))
.andExpect(jsonPath("$.likeStatus", nullValue()))
.andExpect(jsonPath("$.likeCount", is(0)))
.andExpect(status().isOk());
}
@Test
public void getProjects_shouldReturnPublishedProjectsOnly() throws Exception {
final UserEntity user = userEntity("some@mail.com", Roles.ROLE_USER);
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
final Project expProjcet_0 = toCreatedProject(project("title0", "descr", "shortDescr", 44, ProjectStatus.PUBLISHED), creator);
final Project unexpProjcet = toCreatedProject(project("title1", "descr", "shortDescr", 44, ProjectStatus.PROPOSED), creator);
final Project expProjcet_1 = toCreatedProject(project("title2", "descr", "shortDescr", 44, ProjectStatus.PUBLISHED_DEFERRED), creator);
when(projectService.getProjects(user)).thenReturn(Arrays.asList(expProjcet_0, unexpProjcet, expProjcet_1));
MvcResult mvcResult = mockMvc.perform(get("/projects", projectId)
.principal(authentication(user)))
.andExpect(status().isOk())
.andReturn();
toProjectSummaryViewRepresentation(expProjcet_0);
toProjectSummaryViewRepresentation(expProjcet_1);
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project[].class)[0], is(equalTo(expProjcet_0)));
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project[].class)[1], is(equalTo(expProjcet_1)));
}
@Test
public void getProjects_shouldReturnPublishedProjectsForAnonymousUsersToo() throws Exception {
final UserEntity user = userEntity("some@mail.com", Roles.ROLE_USER);
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
final Project expProjcet = toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PUBLISHED), creator);
final Project unexpProjcet = toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PROPOSED), creator);
when(projectService.getProjects(null)).thenReturn(Arrays.asList(expProjcet, unexpProjcet));
MvcResult mvcResult = mockMvc.perform(get("/projects", projectId)
.principal(anonymousAuthentication()))
.andExpect(status().isOk())
.andReturn();
toProjectSummaryViewRepresentation(expProjcet);
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project[].class)[0], is(equalTo(expProjcet)));
}
@Test
public void getProjects_shouldReturnNothingWhenProjectNotPublishedAndProjectCreatorNotRequestor() throws Exception {
final UserEntity user = userEntity("some@mail.com", Roles.ROLE_USER);
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
final Project expProjcet = toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PROPOSED), creator);
when(projectService.getProjects(user)).thenReturn(Collections.singletonList(expProjcet));
MvcResult mvcResult = mockMvc.perform(get("/projects", projectId)
.principal(authentication(user)))
.andExpect(status().isOk())
.andReturn();
toProjectSummaryViewRepresentation(expProjcet);
assertThat(mvcResult.getResponse().getContentAsString(), is("[]"));
}
@Test
public void getProjects_shouldReturnUnpublishedProjectsWhenRequestorIsAdmin() throws Exception {
final UserEntity user = userEntity("some@mail.com", Roles.ROLE_ADMIN);
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
final Project expProjcet = toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PROPOSED), creator);
when(projectService.getProjects(user)).thenReturn(Collections.singletonList(expProjcet));
MvcResult mvcResult = mockMvc.perform(get("/projects", projectId)
.principal(authentication(user)))
.andExpect(status().isOk())
.andReturn();
toProjectSummaryViewRepresentation(expProjcet);
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project[].class)[0], is(equalTo(expProjcet)));
}
@Test
public void getProjects_shouldReturnUnpublishedProjectWhenRequestorIsCreator() throws Exception {
final UserEntity creator = userEntity("creator@mail.com", Roles.ROLE_USER);
final UserEntity anotherCreator = userEntity("creator2@mail.com", Roles.ROLE_USER);
final String projectId = "existingProjectId";
final Project expProjcet = toCreatedProject(project("title", "descr", "shortDescr", 44, ProjectStatus.PROPOSED), creator);
final Project nonExpProjcet = toCreatedProject(project("title2", "descr2", "shortDescr2", 45, ProjectStatus.PROPOSED), anotherCreator);
when(projectService.getProjects(creator)).thenReturn(Arrays.asList(expProjcet, nonExpProjcet));
MvcResult mvcResult = mockMvc.perform(get("/projects", projectId)
.principal(authentication(creator)))
.andExpect(status().isOk())
.andReturn();
toProjectSummaryViewRepresentation(expProjcet);
List<Project> projects = Arrays.asList(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project[].class));
assertThat(projects.size(), is(1));
assertThat("Result should contain creator's proposed project", projects.contains(expProjcet));
}
@Test
public void pledgeProject() throws Exception {
final String email = "some@mail.com";
final String projectId = "some_id";
final UserEntity user = userEntity(email, Roles.ROLE_USER);
Pledge pledge = new Pledge(13);
mockMvc.perform(post("/project/{projectId}/pledges", projectId)
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(pledge)))
.andExpect(status().isCreated());
verify(projectService).pledge(projectId, user, pledge);
}
@Test
public void pledgeProject_shouldRespondWith401IfTheUserWasNotFound() throws Exception {
mockMvc.perform(post("/project/{projectId}/pledges", "some_id")
.principal(new UsernamePasswordAuthenticationToken("foo@bar.com", "somepassword"))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(new Pledge(1))))
.andExpect(status().isUnauthorized());
}
@Test
public void pledgeProject_shouldRespondWith404IfTheProjectWasNotFound() throws Exception {
final String email = "some@mail.com";
final String projectId = "some_foo_id";
final Pledge pledge = new Pledge(1);
final UserEntity user = userEntity(email, Roles.ROLE_USER);
doThrow(ResourceNotFoundException.class).when(projectService).pledge(projectId, user, pledge);
mockMvc.perform(post("/project/{projectId}/pledges", projectId)
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(pledge)))
.andExpect(status().isNotFound());
}
@Test
public void pledgeProject_shouldRespondWith400IfTheRequestObjectIsInvalid() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER);
mockMvc.perform(post("/project/{projectId}/pledges", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content("\"amount\":\"invalidAmount\""))
.andExpect(status().isBadRequest())
.andReturn();
}
@Test
public void pledgeProject_shouldRespondWith400WhenProjectServiceThrowsInvalidRequestEx() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER);
doThrow(InvalidRequestException.pledgeGoalExceeded()).when(projectService).pledge(anyString(), eq(user), any(Pledge.class));
MvcResult mvcResult = mockMvc.perform(post("/project/{projectId}/pledges", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(new Pledge(2))))
.andExpect(status().isBadRequest())
.andReturn();
ErrorResponse expError = new ErrorResponse(InvalidRequestException.pledgeGoalExceeded().getMessage());
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorResponse.class), is(expError));
}
@Test
public void modifyProjectStatus() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
final Project expProject = toCreatedProject(project("title2", "descr2", "shortDescr2", 45, ProjectStatus.PROPOSED), user);
when(projectService.modifyProjectStatus(anyString(), eq(expProject.getStatus()), eq(user))).thenReturn(expProject);
MvcResult mvcResult = mockMvc.perform(patch("/project/{projectId}/status", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(new ProjectStatusUpdate(expProject.getStatus()))))
.andExpect(status().isOk())
.andReturn();
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project.class), is(expProject));
}
@Test
public void modifyProjectStatus_emptyUpdateObjectThrowsBadRequest() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
final Project expProject = toCreatedProject(project("title2", "descr2", "shortDescr2", 45, ProjectStatus.PROPOSED), user);
when(projectService.modifyProjectStatus(anyString(), eq(expProject.getStatus()), eq(user))).thenReturn(expProject);
mockMvc.perform(patch("/project/{projectId}/status", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(new ProjectStatusUpdate(null))))
.andExpect(status().isBadRequest())
.andReturn();
}
@Test
public void modifyProjectStatus_unknownStatusThrowsBadRequest() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
mockMvc.perform(patch("/project/{projectId}/status", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content("{\"status\": \"UNKNOWN_STATUS\"}"))
.andExpect(status().isBadRequest())
.andReturn();
}
@Test
public void modifyProjectMasterdata() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
final Project expProject = toCreatedProject(project("title2", "descr2", "shortDescr2", 45, ProjectStatus.PROPOSED), user);
when(projectService.modifyProjectMasterdata(anyString(), eq(expProject), eq(user))).thenReturn(expProject);
MvcResult mvcResult = mockMvc.perform(put("/project/{projectId}", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(expProject)))
.andExpect(status().isOk())
.andReturn();
assertThat(mapper.readValue(mvcResult.getResponse().getContentAsString(), Project.class), is(expProject));
}
@Test
public void modifyProjectMasterdata_invalidProjectThrowsBadRequestException() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
final Project expProject = toCreatedProject(project(null, "", "shortDescr2", 45, ProjectStatus.PROPOSED), user);
when(projectService.modifyProjectMasterdata(anyString(), eq(expProject), eq(user))).thenReturn(expProject);
MvcResult mvcResult = mockMvc.perform(put("/project/{projectId}", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(expProject)))
.andExpect(status().isBadRequest())
.andReturn();
ErrorResponse errorResponse = mapper.readValue(mvcResult.getResponse().getContentAsString(), ErrorResponse.class);
assertThat(errorResponse.getErrorCode(), is("field_errors"));
assertThat(errorResponse.getFieldViolations().get("description"), is("may not be empty"));
assertThat(errorResponse.getFieldViolations().get("title"), is("may not be empty"));
}
@Test
public void modifyProjectMasterdata_emptyUpdateObjectThrowsBadRequest() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
mockMvc.perform(put("/project/{projectId}", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON)
.content(""))
.andExpect(status().isBadRequest())
.andReturn();
}
@Test
public void addProjectAttachment_shouldDelegateToProjectService() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
final Attachment expectedAttachment = anExpectedAttachment(aPersistedProjectEntity());
MockMultipartFile content = mockedMultipart("somecontent", "test_filename", "text/plain");
MediaType mediaType = mediaType();
when(projectService.addProjectAttachment(eq("some_id"), eq(Attachment.asCreationCommand("test_filename", "text/plain", content.getInputStream())), eq(user)))
.thenReturn(expectedAttachment);
MvcResult mvcRes = mockMvc.perform(fileUpload("/projects/{projectId}/attachments", "some_id")
.file(content)
.principal(authentication(user))
.contentType(mediaType))
.andExpect(status().isOk())
.andReturn();
Attachment res = mapper.readValue(mvcRes.getResponse().getContentAsString(), Attachment.class);
assertAttachmentsEqual(expectedAttachment, res);
}
@Test
public void addProjectAttachment_shouldCloseInputStream() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
final Attachment expectedAttachment = anExpectedAttachment(aPersistedProjectEntity());
MockMultipartFile content = new MockedInputStreamMultipartFile("file", "test_filename", "text/plain");
final InputStream mockedInputStream = content.getInputStream();
MediaType mediaType = mediaType();
when(projectService.addProjectAttachment(eq("some_id"), eq(Attachment.asCreationCommand("test_filename", "text/plain", content.getInputStream())), eq(user)))
.thenReturn(expectedAttachment);
MvcResult mvcRes = mockMvc.perform(fileUpload("/projects/{projectId}/attachments", "some_id")
.file(content)
.principal(authentication(user))
.contentType(mediaType))
.andExpect(status().isOk())
.andReturn();
Attachment res = mapper.readValue(mvcRes.getResponse().getContentAsString(), Attachment.class);
assertAttachmentsEqual(expectedAttachment, res);
verify(mockedInputStream).close();
}
@Test
public void addProjectAttachment_shouldThrowBadRequestOnEmptyFile() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
MockMultipartFile content = mockedMultipart("", "test_filename", "text/plain");
MediaType mediaType = mediaType();
mockMvc.perform(fileUpload("/projects/{projectId}/attachments", "some_id")
.file(content)
.principal(authentication(user))
.contentType(mediaType))
.andExpect(status().isBadRequest())
.andReturn();
}
@Test
public void addProjectAttachment_shouldThrowBadRequestOnUnsupportedMediaType() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
givenControllerSupportsMediaTypes(Collections.singletonList(MediaType.parseMediaType(("application/pdf"))));
MockMultipartFile content = mockedMultipart("someContent", "test_filename", "application/json");
MediaType mediaType = mediaType();
mockMvc.perform(fileUpload("/projects/{projectId}/attachments", "some_id")
.file(content)
.contentType(mediaType)
.principal(authentication(user)))
.andExpect(status().isBadRequest())
.andReturn();
}
@Test
public void addProjectAttachment_shouldAcceptSpecificMediaTypeOnGeneralDefinition() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
givenControllerSupportsMediaTypes(Collections.singletonList(MediaType.parseMediaType(("image/*"))));
MockMultipartFile content = mockedMultipart("someContent", "test_filename", "image/jpeg");
MediaType mediaType = mediaType();
mockMvc.perform(fileUpload("/projects/{projectId}/attachments", "some_id")
.file(content)
.contentType(mediaType)
.principal(authentication(user)))
.andExpect(status().isOk())
.andReturn();
}
@Test
public void serveProjectAttachment_ReturnsResponseWithCorrectMediaType() throws Exception {
final UserEntity user = userEntity("u@s.er", Roles.ROLE_USER);
final String expContent = "someContent";
final ProjectEntity project = aPersistedProjectEntity();
final Attachment expectedAttachment = anExpectedAttachmentWithPayload(project, Optional.of(expContent));
when(projectService.loadProjectAttachment(project.getId(), Attachment.asLookupByIdCommand(expectedAttachment.getId())))
.thenReturn(expectedAttachment);
mockMvc.perform(get("/projects/{projectId}/attachments/{fileRef}", project.getId(), expectedAttachment.getId())
.principal(authentication(user)))
.andExpect(status().isOk())
.andExpect(content().contentType(expectedAttachment.getType()))
.andExpect(header().longValue("Content-Length", expectedAttachment.getSize()))
.andExpect(content().string(expContent))
.andReturn();
}
@Test
public void deleteAttachment_callsProjectServiceAndReturnsNoContent() throws Exception {
final UserEntity user = userEntity("u@s.er", Roles.ROLE_USER);
final String expContent = "someContent";
final ProjectEntity project = aPersistedProjectEntity();
final Attachment expectedAttachment = anExpectedAttachmentWithPayload(project, Optional.of(expContent));
mockMvc.perform(delete("/projects/{projectId}/attachments/{fileRef}", project.getId(), expectedAttachment.getId())
.principal(authentication(user)))
.andExpect(status().isNoContent())
.andReturn();
verify(projectService).deleteProjectAttachment(project.getId(), Attachment.asLookupByIdCommand(expectedAttachment.getId()), user);
}
private void givenControllerSupportsMediaTypes(List<MediaType> mediaTypes) {
ReflectionTestUtils.setField(projectController, "attachmentTypesAllowed", mediaTypes);
}
private void assertAttachmentsEqual(Attachment expected, Attachment actual) {
assertThat(actual.getName(), is(expected.getName()));
assertThat(actual.getType(), is(expected.getType()));
assertThat(actual.getId(), is(expected.getId()));
assertThat(actual.getCreated().getMillis(), is(expected.getCreated().getMillis()));
assertThat(actual.getLinkToFile(), is(expected.getLinkToFile()));
assertThat(actual.getSize(), is(expected.getSize()));
}
private MediaType mediaType() {
HashMap<String, String> contentTypeParams = new HashMap<>();
contentTypeParams.put("boundary", "34643214412434354");
return new MediaType("multipart", "form-data", contentTypeParams);
}
private MockMultipartFile mockedMultipart(String content, String filename, String contentType) {
MockMultipartFile multipartFile = new MockMultipartFile("file", filename, contentType, content.getBytes());
return multipartFile;
}
@Test
public void likeProject_shouldCallLikeMethodFromService() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
mockMvc.perform(post("/projects/{projectId}/likes", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(projectService, only()).likeProject(eq("some_id"), any(UserEntity.class));
}
@Test
public void unlikeProject_shouldCallUnlikeMethodFromService() throws Exception {
final String email = "some@mail.com";
final UserEntity user = userEntity(email, Roles.ROLE_USER, Roles.ROLE_ADMIN);
mockMvc.perform(delete("/projects/{projectId}/likes", "some_id")
.principal(authentication(user))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(projectService, only()).unlikeProject(eq("some_id"), any(UserEntity.class));
}
private Principal authentication(UserEntity userEntity) {
final Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
userEntity.getRoles().forEach(role -> authorities.add(new SimpleGrantedAuthority(role)));
return new UsernamePasswordAuthenticationToken(userEntity.getEmail(), "somepassword", authorities);
}
private Principal anonymousAuthentication() {
return new AnonymousAuthenticationToken("ANONYMOUS", "ANONYMOUS",
Collections.singletonList(new SimpleGrantedAuthority(Roles.ROLE_TRUSTED_ANONYMOUS)));
}
private UserEntity userEntity(String email, String... roles) {
UserEntity userEntity = new UserEntity(email);
userEntity.setId("id_" + email);
userEntity.setRoles(Arrays.asList(roles));
userEntity.setBudget(4000);
when(userRepository.findByEmail(email)).thenReturn(userEntity);
return userEntity;
}
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 Project toCreatedProject(Project project, UserEntity creator) {
Project res = new Project();
res.setBackers(0);
res.setCreator(new ProjectCreator(creator));
res.setDescription(project.getDescription());
res.setLastModifiedDate(new Date());
res.setId(project.getId());
res.setPledgedAmount(0);
res.setPledgeGoal(project.getPledgeGoal());
res.setShortDescription(project.getShortDescription());
res.setStatus(project.getStatus());
res.setTitle(project.getTitle());
res.setPledgedAmountByRequestingUser(12);
return res;
}
/**
* @param expProject to be prepared
* @return <code>expProject</code>
*/
private Project toProjectSummaryViewRepresentation(Project expProject) {
// As it's not part of ProjectSummaryView we remove the concerning fields for assertion purposes
expProject.setDescription(null);
ReflectionTestUtils.setField(expProject.getCreator(), "id", null);
return expProject;
}
private ProjectEntity aPersistedProjectEntity() {
final ProjectEntity res = new ProjectEntity();
res.setId("aProjectId");
return res;
}
private Attachment anExpectedAttachment(ProjectEntity parentProject) {
return anExpectedAttachmentWithPayload(parentProject, Optional.empty());
}
private Attachment anExpectedAttachmentWithPayload(ProjectEntity parentProject, Optional<String> payload) {
return Attachment.asResponse(new AttachmentValue("a_fileRef", "text/plain", "a_filename", 17, DateTime.now()), parentProject,
payload.isPresent() ? new ByteArrayInputStream(payload.get().getBytes()) : null);
}
@Configuration
@EnableWebMvc
static class Config {
@Bean
public ControllerExceptionAdvice controllerExceptionAdvice() {
return new ControllerExceptionAdvice();
}
@Bean
public ProjectController projectController() {
return new ProjectController();
}
@Bean
public ProjectService projectService() {
return mock(ProjectService.class);
}
@Bean
public UserService userService(UserRepository userRepository) {
return new UserService(userRepository, null);
}
@Bean
public UserRepository userRepository() {
return mock(UserRepository.class);
}
@Bean
public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
configurer.setLocation(new ClassPathResource("application.properties"));
return configurer;
}
@Bean
public ProjectRepository projectRepository() {
return mock(ProjectRepository.class);
}
@Bean
public LikeRepository likeRepository() {
return mock(LikeRepository.class);
}
}
static class MockedInputStreamMultipartFile extends MockMultipartFile {
private InputStream mockedInputStream = mock(InputStream.class);
public MockedInputStreamMultipartFile(String name, String originalFilename, String contentType) {
super(name, originalFilename, contentType, new byte[]{0, 1, 2, 3});
}
public MockedInputStreamMultipartFile(String name, byte[] content) {
super(name, content);
}
public MockedInputStreamMultipartFile(String name, InputStream contentStream) throws IOException {
super(name, contentStream);
}
public MockedInputStreamMultipartFile(String name, String originalFilename, String contentType, byte[] content) {
super(name, originalFilename, contentType, content);
}
public MockedInputStreamMultipartFile(String name, String originalFilename, String contentType, InputStream contentStream) throws IOException {
super(name, originalFilename, contentType, contentStream);
}
@Override
public InputStream getInputStream() throws IOException {
return mockedInputStream;
}
}
}