#792 #814 Implement SQLite migration, allow last IP to be nullable in MySQL

- Old SQLite setups have the last IP column as NOT NULL but without a default value. With the new concept (where we don't set a last IP on player registration) it fails.
  - Create an /authme debug child that allows to migrate SQLite (tricky because SQLite does not support dropping or modifying columns)
  - Allow last IP column to be NOT NULL in MySQL as well (extend MySQL /authme debug child)
- Add TODO comments with follow-up issue to extend our commands with new registration IP field
This commit is contained in:
ljacqu
2017-10-21 10:24:40 +02:00
parent b5ea48085c
commit 1651a61063
29 changed files with 688 additions and 130 deletions
@@ -82,7 +82,8 @@ public class AccountsCommandTest {
// given
CommandSender sender = mock(CommandSender.class);
List<String> arguments = Collections.singletonList("SomeUser");
given(dataSource.getAuth("someuser")).willReturn(mock(PlayerAuth.class));
PlayerAuth auth = authWithIp("144.56.77.88");
given(dataSource.getAuth("someuser")).willReturn(auth);
// when
command.executeCommand(sender, arguments);
@@ -11,6 +11,8 @@ import java.util.List;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@@ -20,11 +22,16 @@ import static org.junit.Assert.fail;
public class DebugSectionConsistencyTest {
private static List<Class<?>> debugClasses;
private static List<DebugSection> debugSections;
@BeforeClass
public static void collectClasses() {
debugClasses = new ClassCollector(
TestHelper.SOURCES_FOLDER, TestHelper.PROJECT_ROOT + "command/executable/authme/debug").collectClasses();
// TODO ljacqu 20171021: Improve ClassCollector (pass pkg by class, improve #getInstancesOfType's instantiation)
ClassCollector classCollector = new ClassCollector(
TestHelper.SOURCES_FOLDER, TestHelper.PROJECT_ROOT + "command/executable/authme/debug");
debugClasses = classCollector.collectClasses();
debugSections = classCollector.getInstancesOfType(DebugSection.class, clz -> instantiate(clz));
}
@Test
@@ -40,13 +47,26 @@ public class DebugSectionConsistencyTest {
@Test
public void shouldHaveDifferentSubcommandName() throws IllegalAccessException, InstantiationException {
Set<String> names = new HashSet<>();
for (Class<?> clazz : debugClasses) {
if (DebugSection.class.isAssignableFrom(clazz) && !clazz.isInterface()) {
DebugSection debugSection = (DebugSection) clazz.newInstance();
if (!names.add(debugSection.getName())) {
fail("Encountered name '" + debugSection.getName() + "' a second time in " + clazz);
}
for (DebugSection debugSection : debugSections) {
if (!names.add(debugSection.getName())) {
fail("Encountered name '" + debugSection.getName() + "' a second time in " + debugSection.getClass());
}
}
}
@Test
public void shouldAllHaveDescription() {
for (DebugSection debugSection : debugSections) {
assertThat("Description of '" + debugSection.getClass() + "' may not be null",
debugSection.getDescription(), not(nullValue()));
}
}
private static DebugSection instantiate(Class<? extends DebugSection> clazz) {
try {
return ClassCollector.canInstantiate(clazz) ? clazz.newInstance() : null;
} catch (InstantiationException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}
@@ -2,8 +2,11 @@ package fr.xephi.authme.command.executable.authme.debug;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.data.limbo.LimboPlayer;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.datasource.CacheDataSource;
import fr.xephi.authme.datasource.DataSource;
import org.bukkit.Location;
import org.junit.Before;
import org.junit.Test;
@@ -89,4 +92,39 @@ public class DebugSectionUtilsTest {
// then
assertThat(result, nullValue());
}
@Test
public void shouldReturnSameDataSourceInstance() {
// given
DataSource dataSource = mock(DataSource.class);
// when
DataSource result = DebugSectionUtils.unwrapSourceFromCacheDataSource(dataSource);
// then
assertThat(result, equalTo(dataSource));
}
@Test
public void shouldUnwrapCacheDataSource() {
// given
DataSource source = mock(DataSource.class);
PlayerCache playerCache = mock(PlayerCache.class);
CacheDataSource cacheDataSource = new CacheDataSource(source, playerCache);
// when
DataSource result = DebugSectionUtils.unwrapSourceFromCacheDataSource(cacheDataSource);
// then
assertThat(result, equalTo(source));
}
@Test
public void shouldCastOrReturnNull() {
// given / when / then
assertThat(DebugSectionUtils.castToTypeOrNull("test", String.class), equalTo("test"));
assertThat(DebugSectionUtils.castToTypeOrNull("test", Integer.class), nullValue());
assertThat(DebugSectionUtils.castToTypeOrNull(5, String.class), nullValue());
assertThat(DebugSectionUtils.castToTypeOrNull(5, Integer.class), equalTo(5));
}
}
@@ -7,7 +7,7 @@ import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.CacheDataSource;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.MySQL;
import fr.xephi.authme.datasource.MySqlTestUtil;
import fr.xephi.authme.datasource.SqlDataSourceTestUtil;
import fr.xephi.authme.settings.Settings;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -34,32 +34,6 @@ public class MySqlDefaultChangerTest {
@Mock
private Settings settings;
@Test
public void shouldReturnSameDataSourceInstance() {
// given
DataSource dataSource = mock(DataSource.class);
// when
DataSource result = MySqlDefaultChanger.unwrapSourceFromCacheDataSource(dataSource);
// then
assertThat(result, equalTo(dataSource));
}
@Test
public void shouldUnwrapCacheDataSource() {
// given
DataSource source = mock(DataSource.class);
PlayerCache playerCache = mock(PlayerCache.class);
CacheDataSource cacheDataSource = new CacheDataSource(source, playerCache);
// when
DataSource result = MySqlDefaultChanger.unwrapSourceFromCacheDataSource(cacheDataSource);
// then
assertThat(result, equalTo(source));
}
@Test
public void shouldReturnMySqlConnection() throws SQLException {
// given
@@ -68,7 +42,7 @@ public class MySqlDefaultChangerTest {
HikariDataSource dataSource = mock(HikariDataSource.class);
Connection connection = mock(Connection.class);
given(dataSource.getConnection()).willReturn(connection);
MySQL mySQL = MySqlTestUtil.createMySql(settings, dataSource);
MySQL mySQL = SqlDataSourceTestUtil.createMySql(settings, dataSource);
MySqlDefaultChanger defaultChanger = createDefaultChanger(mySQL);
// when
@@ -0,0 +1,109 @@
package fr.xephi.authme.command.executable.authme.debug;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.SQLite;
import fr.xephi.authme.settings.Settings;
import org.bukkit.command.CommandSender;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import static fr.xephi.authme.AuthMeMatchers.hasAuthBasicData;
import static fr.xephi.authme.AuthMeMatchers.hasAuthLocation;
import static fr.xephi.authme.datasource.SqlDataSourceTestUtil.createSqliteAndInitialize;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
/**
* Integration test for {@link SqliteMigrater}. Uses a real SQLite database.
*/
public class SqliteMigraterIntegrationTest {
private static final String CONFIRMATION_CODE = "ABCD";
private SqliteMigrater sqliteMigrater;
private SQLite sqLite;
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Before
public void setup() throws SQLException, IOException, NoSuchMethodException {
TestHelper.setupLogger();
Settings settings = mock(Settings.class);
TestHelper.returnDefaultsForAllProperties(settings);
File sqliteDbFile = TestHelper.getJarFile(TestHelper.PROJECT_ROOT + "datasource/sqlite.april2016.db");
File tempFile = temporaryFolder.newFile();
Files.copy(sqliteDbFile, tempFile);
Connection con = DriverManager.getConnection("jdbc:sqlite:" + tempFile.getPath());
sqLite = createSqliteAndInitialize(settings, con);
sqliteMigrater = new SqliteMigrater();
ReflectionTestUtils.setField(sqliteMigrater, "dataSource", sqLite);
ReflectionTestUtils.setField(sqliteMigrater, "settings", settings);
ReflectionTestUtils.setField(sqliteMigrater, "confirmationCode", CONFIRMATION_CODE);
sqliteMigrater.setSqLiteField();
}
@Test
public void shouldRun() throws ClassNotFoundException, SQLException {
// given
CommandSender sender = mock(CommandSender.class);
// when
sqliteMigrater.execute(sender, Collections.singletonList(CONFIRMATION_CODE));
// then
List<PlayerAuth> auths = sqLite.getAllAuths();
assertThat(Lists.transform(auths, PlayerAuth::getNickname),
containsInAnyOrder("mysql1", "mysql2", "mysql3", "mysql4", "mysql5", "mysql6"));
PlayerAuth auth1 = getByNameOrFail("mysql1", auths);
assertThat(auth1, hasAuthBasicData("mysql1", "mysql1", "user1@example.com", "192.168.4.41"));
assertThat(auth1, hasAuthLocation(0, 0, 0, "world1", 0, 0));
assertThat(auth1.getLastLogin(), equalTo(1472992664137L));
PlayerAuth auth2 = getByNameOrFail("mysql2", auths);
assertThat(auth2, hasAuthBasicData("mysql2", "Player", "user2@example.com", null));
assertThat(auth2, hasAuthLocation(0, 0, 0, "world2", 0, 0));
assertThat(auth2.getLastLogin(), equalTo(1472992668391L));
PlayerAuth auth3 = getByNameOrFail("mysql3", auths);
assertThat(auth3, hasAuthBasicData("mysql3", "mysql3", null, "132.54.76.98"));
assertThat(auth3, hasAuthLocation(0, 0, 0, "world3", 0, 0));
assertThat(auth3.getLastLogin(), equalTo(1472992672790L));
PlayerAuth auth4 = getByNameOrFail("mysql4", auths);
assertThat(auth4, hasAuthBasicData("mysql4", "MySQL4", null, null));
assertThat(auth4, hasAuthLocation(25, 4, 17, "world4", 0, 0));
assertThat(auth4.getLastLogin(), equalTo(1472992676790L));
PlayerAuth auth5 = getByNameOrFail("mysql5", auths);
assertThat(auth5, hasAuthBasicData("mysql5", "mysql5", null, null));
assertThat(auth5, hasAuthLocation(0, 0, 0, "world5", 0, 0));
assertThat(auth5.getLastLogin(), equalTo(1472992680922L));
PlayerAuth auth6 = getByNameOrFail("mysql6", auths);
assertThat(auth6, hasAuthBasicData("mysql6", "MySql6", "user6@example.com", "44.45.67.188"));
assertThat(auth6, hasAuthLocation(28.5, 53.43, -147.23, "world6", 0, 0));
assertThat(auth6.getLastLogin(), equalTo(1472992686300L));
}
private static PlayerAuth getByNameOrFail(String name, List<PlayerAuth> auths) {
return auths.stream()
.filter(auth -> name.equals(auth.getNickname()))
.findFirst().orElseThrow(() -> new IllegalStateException("No PlayerAuth with name '" + name + "'"));
}
}
@@ -18,12 +18,16 @@ public class PlayerAuthTest {
PlayerAuth auth = PlayerAuth.builder()
.name("Bobby")
.lastLogin(0L)
.lastIp("127.0.0.1")
.email("your@email.com")
.build();
// then
assertThat(auth.getNickname(), equalTo("bobby"));
assertThat(auth.getLastLogin(), nullValue());
// Note ljacqu 20171020: Although 127.0.0.1 is the default value, we need to keep it because it might
// legitimately be the resolved IP of a player
assertThat(auth.getLastIp(), equalTo("127.0.0.1"));
assertThat(auth.getEmail(), nullValue());
}
@@ -50,6 +54,7 @@ public class PlayerAuthTest {
.name("Charlie")
.email(null)
.lastLogin(null)
.lastIp(null)
.groupId(19)
.locPitch(123.004f)
.build();
@@ -57,6 +62,7 @@ public class PlayerAuthTest {
// then
assertThat(auth.getEmail(), nullValue());
assertThat(auth.getLastLogin(), nullValue());
assertThat(auth.getLastIp(), nullValue());
assertThat(auth.getGroupId(), equalTo(19));
assertThat(auth.getPitch(), equalTo(123.004f));
}
@@ -64,7 +64,7 @@ public class FlatFileIntegrationTest {
assertThat(getName("bobby", authList), hasAuthBasicData("bobby", "bobby", null, "123.45.67.89"));
assertThat(getName("bobby", authList), hasAuthLocation(1.05, 2.1, 4.2, "world", 0, 0));
assertThat(getName("bobby", authList).getPassword(), equalToHash("$SHA$11aa0706173d7272$dbba966"));
assertThat(getName("twofields", authList), hasAuthBasicData("twofields", "twofields", null, "127.0.0.1"));
assertThat(getName("twofields", authList), hasAuthBasicData("twofields", "twofields", null, null));
assertThat(getName("twofields", authList).getPassword(), equalToHash("hash1234"));
assertThat(getName("threefields", authList), hasAuthBasicData("threefields", "threefields", null, "33.33.33.33"));
assertThat(getName("fourfields", authList), hasAuthBasicData("fourfields", "fourfields", null, "4.4.4.4"));
@@ -76,7 +76,7 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest {
@Override
protected DataSource getDataSource(String saltColumn) {
when(settings.getProperty(DatabaseSettings.MYSQL_COL_SALT)).thenReturn(saltColumn);
return MySqlTestUtil.createMySql(settings, hikariSource);
return SqlDataSourceTestUtil.createMySql(settings, hikariSource);
}
private static <T> void set(Property<T> property, T value) {
@@ -1,30 +0,0 @@
package fr.xephi.authme.datasource;
import com.zaxxer.hikari.HikariDataSource;
import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension;
import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory;
import fr.xephi.authme.settings.Settings;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Test util for the MySQL data source.
*/
public final class MySqlTestUtil {
private MySqlTestUtil() {
}
public static MySQL createMySql(Settings settings, HikariDataSource hikariDataSource) {
MySqlExtensionsFactory extensionsFactory = mock(MySqlExtensionsFactory.class);
given(extensionsFactory.buildExtension(any())).willReturn(mock(MySqlExtension.class));
return createMySql(settings, hikariDataSource, extensionsFactory);
}
public static MySQL createMySql(Settings settings, HikariDataSource hikariDataSource,
MySqlExtensionsFactory extensionsFactory) {
return new MySQL(settings, hikariDataSource, extensionsFactory);
}
}
@@ -0,0 +1,52 @@
package fr.xephi.authme.datasource;
import com.zaxxer.hikari.HikariDataSource;
import fr.xephi.authme.datasource.mysqlextensions.MySqlExtension;
import fr.xephi.authme.datasource.mysqlextensions.MySqlExtensionsFactory;
import fr.xephi.authme.settings.Settings;
import java.sql.Connection;
import java.sql.SQLException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Test util for the SQL data sources.
*/
public final class SqlDataSourceTestUtil {
private SqlDataSourceTestUtil() {
}
public static MySQL createMySql(Settings settings, HikariDataSource hikariDataSource) {
MySqlExtensionsFactory extensionsFactory = mock(MySqlExtensionsFactory.class);
given(extensionsFactory.buildExtension(any())).willReturn(mock(MySqlExtension.class));
return new MySQL(settings, hikariDataSource, extensionsFactory);
}
public static SQLite createSqlite(Settings settings, Connection connection) {
return new SQLite(settings, connection) {
// Override reload() so it doesn't run SQLite#connect, since we're given a specific Connection to use
@Override
public void reload() {
try {
this.setup();
} catch (SQLException e) {
throw new IllegalStateException(e);
}
}
};
}
public static SQLite createSqliteAndInitialize(Settings settings, Connection connection) {
SQLite sqLite = createSqlite(settings, connection);
try {
sqLite.setup();
} catch (SQLException e) {
throw new IllegalStateException(e);
}
return sqLite;
}
}
@@ -4,10 +4,17 @@ import fr.xephi.authme.TestHelper;
import org.junit.Before;
import org.junit.Test;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Logger;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
@@ -40,4 +47,108 @@ public class SqlDataSourceUtilsTest {
// then
verify(logger).warning(argThat(containsString(msg)));
}
@Test
public void shouldFetchNullableStatus() throws SQLException {
// given
String tableName = "data";
String columnName = "category";
ResultSet resultSet = mock(ResultSet.class);
given(resultSet.getInt("NULLABLE")).willReturn(DatabaseMetaData.columnNullable);
given(resultSet.next()).willReturn(true);
DatabaseMetaData metaData = mock(DatabaseMetaData.class);
given(metaData.getColumns(null, null, tableName, columnName)).willReturn(resultSet);
// when
boolean result = SqlDataSourceUtils.isNotNullColumn(metaData, tableName, columnName);
// then
assertThat(result, equalTo(false));
}
@Test
public void shouldReturnFalseForUnknownNullableStatus() throws SQLException {
// given
String tableName = "comments";
String columnName = "author";
ResultSet resultSet = mock(ResultSet.class);
given(resultSet.getInt("NULLABLE")).willReturn(DatabaseMetaData.columnNullableUnknown);
given(resultSet.next()).willReturn(true);
DatabaseMetaData metaData = mock(DatabaseMetaData.class);
given(metaData.getColumns(null, null, tableName, columnName)).willReturn(resultSet);
// when
boolean result = SqlDataSourceUtils.isNotNullColumn(metaData, tableName, columnName);
// then
assertThat(result, equalTo(false));
}
@Test(expected = IllegalStateException.class)
public void shouldThrowForUnknownColumnInNullableCheck() throws SQLException {
// given
String tableName = "data";
String columnName = "unknown";
ResultSet resultSet = mock(ResultSet.class);
given(resultSet.next()).willReturn(false);
DatabaseMetaData metaData = mock(DatabaseMetaData.class);
given(metaData.getColumns(null, null, tableName, columnName)).willReturn(resultSet);
// when
SqlDataSourceUtils.isNotNullColumn(metaData, tableName, columnName);
// then - expect exception
}
@Test
public void shouldGetDefaultValue() throws SQLException {
// given
String tableName = "data";
String columnName = "category";
ResultSet resultSet = mock(ResultSet.class);
given(resultSet.getObject("COLUMN_DEF")).willReturn("Literature");
given(resultSet.next()).willReturn(true);
DatabaseMetaData metaData = mock(DatabaseMetaData.class);
given(metaData.getColumns(null, null, tableName, columnName)).willReturn(resultSet);
// when
Object defaultValue = SqlDataSourceUtils.getColumnDefaultValue(metaData, tableName, columnName);
// then
assertThat(defaultValue, equalTo("Literature"));
}
@Test(expected = IllegalStateException.class)
public void shouldThrowForUnknownColumnInDefaultValueRetrieval() throws SQLException {
// given
String tableName = "data";
String columnName = "unknown";
ResultSet resultSet = mock(ResultSet.class);
given(resultSet.next()).willReturn(false);
DatabaseMetaData metaData = mock(DatabaseMetaData.class);
given(metaData.getColumns(null, null, tableName, columnName)).willReturn(resultSet);
// when
SqlDataSourceUtils.getColumnDefaultValue(metaData, tableName, columnName);
// then - expect exception
}
@Test
public void shouldHandleNullDefaultValue() throws SQLException {
// given
String tableName = "data";
String columnName = "category";
ResultSet resultSet = mock(ResultSet.class);
given(resultSet.getObject("COLUMN_DEF")).willReturn(null);
given(resultSet.next()).willReturn(true);
DatabaseMetaData metaData = mock(DatabaseMetaData.class);
given(metaData.getColumns(null, null, tableName, columnName)).willReturn(resultSet);
// when
Object defaultValue = SqlDataSourceUtils.getColumnDefaultValue(metaData, tableName, columnName);
// then
assertThat(defaultValue, nullValue());
}
}
@@ -29,6 +29,7 @@ import static fr.xephi.authme.AuthMeMatchers.hasAuthLocation;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@@ -75,7 +76,7 @@ public class LoginSecurityConverterTest {
assertThat(captor.getAllValues().get(0).getLastLogin(), equalTo(1494242093652L));
assertThat(captor.getAllValues().get(0).getRegistrationDate(), equalTo(1494242093400L));
assertThat(captor.getAllValues().get(0).getPassword(), equalToHash("$2a$10$E1Ri7XKeIIBv4qVaiPplgepT7QH9xGFh3hbHfcmCjq7hiW.UBTiGK"));
assertThat(captor.getAllValues().get(0).getLastIp(), equalTo("127.0.0.1"));
assertThat(captor.getAllValues().get(0).getLastIp(), nullValue());
assertThat(captor.getAllValues().get(1).getNickname(), equalTo("player2"));
assertThat(captor.getAllValues().get(1).getLastLogin(), equalTo(1494242174589L));
@@ -84,7 +85,7 @@ public class LoginSecurityConverterTest {
assertThat(captor.getAllValues().get(2).getRealName(), equalTo("Player3"));
assertThat(captor.getAllValues().get(2).getPassword(), equalToHash("$2a$10$WFui8KSXMLDOVXKFpCLyPukPi4M82w1cv/rNojsAnwJjba3pp8sba"));
assertThat(captor.getAllValues().get(2), hasAuthLocation(14.24, 67.99, -12.83, "hubb", -10f, 185f));
assertThat(captor.getAllValues().get(2).getLastIp(), equalTo("127.0.0.1"));
assertThat(captor.getAllValues().get(2).getLastIp(), nullValue());
assertIsCloseTo(captor.getAllValues().get(2).getRegistrationDate(), System.currentTimeMillis(), 500L);
}
@@ -108,7 +109,7 @@ public class LoginSecurityConverterTest {
assertThat(captor.getAllValues().get(0).getRealName(), equalTo("Player1"));
assertThat(captor.getAllValues().get(0).getLastLogin(), equalTo(1494242093000L));
assertThat(captor.getAllValues().get(0).getPassword(), equalToHash("$2a$10$E1Ri7XKeIIBv4qVaiPplgepT7QH9xGFh3hbHfcmCjq7hiW.UBTiGK"));
assertThat(captor.getAllValues().get(0).getLastIp(), equalTo("127.0.0.1"));
assertThat(captor.getAllValues().get(0).getLastIp(), nullValue());
assertIsCloseTo(captor.getAllValues().get(0).getRegistrationDate(), 1494201600000L, 12 * 60 * 60 * 1000);
assertThat(captor.getAllValues().get(1).getNickname(), equalTo("player2"));
@@ -121,7 +121,7 @@ public class EmailRegisterExecutorProviderTest {
PlayerAuth auth = executor.buildPlayerAuth(params);
// then
assertThat(auth, hasAuthBasicData("veronica", "Veronica", "test@example.com", "127.0.0.1"));
assertThat(auth, hasAuthBasicData("veronica", "Veronica", "test@example.com", null));
assertThat(auth.getRegistrationIp(), equalTo("123.45.67.89"));
assertIsCloseTo(auth.getRegistrationDate(), System.currentTimeMillis(), 1000);
assertThat(auth.getPassword().getHash(), stringWithLength(12));
@@ -103,7 +103,7 @@ public class PasswordRegisterExecutorTest {
PlayerAuth auth = executor.buildPlayerAuth(params);
// then
assertThat(auth, hasAuthBasicData("s1m0n", "S1m0N", "mail@example.org", "127.0.0.1"));
assertThat(auth, hasAuthBasicData("s1m0n", "S1m0N", "mail@example.org", null));
assertThat(auth.getRegistrationIp(), equalTo("123.45.67.89"));
assertIsCloseTo(auth.getRegistrationDate(), System.currentTimeMillis(), 500);
assertThat(auth.getPassword(), equalToHash("pass"));
@@ -33,7 +33,7 @@ public class PlayerAuthBuilderHelperTest {
PlayerAuth auth = PlayerAuthBuilderHelper.createPlayerAuth(player, hashedPassword, email);
// then
assertThat(auth, hasAuthBasicData("noah", "Noah", email, "127.0.0.1"));
assertThat(auth, hasAuthBasicData("noah", "Noah", email, null));
assertThat(auth.getRegistrationIp(), equalTo("192.168.34.47"));
assertThat(Math.abs(auth.getRegistrationDate() - System.currentTimeMillis()), lessThan(1000L));
assertThat(auth.getPassword(), equalToHash("myHash0001"));
@@ -213,6 +213,30 @@ public class SessionServiceTest {
verify(dataSource).getAuth(name);
}
@Test
public void shouldHandlePlayerAuthWithNullLastIp() {
// given
String name = "Charles";
Player player = mockPlayerWithNameAndIp(name, "144.117.118.145");
given(dataSource.hasSession(name)).willReturn(true);
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.lastIp(null)
.lastLogin(System.currentTimeMillis()).build();
given(dataSource.getAuth(name)).willReturn(auth);
// when
boolean result = sessionService.canResumeSession(player);
// then
assertThat(result, equalTo(false));
verify(commonService).getProperty(PluginSettings.SESSIONS_ENABLED);
verify(dataSource).hasSession(name);
verify(dataSource).setUnlogged(name);
verify(dataSource).revokeSession(name);
verify(dataSource).getAuth(name);
}
private static Player mockPlayerWithNameAndIp(String name, String ip) {
Player player = mock(Player.class);
given(player.getName()).willReturn(name);