package br.gov.servicos.editor.usuarios.recuperarsenha;
import br.gov.servicos.editor.usuarios.Usuario;
import br.gov.servicos.editor.usuarios.UsuarioInexistenteException;
import br.gov.servicos.editor.usuarios.UsuarioService;
import br.gov.servicos.editor.usuarios.cadastro.CamposSenha;
import br.gov.servicos.editor.usuarios.token.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Optional;
import static br.gov.servicos.editor.usuarios.token.TokenError.EXPIRADO;
import static br.gov.servicos.editor.usuarios.token.TokenError.INVALIDO;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Optional.empty;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class RecuperacaoSenhaServiceTest {
private static final String TOKEN = "token";
private static final java.lang.String ENCRYPTED_TOKEN = "encrypted";
private static final Long USUARIO_ID = 12341234L;
private static final String SENHA = "12341234";
private static final String ENCRYPTED_SENHA = "******";
private static final Long TOKEN_ID = 1L;
public static final int MAX = 10;
@Mock
private GeradorToken geradorToken;
@Mock
private PasswordEncoder passwordEncoder;
@Mock
private TokenRepository repository;
@Mock
private RecuperacaoSenhaValidator validator;
@Mock
private UsuarioService usuarioService;
@InjectMocks
private RecuperacaoSenhaService recuperacaoSenhaService;
@Before
public void setUp() {
when(passwordEncoder.encode(TOKEN)).thenReturn(ENCRYPTED_TOKEN);
when(passwordEncoder.encode(SENHA)).thenReturn(ENCRYPTED_SENHA);
ReflectionTestUtils.setField(recuperacaoSenhaService, "maxTentativasToken", MAX);
}
@Test
public void deveGerarTokenAleatorioEGuardarEncryptadoNoBanco() {
when(geradorToken.gerar()).thenReturn(TOKEN);
String token = recuperacaoSenhaService.gerarTokenParaUsuario(USUARIO_ID.toString());
Token expectedToken = new Token()
.withToken(ENCRYPTED_TOKEN)
.withUsuario(new Usuario().withId(USUARIO_ID))
.withTentativasSobrando(MAX);
verify(repository).save(refEq(expectedToken, "dataCriacao"));
assertThat(token, equalTo(TOKEN));
}
@Test
public void deveDesabilitarUsuarioQuandoGerarToken() {
recuperacaoSenhaService.gerarTokenParaUsuario(USUARIO_ID.toString());
verify(usuarioService).desabilitarUsuario(USUARIO_ID.toString());
}
@Test
public void naoDeveDesabilitarUsuarioQuandoGerarTokenSeTagNaoEstiverDesabilitada() {
ReflectionTestUtils.setField(recuperacaoSenhaService, "desabilitarUsuarioAoCriarToken", false);
recuperacaoSenhaService.gerarTokenParaUsuario(USUARIO_ID.toString());
verify(usuarioService, never()).desabilitarUsuario(USUARIO_ID.toString());
}
@Test
public void deveSalvarSenhaSeTokenForValido() throws TokenInvalido {
FormularioRecuperarSenha formulario = criarFormulario(USUARIO_ID, SENHA);
Usuario usuario = new Usuario();
Token token = new Token().withUsuario(usuario);
when(repository.findByUsuarioId(USUARIO_ID)).thenReturn(newArrayList(token));
when(validator.hasError(formulario, token)).thenReturn(empty());
recuperacaoSenhaService.trocarSenha(formulario);
verify(usuarioService).save(usuario.withSenha(ENCRYPTED_SENHA).withHabilitado(true));
}
@Test
public void deveDeletarTokenCasoSenhaTenhaSidoTrocada() throws TokenInvalido {
FormularioRecuperarSenha formulario = criarFormulario(USUARIO_ID, SENHA);
Usuario usuario = new Usuario();
Token token = new Token()
.withUsuario(usuario)
.withId(TOKEN_ID);
when(repository.findByUsuarioId(USUARIO_ID)).thenReturn(newArrayList(token));
when(validator.hasError(formulario, token)).thenReturn(empty());
recuperacaoSenhaService.trocarSenha(formulario);
verify(repository).delete(TOKEN_ID);
}
@Test
public void naoDeveSalvarSenhaSeTokenForInvalido() {
FormularioRecuperarSenha formulario = criarFormulario(USUARIO_ID, SENHA);
Usuario usuario = new Usuario();
Token token = new Token().withUsuario(usuario).withTentativasSobrando(0);
when(repository.findByUsuarioId(USUARIO_ID)).thenReturn(newArrayList(token));
when(validator.hasError(formulario, token)).thenReturn(Optional.of(INVALIDO));
try {
recuperacaoSenhaService.trocarSenha(formulario);
fail();
} catch (TokenInvalido ignored) {
verify(usuarioService, never()).save(usuario.withSenha(ENCRYPTED_SENHA));
}
}
@Test
public void deveIncrementarNumeroDeTentativasSeTokenForInvalido() throws TokenInvalido {
FormularioRecuperarSenha formulario = criarFormulario(USUARIO_ID, SENHA);
Usuario usuario = new Usuario();
Token token = new Token()
.withUsuario(usuario)
.withTentativasSobrando(MAX);
Token expectedToken = new Token()
.withUsuario(usuario)
.withTentativasSobrando(MAX - 1);
when(repository.findByUsuarioId(USUARIO_ID)).thenReturn(newArrayList(token));
when(validator.hasError(formulario, token)).thenReturn(Optional.of(INVALIDO));
try {
recuperacaoSenhaService.trocarSenha(formulario);
} catch (CpfTokenInvalido e) {
verify(repository).save(expectedToken);
}
}
@Test
public void deveLancarExcecaoCasoTokenSejaInvalidoComMensagemDizendoQuantasTentativasEstaoFaltando() throws TokenInvalido {
FormularioRecuperarSenha formulario = criarFormulario(USUARIO_ID, SENHA);
Usuario usuario = new Usuario();
Token token = new Token()
.withUsuario(usuario)
.withTentativasSobrando(MAX);
when(repository.findByUsuarioId(USUARIO_ID)).thenReturn(newArrayList(token));
when(validator.hasError(formulario, token)).thenReturn(Optional.of(INVALIDO));
try {
recuperacaoSenhaService.trocarSenha(formulario);
fail();
} catch (CpfTokenInvalido e) {
assertThat(e.getTentativasSobrando(), equalTo(MAX - 1));
}
}
@Test(expected = TokenExpirado.class)
public void deveLancarExcecaoDeTokenExpiradoCasoTokenEstejaExpirado() throws TokenInvalido {
FormularioRecuperarSenha formulario = criarFormulario(USUARIO_ID, SENHA);
Usuario usuario = new Usuario();
Token token = new Token()
.withUsuario(usuario)
.withTentativasSobrando(MAX);
when(repository.findByUsuarioId(USUARIO_ID)).thenReturn(newArrayList(token));
when(validator.hasError(formulario, token)).thenReturn(Optional.of(EXPIRADO));
recuperacaoSenhaService.trocarSenha(formulario);
}
@Test(expected = UsuarioInexistenteException.class)
public void deveLancarExcecaoSeNaoEncontrarTokenParaUsuario() throws TokenInvalido {
FormularioRecuperarSenha formulario = criarFormulario(USUARIO_ID, SENHA);
when(repository.findByUsuarioId(USUARIO_ID)).thenReturn(newArrayList());
recuperacaoSenhaService.trocarSenha(formulario);
}
private FormularioRecuperarSenha criarFormulario(Long usuarioId, String senha) {
CamposVerificacaoRecuperarSenha camposVerificacaoRecuperarSenha = new CamposVerificacaoRecuperarSenha()
.withUsuarioId(usuarioId.toString());
return new FormularioRecuperarSenha()
.withCamposVerificacaoRecuperarSenha(camposVerificacaoRecuperarSenha)
.withCamposSenha(new CamposSenha().withSenha(senha));
}
}