/** * 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 com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import org.jtalks.common.model.entity.Component; import org.jtalks.common.service.security.SecurityContextFacade; import org.jtalks.jcommune.model.dto.LoginUserDto; import org.jtalks.jcommune.model.dto.RegisterUserDto; import org.jtalks.jcommune.model.dto.UserDto; import org.jtalks.jcommune.model.entity.AnonymousUser; import org.jtalks.jcommune.model.entity.JCUser; import org.jtalks.jcommune.plugin.api.core.ExtendedPlugin; import org.jtalks.jcommune.plugin.api.core.RegistrationPlugin; import org.jtalks.jcommune.plugin.api.exceptions.NoConnectionException; import org.jtalks.jcommune.plugin.api.exceptions.NotFoundException; import org.jtalks.jcommune.plugin.api.exceptions.UnexpectedErrorException; import org.jtalks.jcommune.plugin.api.filters.TypeFilter; import org.jtalks.jcommune.plugin.api.web.dto.json.JsonResponse; import org.jtalks.jcommune.plugin.api.web.dto.json.JsonResponseStatus; import org.jtalks.jcommune.service.*; import org.jtalks.jcommune.service.exceptions.MailingFailedException; import org.jtalks.jcommune.service.exceptions.UserTriesActivatingAccountAgainException; import org.jtalks.jcommune.service.nontransactional.MailService; import org.jtalks.jcommune.service.util.AuthenticationStatus; import org.jtalks.jcommune.web.dto.RestorePasswordDto; import org.jtalks.jcommune.web.util.MutableHttpRequest; import org.jtalks.jcommune.web.validation.editors.DefaultStringEditor; import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.retry.policy.NeverRetryPolicy; import org.springframework.retry.support.RetryTemplate; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.servlet.ModelAndView; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; import java.util.Locale; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; import static org.springframework.test.web.ModelAndViewAssert.*; import static org.testng.Assert.*; /** * @author Evgeniy Naumenko * @author Andrey Pogorelov */ public class UserControllerTest { private final String USER_NAME = "username"; private final String EMAIL = "mail@mail.com"; private UserController userController; private UserService userService; private MailService mailService; private PluginService pluginService; private Authenticator authenticator; private HttpServletRequest request; private HttpServletResponse response; private RetryTemplate retryTemplate; private ComponentService componentService; private GroupService groupService; private SpamProtectionService spamProtectionService; private RequestCache requestCache; @BeforeMethod public void setUp() throws IOException { userService = mock(UserService.class); mailService = mock(MailService.class); pluginService = mock(PluginService.class); authenticator = mock(Authenticator.class); request = mock(HttpServletRequest.class); response = mock(HttpServletResponse.class); componentService = mock(ComponentService.class); groupService = mock(GroupService.class); retryTemplate = new RetryTemplate(); spamProtectionService = mock(SpamProtectionService.class); requestCache = new HttpSessionRequestCache(); retryTemplate.setRetryPolicy(new NeverRetryPolicy()); SecurityContextFacade securityFacade = mock(SecurityContextFacade.class); SecurityContext securityContext = mock(SecurityContext.class); when(securityFacade.getContext()).thenReturn(securityContext); when(request.getHeader("X-FORWARDED-FOR")).thenReturn("192.168.1.1"); when(spamProtectionService.isEmailInBlackList(anyString())).thenReturn(false); userController = new UserController(userService, authenticator, pluginService, userService, mailService, retryTemplate, componentService, groupService, spamProtectionService, requestCache); } @Test public void testInitBinderStringTrimmerEditor() { WebDataBinder binder = mock(WebDataBinder.class); userController.initBinder(binder); verify(binder).registerCustomEditor(eq(String.class), any(StringTrimmerEditor.class)); } @Test public void testInitBinderDefaultStringEditor() { WebDataBinder binder = mock(WebDataBinder.class); userController.initBinder(binder); verify(binder).registerCustomEditor(eq(String.class), any(DefaultStringEditor.class)); } @Test public void userMustBeAbleToOpenRegistrationPage_ifHeIsNotLoggedIn() throws Exception { when(userService.getCurrentUser()).thenReturn(new AnonymousUser()); ModelAndView mav = userController.registrationPage(null, null); assertViewName(mav, "registration"); RegisterUserDto dto = assertAndReturnModelAttributeOfType(mav, "newUser", RegisterUserDto.class); assertNullFields(dto); } @Test public void whenOpeningRegistrationPage_userMustBeRedirectedToMainPage_ifHeIsLoggedIn() throws Exception { when(userService.getCurrentUser()).thenReturn(new JCUser("username", null, null)); ModelAndView mav = userController.registrationPage(null, null); assertViewName(mav, "redirect:/"); } @Test public void testRegistrationFormWithoutAnyPluginShouldBeSuccessful() { JsonResponse response = userController.registrationForm(request, Locale.ENGLISH); assertEquals(response.getStatus(), JsonResponseStatus.SUCCESS); } @Test public void testRegistrationFormWithAvailablePluginShouldBeSuccessful() { RegistrationPlugin plugin = mock(RegistrationPlugin.class); when(pluginService.getRegistrationPlugins()).thenReturn( new ImmutableMap.Builder<Long, RegistrationPlugin>().put(1L, plugin).build()); JsonResponse response = userController.registrationForm(request, Locale.ENGLISH); assertEquals(response.getStatus(), JsonResponseStatus.SUCCESS); } @Test public void testPluginActionForAvailablePluginShouldBeSuccessful() throws org.jtalks.common.service.exceptions.NotFoundException { ExtendedPlugin plugin = mock(ExtendedPlugin.class); HttpServletResponse response = mock(HttpServletResponse.class); HttpServletRequest request = mock(HttpServletRequest.class); String pluginId = "1"; when(pluginService.getPluginById(eq(pluginId), any(TypeFilter.class))).thenReturn(plugin); userController.pluginAction(pluginId, "someAction", request, response); } @Test public void testPluginActionIfPluginNotFound() throws org.jtalks.common.service.exceptions.NotFoundException { HttpServletResponse response = mock(HttpServletResponse.class); HttpServletRequest request = mock(HttpServletRequest.class); String pluginId = "1"; when(pluginService.getPluginById(eq(pluginId), any(TypeFilter.class))) .thenThrow(new org.jtalks.common.service.exceptions.NotFoundException()); userController.pluginAction(pluginId, "someAction", request, response); } @Test public void testRegisterUserShouldBeSuccessful() throws Exception { RegisterUserDto dto = createRegisterUserDto(null); BindingResult bindingResult = new BeanPropertyBindingResult(dto, "newUser"); when(authenticator.register(dto)).thenReturn(bindingResult); ModelAndView mav = userController.registerUser(dto, request, Locale.ENGLISH); assertViewName(mav, "afterRegistration"); verify(authenticator).register(dto); } @Test public void testRegisterValidationFail() throws Exception { RegisterUserDto dto = createRegisterUserDto(null); BindingResult bindingResult = mock(BindingResult.class); when(bindingResult.hasErrors()).thenReturn(true); when(authenticator.register(dto)).thenReturn(bindingResult); ModelAndView mav = userController.registerUser(dto, request, Locale.ENGLISH); assertViewName(mav, "registration"); } @Test public void testRegisterFailIfUnexpectedErrorOccurred() throws Exception { RegisterUserDto dto = createRegisterUserDto(null); doThrow(new UnexpectedErrorException()).when(authenticator).register(dto); ModelAndView mav = userController.registerUser(dto, request, Locale.ENGLISH); assertViewName(mav, UserController.REG_SERVICE_UNEXPECTED_ERROR_URL); } @Test public void testRegisterFailIfConnectionErrorOccurred() throws Exception { RegisterUserDto dto = createRegisterUserDto(null); doThrow(new NoConnectionException()).when(authenticator).register(dto); ModelAndView mav = userController.registerUser(dto, request, Locale.ENGLISH); assertViewName(mav, UserController.REG_SERVICE_CONNECTION_ERROR_URL); } @Test public void testRegisterFailIfHoneypotCaptchaNotNull() throws Exception { RegisterUserDto dto = createRegisterUserDto("anyString"); ModelAndView mav = userController.registerUser(dto, request, Locale.ENGLISH); assertViewName(mav, UserController.REG_SERVICE_HONEYPOT_FILLED_ERROR_URL); } @Test public void testRegisterUserAjaxShouldBeSuccessful() throws Exception { RegisterUserDto dto = createRegisterUserDto(null); BindingResult bindingResult = new BeanPropertyBindingResult(dto, "newUser"); when(authenticator.register(dto)).thenReturn(bindingResult); JsonResponse response = userController.registerUserAjax(dto, request, Locale.ENGLISH); assertEquals(response.getStatus(), JsonResponseStatus.SUCCESS, "User without validation errors should pass registration."); } @Test public void testRegisterAjaxValidationFail() throws Exception { RegisterUserDto dto = createRegisterUserDto(null); BindingResult bindingResult = mock(BindingResult.class); when(bindingResult.hasErrors()).thenReturn(true); when(authenticator.register(dto)).thenReturn(bindingResult); JsonResponse response = userController.registerUserAjax(dto, request, Locale.ENGLISH); assertEquals(response.getStatus(), JsonResponseStatus.FAIL, "User with validation errors should fail registration."); } @Test public void testRegisterAjaxFailIfUnexpectedErrorOccurred() throws Exception { RegisterUserDto dto = createRegisterUserDto(null); doThrow(new UnexpectedErrorException()).when(authenticator).register(dto); JsonResponse response = userController.registerUserAjax(dto, request, Locale.ENGLISH); assertEquals(response.getStatus(), JsonResponseStatus.FAIL, "Unexpected error should fail registration."); } @Test public void testRegisterAjaxFailIfConnectionErrorOccurred() throws Exception { RegisterUserDto dto = createRegisterUserDto(null); doThrow(new NoConnectionException()).when(authenticator).register(dto); JsonResponse response = userController.registerUserAjax(dto, request, Locale.ENGLISH); assertEquals(response.getStatus(), JsonResponseStatus.FAIL, "Connection error should fail registration."); } @Test public void testRegisterAjaxFailIfHoneypotCaptchaNotNull() throws Exception { RegisterUserDto dto = createRegisterUserDto("anyString"); JsonResponse response = userController.registerUserAjax(dto, request, Locale.ENGLISH); assertEquals(response.getStatus(), JsonResponseStatus.FAIL, "HoneypotException should fail registration."); } @Test public void testRestorePasswordPage() { assertViewName(userController.showRestorePasswordPage(), "restorePassword"); } @Test public void testRestorePassword() throws Exception { RestorePasswordDto dto = new RestorePasswordDto(); dto.setUserEmail(EMAIL); BindingResult bindingResult = new BeanPropertyBindingResult(dto, "email"); ModelAndView mav = userController.restorePassword(dto, bindingResult); verify(userService, times(1)).restorePassword(EMAIL); assertModelAttributeValue(mav, "message", "label.restorePassword.completed"); } @Test public void testRestorePasswordWrongMail() throws Exception { RestorePasswordDto dto = new RestorePasswordDto(); dto.setUserEmail(EMAIL); BindingResult bindingResult = new BeanPropertyBindingResult(dto, "email"); bindingResult.addError(new FieldError("", "", "")); ModelAndView mav = userController.restorePassword(dto, bindingResult); verifyZeroInteractions(userService); assertViewName(mav, "restorePassword"); } @Test public void testRestorePasswordFail() throws Exception { Exception fail = new MailingFailedException(new RuntimeException()); doThrow(fail).when(userService).restorePassword(anyString()); RestorePasswordDto dto = new RestorePasswordDto(); dto.setUserEmail(EMAIL); BindingResult bindingResult = new BeanPropertyBindingResult(dto, "email"); userController.restorePassword(dto, bindingResult); verify(userService, times(1)).restorePassword(EMAIL); assertTrue(bindingResult.hasErrors()); } @Test public void testActivateAccount() throws Exception { JCUser user = new JCUser("username", "password", null); user.setPassword("password"); when(userService.getByUuid(USER_NAME)).thenReturn(user); String viewName = userController.activateAccount(USER_NAME, request, response); verify(authenticator, times(1)).activateAccount(user.getUuid()); verify(userService, times(1)).loginUser(any(LoginUserDto.class), any(MutableHttpRequest.class), eq(response)); assertEquals("redirect:/", viewName); } @Test public void testActivateAccountFail() throws Exception { doThrow(new NotFoundException()).when(userService).getByUuid(anyString()); String viewName = userController.activateAccount(USER_NAME, request, response); assertEquals("errors/activationExpired", viewName); } @Test public void testActivateAccountAgain() throws Exception { JCUser user = new JCUser("username", "password", null); user.setEnabled(true); when(userService.getByUuid(USER_NAME)).thenReturn(user); doThrow(new UserTriesActivatingAccountAgainException()).when(authenticator).activateAccount(anyString()); String viewName = userController.activateAccount(USER_NAME, request, response); assertEquals("redirect:/", viewName); } @Test(dataProvider = "referers") public void testLoginUserLogged(String referer) { when(userService.getCurrentUser()).thenReturn(new JCUser("username", null, null)); when(request.getHeader("referer")).thenReturn(referer); ModelAndView mav = userController.loginPage(request, response); assertEquals(mav.getViewName(), "redirect:" + referer); verify(userService).getCurrentUser(); } @Test public void testLoginUserNotLogged() { when(userService.getCurrentUser()).thenReturn(new AnonymousUser()); ModelAndView mav = userController.loginPage(request, response); assertEquals(mav.getViewName(), UserController.LOGIN); verify(userService).getCurrentUser(); } @DataProvider public Object[][] referers() { return new Object[][]{ {"/"}, {"/referer1"}, {"/referer/url1"}, }; } @Test(enabled = false) public void testAjaxLoginSuccess() throws Exception { when(userService.loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(AuthenticationStatus.AUTHENTICATED); JsonResponse response = userController.loginAjax(null, null, "on", null, null); assertEquals(response.getStatus(), JsonResponseStatus.SUCCESS); LoginUserDto loginUserDto = new LoginUserDto("userName", "password", true, "192.168.1.1"); verify(userService).loginUser(loginUserDto, any(HttpServletRequest.class), any(HttpServletResponse.class)); } @Test public void testAjaxLoginFailure() throws Exception { when(userService.loginUser(any(LoginUserDto.class),any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(AuthenticationStatus.AUTHENTICATION_FAIL); JsonResponse response = userController.loginAjax(null, null, "on", request, null); assertEquals(response.getStatus(), JsonResponseStatus.FAIL); verify(userService).loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); } @Test public void testLoginAjaxUserShouldFailIfConnectionErrorOccurred() throws Exception { when(userService.loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class))) .thenThrow(new NoConnectionException()); JsonResponse response = userController.loginAjax(null, null, "on", request, null); assertEquals(response.getStatus(), JsonResponseStatus.FAIL); verify(userService).loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); } @Test public void testLoginAjaxUserShouldFailIfUnexpectedErrorOccurred() throws Exception { when(userService.loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class))) .thenThrow(new UnexpectedErrorException()); JsonResponse response = userController.loginAjax(null, null, "on", request, null); assertEquals(response.getStatus(), JsonResponseStatus.FAIL); verify(userService).loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); } @Test(enabled = false) public void testLoginWithCorrectParametersShouldBeSuccessful() throws Exception { LoginUserDto loginUserDto = new LoginUserDto("userName", "password", true, "192.168.1.1"); when(userService.loginUser(loginUserDto, any(HttpServletRequest.class), any(HttpServletResponse.class))) .thenReturn(AuthenticationStatus.AUTHENTICATED); ModelAndView view = userController.login(loginUserDto, "on", null, request, null); assertEquals(view.getViewName(), "redirect:/"); verify(userService).loginUser(loginUserDto, any(HttpServletRequest.class), any(HttpServletResponse.class)); } @Test public void testLoginWithIncorrectParametersShouldFail() throws Exception { when(userService.loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class))) .thenReturn(AuthenticationStatus.AUTHENTICATION_FAIL); LoginUserDto loginUserDto = new LoginUserDto(); userController.login(loginUserDto, null, "on", request, null); verify(userService).loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); } @Test public void testLoginUserShouldFailIfConnectionErrorOccurred() throws Exception { when(userService.loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class))) .thenThrow(new NoConnectionException()); LoginUserDto loginUserDto = new LoginUserDto(); ModelAndView view = userController.login(loginUserDto, null, "on", request, null); assertEquals(view.getViewName(), UserController.AUTH_SERVICE_FAIL_URL); verify(userService).loginUser(eq(loginUserDto), any(HttpServletRequest.class), any(HttpServletResponse.class)); } @Test public void testLoginUserShouldFailIfUnexpectedErrorOccurred() throws Exception { when(userService.loginUser(any(LoginUserDto.class), any(HttpServletRequest.class), any(HttpServletResponse.class))) .thenThrow(new UnexpectedErrorException()); LoginUserDto loginUserDto = new LoginUserDto(); ModelAndView view = userController.login(loginUserDto, null, "on", request, null); assertEquals(view.getViewName(), UserController.AUTH_SERVICE_FAIL_URL); verify(userService).loginUser(eq(loginUserDto), any(HttpServletRequest.class), any(HttpServletResponse.class)); } @Test public void testGetUsernameListSuccess() { String pattern = "us"; List<String> usernames = Lists.newArrayList("User1", "User2", "User3"); when(userService.getUsernames(pattern)).thenReturn(usernames); JsonResponse response = userController.usernameList(pattern); assertEquals(response.getStatus(), JsonResponseStatus.SUCCESS); } @Test public void testSearchUsersNullSearchKey() { Component component = createDefaultComponent(); when(componentService.getComponentOfForum()).thenReturn(component); ModelAndView mav = userController.searchUsers(null); verify(componentService).checkPermissionsForComponent(component.getId()); assertEquals(mav.getViewName(), UserController.USER_SEARCH); assertFalse(mav.getModel().containsKey(UserController.USERS_ATTR_NAME)); } private Component createDefaultComponent() { Component component = new Component(); component.setId(1); return component; } @Test public void testSearchUsersEmptySearchKey() { Component component = createDefaultComponent(); when(componentService.getComponentOfForum()).thenReturn(component); ModelAndView mav = userController.searchUsers(""); verify(componentService).checkPermissionsForComponent(component.getId()); assertEquals(mav.getViewName(), UserController.USER_SEARCH); assertFalse(mav.getModel().containsKey(UserController.USERS_ATTR_NAME)); } @Test public void testSearchUsers() { Component component = createDefaultComponent(); String searchKey = "key"; List<JCUser> users = Lists.asList(new JCUser("user", "email@email.com", "pwd"), new JCUser[0]); when(componentService.getComponentOfForum()).thenReturn(component); when(userService.findByUsernameOrEmail(component.getId(), searchKey)).thenReturn(users); ModelAndView mav = userController.searchUsers(searchKey); assertEquals(mav.getViewName(), UserController.USER_SEARCH); assertEquals(mav.getModel().get(UserController.USERS_ATTR_NAME), users); } @Test public void searchUsersShouldTrimSearchKey() { Component component = createDefaultComponent(); String searchKey = " key "; when(componentService.getComponentOfForum()).thenReturn(component); userController.searchUsers(searchKey); verify(userService).findByUsernameOrEmail(component.getId(), searchKey.trim()); } @Test public void getUserGroups() throws NotFoundException { long userID = 1l; Component component = createDefaultComponent(); when(componentService.getComponentOfForum()).thenReturn(component); userController.userGroups(userID); verify(userService).getUserGroupIDs(component.getId(), userID); } @Test public void addUserToGroup() throws Exception { long userID = 1l; long groupID = 2l; Component component = createDefaultComponent(); when(componentService.getComponentOfForum()).thenReturn(component); userController.addUserToGroup(userID, groupID); verify(userService).addUserToGroup(component.getId(), userID, groupID); } @Test public void deleteUserFromGroup() throws Exception { long userID = 1l; long groupID = 2l; Component component = createDefaultComponent(); when(componentService.getComponentOfForum()).thenReturn(component); userController.deleteUserFromGroup(userID, groupID); verify(userService).deleteUserFromGroup(component.getId(), userID, groupID); } private void assertNullFields(RegisterUserDto dto) { assertNull(dto.getUserDto()); assertNull(dto.getPasswordConfirm()); } private RegisterUserDto createRegisterUserDto(String honeypotCaptcha) { UserDto userDto = new UserDto(); userDto.setUsername(USER_NAME); userDto.setEmail(EMAIL); userDto.setPassword("password"); RegisterUserDto dto = new RegisterUserDto(); dto.setPasswordConfirm("password"); dto.setUserDto(userDto); dto.setHoneypotCaptcha(honeypotCaptcha); return dto; } }