/**
* Copyright (C) 2011 JTalks.org Team
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jtalks.jcommune.web.controller;
import org.jtalks.common.model.entity.User;
import org.jtalks.jcommune.model.entity.JCUser;
import org.jtalks.jcommune.model.entity.PrivateMessage;
import org.jtalks.jcommune.model.entity.PrivateMessageStatus;
import org.jtalks.jcommune.plugin.api.exceptions.NotFoundException;
import org.jtalks.jcommune.service.PrivateMessageService;
import org.jtalks.jcommune.service.UserService;
import org.jtalks.jcommune.service.nontransactional.BBCodeService;
import org.jtalks.jcommune.web.dto.PrivateMessageDto;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static io.qala.datagen.RandomShortApi.alphanumeric;
import static io.qala.datagen.RandomValue.between;
import static io.qala.datagen.StringModifier.Impls.prefix;
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.ModelAndViewAssert.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.testng.Assert.assertEquals;
/**
* @author Pavel Vervenko
* @author Max Malakhov
* @author Alexandre Teterin
* @author Evheniy Naumenko
* @author Oleg Tkachenko
*/
public class PrivateMessageControllerTest {
private static final long PM_ID = 2L;
private static final String PAGE_NUMBER = "1";
private static final JCUser JC_USER = getRandomJCUser();
private static final String USERNAME = JC_USER.getUsername();
private static final String TITLE = alphanumeric(PrivateMessage.MIN_TITLE_LENGTH, PrivateMessage.MAX_TITLE_LENGTH);
private static final String BODY = alphanumeric(PrivateMessage.MIN_MESSAGE_LENGTH, PrivateMessage.MAX_MESSAGE_LENGTH);
private PrivateMessageController controller;
@Mock
private PrivateMessageService pmService;
@Mock
private BBCodeService bbCodeService;
@Mock
private UserService userService;
private MockMvc mockMvc;
private Page<PrivateMessage> expectedPage;
@BeforeClass
public void setUp(){
expectedPage = new PageImpl<>(Collections.singletonList(getPrivateMessage()));
}
@BeforeMethod
public void init() {
JC_USER.setId(1);
MockitoAnnotations.initMocks(this);
controller = new PrivateMessageController(pmService, bbCodeService, userService);
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void testInitBinder() {
WebDataBinder binder = mock(WebDataBinder.class);
controller.initBinder(binder);
verify(binder).registerCustomEditor(eq(String.class), any(StringTrimmerEditor.class));
}
@Test
public void inboxPage() {
when(pmService.getInboxForCurrentUser(PAGE_NUMBER)).thenReturn(expectedPage);
when(userService.getCurrentUser()).thenReturn(JC_USER);
//invoke the object under test
ModelAndView mav = controller.inboxPage(PAGE_NUMBER);
//check expectations
verify(pmService).getInboxForCurrentUser(PAGE_NUMBER);
//check result
assertViewName(mav, "pm/inbox");
assertModelAttributeAvailable(mav, "inboxPage");
}
@Test
public void outboxPage() {
when(pmService.getOutboxForCurrentUser(PAGE_NUMBER)).thenReturn(expectedPage);
when(userService.getCurrentUser()).thenReturn(JC_USER);
//invoke the object under test
ModelAndView mav = controller.outboxPage(PAGE_NUMBER);
//check expectations
verify(pmService).getOutboxForCurrentUser(PAGE_NUMBER);
//check result
assertViewName(mav, "pm/outbox");
assertModelAttributeAvailable(mav, "outboxPage");
}
@Test
public void draftsPage() {
when(pmService.getDraftsForCurrentUser(PAGE_NUMBER)).thenReturn(expectedPage);
//invoke the object under test
ModelAndView mav = controller.draftsPage(PAGE_NUMBER);
//check expectations
verify(pmService).getDraftsForCurrentUser(PAGE_NUMBER);
//check result
assertViewName(mav, "pm/drafts");
assertModelAttributeAvailable(mav, "draftsPage");
}
@Test
public void newPmPage() throws NotFoundException {
when(userService.getCurrentUser()).thenReturn(JC_USER);
//invoke the object under test
ModelAndView mav = controller.newPmPage(null);
//check result
verify(pmService).checkPermissionsToSend(JC_USER.getId());
assertViewName(mav, "pm/pmForm");
assertAndReturnModelAttributeOfType(mav, "privateMessageDto", PrivateMessageDto.class);
}
@Test
public void newPmPageWithUserSet() throws NotFoundException {
//invoke the object under test
when(userService.getCurrentUser()).thenReturn(JC_USER);
when(userService.get(JC_USER.getId())).thenReturn(JC_USER);
ModelAndView mav = controller.newPmPage(JC_USER.getId());
//check result
verify(pmService).checkPermissionsToSend(JC_USER.getId());
assertViewName(mav, "pm/pmForm");
PrivateMessageDto dto = assertAndReturnModelAttributeOfType(mav, "privateMessageDto", PrivateMessageDto.class);
assertEquals(dto.getRecipient(), JC_USER.getUsername());
}
@Test(expectedExceptions = NotFoundException.class)
public void newPmPageWithWrongUserSet() throws NotFoundException {
when(userService.getCurrentUser()).thenReturn(JC_USER);
doThrow(new NotFoundException()).when(userService).get(JC_USER.getId());
controller.newPmPage(JC_USER.getId());
}
@Test
public void sendMessage() throws NotFoundException {
when(userService.getByUsername(USERNAME)).thenReturn(JC_USER);
when(userService.getCurrentUser()).thenReturn(JC_USER);
PrivateMessageDto dto = getPrivateMessageDto();
BindingResult bindingResult = new BeanPropertyBindingResult(dto, "privateMessageDto");
ModelAndView mav = controller.sendMessage(dto, bindingResult);
assertEquals(mav.getViewName(), "redirect:/outbox");
verify(pmService).sendMessage(dto.getTitle(), dto.getBody(), JC_USER, JC_USER);
}
@Test
public void sendDraftMessage() throws NotFoundException {
when(userService.getByUsername(USERNAME)).thenReturn(JC_USER);
when(userService.getCurrentUser()).thenReturn(JC_USER);
PrivateMessageDto dto = getPrivateMessageDto();
dto.setId(4);
BindingResult bindingResult = new BeanPropertyBindingResult(dto, "privateMessageDto");
ModelAndView mav = controller.sendMessage(dto, bindingResult);
assertEquals(mav.getViewName(), "redirect:/outbox");
verify(pmService).sendDraft(dto.getId(), dto.getTitle(), dto.getBody(), JC_USER, JC_USER);
}
@Test
public void sendMessageWithErrors() throws NotFoundException {
PrivateMessageDto dto = getPrivateMessageDto();
BeanPropertyBindingResult resultWithErrors = mock(BeanPropertyBindingResult.class);
when(resultWithErrors.hasErrors()).thenReturn(true);
ModelAndView mav = controller.sendMessage(dto, resultWithErrors);
assertEquals(mav.getViewName(), "pm/pmForm");
}
@Test(expectedExceptions = NotFoundException.class)
public void sendMessageWithWrongUser() throws NotFoundException {
PrivateMessageDto dto = getPrivateMessageDto();
doThrow(new NotFoundException()).when(pmService).
sendMessage(anyString(), anyString(), any(JCUser.class), any(JCUser.class));
BindingResult bindingResult = new BeanPropertyBindingResult(dto, "privateMessageDto");
controller.sendMessage(dto, bindingResult);
}
@Test
public void replyPage() throws NotFoundException {
PrivateMessage pm = getPrivateMessage();
//set expectations
when(pmService.get(PM_ID)).thenReturn(pm);
//invoke the object under test
ModelAndView mav = controller.replyPage(PM_ID);
//check expectations
verify(pmService).get(PM_ID);
//check result
assertViewName(mav, "pm/pmForm");
assertAndReturnModelAttributeOfType(mav, "privateMessageDto", PrivateMessageDto.class);
}
@Test
public void quotePage() throws NotFoundException {
PrivateMessage pm = getPrivateMessage();
//set expectations
when(pmService.get(PM_ID)).thenReturn(pm);
//invoke the object under test
ModelAndView mav = controller.quotePage(PM_ID);
//check expectations
verify(pmService).get(PM_ID);
//check result
assertViewName(mav, "pm/pmForm");
assertAndReturnModelAttributeOfType(mav, "privateMessageDto", PrivateMessageDto.class);
}
@Test
public void showPmPageInbox() throws NotFoundException {
PrivateMessage pm = getPrivateMessage();
//set expectations
when(pmService.get(PM_ID)).thenReturn(pm);
//invoke the object under test
ModelAndView mav = controller.showPmPage(PM_ID);
//check expectations
verify(pmService).get(PM_ID);
//check result
assertViewName(mav, "pm/showPm");
PrivateMessage actualPm = assertAndReturnModelAttributeOfType(mav, "pm", PrivateMessage.class);
assertEquals(actualPm, pm);
}
@Test(expectedExceptions = NotFoundException.class)
public void cannotBeShowedPm() throws NotFoundException {
//set expectations
when(pmService.get(PM_ID)).thenThrow(new NotFoundException());
//invoke the object under test
controller.showPmPage(PM_ID);
//check expectations
verify(pmService).get(PM_ID);
}
@Test
public void editDraftPage() throws NotFoundException {
PrivateMessage pm = getPrivateMessage();
pm.setId(PM_ID);
pm.setStatus(PrivateMessageStatus.DRAFT);
//set expectations
when(pmService.get(PM_ID)).thenReturn(pm);
//invoke the object under test
ModelAndView mav = controller.editDraftPage(PM_ID);
//check expectations
verify(pmService).get(PM_ID);
//check result
assertViewName(mav, "pm/pmForm");
PrivateMessageDto dto = assertAndReturnModelAttributeOfType(mav, "privateMessageDto", PrivateMessageDto.class);
assertEquals(dto.getId(), PM_ID);
}
@Test(expectedExceptions = NotFoundException.class)
public void editDraftPageNotDraft() throws NotFoundException {
PrivateMessage pm = getPrivateMessage();
when(pmService.get(PM_ID)).thenReturn(pm);
controller.editDraftPage(PM_ID);
}
@Test
public void saveDraftPost() throws Exception {
when(userService.getByUsername(USERNAME)).thenReturn(JC_USER);
when(userService.getCurrentUser()).thenReturn(JC_USER);
saveDraft(TITLE, BODY, USERNAME)
.andExpect(model().hasNoErrors())
.andExpect(status().isMovedTemporarily())
.andExpect(redirectedUrl("/drafts"));
verify(pmService).saveDraft(PM_ID, JC_USER, TITLE, BODY, JC_USER);
}
@Test
public void testSaveDraftGet() throws Exception {
when(userService.getByUsername(USERNAME)).thenReturn(JC_USER);
when(userService.getCurrentUser()).thenReturn(JC_USER);
mockMvc.perform(get("/pm/save")
.param("title", TITLE)
.param("body", BODY)
.param("recipient", USERNAME))
.andExpect(model().hasNoErrors())
.andExpect(status().isMovedTemporarily())
.andExpect(redirectedUrl("/drafts"));
verify(pmService).saveDraft(0, JC_USER, TITLE, BODY, JC_USER);
}
@Test
public void saveDraftShouldBackToPmFormIfTitleIsInvalid() throws Exception {
String invalidTitle = alphanumeric(PrivateMessage.MAX_TITLE_LENGTH + 1);
saveDraft(invalidTitle, BODY, USERNAME)
.andExpect(model()
.attributeHasFieldErrors("privateMessageDto", "title"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("pm/pmForm"));
}
@Test
public void saveDraftShouldDeleteDraftIfTitleAndBodyAreEmptyAndRecipientIsNotExists() throws Exception {
saveDraft("", "", null)
.andExpect(model()
.attributeHasErrors("privateMessageDto"))
.andExpect(view().name("redirect:/drafts"))
.andExpect(status().isMovedTemporarily());
verify(pmService).delete(anyList());
}
@Test
public void testDeletePm() throws NotFoundException {
List<Long> pmIds = Arrays.asList(1L, 2L);
when(pmService.delete(Arrays.asList(1L, 2L))).thenReturn("aaa");
String result = controller.deleteMessages(pmIds);
assertEquals(result, "redirect:/aaa");
}
private PrivateMessageDto getPrivateMessageDto() {
PrivateMessageDto dto = new PrivateMessageDto();
dto.setBody(BODY);
dto.setTitle(TITLE);
dto.setRecipient(USERNAME);
return dto;
}
private PrivateMessage getPrivateMessage() {
return new PrivateMessage(JC_USER,
getRandomJCUser(), TITLE, BODY);
}
private static JCUser getRandomJCUser() {
String username = alphanumeric(User.USERNAME_MIN_LENGTH, User.USERNAME_MAX_LENGTH);
String email = alphanumeric(1, 30) +
between(3, 15).with(prefix("@")).alphanumeric() +
between(3, 5).with(prefix(".")).english();
String password = alphanumeric(User.PASSWORD_MIN_LENGTH, User.PASSWORD_MAX_LENGTH);
return new JCUser(username, email, password);
}
private ResultActions saveDraft(String title, String body, String recipient) throws Exception {
return this.mockMvc.perform(post("/pm/save")
.param("id", String.valueOf(PM_ID))
.param("title", title)
.param("body", body)
.param("recipient", recipient));
}
}