public class MassUpdater {
private static final Logger LOGGER = LoggerFactory.getLogger(MassUpdater.class);
- private static final String FAILURE_MESSAGE = "Fail to migrate data";
private static final int GROUP_SIZE = 1000;
private final Database db;
}
} catch (SQLException e) {
- LOGGER.error(FAILURE_MESSAGE, e);
SqlUtil.log(LOGGER, e);
- throw MessageException.of(FAILURE_MESSAGE);
-
+ throw processError(e);
} catch (Exception e) {
- LOGGER.error(FAILURE_MESSAGE, e);
- throw MessageException.of(FAILURE_MESSAGE);
-
+ throw processError(e);
} finally {
DbUtils.closeQuietly(writeStatement);
DbUtils.closeQuietly(writeConnection);
}
}
+ private static MessageException processError(Exception e) {
+ String message = String.format("Fail to migrate data, error is : %s", e.getMessage());
+ LOGGER.error(message, e);
+ throw MessageException.of(message);
+ }
+
@VisibleForTesting
static String convertSelectSql(String selectSql, Database db){
String newSelectSql = selectSql;
package org.sonar.server.db.migrations;
+import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.utils.MessageException;
import org.sonar.core.persistence.Database;
+import org.sonar.core.persistence.TestDatabase;
import org.sonar.core.persistence.dialect.Dialect;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class MassUpdaterTest {
- @Mock
- Database db;
+ @ClassRule
+ public static TestDatabase db = new TestDatabase().schema(MassUpdaterTest.class, "schema.sql");
+
+ static class Row {
+ private Long id;
+ }
+
+ @Test
+ public void execute() throws Exception {
+ db.prepareDbUnit(getClass(), "migrate_data.xml");
+
+ new MassUpdater(db.database()).execute(
+ new MassUpdater.InputLoader<Row>() {
+ @Override
+ public String selectSql() {
+ return "SELECT i.id FROM issues i";
+ }
+
+ @Override
+ public Row load(ResultSet rs) throws SQLException {
+ Row row = new Row();
+ row.id = SqlUtil.getLong(rs, 1);
+ return row;
+ }
+ },
+ new MassUpdater.InputConverter<Row>() {
+ @Override
+ public String updateSql() {
+ return "UPDATE issues SET severity=? WHERE id=?";
+ }
+
+ @Override
+ public boolean convert(Row row, PreparedStatement updateStatement) throws SQLException {
+ updateStatement.setString(1, "MAJOR");
+ updateStatement.setLong(2, row.id);
+ return true;
+ }
+ }
+ );
+
+ db.assertDbUnit(getClass(), "migrate_data_result.xml", "issues");
+ }
+
+ @Test
+ public void fail_on_bad_sql_request() throws Exception {
+ db.prepareDbUnit(getClass(), "migrate_data.xml");
+
+ try {
+ new MassUpdater(db.database()).execute(
+ new MassUpdater.InputLoader<Row>() {
+ @Override
+ public String selectSql() {
+ return "<INVALID QUERY>";
+ }
+
+ @Override
+ public Row load(ResultSet rs) throws SQLException {
+ return new Row();
+ }
+ },
+ new MassUpdater.InputConverter<Row>() {
+ @Override
+ public String updateSql() {
+ return "<INVALID QUERY>";
+ }
+
+ @Override
+ public boolean convert(Row row, PreparedStatement updateStatement) throws SQLException {
+ return true;
+ }
+ }
+ );
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(MessageException.class);
+ }
+ }
+
+ @Test
+ public void fail_on_unknown_error() throws Exception {
+ db.prepareDbUnit(getClass(), "migrate_data.xml");
+
+ try {
+ new MassUpdater(db.database()).execute(
+ new MassUpdater.InputLoader<Row>() {
+ @Override
+ public String selectSql() {
+ return "SELECT i.id FROM issues i";
+ }
+
+ @Override
+ public Row load(ResultSet rs) throws SQLException {
+ Row row = new Row();
+ row.id = SqlUtil.getLong(rs, 1);
+ return row;
+ }
+ },
+ new MassUpdater.InputConverter<Row>() {
+ @Override
+ public String updateSql() {
+ throw new RuntimeException("Unknown error");
+ }
+
+ @Override
+ public boolean convert(Row row, PreparedStatement updateStatement) throws SQLException {
+ return true;
+ }
+ }
+ );
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(MessageException.class);
+ }
+ }
@Test
public void convert_select_sql() throws Exception {
+ Database db = mock(Database.class);
+
Dialect dialect = mock(Dialect.class);
when(dialect.getTrueSqlValue()).thenReturn("true");
when(dialect.getFalseSqlValue()).thenReturn("false");
--- /dev/null
+-- 4.3
+
+CREATE TABLE "ISSUES" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "KEE" VARCHAR(50) UNIQUE NOT NULL,
+ "COMPONENT_ID" INTEGER NOT NULL,
+ "ROOT_COMPONENT_ID" INTEGER,
+ "RULE_ID" INTEGER,
+ "SEVERITY" VARCHAR(10),
+ "MANUAL_SEVERITY" BOOLEAN NOT NULL,
+ "MESSAGE" VARCHAR(4000),
+ "LINE" INTEGER,
+ "EFFORT_TO_FIX" DOUBLE,
+ "STATUS" VARCHAR(20),
+ "RESOLUTION" VARCHAR(20),
+ "CHECKSUM" VARCHAR(1000),
+ "REPORTER" VARCHAR(40),
+ "ASSIGNEE" VARCHAR(40),
+ "AUTHOR_LOGIN" VARCHAR(100),
+ "ACTION_PLAN_KEY" VARCHAR(50) NULL,
+ "ISSUE_ATTRIBUTES" VARCHAR(4000),
+ "ISSUE_CREATION_DATE" TIMESTAMP,
+ "ISSUE_CLOSE_DATE" TIMESTAMP,
+ "ISSUE_UPDATE_DATE" TIMESTAMP,
+ "CREATED_AT" TIMESTAMP,
+ "UPDATED_AT" TIMESTAMP,
+ "TECHNICAL_DEBT" INTEGER
+);