Unit test ConsoleLogger + clean up and unit test RecoverEmailCommand

This commit is contained in:
ljacqu 2016-07-22 22:09:55 +02:00
parent a8df8ceb09
commit 914462fc3f
4 changed files with 381 additions and 31 deletions

View File

@ -44,36 +44,27 @@ public class RecoverEmailCommand extends PlayerCommand {
commandService.send(player, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
return;
}
if (dataSource.isAuthAvailable(playerName)) {
if (playerCache.isAuthenticated(playerName)) {
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return;
}
PlayerAuth auth;
if (playerCache.isAuthenticated(playerName)) {
auth = playerCache.getAuth(playerName);
} else if (dataSource.isAuthAvailable(playerName)) {
auth = dataSource.getAuth(playerName);
} else {
commandService.send(player, MessageKey.UNKNOWN_USER);
return;
}
if (!playerMail.equalsIgnoreCase(auth.getEmail()) || "your@email.com".equalsIgnoreCase(playerMail)
|| "your@email.com".equalsIgnoreCase(auth.getEmail())) {
commandService.send(player, MessageKey.INVALID_EMAIL);
return;
}
String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH));
HashedPassword hashNew = passwordSecurity.computeHash(thePass, playerName);
auth.setPassword(hashNew);
dataSource.updatePassword(auth);
sendMailSsl.sendPasswordMail(auth, thePass);
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
} else {
commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
if (playerCache.isAuthenticated(playerName)) {
commandService.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return;
}
PlayerAuth auth = dataSource.getAuth(playerName);
if (auth == null) {
commandService.send(player, MessageKey.REGISTER_EMAIL_MESSAGE);
return;
}
if (!playerMail.equalsIgnoreCase(auth.getEmail()) || "your@email.com".equalsIgnoreCase(auth.getEmail())) {
commandService.send(player, MessageKey.INVALID_EMAIL);
return;
}
String thePass = RandomString.generate(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH));
HashedPassword hashNew = passwordSecurity.computeHash(thePass, playerName);
auth.setPassword(hashNew);
dataSource.updatePassword(auth);
sendMailSsl.sendPasswordMail(auth, thePass);
commandService.send(player, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
}
}

View File

@ -0,0 +1,142 @@
package fr.xephi.authme;
import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.List;
import java.util.logging.Logger;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Test for {@link ConsoleLogger}.
*/
@RunWith(MockitoJUnitRunner.class)
public class ConsoleLoggerTest {
@Mock
private Logger logger;
@Mock
private NewSetting settings;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
private File logFile;
@Before
public void setMockLogger() throws IOException {
ConsoleLogger.setLogger(logger);
File folder = temporaryFolder.newFolder();
File logFile = new File(folder, "authme.log");
if (!logFile.createNewFile()) {
throw new IOException("Could not create file '" + logFile.getPath() + "'");
}
ConsoleLogger.setLogFile(logFile);
this.logFile = logFile;
}
@After
public void closeFileHandlers() {
ConsoleLogger.close();
}
@Test
public void shouldLogToFile() throws IOException {
// given
ConsoleLogger.setLoggingOptions(newSettings(true, LogLevel.FINE));
// when
ConsoleLogger.fine("Logging a FINE message");
ConsoleLogger.debug("Logging a DEBUG message");
ConsoleLogger.info("This is an INFO message");
// then
verify(logger, times(2)).info(anyString());
verifyNoMoreInteractions(logger);
List<String> loggedLines = Files.readAllLines(logFile.toPath(), Charset.forName("UTF-8"));
assertThat(loggedLines, hasSize(2));
assertThat(loggedLines.get(0), containsString("[FINE] Logging a FINE message"));
assertThat(loggedLines.get(1), containsString("[INFO] This is an INFO message"));
}
@Test
public void shouldNotLogToFile() throws IOException {
// given
ConsoleLogger.setLoggingOptions(newSettings(false, LogLevel.DEBUG));
// when
ConsoleLogger.debug("Created test");
ConsoleLogger.warning("Encountered a warning");
// then
verify(logger).info("Debug: Created test");
verify(logger).warning("Encountered a warning");
verifyNoMoreInteractions(logger);
assertThat(logFile.length(), equalTo(0L));
}
@Test
public void shouldLogStackTraceToFile() throws IOException {
// given
ConsoleLogger.setLoggingOptions(newSettings(true, LogLevel.INFO));
Exception e = new IllegalStateException("Test exception message");
// when
ConsoleLogger.info("Info text");
ConsoleLogger.debug("Debug message");
ConsoleLogger.fine("Fine-level message");
ConsoleLogger.logException("Exception occurred:", e);
// then
verify(logger).info("Info text");
verify(logger).warning("Exception occurred: [IllegalStateException]: Test exception message");
verifyNoMoreInteractions(logger);
List<String> loggedLines = Files.readAllLines(logFile.toPath(), Charset.forName("UTF-8"));
assertThat(loggedLines.size(), greaterThan(3));
assertThat(loggedLines.get(0), containsString("[INFO] Info text"));
assertThat(loggedLines.get(1),
containsString("[WARN] Exception occurred: [IllegalStateException]: Test exception message"));
// Check that we have this class' full name somewhere in the file -> stacktrace of Exception e
assertThat(StringUtils.join("", loggedLines), containsString(getClass().getCanonicalName()));
}
@Test
public void shouldHaveHiddenConstructor() {
TestHelper.validateHasOnlyPrivateEmptyConstructor(ConsoleLogger.class);
}
private static NewSetting newSettings(boolean logToFile, LogLevel logLevel) {
NewSetting settings = mock(NewSetting.class);
given(settings.getProperty(SecuritySettings.USE_LOGGING)).willReturn(logToFile);
given(settings.getProperty(PluginSettings.LOG_LEVEL)).willReturn(logLevel);
return settings;
}
}

View File

@ -52,7 +52,7 @@ public final class TestHelper {
*/
public static Path getJarPath(String path) {
String sqlFilePath = getUriOrThrow(path).getPath();
// Windows preprends the path with a '/' or '\', which Paths cannot handle
// Windows prepends the path with a '/' or '\', which Paths cannot handle
String appropriatePath = System.getProperty("os.name").contains("indow")
? sqlFilePath.substring(1)
: sqlFilePath;

View File

@ -0,0 +1,217 @@
package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.properties.EmailSettings;
import org.bukkit.entity.Player;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import java.util.Collections;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
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.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Test for {@link RecoverEmailCommand}.
*/
@RunWith(MockitoJUnitRunner.class)
public class RecoverEmailCommandTest {
private static final String DEFAULT_EMAIL = "your@email.com";
@InjectMocks
private RecoverEmailCommand command;
@Mock
private PasswordSecurity passwordSecurity;
@Mock
private CommandService commandService;
@Mock
private DataSource dataSource;
@Mock
private PlayerCache playerCache;
@Mock
private SendMailSSL sendMailSsl;
@BeforeClass
public static void initLogger() {
TestHelper.setupLogger();
}
@Test
public void shouldHandleMissingMailProperties() {
// given
given(sendMailSsl.hasAllInformation()).willReturn(false);
Player sender = mock(Player.class);
// when
command.executeCommand(sender, Collections.singletonList("some@email.tld"));
// then
verify(commandService).send(sender, MessageKey.INCOMPLETE_EMAIL_SETTINGS);
verifyZeroInteractions(dataSource, passwordSecurity);
}
@Test
public void shouldShowErrorForAuthenticatedUser() {
// given
String name = "Bobby";
Player sender = mock(Player.class);
given(sender.getName()).willReturn(name);
given(sendMailSsl.hasAllInformation()).willReturn(true);
given(playerCache.isAuthenticated(name)).willReturn(true);
// when
command.executeCommand(sender, Collections.singletonList("bobby@example.org"));
// then
verify(sendMailSsl).hasAllInformation();
verifyZeroInteractions(dataSource);
verify(commandService).send(sender, MessageKey.ALREADY_LOGGED_IN_ERROR);
}
@Test
public void shouldShowRegisterMessageForUnregisteredPlayer() {
// given
String name = "Player123";
Player sender = mock(Player.class);
given(sender.getName()).willReturn(name);
given(sendMailSsl.hasAllInformation()).willReturn(true);
given(playerCache.isAuthenticated(name)).willReturn(false);
given(dataSource.getAuth(name)).willReturn(null);
// when
command.executeCommand(sender, Collections.singletonList("someone@example.com"));
// then
verify(sendMailSsl).hasAllInformation();
verify(dataSource).getAuth(name);
verifyNoMoreInteractions(dataSource);
verify(commandService).send(sender, MessageKey.REGISTER_EMAIL_MESSAGE);
}
@Test
public void shouldHandleDefaultEmail() {
// given
String name = "Tract0r";
Player sender = mock(Player.class);
given(sender.getName()).willReturn(name);
given(sendMailSsl.hasAllInformation()).willReturn(true);
given(playerCache.isAuthenticated(name)).willReturn(false);
given(dataSource.getAuth(name)).willReturn(authWithEmail(DEFAULT_EMAIL));
// when
command.executeCommand(sender, Collections.singletonList(DEFAULT_EMAIL));
// then
verify(sendMailSsl).hasAllInformation();
verify(dataSource).getAuth(name);
verifyNoMoreInteractions(dataSource);
verify(commandService).send(sender, MessageKey.INVALID_EMAIL);
}
@Test
public void shouldHandleInvalidEmailInput() {
// given
String name = "Rapt0r";
Player sender = mock(Player.class);
given(sender.getName()).willReturn(name);
given(sendMailSsl.hasAllInformation()).willReturn(true);
given(playerCache.isAuthenticated(name)).willReturn(false);
given(dataSource.getAuth(name)).willReturn(authWithEmail("raptor@example.org"));
// when
command.executeCommand(sender, Collections.singletonList("wrong-email@example.com"));
// then
verify(sendMailSsl).hasAllInformation();
verify(dataSource).getAuth(name);
verifyNoMoreInteractions(dataSource);
verify(commandService).send(sender, MessageKey.INVALID_EMAIL);
}
@Test
public void shouldResetPasswordAndSendEmail() {
// given
String name = "Vultur3";
Player sender = mock(Player.class);
given(sender.getName()).willReturn(name);
given(sendMailSsl.hasAllInformation()).willReturn(true);
given(playerCache.isAuthenticated(name)).willReturn(false);
String email = "vulture@example.com";
PlayerAuth auth = authWithEmail(email);
given(dataSource.getAuth(name)).willReturn(auth);
given(commandService.getProperty(EmailSettings.RECOVERY_PASSWORD_LENGTH)).willReturn(20);
given(passwordSecurity.computeHash(anyString(), eq(name)))
.willAnswer(new Answer<HashedPassword>() {
@Override
public HashedPassword answer(InvocationOnMock invocationOnMock) {
return new HashedPassword((String) invocationOnMock.getArguments()[0]);
}
});
// when
command.executeCommand(sender, Collections.singletonList(email.toUpperCase()));
// then
verify(sendMailSsl).hasAllInformation();
verify(dataSource).getAuth(name);
verify(passwordSecurity).computeHash(anyString(), eq(name));
verify(dataSource).updatePassword(auth);
assertThat(auth.getPassword().getHash(), stringWithLength(20));
verify(sendMailSsl).sendPasswordMail(eq(auth), argThat(stringWithLength(20)));
verify(commandService).send(sender, MessageKey.RECOVERY_EMAIL_SENT_MESSAGE);
}
private static PlayerAuth authWithEmail(String email) {
return PlayerAuth.builder()
.name("tester")
.email(email)
.build();
}
private static Matcher<String> stringWithLength(final int length) {
return new TypeSafeMatcher<String>() {
@Override
public void describeTo(Description description) {
description.appendText("String of length " + length);
}
@Override
protected boolean matchesSafely(String s) {
return s.length() == length;
}
};
}
}