mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-27 04:35:12 +01:00
#392 Start integration test for SQLite
This commit is contained in:
parent
dfa3921740
commit
e8d627c0e1
7
pom.xml
7
pom.xml
@ -376,6 +376,13 @@
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- JDBC driver for datasource integration tests -->
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.8.11.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Log4J Logger (required by the console filter) -->
|
||||
<dependency>
|
||||
|
@ -1,12 +1,11 @@
|
||||
package fr.xephi.authme.cache.auth;
|
||||
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import static com.google.common.base.Objects.firstNonNull;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
@ -85,20 +84,6 @@ public class PlayerAuth {
|
||||
this(nickname, new HashedPassword(hash), -1, ip, lastLogin, 0, 0, 0, "world", email, realName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for PlayerAuth.
|
||||
*
|
||||
* @param nickname String
|
||||
* @param hash String
|
||||
* @param salt String
|
||||
* @param ip String
|
||||
* @param lastLogin long
|
||||
* @param realName String
|
||||
*/
|
||||
public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, String realName) {
|
||||
this(nickname, new HashedPassword(hash, salt), -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for PlayerAuth.
|
||||
*
|
||||
@ -118,44 +103,6 @@ public class PlayerAuth {
|
||||
this(nickname, new HashedPassword(hash), -1, ip, lastLogin, x, y, z, world, email, realName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for PlayerAuth.
|
||||
*
|
||||
* @param nickname String
|
||||
* @param hash String
|
||||
* @param salt String
|
||||
* @param ip String
|
||||
* @param lastLogin long
|
||||
* @param x double
|
||||
* @param y double
|
||||
* @param z double
|
||||
* @param world String
|
||||
* @param email String
|
||||
* @param realName String
|
||||
*/
|
||||
public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, double x, double y,
|
||||
double z, String world, String email, String realName) {
|
||||
this(nickname, new HashedPassword(hash, salt), -1, ip, lastLogin,
|
||||
x, y, z, world, email, realName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for PlayerAuth.
|
||||
*
|
||||
* @param nickname String
|
||||
* @param hash String
|
||||
* @param salt String
|
||||
* @param groupId int
|
||||
* @param ip String
|
||||
* @param lastLogin long
|
||||
* @param realName String
|
||||
*/
|
||||
public PlayerAuth(String nickname, String hash, String salt, int groupId, String ip,
|
||||
long lastLogin, String realName) {
|
||||
this(nickname, new HashedPassword(hash, salt), groupId, ip, lastLogin,
|
||||
0, 0, 0, "world", "your@email.com", realName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for PlayerAuth.
|
||||
*
|
||||
@ -171,8 +118,8 @@ public class PlayerAuth {
|
||||
* @param email String
|
||||
* @param realName String
|
||||
*/
|
||||
public PlayerAuth(String nickname, HashedPassword password, int groupId, String ip, long lastLogin,
|
||||
double x, double y, double z, String world, String email, String realName) {
|
||||
private PlayerAuth(String nickname, HashedPassword password, int groupId, String ip, long lastLogin,
|
||||
double x, double y, double z, String world, String email, String realName) {
|
||||
this.nickname = nickname.toLowerCase();
|
||||
this.password = password;
|
||||
this.ip = ip;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package fr.xephi.authme.datasource;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
@ -46,6 +47,21 @@ public class SQLite implements DataSource {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
SQLite(NewSetting settings, Connection connection, boolean executeSetup) {
|
||||
this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||
this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
||||
this.col = new Columns(settings);
|
||||
this.con = connection;
|
||||
if (executeSetup) {
|
||||
try {
|
||||
setup();
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void connect() throws ClassNotFoundException, SQLException {
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
ConsoleLogger.info("SQLite driver loaded");
|
||||
|
@ -2,6 +2,8 @@ package fr.xephi.authme;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* AuthMe test utilities.
|
||||
@ -18,11 +20,31 @@ public final class TestHelper {
|
||||
* @return The project file
|
||||
*/
|
||||
public static File getJarFile(String path) {
|
||||
URL url = getUrlOrThrow(path);
|
||||
return new File(url.getFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Path} to a file in the JAR's resources (main or test).
|
||||
*
|
||||
* @param path The absolute path to the file
|
||||
* @return The Path object to the file
|
||||
*/
|
||||
public static Path getJarPath(String path) {
|
||||
String sqlFilePath = getUrlOrThrow(path).getPath();
|
||||
// Windows preprends the path with a '/' or '\', which Paths cannot handle
|
||||
String appropriatePath = System.getProperty("os.name").contains("indow")
|
||||
? sqlFilePath.substring(1)
|
||||
: sqlFilePath;
|
||||
return Paths.get(appropriatePath);
|
||||
}
|
||||
|
||||
private static URL getUrlOrThrow(String path) {
|
||||
URL url = TestHelper.class.getResource(path);
|
||||
if (url == null) {
|
||||
throw new IllegalStateException("File '" + path + "' could not be loaded");
|
||||
}
|
||||
return new File(url.getFile());
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
|
91
src/test/java/fr/xephi/authme/datasource/AuthMeMatchers.java
Normal file
91
src/test/java/fr/xephi/authme/datasource/AuthMeMatchers.java
Normal file
@ -0,0 +1,91 @@
|
||||
package fr.xephi.authme.datasource;
|
||||
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Custom matchers for AuthMe entities.
|
||||
*/
|
||||
public final class AuthMeMatchers {
|
||||
|
||||
private AuthMeMatchers() {
|
||||
}
|
||||
|
||||
public static Matcher<? super HashedPassword> equalToHash(final String hash) {
|
||||
return equalToHash(hash, null);
|
||||
}
|
||||
|
||||
public static Matcher<? super HashedPassword> equalToHash(final String hash, final String salt) {
|
||||
return new BaseMatcher<HashedPassword>() {
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
if (item instanceof HashedPassword) {
|
||||
HashedPassword input = (HashedPassword) item;
|
||||
return Objects.equals(hash, input.getHash()) && Objects.equals(salt, input.getSalt());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
String representation = "'" + hash + "'";
|
||||
if (salt != null) {
|
||||
representation += ", '" + salt + "'";
|
||||
}
|
||||
description.appendValue("HashedPassword(" + representation + ")");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<? super PlayerAuth> hasAuthBasicData(final String name, final String realName,
|
||||
final String email, final String ip) {
|
||||
return new BaseMatcher<PlayerAuth>() {
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
if (item instanceof PlayerAuth) {
|
||||
PlayerAuth input = (PlayerAuth) item;
|
||||
return Objects.equals(name, input.getNickname())
|
||||
&& Objects.equals(realName, input.getRealName())
|
||||
&& Objects.equals(email, input.getEmail())
|
||||
&& Objects.equals(ip, input.getIp());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendValue(String.format("PlayerAuth with name %s, realname %s, email %s, ip %s",
|
||||
name, realName, email, ip));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static Matcher<? super PlayerAuth> hasAuthLocation(final double x, final double y, final double z,
|
||||
final String world) {
|
||||
return new BaseMatcher<PlayerAuth>() {
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
if (item instanceof PlayerAuth) {
|
||||
PlayerAuth input = (PlayerAuth) item;
|
||||
return Objects.equals(x, input.getQuitLocX())
|
||||
&& Objects.equals(y, input.getQuitLocY())
|
||||
&& Objects.equals(z, input.getQuitLocZ())
|
||||
&& Objects.equals(world, input.getWorld());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendValue(String.format("PlayerAuth with quit location (x: %f, y: %f, z: %f, world: %s)",
|
||||
x, y, z, world));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
package fr.xephi.authme.datasource;
|
||||
|
||||
import fr.xephi.authme.ConsoleLoggerTestInitializer;
|
||||
import fr.xephi.authme.TestHelper;
|
||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import fr.xephi.authme.settings.NewSetting;
|
||||
import fr.xephi.authme.settings.domain.Property;
|
||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import static fr.xephi.authme.datasource.AuthMeMatchers.equalToHash;
|
||||
import static fr.xephi.authme.datasource.AuthMeMatchers.hasAuthBasicData;
|
||||
import static fr.xephi.authme.datasource.AuthMeMatchers.hasAuthLocation;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Integration test for {@link SQLite}.
|
||||
*/
|
||||
public class SQLiteIntegrationTest {
|
||||
|
||||
/** Mock for a settings instance. */
|
||||
private static NewSetting settings;
|
||||
/** Collection of SQL statements to execute for initialization of a test. */
|
||||
private static String[] sqlInitialize;
|
||||
/** Connection to the SQLite test database. */
|
||||
private Connection con;
|
||||
|
||||
/**
|
||||
* Set up the settings mock to return specific values for database settings and load {@link #sqlInitialize}.
|
||||
*/
|
||||
@BeforeClass
|
||||
public static void initializeSettings() throws IOException, ClassNotFoundException {
|
||||
// Check that we have an implementation for SQLite
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
|
||||
settings = mock(NewSetting.class);
|
||||
when(settings.getProperty(any(Property.class))).thenAnswer(new Answer() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
return ((Property) invocation.getArguments()[0]).getDefaultValue();
|
||||
}
|
||||
});
|
||||
set(DatabaseSettings.MYSQL_DATABASE, "sqlite-test");
|
||||
set(DatabaseSettings.MYSQL_TABLE, "authme");
|
||||
set(DatabaseSettings.MYSQL_COL_SALT, "salt");
|
||||
ConsoleLoggerTestInitializer.setupLogger();
|
||||
|
||||
Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sqlite-initialize.sql");
|
||||
// Note ljacqu 20160221: It appears that we can only run one statement per Statement.execute() so we split
|
||||
// the SQL file by ";\n" as to get the individual statements
|
||||
sqlInitialize = new String(Files.readAllBytes(sqlInitFile)).split(";\\n");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initializeConnectionAndTable() throws SQLException, ClassNotFoundException {
|
||||
silentClose(con);
|
||||
Connection connection = DriverManager.getConnection("jdbc:sqlite::memory:");
|
||||
try (Statement st = connection.createStatement()) {
|
||||
st.execute("DROP TABLE IF EXISTS authme");
|
||||
for (String statement : sqlInitialize) {
|
||||
st.execute(statement);
|
||||
}
|
||||
}
|
||||
con = connection;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnIfAuthIsAvailableOrNot() {
|
||||
// given
|
||||
DataSource dataSource = new SQLite(settings, con, false);
|
||||
|
||||
// when
|
||||
boolean bobby = dataSource.isAuthAvailable("bobby");
|
||||
boolean chris = dataSource.isAuthAvailable("chris");
|
||||
boolean user = dataSource.isAuthAvailable("USER");
|
||||
|
||||
// then
|
||||
assertThat(bobby, equalTo(true));
|
||||
assertThat(chris, equalTo(false));
|
||||
assertThat(user, equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnPassword() {
|
||||
// given
|
||||
DataSource dataSource = new SQLite(settings, con, false);
|
||||
|
||||
// when
|
||||
HashedPassword bobbyPassword = dataSource.getPassword("bobby");
|
||||
HashedPassword invalidPassword = dataSource.getPassword("doesNotExist");
|
||||
HashedPassword userPassword = dataSource.getPassword("user");
|
||||
|
||||
// then
|
||||
assertThat(bobbyPassword, equalToHash(
|
||||
"$SHA$11aa0706173d7272$dbba96681c2ae4e0bfdf226d70fbbc5e4ee3d8071faa613bc533fe8a64817d10"));
|
||||
assertThat(invalidPassword, nullValue());
|
||||
assertThat(userPassword, equalToHash("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetAuth() {
|
||||
// given
|
||||
DataSource dataSource = new SQLite(settings, con, false);
|
||||
|
||||
// when
|
||||
PlayerAuth invalidAuth = dataSource.getAuth("notInDB");
|
||||
PlayerAuth bobbyAuth = dataSource.getAuth("Bobby");
|
||||
PlayerAuth userAuth = dataSource.getAuth("user");
|
||||
|
||||
// then
|
||||
assertThat(invalidAuth, nullValue());
|
||||
|
||||
assertThat(bobbyAuth, hasAuthBasicData("bobby", "Bobby", "your@email.com", "123.45.67.89"));
|
||||
assertThat(bobbyAuth, hasAuthLocation(1.05, 2.1, 4.2, "world"));
|
||||
assertThat(bobbyAuth.getLastLogin(), equalTo(1449136800L));
|
||||
assertThat(bobbyAuth.getPassword(), equalToHash(
|
||||
"$SHA$11aa0706173d7272$dbba96681c2ae4e0bfdf226d70fbbc5e4ee3d8071faa613bc533fe8a64817d10"));
|
||||
|
||||
assertThat(userAuth, hasAuthBasicData("user", "user", "user@example.org", "34.56.78.90"));
|
||||
assertThat(userAuth, hasAuthLocation(124.1, 76.3, -127.8, "nether"));
|
||||
assertThat(userAuth.getLastLogin(), equalTo(1453242857L));
|
||||
assertThat(userAuth.getPassword(), equalToHash("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"));
|
||||
}
|
||||
|
||||
private static <T> void set(Property<T> property, T value) {
|
||||
when(settings.getProperty(property)).thenReturn(value);
|
||||
}
|
||||
|
||||
private static void silentClose(Connection con) {
|
||||
if (con != null) {
|
||||
try {
|
||||
if (!con.isClosed()) {
|
||||
con.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// silent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
-- Important: separate SQL statements by ; followed directly by a newline. We split the file contents by ";\n"
|
||||
|
||||
CREATE TABLE authme (
|
||||
id INTEGER AUTO_INCREMENT,
|
||||
username VARCHAR(255) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
ip VARCHAR(40) NOT NULL,
|
||||
lastlogin BIGINT,
|
||||
x DOUBLE NOT NULL DEFAULT '0.0',
|
||||
y DOUBLE NOT NULL DEFAULT '0.0',
|
||||
z DOUBLE NOT NULL DEFAULT '0.0',
|
||||
world VARCHAR(255) NOT NULL DEFAULT 'world',
|
||||
email VARCHAR(255) DEFAULT 'your@email.com',
|
||||
isLogged INT DEFAULT '0', realname VARCHAR(255) NOT NULL DEFAULT 'Player',
|
||||
salt varchar(255),
|
||||
CONSTRAINT table_const_prim PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
INSERT INTO authme (id, username, password, ip, lastlogin, x, y, z, world, email, isLogged, realname, salt)
|
||||
VALUES (1,'bobby','$SHA$11aa0706173d7272$dbba96681c2ae4e0bfdf226d70fbbc5e4ee3d8071faa613bc533fe8a64817d10','123.45.67.89',1449136800,1.05,2.1,4.2,'world','your@email.com',0,'Bobby',NULL);
|
||||
INSERT INTO authme (id, username, password, ip, lastlogin, x, y, z, world, email, isLogged, realname, salt)
|
||||
VALUES (NULL,'user','b28c32f624a4eb161d6adc9acb5bfc5b','34.56.78.90',1453242857,124.1,76.3,-127.8,'nether','user@example.org',0,'user','f750ba32');
|
Loading…
Reference in New Issue
Block a user