diff --git a/pom.xml b/pom.xml index fd994681..94c8b48e 100644 --- a/pom.xml +++ b/pom.xml @@ -376,13 +376,19 @@ compile true - + org.xerial sqlite-jdbc 3.8.11.2 test + + com.h2database + h2 + 1.4.191 + test + diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 77314066..99ba7247 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -81,6 +81,19 @@ public class MySQL implements DataSource { } } + MySQL(NewSetting settings, HikariDataSource hikariDataSource) { + this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST); + this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT); + this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME); + this.password = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD); + this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE); + this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); + this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS); + this.col = new Columns(settings); + this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH); + ds = hikariDataSource; + } + private synchronized void setConnectionArguments() throws RuntimeException { ds = new HikariDataSource(); ds.setPoolName("AuthMeMYSQLPool"); diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index 787b6b0c..5a582be4 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -48,18 +48,11 @@ public class SQLite implements DataSource { } @VisibleForTesting - SQLite(NewSetting settings, Connection connection, boolean executeSetup) { + SQLite(NewSetting settings, Connection connection) { 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 { diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java new file mode 100644 index 00000000..eedd781f --- /dev/null +++ b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java @@ -0,0 +1,110 @@ +package fr.xephi.authme.datasource; + +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.security.crypts.HashedPassword; +import org.junit.Test; + +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; + +/** + * Abstract class for data source integration tests. + */ +public abstract class AbstractDataSourceIntegrationTest { + + protected abstract DataSource getDataSource(); + + @Test + public void shouldReturnIfAuthIsAvailableOrNot() { + // given + DataSource dataSource = getDataSource(); + + // when + boolean isBobbyAvailable = dataSource.isAuthAvailable("bobby"); + boolean isChrisAvailable = dataSource.isAuthAvailable("chris"); + boolean isUserAvailable = dataSource.isAuthAvailable("USER"); + + // then + assertThat(isBobbyAvailable, equalTo(true)); + assertThat(isChrisAvailable, equalTo(false)); + assertThat(isUserAvailable, equalTo(true)); + } + + @Test + public void shouldReturnPassword() { + // given + DataSource dataSource = getDataSource(); + + // when + HashedPassword bobbyPassword = dataSource.getPassword("bobby"); + HashedPassword invalidPassword = dataSource.getPassword("doesNotExist"); + HashedPassword userPassword = dataSource.getPassword("user"); + + // then + assertThat(bobbyPassword, equalToHash("$SHA$11aa0706173d7272$dbba966")); + assertThat(invalidPassword, nullValue()); + assertThat(userPassword, equalToHash("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32")); + } + + @Test + public void shouldGetAuth() { + // given + DataSource dataSource = getDataSource(); + + // 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$dbba966")); + + 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")); + } + + @Test + public void shouldFindIfEmailExists() { + // given + DataSource dataSource = getDataSource(); + + // when + boolean isUserMailPresent = dataSource.isEmailStored("user@example.org"); + boolean isUserMailPresentCaseInsensitive = dataSource.isEmailStored("user@example.ORG"); + boolean isInvalidMailPresent = dataSource.isEmailStored("not-in-database@example.com"); + + // then + assertThat(isUserMailPresent, equalTo(true)); + assertThat(isUserMailPresentCaseInsensitive, equalTo(true)); + assertThat(isInvalidMailPresent, equalTo(false)); + } + + @Test + public void shouldCountAuthsByEmail() { + // given + DataSource dataSource = getDataSource(); + + // when + int userMailCount = dataSource.countAuthsByEmail("user@example.ORG"); + int invalidMailCount = dataSource.countAuthsByEmail("not.in.db@example.com"); + dataSource.saveAuth(PlayerAuth.builder().name("Test").email("user@EXAMPLE.org").build()); + int newUserCount = dataSource.countAuthsByEmail("user@Example.org"); + + // then + assertThat(userMailCount, equalTo(1)); + assertThat(invalidMailCount, equalTo(0)); + assertThat(newUserCount, equalTo(2)); + } + +} diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java new file mode 100644 index 00000000..34a2a6af --- /dev/null +++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java @@ -0,0 +1,98 @@ +package fr.xephi.authme.datasource; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import fr.xephi.authme.ConsoleLoggerTestInitializer; +import fr.xephi.authme.TestHelper; +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.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.SQLException; +import java.sql.Statement; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Integration test for {@link MySQL}. + */ +public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { + + /** Mock of 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 H2 test database. */ + private HikariDataSource hikariSource; + + /** + * 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 H2 driver + Class.forName("org.h2.jdbcx.JdbcDataSource"); + + 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, "h2_test"); + set(DatabaseSettings.MYSQL_TABLE, "authme"); + set(DatabaseSettings.MYSQL_COL_SALT, "salt"); + ConsoleLoggerTestInitializer.setupLogger(); + + Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sql-initialize.sql"); + sqlInitialize = new String(Files.readAllBytes(sqlInitFile)).split(";\\n"); + } + + @Before + public void initializeConnectionAndTable() throws SQLException { + silentClose(hikariSource); + HikariConfig config = new HikariConfig(); + config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); + config.setConnectionTestQuery("VALUES 1"); + config.addDataSourceProperty("URL", "jdbc:h2:mem:test"); + config.addDataSourceProperty("user", "sa"); + config.addDataSourceProperty("password", "sa"); + HikariDataSource ds = new HikariDataSource(config); + Connection connection = ds.getConnection(); + + try (Statement st = connection.createStatement()) { + st.execute("DROP TABLE IF EXISTS authme"); + for (String statement : sqlInitialize) { + st.execute(statement); + } + } + hikariSource = ds; + } + + @Override + protected DataSource getDataSource() { + return new MySQL(settings, hikariSource); + } + + private static void set(Property property, T value) { + when(settings.getProperty(property)).thenReturn(value); + } + + private static void silentClose(HikariDataSource con) { + if (con != null && !con.isClosed()) { + con.close(); + } + } + +} diff --git a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java index bf211b2e..5c08b479 100644 --- a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java @@ -2,14 +2,11 @@ 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; @@ -21,12 +18,6 @@ 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; @@ -34,7 +25,7 @@ import static org.mockito.Mockito.when; /** * Integration test for {@link SQLite}. */ -public class SQLiteIntegrationTest { +public class SQLiteIntegrationTest extends AbstractDataSourceIntegrationTest { /** Mock of a settings instance. */ private static NewSetting settings; @@ -63,7 +54,7 @@ public class SQLiteIntegrationTest { set(DatabaseSettings.MYSQL_COL_SALT, "salt"); ConsoleLoggerTestInitializer.setupLogger(); - Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sqlite-initialize.sql"); + Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sql-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"); @@ -82,93 +73,9 @@ public class SQLiteIntegrationTest { con = connection; } - @Test - public void shouldReturnIfAuthIsAvailableOrNot() { - // given - DataSource dataSource = new SQLite(settings, con, false); - - // when - boolean isBobbyAvailable = dataSource.isAuthAvailable("bobby"); - boolean isChrisAvailable = dataSource.isAuthAvailable("chris"); - boolean isUserAvailable = dataSource.isAuthAvailable("USER"); - - // then - assertThat(isBobbyAvailable, equalTo(true)); - assertThat(isChrisAvailable, equalTo(false)); - assertThat(isUserAvailable, 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$dbba966")); - 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$dbba966")); - - 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")); - } - - @Test - public void shouldFindIfEmailExists() { - // given - DataSource dataSource = new SQLite(settings, con, false); - - // when - boolean isUserMailPresent = dataSource.isEmailStored("user@example.org"); - boolean isUserMailPresentCaseInsensitive = dataSource.isEmailStored("user@example.ORG"); - boolean isInvalidMailPresent = dataSource.isEmailStored("not-in-database@example.com"); - - // then - assertThat(isUserMailPresent, equalTo(true)); - assertThat(isUserMailPresentCaseInsensitive, equalTo(true)); - assertThat(isInvalidMailPresent, equalTo(false)); - } - - @Test - public void shouldCountAuthsByEmail() { - // given - DataSource dataSource = new SQLite(settings, con, false); - - // when - int userMailCount = dataSource.countAuthsByEmail("user@example.ORG"); - int invalidMailCount = dataSource.countAuthsByEmail("not.in.db@example.com"); - dataSource.saveAuth(PlayerAuth.builder().name("Test").email("user@EXAMPLE.org").build()); - int newUserCount = dataSource.countAuthsByEmail("user@Example.org"); - - // then - assertThat(userMailCount, equalTo(1)); - assertThat(invalidMailCount, equalTo(0)); - assertThat(newUserCount, equalTo(2)); + @Override + protected DataSource getDataSource() { + return new SQLite(settings, con); } private static void set(Property property, T value) { @@ -186,6 +93,4 @@ public class SQLiteIntegrationTest { } } } - - } diff --git a/src/test/resources/datasource-integration/sqlite-initialize.sql b/src/test/resources/datasource-integration/sql-initialize.sql similarity index 100% rename from src/test/resources/datasource-integration/sqlite-initialize.sql rename to src/test/resources/datasource-integration/sql-initialize.sql