/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.server.database; import java.io.File; import java.io.IOException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import com.googlecode.junit.ext.JunitExtRunner; import com.googlecode.junit.ext.RunIf; import com.thoughtworks.go.database.Database; import com.thoughtworks.go.junitext.DatabaseChecker; import com.thoughtworks.go.util.SystemEnvironment; import org.apache.commons.dbcp.BasicDataSource; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import static com.thoughtworks.go.server.database.DatabaseFixture.assertColumnType; import static com.thoughtworks.go.server.database.DatabaseFixture.numericQuery; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(JunitExtRunner.class) @RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2}) public class H2DatabaseTest { private H2Database h2Database; private DatabaseFixture dbFixture; @Before public void copyDatabaseDirectory() throws IOException { System.setProperty("db.maxActive","20"); System.setProperty("db.maxIdle","10"); dbFixture = new DatabaseFixture(); dbFixture.copyH2Db(); SystemEnvironment env = dbFixture.env(); env.setDebugMode(false); h2Database = new H2Database(env); h2Database.startDatabase(); } @After public void deleteTempDbDirectory() throws IOException, SQLException { h2Database.shutdown(); try { Thread.sleep(2000); } catch (InterruptedException ignored) { } dbFixture.tearDown(); } @Test public void shouldBeAbleToStartANewDatabase() throws SQLException { h2Database.startDatabase(); Connection connection = h2Database.createDataSource().getConnection(); ResultSet set = connection.getMetaData().getTables(null, null, null, null); assertThat(set.next(), is(true)); } @Test public void shouldUpgradeDatabase() throws SQLException { h2Database.shutdown(); h2Database.startDatabase(); BasicDataSource dataSource = h2Database.createDataSource(); h2Database.upgrade(); h2Database.startDatabase(); dataSource = h2Database.createDataSource(); Connection connection = dataSource.getConnection(); ResultSet set = connection.getMetaData().getTables(null, null, null, null); assertThat(set.next(), is(true)); } @Test public void shouldBackupOldDatabaseWhenUpgrading() throws SQLException, IOException { dbFixture.copyOldDb(); h2Database.startDatabase(); h2Database.upgrade(); assertThat(dbFixture.oldDb().exists(), is(false)); File backup = dbFixture.backupFile(); assertThat(backup.exists(), is(true)); assertThat(backup.getName(), matches(".+\\d\\d\\d\\d-\\d\\d-\\d\\d-\\d\\d\\d\\d\\.zip")); } private Matcher<String> matches(final String regex) { return new TypeSafeMatcher<String>() { public boolean matchesSafely(String item) { return item.matches(regex); } public void describeTo(Description description) { description.appendText("should match " + regex); } }; } @Test public void shouldDeleteEmptyHsqldbDirectory() throws SQLException, IOException { dbFixture.oldDb().mkdir(); h2Database.startDatabase(); h2Database.upgrade(); assertThat(dbFixture.oldDb().exists(), is(false)); } @Test public void shouldMigrateBuildbufferToTextColumn() throws SQLException, IOException { dbFixture.copyOldDb(); h2Database.startDatabase(); h2Database.upgrade(); BasicDataSource dataSource = h2Database.createDataSource(); assertColumnType(dataSource, "modifications", "comment", DatabaseFixture.LONGVARCHAR); assertColumnType(dataSource, "properties", "value", "VARCHAR(255)"); } @Test public void shouldPopulateModificationTablePipelineIdWithTheCorrectPipeline_CaseInSensitiveIssue() throws Exception { dbFixture.copyDeltas(); dbFixture.copyH2Db("migration84_test_db.zip"); H2Database database = new H2Database(dbFixture.env()); database.startDatabase(); database.upgrade(); database.shutdown(); database.startDatabase(); int afterRename = numericQuery("SELECT pipelineId FROM modifications WHERE revision = 'Zoo/4/foo/1'", database); int beforeRename = numericQuery("SELECT pipelineId FROM modifications WHERE revision = 'zoo/1/up-stage/1'", database); assertThat(afterRename == beforeRename, is(false)); } @Test public void shouldUseMVCCWhenRunning() throws Exception { h2Database.startDatabase(); h2Database.upgrade(); BasicDataSource dataSource = h2Database.createDataSource(); assertThat(dataSource.getUrl(), containsString("MVCC=TRUE")); } @Test public void shouldBackupDatabase() throws Exception { File destDir = new File("."); SystemEnvironment systemEnvironment = mock(SystemEnvironment.class); Database database = new H2Database(systemEnvironment); Database spy = spy(database); BasicDataSource dataSource = mock(BasicDataSource.class); Connection connection = mock(Connection.class); Statement statement = mock(Statement.class); doReturn(dataSource).when(spy).createDataSource(); when(dataSource.getConnection()).thenReturn(connection); when(connection.createStatement()).thenReturn(statement); when(statement.execute(anyString())).thenReturn(true); spy.backup(destDir); verify(statement).execute(anyString()); } @Test public void shouldThrowUpWhenBackupFails() throws Exception { File destDir = new File("."); SystemEnvironment systemEnvironment = mock(SystemEnvironment.class); Database database = new H2Database(systemEnvironment); Database spy = spy(database); BasicDataSource dataSource = mock(BasicDataSource.class); Connection connection = mock(Connection.class); Statement statement = mock(Statement.class); doReturn(dataSource).when(spy).createDataSource(); when(dataSource.getConnection()).thenReturn(connection); when(connection.createStatement()).thenReturn(statement); when(statement.execute(anyString())).thenThrow(new SQLException("i failed")); try { spy.backup(destDir); } catch (RuntimeException e) { assertThat(e.getMessage(), is("i failed")); } verify(statement).execute(anyString()); } @Test public void shouldUseParamterizedActiveAndIdleConnections() throws Exception { BasicDataSource dataSource = h2Database.createDataSource(); assertThat(dataSource.getMaxActive(),is(20)); assertThat(dataSource.getMaxIdle(),is(10)); } @Test @RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2}) public void shouldGetDialect() throws Exception { assertThat(h2Database.dialectForHibernate(), is(H2Database.DIALECT_H2)); } @Test @RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2}) public void shouldGetDatabaseType() throws Exception { assertThat(h2Database.getType(), is("h2")); } @Test @RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2}) public void shouldGetDatabaseSpecificIbatisConfigXmlLocation() throws Exception { assertThat(h2Database.getIbatisConfigXmlLocation(), nullValue()); } }