package gov.samhsa.consent2share.service.account; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import gov.samhsa.consent2share.domain.account.EmailToken; import gov.samhsa.consent2share.domain.account.EmailTokenRepository; import gov.samhsa.consent2share.domain.account.TokenGenerator; import gov.samhsa.consent2share.domain.account.UsersRepository; import gov.samhsa.consent2share.domain.commondomainservices.EmailSender; import gov.samhsa.consent2share.domain.commondomainservices.EmailType; import gov.samhsa.consent2share.domain.patient.Patient; import gov.samhsa.consent2share.domain.patient.PatientRepository; import gov.samhsa.consent2share.domain.staff.StaffRepository; import gov.samhsa.consent2share.infrastructure.security.EmailAddressNotExistException; import gov.samhsa.consent2share.infrastructure.security.TokenNotExistException; import gov.samhsa.consent2share.infrastructure.security.UsernameNotExistException; import java.util.Collection; import javax.mail.MessagingException; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.mockito.ArgumentMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; public class PasswordResetServiceImplTest { private PasswordResetServiceImpl sut; private PatientRepository patientRepository; private TokenGenerator tokenGenerator; private Integer passwordResetTokenExpireInHours; private EmailTokenRepository passwordResetTokenRepository; private EmailSender emailSender; private PasswordEncoder passwordEncoder; private UsersRepository usersRepository; private StaffRepository staffRepository; final Logger logger = LoggerFactory.getLogger(this.getClass()); @Rule public TestWatcher testWatcher = new TestWatcher() { @Override protected void starting(Description description) { logger.info("{} being run...", description.getMethodName()); } }; @Before public void setUp() { // Mock dependencies and create sut // Just to save a few lines of code for each individual test // But independency, clarity of the unit tests are much more important // than code reuse usersRepository = mock(UsersRepository.class); patientRepository = mock(PatientRepository.class); tokenGenerator = mock(TokenGenerator.class); passwordResetTokenExpireInHours = 8; passwordResetTokenRepository = mock(EmailTokenRepository.class); emailSender = mock(EmailSender.class); passwordEncoder = mock(PasswordEncoder.class); staffRepository = mock(StaffRepository.class); sut = new PasswordResetServiceImpl(passwordResetTokenExpireInHours, usersRepository, patientRepository, staffRepository, tokenGenerator, passwordResetTokenRepository, emailSender, passwordEncoder); } @Test(expected = IllegalArgumentException.class) public void createPasswordResetToken_Throws_Exception_When_Username_Has_Whitespaces_Only() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { sut.createPasswordResetToken(" ", "emailAddress", "resetPasswordLinkPlaceHolder"); } @Test(expected = IllegalArgumentException.class) public void createPasswordResetToken_Throws_Exception_When_Username_Is_Null() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { sut.createPasswordResetToken(null, "emailAddress", "resetPasswordLinkPlaceHolder"); } @Test(expected = IllegalArgumentException.class) public void testCreatePasswordResetToken_Throws_Exception_When_Email_Has_Whitespaces_Only() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { sut.createPasswordResetToken("username", " ", "resetPasswordLinkPlaceHolder"); } @Test(expected = IllegalArgumentException.class) public void testCreatePasswordResetToken_Throws_Exception_When_Email_Is_Null() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { sut.createPasswordResetToken("username", null, "resetPasswordLinkPlaceHolder"); } @Test(expected = IllegalArgumentException.class) public void testCreatePasswordResetToken_Throws_Exception_When_ResetPasswordLinkPlaceHolder_Has_Whitespaces_Only() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { sut.createPasswordResetToken("username", "emailAddress", " "); } @Test(expected = IllegalArgumentException.class) public void testCreatePasswordResetToken_Throws_Exception_When_ResetPasswordLinkPlaceHolder_Is_Null() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { sut.createPasswordResetToken("username", "emailAddress", null); } @Test public void testCreatePasswordResetToken_Succeeds_When_ResetPasswordLinkPlaceHolder_End_Correctly() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { // Arrange final String emailAddress = "emailAddress"; Patient patient = mock(Patient.class); when(patientRepository.findByUsername(anyString())).thenReturn(patient); when(patient.getEmail()).thenReturn(emailAddress); final String resetPasswordLinkPlaceHolder = "http://comsent2share.com/resetPassword.html?token=%s"; // Act sut.createPasswordResetToken("username", emailAddress, resetPasswordLinkPlaceHolder); } @Test(expected = UsernameNotExistException.class) public void testCreatePasswordResetToken_Throws_Exception_When_Username_Not_Exist() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { // Arrange when(usersRepository.loadUserByUsername(anyString())).thenThrow( new UsernameNotFoundException("The Message")); final String resetPasswordLinkPlaceHolder = "http://comsent2share.com/resetPassword.html?token=%s"; final String emailAddress = "emailAddress"; // Act sut.createPasswordResetToken("username", emailAddress, resetPasswordLinkPlaceHolder); } @Test(expected = EmailAddressNotExistException.class) public void testCreatePasswordResetToken_Throws_Exception_When_EmailAddress_Not_Exist() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { // Arrange final String resetPasswordLinkPlaceHolder = "http://comsent2share.com/resetPassword.html?token=%s"; final String emailAddress = "emailAddress"; final String anotherEmailAddress = "anotherEmailAddress"; Patient patient = mock(Patient.class); when(patientRepository.findByUsername(anyString())).thenReturn(patient); when(patient.getEmail()).thenReturn(anotherEmailAddress); // Act sut.createPasswordResetToken("username", emailAddress, resetPasswordLinkPlaceHolder); } @Test public void testCreatePasswordResetToken_PasswordResetToken_With_Correct_ExpireInHours_Is_Saved_By_PasswordResetTokenRepository() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { // Arrange final String resetPasswordLinkPlaceHolder = "http://comsent2share.com/resetPassword.html?token=%s"; final String emailAddress = "emailAddress"; Patient patient = mock(Patient.class); when(patientRepository.findByUsername(anyString())).thenReturn(patient); when(patient.getEmail()).thenReturn(emailAddress); passwordResetTokenExpireInHours = 5; sut = new PasswordResetServiceImpl(passwordResetTokenExpireInHours, usersRepository, patientRepository, staffRepository, tokenGenerator, passwordResetTokenRepository, emailSender, passwordEncoder); // Act sut.createPasswordResetToken("username", emailAddress, resetPasswordLinkPlaceHolder); // Assert verify(passwordResetTokenRepository, times(1)).save( argThat(new IsPasswordResetTokenWithCorrectExpireInHours( passwordResetTokenExpireInHours))); } private class IsPasswordResetTokenWithCorrectExpireInHours extends ArgumentMatcher<EmailToken> { private Integer expireInHours; public IsPasswordResetTokenWithCorrectExpireInHours( Integer passwordResetTokenExpireInHours) { this.expireInHours = passwordResetTokenExpireInHours; } @Override public boolean matches(Object argument) { EmailToken passwordResetToken = (EmailToken) argument; if (passwordResetToken.getExpireInHours() == expireInHours) { return true; } return false; } } @Test public void testCreatePasswordResetToken_PasswordResetToken_With_Correct_Token_Is_Saved_By_PasswordResetTokenRepository() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { // Arrange final String resetPasswordLinkPlaceHolder = "http://comsent2share.com/resetPassword.html?token=%s"; final String emailAddress = "emailAddress"; Patient patient = mock(Patient.class); when(patientRepository.findByUsername(anyString())).thenReturn(patient); when(patient.getEmail()).thenReturn(emailAddress); final String token = "TheToken"; when(tokenGenerator.generateToken()).thenReturn(token); sut = new PasswordResetServiceImpl(passwordResetTokenExpireInHours, usersRepository, patientRepository, staffRepository, tokenGenerator, passwordResetTokenRepository, emailSender, passwordEncoder); // Act sut.createPasswordResetToken("username", emailAddress, resetPasswordLinkPlaceHolder); // Assert verify(passwordResetTokenRepository, times(1)).save( argThat(new IsPasswordResetTokenWithCorrectToken(token))); } private class IsPasswordResetTokenWithCorrectToken extends ArgumentMatcher<EmailToken> { private String token; public IsPasswordResetTokenWithCorrectToken(String token) { this.token = token; } @Override public boolean matches(Object argument) { EmailToken passwordResetToken = (EmailToken) argument; if (passwordResetToken.getToken().equals(token)) { return true; } return false; } } @Test public void testCreatePasswordResetToken_PasswordResetToken_With_Correct_RequestDateTime_Is_Saved_By_PasswordResetTokenRepository() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { // Arrange final String resetPasswordLinkPlaceHolder = "http://comsent2share.com/resetPassword.html?token=%s"; final String emailAddress = "emailAddress"; Patient patient = mock(Patient.class); when(patientRepository.findByUsername(anyString())).thenReturn(patient); when(patient.getEmail()).thenReturn(emailAddress); sut = new PasswordResetServiceImpl(passwordResetTokenExpireInHours, usersRepository, patientRepository, staffRepository, tokenGenerator, passwordResetTokenRepository, emailSender, passwordEncoder); // Act sut.createPasswordResetToken("username", emailAddress, resetPasswordLinkPlaceHolder); // Assert verify(passwordResetTokenRepository, times(1)).save( argThat(new IsPasswordResetTokenWithCorrectRequestDateTime())); } private class IsPasswordResetTokenWithCorrectRequestDateTime extends ArgumentMatcher<EmailToken> { @Override public boolean matches(Object argument) { EmailToken passwordResetToken = (EmailToken) argument; if (passwordResetToken.getRequestDateTime() != null) { return true; } return false; } } @Test public void testCreatePasswordResetToken_Email_Is_Sent_Successfully() throws UsernameNotExistException, EmailAddressNotExistException, MessagingException { // Arrange final String resetPasswordLinkPlaceHolder = "http://comsent2share.com/resetPassword.html?token=%s"; final String emailAddress = "emailAddress"; Patient patient = mock(Patient.class); when(patientRepository.findByUsername(anyString())).thenReturn(patient); when(patient.getEmail()).thenReturn(emailAddress); sut = new PasswordResetServiceImpl(passwordResetTokenExpireInHours, usersRepository, patientRepository, staffRepository, tokenGenerator, passwordResetTokenRepository, emailSender, passwordEncoder); // Act sut.createPasswordResetToken("username", emailAddress, resetPasswordLinkPlaceHolder); // Assert verify(emailSender, times(1)).sendMessage(anyString(), anyString(), eq(EmailType.PASSWORD_RESET_REQUEST), anyString(), anyString()); } @Test(expected = IllegalArgumentException.class) public void testIsPasswordResetTokenExpired_Throws_Exception_When_Token_Has_Whitespaces_Only() throws TokenNotExistException { sut.isPasswordResetTokenExpired(" "); } @Test(expected = IllegalArgumentException.class) public void testIsPasswordResetTokenExpired_Throws_Exception_When_Token_Is_Null() throws TokenNotExistException { sut.isPasswordResetTokenExpired(null); } @Test(expected = TokenNotExistException.class) public void testIsPasswordResetTokenExpired_Throws_Exception_When_PasswordToken_Not_Exist() throws TokenNotExistException { // Arrange final String token = "TheToken"; when(passwordResetTokenRepository.findByToken(token)).thenReturn(null); // Act sut.isPasswordResetTokenExpired(token); } @Test public void testIsPasswordResetTokenExpired_Returns_True_Successfully() throws TokenNotExistException { // Arrange final String token = "TheToken"; EmailToken passwordResetToken = mock(EmailToken.class); when(passwordResetToken.isTokenExpired()).thenReturn(true); when(passwordResetTokenRepository.findByToken(token)).thenReturn( passwordResetToken); // Act Boolean result = sut.isPasswordResetTokenExpired(token); // Assert assertTrue(result); } @Test public void testIsPasswordResetTokenExpired_Returns_False_Successfully() throws TokenNotExistException { // Arrange final String token = "TheToken"; EmailToken passwordResetToken = mock(EmailToken.class); when(passwordResetToken.isTokenExpired()).thenReturn(false); when(passwordResetTokenRepository.findByToken(token)).thenReturn( passwordResetToken); // Act Boolean result = sut.isPasswordResetTokenExpired(token); // Assert assertFalse(result); } // @Ignore // @Test // public void // testResetPassword_UserDetails_With_Correct_Authorities_Is_Updated_By_UsersRepository() // throws TokenNotExistException, TokenExpiredException, // UsernameNotExistException, MessagingException { // // Arrange // final String token = "TheToken"; // final String username = "Username"; // final String password = "Password"; // final String encodedPassword = "encodedPassword"; // PasswordResetDto passwordResetDto = mock(PasswordResetDto.class); // when(passwordResetDto.getToken()).thenReturn(token); // when(passwordResetDto.getPassword()).thenReturn(password); // EmailToken passwordResetToken = mock(EmailToken.class); // when(passwordResetToken.isTokenExpired()).thenReturn(false); // when(passwordResetToken.getUsername()).thenReturn(username); // when(passwordResetTokenRepository.findByToken(token)).thenReturn( // passwordResetToken); // Users user = mock(Users.class); // Collection<? extends GrantedAuthority> authorities = (Collection<? // extends GrantedAuthority>) mock(Collection.class); // Iterator<? extends GrantedAuthority> authoritiesIterator = // mock(Iterator.class); // when(authoritiesIterator.hasNext()).thenReturn(false); // when(authorities.iterator()).thenReturn((Iterator) authoritiesIterator); // // when(user.getAuthorities()).thenReturn((Set<GrantedAuthority>) // authorities); // when(usersRepository.loadUserByUsername(username)).thenReturn( // user); // // when(passwordEncoder.encode(password)).thenReturn(encodedPassword); // // // Act // sut.resetPassword(passwordResetDto, anyString()); // // // Assert // verify(usersRepository, times(1)).updateUser( // argThat(new IsUserDetailsnWithCorrectAuthorities(authorities))); // } private class IsUserDetailsnWithCorrectAuthorities extends ArgumentMatcher<UserDetails> { private Collection<? extends GrantedAuthority> authorities; public IsUserDetailsnWithCorrectAuthorities( Collection<? extends GrantedAuthority> authorities) { this.authorities = authorities; } @Override public boolean matches(Object argument) { UserDetails userDetails = (UserDetails) argument; if (userDetails.getAuthorities() != null) { return true; } return false; } } }