diff options
author | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-07-20 14:50:42 +0200 |
---|---|---|
committer | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-07-21 09:42:28 +0200 |
commit | 8b1835860ef2b530c18a57c9385f6c3e9f15c850 (patch) | |
tree | 0b0a6809fed7cf6af22ae39fc1fce772b2031383 | |
parent | 07b4c8e17dab7f7a11a7bc4bde962411a6bd4f79 (diff) | |
download | sonarqube-8b1835860ef2b530c18a57c9385f6c3e9f15c850.tar.gz sonarqube-8b1835860ef2b530c18a57c9385f6c3e9f15c850.zip |
SONAR-6652 ws system/db_migration_status status of database migration
7 files changed, 497 insertions, 137 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 26c3a75f8a9..92cdbaaa37d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -185,6 +185,7 @@ import org.sonar.server.platform.monitoring.JvmPropertiesMonitor; import org.sonar.server.platform.monitoring.PluginsMonitor; import org.sonar.server.platform.monitoring.SonarQubeMonitor; import org.sonar.server.platform.monitoring.SystemMonitor; +import org.sonar.server.platform.ws.DbMigrationStatusAction; import org.sonar.server.platform.ws.InfoAction; import org.sonar.server.platform.ws.L10nWs; import org.sonar.server.platform.ws.MigrateDbAction; @@ -694,7 +695,6 @@ public class PlatformLevel4 extends PlatformLevel { RestartAction.class, InfoAction.class, UpgradesAction.class, - MigrateDbAction.class, StatusAction.class, SystemWs.class, SystemMonitor.class, @@ -703,6 +703,8 @@ public class PlatformLevel4 extends PlatformLevel { PluginsMonitor.class, JvmPropertiesMonitor.class, DatabaseMonitor.class, + MigrateDbAction.class, + DbMigrationStatusAction.class, // Plugins WS PluginWSCommons.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelSafeMode.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelSafeMode.java index c1445a403b6..190436d17f5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelSafeMode.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevelSafeMode.java @@ -19,6 +19,7 @@ */ package org.sonar.server.platform.platformlevel; +import org.sonar.server.platform.ws.DbMigrationStatusAction; import org.sonar.server.platform.ws.MigrateDbAction; import org.sonar.server.platform.ws.StatusAction; import org.sonar.server.platform.ws.SystemWs; @@ -36,6 +37,7 @@ public class PlatformLevelSafeMode extends PlatformLevel { // Server WS StatusAction.class, MigrateDbAction.class, + DbMigrationStatusAction.class, SystemWs.class, // Listing WS diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/DbMigrationJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/DbMigrationJsonWriter.java new file mode 100644 index 00000000000..567d06800f5 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/DbMigrationJsonWriter.java @@ -0,0 +1,132 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.platform.ws; + +import org.sonar.api.utils.text.JsonWriter; +import org.sonar.db.version.DatabaseMigration; + +import static org.sonar.db.version.DatabaseMigration.Status.NONE; +import static org.sonar.db.version.DatabaseMigration.Status.RUNNING; + +public class DbMigrationJsonWriter { + static final String FIELD_STATE = "state"; + static final String FIELD_MESSAGE = "message"; + static final String FIELD_STARTED_AT = "startedAt"; + + static final String STATUS_NO_MIGRATION = "NO_MIGRATION"; + static final String STATUS_NOT_SUPPORTED = "NOT_SUPPORTED"; + static final String STATUS_MIGRATION_RUNNING = "MIGRATION_RUNNING"; + static final String STATUS_MIGRATION_FAILED = "MIGRATION_FAILED"; + static final String STATUS_MIGRATION_SUCCEEDED = "MIGRATION_SUCCEEDED"; + + static final String UNSUPPORTED_DATABASE_MIGRATION_STATUS = "Unsupported DatabaseMigration status"; + static final String MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE = "Upgrade is not supported on embedded database."; + static final String MESSAGE_MIGRATION_NEEDED = "Database migration is required. DB migration can be started using WS /api/system/migrate_db."; + static final String MESSAGE_STATUS_NONE = "Database is up-to-date, no migration needed."; + static final String MESSAGE_STATUS_RUNNING = "Database migration is running."; + static final String MESSAGE_STATUS_SUCCEEDED = "Migration succeeded."; + static final String MESSAGE_STATUS_FAILED = "Migration failed: %s.<br/> Please check logs."; + + private DbMigrationJsonWriter() { + // static methods only + } + + static void write(JsonWriter json, DatabaseMigration databaseMigration) { + json.beginObject() + .prop(FIELD_STATE, statusToJson(databaseMigration.status())) + .prop(FIELD_MESSAGE, buildMessage(databaseMigration)) + .propDateTime(FIELD_STARTED_AT, databaseMigration.startedAt()) + .endObject(); + } + + static void writeNotSupportedResponse(JsonWriter json) { + json.beginObject() + .prop(FIELD_STATE, STATUS_NOT_SUPPORTED) + .prop(FIELD_MESSAGE, MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE) + .endObject(); + } + + static void writeJustStartedResponse(JsonWriter json, DatabaseMigration databaseMigration) { + json.beginObject() + .prop(FIELD_STATE, statusToJson(RUNNING)) + .prop(FIELD_MESSAGE, MESSAGE_STATUS_RUNNING) + .propDateTime(FIELD_STARTED_AT, databaseMigration.startedAt()) + .endObject(); + } + + static void writeMigrationNeededResponse(JsonWriter json) { + json.beginObject() + .prop(FIELD_STATE, statusToJson(NONE)) + .prop(FIELD_MESSAGE, MESSAGE_MIGRATION_NEEDED) + .endObject(); + } + + private static String statusToJson(DatabaseMigration.Status status) { + switch (status) { + case NONE: + return STATUS_NO_MIGRATION; + case RUNNING: + return STATUS_MIGRATION_RUNNING; + case FAILED: + return STATUS_MIGRATION_FAILED; + case SUCCEEDED: + return STATUS_MIGRATION_SUCCEEDED; + default: + throw new IllegalArgumentException( + "Unsupported DatabaseMigration.Status " + status + " can not be converted to JSON value"); + } + } + + private static String buildMessage(DatabaseMigration databaseMigration) { + switch (databaseMigration.status()) { + case NONE: + return MESSAGE_STATUS_NONE; + case RUNNING: + return MESSAGE_STATUS_RUNNING; + case SUCCEEDED: + return MESSAGE_STATUS_SUCCEEDED; + case FAILED: + return String.format(MESSAGE_STATUS_FAILED, failureMessage(databaseMigration)); + default: + return UNSUPPORTED_DATABASE_MIGRATION_STATUS; + } + } + + private static String failureMessage(DatabaseMigration databaseMigration) { + Throwable failureError = databaseMigration.failureError(); + if (failureError == null) { + return "No failure error"; + } + return failureError.getMessage(); + } + + static String statusDescription() { + return + "State values are:" + + "<ul>" + + "<li>NO_MIGRATION: DB is up to date with current version of SonarQube.</li>" + + "<li>NOT_SUPPORTED: Migration is not supported on embedded databases.</li>" + + "<li>MIGRATION_RUNNING: DB migration is under go.</li>" + + "<li>MIGRATION_SUCCEEDED: DB migration has run and has been successful.</li>" + + "<li>MIGRATION_FAILED: DB migration has run and failed. SonarQube must be restarted in order to retry a " + + "DB migration (optionally after DB has been restored from backup).</li>"; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/DbMigrationStatusAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/DbMigrationStatusAction.java new file mode 100644 index 00000000000..0710c1ed472 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/DbMigrationStatusAction.java @@ -0,0 +1,92 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.platform.ws; + +import com.google.common.io.Resources; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.text.JsonWriter; +import org.sonar.db.Database; +import org.sonar.db.version.DatabaseMigration; +import org.sonar.db.version.DatabaseVersion; + +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.UNSUPPORTED_DATABASE_MIGRATION_STATUS; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.statusDescription; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.write; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.writeMigrationNeededResponse; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.writeNotSupportedResponse; + +/** + * Implementation of the {@code db_migration_status} action for the System WebService. + */ +public class DbMigrationStatusAction implements SystemWsAction { + + private final DatabaseVersion databaseVersion; + private final DatabaseMigration databaseMigration; + private final Database database; + + public DbMigrationStatusAction(DatabaseVersion databaseVersion, Database database, DatabaseMigration databaseMigration) { + this.databaseVersion = databaseVersion; + this.database = database; + this.databaseMigration = databaseMigration; + } + + @Override + public void define(WebService.NewController controller) { + controller.createAction("db_migration_status") + .setDescription("Display the database migration status of SonarQube." + + "<br/>" + + statusDescription()) + .setSince("5.2") + .setHandler(this) + .setResponseExample(Resources.getResource(this.getClass(), "example-migrate_db.json")); + } + + @Override + public void handle(Request request, Response response) throws Exception { + Integer currentVersion = databaseVersion.getVersion(); + + JsonWriter json = response.newJsonWriter(); + try { + if (currentVersion >= DatabaseVersion.LAST_VERSION) { + write(json, databaseMigration); + } else if (!database.getDialect().supportsMigration()) { + writeNotSupportedResponse(json); + } else { + switch (databaseMigration.status()) { + case RUNNING: + case FAILED: + case SUCCEEDED: + write(json, databaseMigration); + break; + case NONE: + writeMigrationNeededResponse(json); + break; + default: + throw new IllegalArgumentException(UNSUPPORTED_DATABASE_MIGRATION_STATUS); + } + } + } finally { + json.close(); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/MigrateDbAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/MigrateDbAction.java index 206d12a972a..80e82906290 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/MigrateDbAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/MigrateDbAction.java @@ -28,29 +28,17 @@ import org.sonar.db.Database; import org.sonar.db.version.DatabaseMigration; import org.sonar.db.version.DatabaseVersion; -import static org.sonar.db.version.DatabaseMigration.Status.RUNNING; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.UNSUPPORTED_DATABASE_MIGRATION_STATUS; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.statusDescription; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.write; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.writeJustStartedResponse; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.writeNotSupportedResponse; /** * Implementation of the {@code migrate_db} action for the System WebService. */ public class MigrateDbAction implements SystemWsAction { - private static final String UNSUPPORTED_DATABASE_MIGRATION_STATUS = "Unsupported DatabaseMigration status"; - private static final String MESSAGE_STATUS_NONE = "Database is up-to-date, no migration needed."; - private static final String MESSAGE_STATUS_RUNNING = "Database migration is running."; - private static final String MESSAGE_STATUS_SUCCEEDED = "Migration succeeded."; - private static final String MESSAGE_STATUS_FAILED = "Migration failed: %s.<br/> Please check logs."; - - private static final String STATUS_NO_MIGRATION = "NO_MIGRATION"; - private static final String STATUS_NOT_SUPPORTED = "NOT_SUPPORTED"; - private static final String STATUS_MIGRATION_RUNNING = "MIGRATION_RUNNING"; - private static final String STATUS_MIGRATION_FAILED = "MIGRATION_FAILED"; - private static final String STATUS_MIGRATION_SUCCEEDED = "MIGRATION_SUCCEEDED"; - - private static final String PROPERTY_STATE = "state"; - private static final String PROPERTY_MESSAGE = "message"; - private static final String PROPERTY_STARTED_AT = "startedAt"; - private final DatabaseVersion databaseVersion; private final DatabaseMigration databaseMigration; private final Database database; @@ -69,15 +57,7 @@ public class MigrateDbAction implements SystemWsAction { "Sending a POST request to this URL starts the DB migration. " + "It is strongly advised to <strong>make a database backup</strong> before invoking this WS." + "<br/>" + - "State values are:" + - "<ul>" + - "<li>NO_MIGRATION: DB is up to date with current version of SonarQube.</li>" + - "<li>NOT_SUPPORTED: Migration is not supported on embedded databases.</li>" + - "<li>MIGRATION_RUNNING: DB migration is under go.</li>" + - "<li>MIGRATION_SUCCEEDED: DB migration has run and has been successful.</li>" + - "<li>MIGRATION_FAILED: DB migration has run and failed. SonarQube must be restarted in order to retry a " + - "DB migration (optionally after DB has been restored from backup).</li>" + - "</ul>") + statusDescription()) .setSince("5.2") .setPost(true) .setHandler(this) @@ -91,93 +71,29 @@ public class MigrateDbAction implements SystemWsAction { throw new IllegalStateException("Version can not be retrieved from Database. Database is either blank or corrupted"); } - if (currentVersion >= DatabaseVersion.LAST_VERSION) { - writeResponse(response, databaseMigration); - } else if (!database.getDialect().supportsMigration()) { - writeNotSupportedResponse(response); - } else { - switch (databaseMigration.status()) { - case RUNNING: - case FAILED: - case SUCCEEDED: - writeResponse(response, databaseMigration); - break; - case NONE: - databaseMigration.startIt(); - writeNoneResponse(response, databaseMigration); - break; - default: - throw new IllegalArgumentException(UNSUPPORTED_DATABASE_MIGRATION_STATUS); + JsonWriter json = response.newJsonWriter(); + try { + if (currentVersion >= DatabaseVersion.LAST_VERSION) { + write(json, databaseMigration); + } else if (!database.getDialect().supportsMigration()) { + writeNotSupportedResponse(json); + } else { + switch (databaseMigration.status()) { + case RUNNING: + case FAILED: + case SUCCEEDED: + write(json, databaseMigration); + break; + case NONE: + databaseMigration.startIt(); + writeJustStartedResponse(json, databaseMigration); + break; + default: + throw new IllegalArgumentException(UNSUPPORTED_DATABASE_MIGRATION_STATUS); + } } + } finally { + json.close(); } } - - private static void writeNotSupportedResponse(Response response) { - JsonWriter jsonWriter = response.newJsonWriter(); - jsonWriter.beginObject() - .prop(PROPERTY_STATE, STATUS_NOT_SUPPORTED) - .prop(PROPERTY_MESSAGE, "Upgrade is not supported on embedded database.") - .endObject(); - jsonWriter.close(); - } - - private void writeNoneResponse(Response response, DatabaseMigration databaseMigration) { - JsonWriter jsonWriter = response.newJsonWriter(); - jsonWriter.beginObject() - .prop(PROPERTY_STATE, statusToJson(RUNNING)) - .prop(PROPERTY_MESSAGE, MESSAGE_STATUS_RUNNING) - .propDateTime(PROPERTY_STARTED_AT, databaseMigration.startedAt()) - .endObject(); - jsonWriter.close(); - } - - private void writeResponse(Response response, DatabaseMigration databaseMigration) { - JsonWriter jsonWriter = response.newJsonWriter(); - jsonWriter.beginObject() - .prop(PROPERTY_STATE, statusToJson(databaseMigration.status())) - .prop(PROPERTY_MESSAGE, buildMessage(databaseMigration)) - .propDateTime(PROPERTY_STARTED_AT, databaseMigration.startedAt()) - .endObject(); - jsonWriter.close(); - } - - private String statusToJson(DatabaseMigration.Status status) { - switch (status) { - case NONE: - return STATUS_NO_MIGRATION; - case RUNNING: - return STATUS_MIGRATION_RUNNING; - case FAILED: - return STATUS_MIGRATION_FAILED; - case SUCCEEDED: - return STATUS_MIGRATION_SUCCEEDED; - default: - throw new IllegalArgumentException( - "Unsupported DatabaseMigration.Status " + status + " can not be converted to JSON value"); - } - } - - private static String buildMessage(DatabaseMigration databaseMigration) { - switch (databaseMigration.status()) { - case NONE: - return MESSAGE_STATUS_NONE; - case RUNNING: - return MESSAGE_STATUS_RUNNING; - case SUCCEEDED: - return MESSAGE_STATUS_SUCCEEDED; - case FAILED: - return String.format(MESSAGE_STATUS_FAILED, failureMessage(databaseMigration)); - default: - return UNSUPPORTED_DATABASE_MIGRATION_STATUS; - } - } - - private static String failureMessage(DatabaseMigration databaseMigration) { - Throwable failureError = databaseMigration.failureError(); - if (failureError == null) { - return "No failure error"; - } - return failureError.getMessage(); - } - } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/DbMigrationStatusActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/DbMigrationStatusActionTest.java new file mode 100644 index 00000000000..81153c39368 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/DbMigrationStatusActionTest.java @@ -0,0 +1,214 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.platform.ws; + +import com.google.common.collect.ImmutableList; +import java.util.Arrays; +import java.util.Date; +import javax.annotation.Nullable; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.server.ws.Request; +import org.sonar.api.utils.DateUtils; +import org.sonar.db.Database; +import org.sonar.db.dialect.Dialect; +import org.sonar.db.version.DatabaseMigration; +import org.sonar.db.version.DatabaseMigration.Status; +import org.sonar.db.version.DatabaseVersion; +import org.sonar.server.ws.WsTester; + +import static com.google.common.base.Predicates.in; +import static com.google.common.base.Predicates.not; +import static com.google.common.collect.Iterables.filter; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.db.version.DatabaseMigration.Status.FAILED; +import static org.sonar.db.version.DatabaseMigration.Status.NONE; +import static org.sonar.db.version.DatabaseMigration.Status.RUNNING; +import static org.sonar.db.version.DatabaseMigration.Status.SUCCEEDED; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.MESSAGE_MIGRATION_NEEDED; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.MESSAGE_STATUS_NONE; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.MESSAGE_STATUS_RUNNING; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.MESSAGE_STATUS_SUCCEEDED; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.STATUS_MIGRATION_FAILED; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.STATUS_MIGRATION_RUNNING; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.STATUS_MIGRATION_SUCCEEDED; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.STATUS_NOT_SUPPORTED; +import static org.sonar.server.platform.ws.DbMigrationJsonWriter.STATUS_NO_MIGRATION; +import static org.sonar.test.JsonAssert.assertJson; + +public class DbMigrationStatusActionTest { + + private static final Date SOME_DATE = new Date(); + private static final String SOME_THROWABLE_MSG = "blablabla pop !"; + private static final String DEFAULT_ERROR_MSG = "No failure error"; + private static final int CURRENT_VERSION = DatabaseVersion.LAST_VERSION; + private static final int OLD_VERSION = CURRENT_VERSION - 1; + private static final int NEWER_VERSION = CURRENT_VERSION + 1; + + DatabaseVersion databaseVersion = mock(DatabaseVersion.class); + Database database = mock(Database.class); + Dialect dialect = mock(Dialect.class); + DatabaseMigration databaseMigration = mock(DatabaseMigration.class); + DbMigrationStatusAction underTest = new DbMigrationStatusAction(databaseVersion, database, databaseMigration); + + Request request = mock(Request.class); + WsTester.TestResponse response = new WsTester.TestResponse(); + + @Before + public void wireMocksTogether() { + when(database.getDialect()).thenReturn(dialect); + } + + @Test + public void verify_example() throws Exception { + when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); + when(dialect.supportsMigration()).thenReturn(true); + when(databaseMigration.status()).thenReturn(RUNNING); + when(databaseMigration.startedAt()).thenReturn(DateUtils.parseDateTime("2015-02-23T18:54:23+0100")); + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(getClass().getResource("example-migrate_db.json")); + } + + @Test + public void msg_is_operational_and_state_from_databasemigration_when_databaseversion_is_equal_to_currentversion() throws Exception { + when(databaseVersion.getVersion()).thenReturn(CURRENT_VERSION); + when(databaseMigration.status()).thenReturn(NONE); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NO_MIGRATION, MESSAGE_STATUS_NONE)); + } + + // this test will raise a IllegalArgumentException when an unsupported value is added to the Status enum + @Test + public void defensive_test_all_values_of_Status_must_be_supported() throws Exception { + for (Status status : filter(Arrays.asList(Status.values()), not(in(ImmutableList.of(NONE, RUNNING, FAILED, SUCCEEDED))))) { + when(databaseVersion.getVersion()).thenReturn(CURRENT_VERSION); + when(databaseMigration.status()).thenReturn(status); + + underTest.handle(request, response); + } + } + + @Test + public void state_from_databasemigration_when_databaseversion_greater_than_currentversion() throws Exception { + when(databaseVersion.getVersion()).thenReturn(NEWER_VERSION); + when(databaseMigration.status()).thenReturn(NONE); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NO_MIGRATION, MESSAGE_STATUS_NONE)); + } + + @Test + public void state_is_NONE_with_specific_msg_when_version_is_less_than_current_version_and_dialect_does_not_support_migration() throws Exception { + when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); + when(dialect.supportsMigration()).thenReturn(false); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NOT_SUPPORTED, MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE)); + } + + @Test + public void state_from_databasemigration_when_dbmigration_status_is_RUNNING() throws Exception { + when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); + when(dialect.supportsMigration()).thenReturn(true); + when(databaseMigration.status()).thenReturn(RUNNING); + when(databaseMigration.startedAt()).thenReturn(SOME_DATE); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_RUNNING, MESSAGE_STATUS_RUNNING, SOME_DATE)); + } + + @Test + public void state_from_databasemigration_and_msg_includes_error_when_dbmigration_status_is_FAILED() throws Exception { + when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); + when(dialect.supportsMigration()).thenReturn(true); + when(databaseMigration.status()).thenReturn(FAILED); + when(databaseMigration.startedAt()).thenReturn(SOME_DATE); + when(databaseMigration.failureError()).thenReturn(new UnsupportedOperationException(SOME_THROWABLE_MSG)); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_FAILED, failedMsg(SOME_THROWABLE_MSG), SOME_DATE)); + } + + @Test + public void state_from_databasemigration_and_msg_has_default_msg_when_dbmigration_status_is_FAILED() throws Exception { + when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); + when(dialect.supportsMigration()).thenReturn(true); + when(databaseMigration.status()).thenReturn(FAILED); + when(databaseMigration.startedAt()).thenReturn(SOME_DATE); + when(databaseMigration.failureError()).thenReturn(null); // no failure throwable caught + + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_FAILED, failedMsg(DEFAULT_ERROR_MSG), SOME_DATE)); + } + + @Test + public void state_from_databasemigration_and_msg_has_default_msg_when_dbmigration_status_is_SUCCEEDED() throws Exception { + when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); + when(dialect.supportsMigration()).thenReturn(true); + when(databaseMigration.status()).thenReturn(SUCCEEDED); + when(databaseMigration.startedAt()).thenReturn(SOME_DATE); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_SUCCEEDED, MESSAGE_STATUS_SUCCEEDED, SOME_DATE)); + } + + @Test + public void start_migration_and_return_state_from_databasemigration_when_dbmigration_status_is_NONE() throws Exception { + when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); + when(dialect.supportsMigration()).thenReturn(true); + when(databaseMigration.status()).thenReturn(NONE); + when(databaseMigration.startedAt()).thenReturn(SOME_DATE); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NO_MIGRATION, MESSAGE_MIGRATION_NEEDED)); + } + + private static String failedMsg(@Nullable String t) { + return "Migration failed: " + t + ".<br/> Please check logs."; + } + + private static String expectedResponse(String status, String msg) { + return "{" + + "\"state\":\"" + status + "\"," + + "\"message\":\"" + msg + "\"" + + "}"; + } + + private static String expectedResponse(String status, String msg, Date date) { + return "{" + + "\"state\":\"" + status + "\"," + + "\"message\":\"" + msg + "\"," + + "\"startedAt\":\"" + DateUtils.formatDateTime(date) + "\"" + + "}"; + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/MigrateDbActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/MigrateDbActionTest.java index ecf87a714b9..3f022cb4428 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/MigrateDbActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/MigrateDbActionTest.java @@ -48,21 +48,23 @@ import static org.sonar.test.JsonAssert.assertJson; public class MigrateDbActionTest { - private static final String UPTODATE_MSG = "Database is up-to-date, no migration needed."; - private static final String MIG_NOT_SUPPORTED_MSG = "Upgrade is not supported on embedded database."; - private static final String RUNNING_MSG = "Database migration is running."; private static final Date SOME_DATE = new Date(); private static final String SOME_THROWABLE_MSG = "blablabla pop !"; private static final String DEFAULT_ERROR_MSG = "No failure error"; - private static final String MIG_SUCCESS_MSG = "Migration succeeded."; private static final int CURRENT_VERSION = DatabaseVersion.LAST_VERSION; private static final int OLD_VERSION = CURRENT_VERSION - 1; private static final int NEWER_VERSION = CURRENT_VERSION + 1; - private static final String STATUS_NONE = "NO_MIGRATION"; - private static final String STATUS_NOT_SUPPORTED = "NOT_SUPPORTED"; - private static final String STATUS_RUNNING = "MIGRATION_RUNNING"; - private static final String STATUS_SUCCEEDED = "MIGRATION_SUCCEEDED"; - private static final String STATUS_FAILED = "MIGRATION_FAILED"; + + static final String STATUS_NO_MIGRATION = "NO_MIGRATION"; + static final String STATUS_NOT_SUPPORTED = "NOT_SUPPORTED"; + static final String STATUS_MIGRATION_RUNNING = "MIGRATION_RUNNING"; + static final String STATUS_MIGRATION_FAILED = "MIGRATION_FAILED"; + static final String STATUS_MIGRATION_SUCCEEDED = "MIGRATION_SUCCEEDED"; + + static final String MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE = "Upgrade is not supported on embedded database."; + static final String MESSAGE_STATUS_NONE = "Database is up-to-date, no migration needed."; + static final String MESSAGE_STATUS_RUNNING = "Database migration is running."; + static final String MESSAGE_STATUS_SUCCEEDED = "Migration succeeded."; DatabaseVersion databaseVersion = mock(DatabaseVersion.class); Database database = mock(Database.class); @@ -97,13 +99,13 @@ public class MigrateDbActionTest { } @Test - public void msg_is_operational_and_state_from_databasemigration_when_databaseversion_is_equal_to_currentversion() throws Exception { + public void msg_is_operational_and_state_from_database_migration_when_database_version_is_equal_to_current_version() throws Exception { when(databaseVersion.getVersion()).thenReturn(CURRENT_VERSION); when(databaseMigration.status()).thenReturn(NONE); underTest.handle(request, response); - assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NONE, UPTODATE_MSG)); + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NO_MIGRATION, MESSAGE_STATUS_NONE)); } // this test will raise a IllegalArgumentException when an unsupported value is added to the Status enum @@ -118,13 +120,13 @@ public class MigrateDbActionTest { } @Test - public void state_from_databasemigration_when_databaseversion_greater_than_currentversion() throws Exception { + public void state_from_database_migration_when_databaseversion_greater_than_currentversion() throws Exception { when(databaseVersion.getVersion()).thenReturn(NEWER_VERSION); when(databaseMigration.status()).thenReturn(NONE); underTest.handle(request, response); - assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NONE, UPTODATE_MSG)); + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NO_MIGRATION, MESSAGE_STATUS_NONE)); } @Test @@ -134,11 +136,11 @@ public class MigrateDbActionTest { underTest.handle(request, response); - assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NOT_SUPPORTED, MIG_NOT_SUPPORTED_MSG)); + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_NOT_SUPPORTED, MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE)); } @Test - public void state_from_databasemigration_when_dbmigration_status_is_RUNNING() throws Exception { + public void state_from_database_migration_when_dbmigration_status_is_RUNNING() throws Exception { when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); when(dialect.supportsMigration()).thenReturn(true); when(databaseMigration.status()).thenReturn(RUNNING); @@ -146,11 +148,11 @@ public class MigrateDbActionTest { underTest.handle(request, response); - assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_RUNNING, RUNNING_MSG, SOME_DATE)); + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_RUNNING, MESSAGE_STATUS_RUNNING, SOME_DATE)); } @Test - public void state_from_databasemigration_and_msg_includes_error_when_dbmigration_status_is_FAILED() throws Exception { + public void state_from_database_migration_and_msg_includes_error_when_dbmigration_status_is_FAILED() throws Exception { when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); when(dialect.supportsMigration()).thenReturn(true); when(databaseMigration.status()).thenReturn(FAILED); @@ -159,11 +161,11 @@ public class MigrateDbActionTest { underTest.handle(request, response); - assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_FAILED, failedMsg(SOME_THROWABLE_MSG), SOME_DATE)); + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_FAILED, failedMsg(SOME_THROWABLE_MSG), SOME_DATE)); } @Test - public void state_from_databasemigration_and_msg_has_default_msg_when_dbmigration_status_is_FAILED() throws Exception { + public void state_from_database_migration_and_msg_has_default_msg_when_dbmigration_status_is_FAILED() throws Exception { when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); when(dialect.supportsMigration()).thenReturn(true); when(databaseMigration.status()).thenReturn(FAILED); @@ -172,11 +174,11 @@ public class MigrateDbActionTest { underTest.handle(request, response); - assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_FAILED, failedMsg(DEFAULT_ERROR_MSG), SOME_DATE)); + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_FAILED, failedMsg(DEFAULT_ERROR_MSG), SOME_DATE)); } @Test - public void state_from_databasemigration_and_msg_has_default_msg_when_dbmigration_status_is_SUCCEEDED() throws Exception { + public void state_from_database_migration_and_msg_has_default_msg_when_dbmigration_status_is_SUCCEEDED() throws Exception { when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); when(dialect.supportsMigration()).thenReturn(true); when(databaseMigration.status()).thenReturn(SUCCEEDED); @@ -184,11 +186,11 @@ public class MigrateDbActionTest { underTest.handle(request, response); - assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_SUCCEEDED, MIG_SUCCESS_MSG, SOME_DATE)); + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_SUCCEEDED, MESSAGE_STATUS_SUCCEEDED, SOME_DATE)); } @Test - public void start_migration_and_return_state_from_databasemigration_when_dbmigration_status_is_NONE() throws Exception { + public void start_migration_and_return_state_from_database_migration_when_dbmigration_status_is_NONE() throws Exception { when(databaseVersion.getVersion()).thenReturn(OLD_VERSION); when(dialect.supportsMigration()).thenReturn(true); when(databaseMigration.status()).thenReturn(NONE); @@ -197,7 +199,7 @@ public class MigrateDbActionTest { underTest.handle(request, response); verify(databaseMigration).startIt(); - assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_RUNNING, RUNNING_MSG, SOME_DATE)); + assertJson(response.outputAsString()).isSimilarTo(expectedResponse(STATUS_MIGRATION_RUNNING, MESSAGE_STATUS_RUNNING, SOME_DATE)); } private static String failedMsg(@Nullable String t) { |