/*************************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.IOException;
import java.sql.SQLException;
import com.googlecode.junit.ext.JunitExtRunner;
import com.googlecode.junit.ext.RunIf;
import com.thoughtworks.go.junitext.DatabaseChecker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@RunWith(JunitExtRunner.class)
public class DbMigrationTest {
private DatabaseFixture dbFixture;
private H2Database h2Database;
@Before
public void setUp() throws Exception {
dbFixture = new DatabaseFixture();
}
@After
public void deleteTempDbDirectory() throws IOException, SQLException {
h2Database.shutdown();
try {
Thread.sleep(2000);
} catch (InterruptedException ignored) {
}
//dbFixture.tearDown();
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void testMigration86() throws IOException, SQLException {
dbFixture.copyDeltas();
dbFixture.copyH2Db("migration86_test_db.zip");
h2Database = new H2Database(dbFixture.env());
h2Database.startDatabase();
h2Database.upgrade();
assertPmrFromIdAndActualFromId("down", 2, 7, 7);
assertPmrFromIdAndActualFromId("down", 3, 10, 8);
assertPmrFromIdAndActualFromId("other", 1, 11, 11);
assertPmrFromIdAndActualFromId("up", 1, 6, 6);
assertPmrFromIdAndActualFromId("up", 5, 6, 6);
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void testMigration_230006_user_name_case_insensitivity() throws IOException, SQLException {
dbFixture.copyDeltas();
dbFixture.copyH2Db("with-usernames-in-different-cases.zip");
h2Database = new H2Database(dbFixture.env());
h2Database.startDatabase();
h2Database.upgrade();
matchUserAttributesForUsername("foo", "foo@foo.com", true, "foo");
matchUserAttributesForUsername("bar", "baz@bar.com", true, "BAR");
matchUserAttributesForUsername("baz", "baz@baz.com", false, "baz");
matchUserAttributesForUsername("quux", "quux@quux.com", true, "quux");
assertThat(DatabaseFixture.query("select count(*) from users", h2Database), is(new Object[][]{{5l}}));
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void testMigration_230001_should_create_column_if_not_exist() throws Exception {
dbFixture.copyDeltas();
dbFixture.copyH2Db("with-usernames-in-different-cases.zip");
h2Database = new H2Database(dbFixture.env());
h2Database.startDatabase();
assertThat(DatabaseFixture.query("SELECT COUNT(*) FROM information_schema.COLUMNS WHERE COLUMN_NAME='ARTIFACTSDELETED' AND TABLE_NAME='STAGES' AND TABLE_SCHEMA='PUBLIC'", h2Database),
is(new Object[][]{{0L}}));
h2Database.upgrade();
assertThat(DatabaseFixture.query("SELECT COUNT(*) FROM information_schema.COLUMNS WHERE COLUMN_NAME='ARTIFACTSDELETED' AND TABLE_NAME='STAGES' AND TABLE_SCHEMA='PUBLIC'", h2Database),
is(new Object[][]{{1L}}));
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void testMigration_230001_should_not_create_column_if_exist() throws Exception {
dbFixture.copyDeltas();
dbFixture.copyH2Db("with-usernames-in-different-cases.zip");
h2Database = new H2Database(dbFixture.env());
h2Database.startDatabase();
DatabaseFixture.update("ALTER TABLE STAGES ADD COLUMN `ARTIFACTSDELETED` Boolean DEFAULT FALSE NOT NULL", h2Database);
assertThat(DatabaseFixture.query("SELECT COUNT(*) FROM information_schema.COLUMNS WHERE COLUMN_NAME='ARTIFACTSDELETED' AND TABLE_NAME='STAGES' AND TABLE_SCHEMA='PUBLIC'", h2Database),
is(new Object[][]{{1L}}));
try {
h2Database.upgrade();
}catch (Exception e) {
fail("should not throw up");
}
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void testMigration_1501001_should_rename_pipelineselections_unselected_pipelines_to_selections() throws Exception {
dbFixture.copyDeltas();
dbFixture.copyH2Db("with-usernames-in-different-cases.zip");
h2Database = new H2Database(dbFixture.env());
h2Database.startDatabase();
h2Database.upgrade();
doesNotHaveColumn("PIPELINESELECTIONS", "UNSELECTEDPIPELINES");
hasColumn("PIPELINESELECTIONS", "SELECTIONS");
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void testMigration_1501001_add_column_isblacklist_to_pipelineselections() throws Exception {
dbFixture.copyDeltas();
dbFixture.copyH2Db("with-usernames-in-different-cases.zip");
h2Database = new H2Database(dbFixture.env());
h2Database.startDatabase();
doesNotHaveColumn("PIPELINESELECTIONS", "ISBLACKLIST");
h2Database.upgrade();
hasColumn("PIPELINESELECTIONS", "ISBLACKLIST");
columnHasType("PIPELINESELECTIONS", "ISBLACKLIST", "BOOLEAN");
columnHasDefault("PIPELINESELECTIONS", "ISBLACKLIST", "TRUE");
}
@Test
@RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2})
public void testMigration_1501002_should_add_comment_column_to_pipelines() throws Exception {
dbFixture.copyDeltas();
dbFixture.copyH2Db("with-usernames-in-different-cases.zip");
h2Database = new H2Database(dbFixture.env());
h2Database.startDatabase();
doesNotHaveColumn("PIPELINES", "COMMENT");
h2Database.upgrade();
hasColumn("PIPELINES", "COMMENT");
}
private void columnHasDefault(String table, String column, String defaultValue) {
assertThat(DatabaseFixture.query(String.format("SELECT COLUMN_DEFAULT FROM information_schema.COLUMNS WHERE COLUMN_NAME='%s' AND TABLE_NAME='%s' AND TABLE_SCHEMA='PUBLIC'", column, table), h2Database),
is(new Object[][]{{defaultValue}}));
}
private void columnHasType(String table, String column, String type) {
assertThat(DatabaseFixture.query(String.format("SELECT TYPE_NAME FROM information_schema.COLUMNS WHERE COLUMN_NAME='%s' AND TABLE_NAME='%s' AND TABLE_SCHEMA='PUBLIC'", column, table), h2Database),
is(new Object[][]{{type}}));
}
private void hasColumn(String table, String column) {
assertThat(DatabaseFixture.query(String.format("SELECT COUNT(*) FROM information_schema.COLUMNS WHERE COLUMN_NAME='%s' AND TABLE_NAME='%s' AND TABLE_SCHEMA='PUBLIC'", column, table), h2Database),
is(new Object[][]{{1L}}));
}
private void doesNotHaveColumn(String table, String column) {
assertThat(DatabaseFixture.query(String.format("SELECT COUNT(*) FROM information_schema.COLUMNS WHERE COLUMN_NAME='%s' AND TABLE_NAME='%s' AND TABLE_SCHEMA='PUBLIC'", column, table), h2Database),
is(new Object[][]{{0L}}));
}
private void matchUserAttributesForUsername(final String username, final String email, final boolean enabled, final String actualName) {
assertThat(DatabaseFixture.query("select name, email, enabled from users where name = '" + username + "'", h2Database), is(new Object[][]{{actualName, email, enabled}}));
}
private void assertPmrFromIdAndActualFromId(final String pipelineName, final int counter, final long fromId, final long actualFromId) {
assertThat(DatabaseFixture.query(pmrFor(pipelineName, counter), h2Database), is(new Object[][]{{fromId, actualFromId}}));
}
private String pmrFor(final String pipelineName, final int counter) {
return "SELECT fromRevisionId, actualFromRevisionId "
+ " FROM pipelineMaterialRevisions pmr "
+ " INNER JOIN pipelines p ON p.id = pmr.pipelineId "
+ " WHERE p.name = '" + pipelineName + "' AND p.counter = " + counter;
}
}