Browse Source

SONAR-22141 added new endpoint /api/v2/system/migrations-status

pull/3361/head
lukasz-jarocki-sonarsource 1 month ago
parent
commit
80942bfb97

+ 27
- 1
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/DatabaseMigrationState.java View File

@@ -24,8 +24,34 @@ import javax.annotation.CheckForNull;

public interface DatabaseMigrationState {

String UNSUPPORTED_DATABASE_MIGRATION_STATUS = "Unsupported DatabaseMigration status";
String NO_CONNECTION_TO_DB = "Cannot connect to Database.";

enum Status {
NONE, RUNNING, FAILED, SUCCEEDED
NONE("NO_MIGRATION", "Database is up-to-date, no migration needed."),
RUNNING("MIGRATION_RUNNING", "Database migration is running."),
FAILED("MIGRATION_FAILED", "Migration failed: %s.<br/> Please check logs."),
SUCCEEDED("MIGRATION_SUCCEEDED", "Migration succeeded."),
STATUS_NOT_SUPPORTED("NOT_SUPPORTED", "Upgrade is not supported on embedded database."),
MIGRATION_REQUIRED("MIGRATION_REQUIRED", "Database migration is required. DB migration can be started using WS /api/system/migrate_db.");

private final String stringRepresentation;
private final String message;

Status(String stringRepresentation, String message) {
this.stringRepresentation = stringRepresentation;
this.message = message;
}

public String getMessage() {
return message;
}

@Override
public String toString() {
return stringRepresentation;
}

}

/**

+ 1
- 0
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java View File

@@ -23,6 +23,7 @@ public class WebApiEndpoints {
private static final String SYSTEM_ENDPOINTS = "/system";
public static final String LIVENESS_ENDPOINT = SYSTEM_ENDPOINTS + "/liveness";
public static final String HEALTH_ENDPOINT = SYSTEM_ENDPOINTS + "/health";
public static final String DATABASE_MIGRATIONS_ENDPOINT = SYSTEM_ENDPOINTS + "/migrations-status";

public static final String USERS_MANAGEMENT_DOMAIN = "/users-management";
public static final String USER_ENDPOINT = USERS_MANAGEMENT_DOMAIN + "/users";

+ 86
- 0
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/system/controller/DatabaseMigrationsController.java View File

@@ -0,0 +1,86 @@
/*
* SonarQube
* Copyright (C) 2009-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.v2.api.system.controller;

import io.swagger.v3.oas.annotations.Operation;
import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;
import org.sonar.server.v2.common.DateString;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import static com.google.common.base.Preconditions.checkState;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.NO_CONNECTION_TO_DB;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.UNSUPPORTED_DATABASE_MIGRATION_STATUS;
import static org.sonar.server.v2.WebApiEndpoints.DATABASE_MIGRATIONS_ENDPOINT;

@RestController
@RequestMapping(DATABASE_MIGRATIONS_ENDPOINT)
public class DatabaseMigrationsController {

private final DatabaseVersion databaseVersion;
private final DatabaseMigrationState databaseMigrationState;
private final Database database;

public DatabaseMigrationsController(DatabaseVersion databaseVersion, DatabaseMigrationState databaseMigrationState, Database database) {
this.databaseVersion = databaseVersion;
this.databaseMigrationState = databaseMigrationState;
this.database = database;
}

@Operation(summary = "Gets the status of ongoing database migrations, if any", description = "Return the detailed status of ongoing database migrations" +
" including starting date. If no migration is ongoing or needed it is still possible to call this endpoint and receive appropriate information.")
@GetMapping
public DatabaseMigrationsResponse getStatus() {
Optional<Long> currentVersion = databaseVersion.getVersion();
checkState(currentVersion.isPresent(), NO_CONNECTION_TO_DB);
DatabaseVersion.Status status = databaseVersion.getStatus();
if (status == DatabaseVersion.Status.UP_TO_DATE || status == DatabaseVersion.Status.REQUIRES_DOWNGRADE) {
return new DatabaseMigrationsResponse(databaseMigrationState);
} else if (!database.getDialect().supportsMigration()) {
return new DatabaseMigrationsResponse(DatabaseMigrationState.Status.STATUS_NOT_SUPPORTED);
} else {
return switch (databaseMigrationState.getStatus()) {
case RUNNING, FAILED, SUCCEEDED -> new DatabaseMigrationsResponse(databaseMigrationState);
case NONE -> new DatabaseMigrationsResponse(DatabaseMigrationState.Status.MIGRATION_REQUIRED);
default -> throw new IllegalArgumentException(UNSUPPORTED_DATABASE_MIGRATION_STATUS);
};
}

}

public record DatabaseMigrationsResponse(String status, @Nullable String startedAt, @Nullable String message) {

public DatabaseMigrationsResponse(DatabaseMigrationState state) {
this(state.getStatus().toString(),
DateString.from(state.getStartedAt()),
state.getError() != null ? state.getError().getMessage() : state.getStatus().getMessage());
}

public DatabaseMigrationsResponse(DatabaseMigrationState.Status status) {
this(status.toString(), null, status.getMessage());
}
}

}

+ 37
- 0
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/DateString.java View File

@@ -0,0 +1,37 @@
/*
* SonarQube
* Copyright (C) 2009-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.v2.common;

import java.util.Date;
import javax.annotation.Nullable;

public class DateString {

private DateString() {
// intentionally empty
}

public static String from(@Nullable Date date) {
if (date == null) {
return null;
}
return date.toString();
}
}

+ 10
- 0
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java View File

@@ -22,6 +22,7 @@ package org.sonar.server.v2.config;
import javax.annotation.Nullable;
import org.sonar.api.platform.Server;
import org.sonar.api.resources.Languages;
import org.sonar.db.Database;
import org.sonar.db.DbClient;
import org.sonar.server.common.gitlab.config.GitlabConfigurationService;
import org.sonar.server.common.group.service.GroupMembershipService;
@@ -41,6 +42,8 @@ import org.sonar.server.common.user.service.UserService;
import org.sonar.server.health.HealthChecker;
import org.sonar.server.platform.NodeInformation;
import org.sonar.server.platform.ServerFileSystem;
import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;
import org.sonar.server.rule.RuleDescriptionFormatter;
import org.sonar.server.user.SystemPasscode;
import org.sonar.server.user.UserSession;
@@ -69,6 +72,7 @@ import org.sonar.server.v2.api.projects.controller.DefaultBoundProjectsControlle
import org.sonar.server.v2.api.rule.controller.DefaultRuleController;
import org.sonar.server.v2.api.rule.controller.RuleController;
import org.sonar.server.v2.api.rule.converter.RuleRestResponseGenerator;
import org.sonar.server.v2.api.system.controller.DatabaseMigrationsController;
import org.sonar.server.v2.api.system.controller.DefaultLivenessController;
import org.sonar.server.v2.api.system.controller.HealthController;
import org.sonar.server.v2.api.system.controller.LivenessController;
@@ -102,6 +106,12 @@ public class PlatformLevel4WebConfig {
return new HealthController(healthChecker, systemPasscode, nodeInformation, userSession);
}

@Bean
public DatabaseMigrationsController databaseMigrationsController(DatabaseVersion databaseVersion, DatabaseMigrationState databaseMigrationState,
Database database) {
return new DatabaseMigrationsController(databaseVersion, databaseMigrationState, database);
}

@Bean
public UsersSearchRestResponseGenerator usersSearchResponseGenerator(UserSession userSession) {
return new UsersSearchRestResponseGenerator(userSession);

+ 10
- 0
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/SafeModeWebConfig.java View File

@@ -19,11 +19,15 @@
*/
package org.sonar.server.v2.config;

import org.sonar.db.Database;
import org.sonar.server.common.health.DbConnectionNodeCheck;
import org.sonar.server.common.platform.LivenessChecker;
import org.sonar.server.common.platform.SafeModeLivenessCheckerImpl;
import org.sonar.server.health.HealthChecker;
import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;
import org.sonar.server.user.SystemPasscode;
import org.sonar.server.v2.api.system.controller.DatabaseMigrationsController;
import org.sonar.server.v2.api.system.controller.DefaultLivenessController;
import org.sonar.server.v2.api.system.controller.HealthController;
import org.sonar.server.v2.api.system.controller.LivenessController;
@@ -51,4 +55,10 @@ public class SafeModeWebConfig {
public HealthController healthController(HealthChecker healthChecker, SystemPasscode systemPasscode) {
return new HealthController(healthChecker, systemPasscode);
}

@Bean
public DatabaseMigrationsController databaseMigrationsController(DatabaseVersion databaseVersion, DatabaseMigrationState databaseMigrationState,
Database database) {
return new DatabaseMigrationsController(databaseVersion, databaseMigrationState, database);
}
}

+ 152
- 0
server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/system/controller/DatabaseMigrationsControllerTest.java View File

@@ -0,0 +1,152 @@
/*
* SonarQube
* Copyright (C) 2009-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program 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.
*
* This program 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.v2.api.system.controller;

import java.util.Date;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.sonar.db.Database;
import org.sonar.db.dialect.Dialect;
import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;
import org.sonar.server.v2.api.ControllerTester;
import org.springframework.test.web.servlet.MockMvc;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.FAILED;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.NONE;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.RUNNING;
import static org.sonar.server.v2.WebApiEndpoints.DATABASE_MIGRATIONS_ENDPOINT;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

class DatabaseMigrationsControllerTest {

private static final Date SOME_DATE = new Date();
private final DatabaseVersion databaseVersion = mock();
private final DatabaseMigrationState migrationState = mock();
private final Dialect dialect = mock(Dialect.class);
private final Database database = mock();
private final MockMvc mockMvc = ControllerTester.getMockMvc(new DatabaseMigrationsController(databaseVersion, migrationState, database));

@BeforeEach
public void before() {
when(database.getDialect()).thenReturn(dialect);
when(databaseVersion.getVersion()).thenReturn(Optional.of(1L));
}

@Test
void getStatus_whenDatabaseHasNoVersion_return500() throws Exception {
Mockito.reset(databaseVersion);
when(databaseVersion.getVersion()).thenReturn(Optional.empty());

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().is5xxServerError(),
content().json("{\"message\":\"Cannot connect to Database.\"}"));
}

@Test
void getStatus_migrationNotNeeded_returnUpToDateStatus() throws Exception {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE);
when(migrationState.getStatus()).thenReturn(NONE);

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
content().json("{\"status\":\"NO_MIGRATION\",\"message\":\"Database is up-to-date, no migration needed.\"}"));
}

@Test
void getStatus_whenDowngradeRequired_returnNone() throws Exception {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_DOWNGRADE);
when(migrationState.getStatus()).thenReturn(NONE);

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
content().json("{\"status\":\"NO_MIGRATION\",\"message\":\"Database is up-to-date, no migration needed.\"}"));
}

@Test
void getStatus_whenDbRequiresUpgradeButDialectIsNotSupported_returnNotSupported() throws Exception {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.FRESH_INSTALL);
when(dialect.supportsMigration()).thenReturn(false);

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
content().json("{\"status\":\"NOT_SUPPORTED\",\"message\":\"Upgrade is not supported on embedded database.\"}"));
}

@Test
void getStatus_whenDbMigrationsRunning_returnRunning() throws Exception {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
when(dialect.supportsMigration()).thenReturn(true);
when(migrationState.getStatus()).thenReturn(RUNNING);
when(migrationState.getStartedAt()).thenReturn(SOME_DATE);

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
content().json("{\"status\":\"MIGRATION_RUNNING\",\"message\":\"Database migration is running.\"}"));
}

@Test
void getStatus_whenDbMigrationsFailed_returnFailed() throws Exception {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
when(dialect.supportsMigration()).thenReturn(true);
when(migrationState.getStatus()).thenReturn(DatabaseMigrationState.Status.FAILED);
when(migrationState.getStartedAt()).thenReturn(SOME_DATE);

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
content().json("{\"status\":\"MIGRATION_FAILED\",\"message\":\"Migration failed: %s.<br/> Please check logs.\"}"));
}

@Test
void getStatus_whenDbMigrationsSucceeded_returnSucceeded() throws Exception {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
when(dialect.supportsMigration()).thenReturn(true);
when(migrationState.getStatus()).thenReturn(DatabaseMigrationState.Status.SUCCEEDED);
when(migrationState.getStartedAt()).thenReturn(SOME_DATE);

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
content().json("{\"status\":\"MIGRATION_SUCCEEDED\",\"message\":\"Migration succeeded.\"}"));
}


@Test
void getStatus_whenMigrationRequired_returnMigrationRequired() throws Exception {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.REQUIRES_UPGRADE);
when(dialect.supportsMigration()).thenReturn(true);
when(migrationState.getStatus()).thenReturn(NONE);
when(migrationState.getStartedAt()).thenReturn(SOME_DATE);

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
content().json("{\"status\":\"MIGRATION_REQUIRED\",\"message\":\"Database migration is required. DB migration " +
"can be started using WS /api/system/migrate_db.\"}"));
}

@Test
void getStatus_whenMigrationFailedWithError_IncludeErrorInResponse() throws Exception {
when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.FRESH_INSTALL);
when(dialect.supportsMigration()).thenReturn(true);
when(migrationState.getStatus()).thenReturn(FAILED);
when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
when(migrationState.getError()).thenReturn(new UnsupportedOperationException("error message"));

mockMvc.perform(get(DATABASE_MIGRATIONS_ENDPOINT)).andExpectAll(status().isOk(),
content().json("{\"status\":\"MIGRATION_FAILED\",\"message\":\"error message\"}"));
}
}

+ 19
- 62
server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/DbMigrationJsonWriter.java View File

@@ -22,6 +22,8 @@ package org.sonar.server.platform.ws;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.platform.db.migration.DatabaseMigrationState;

import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.FAILED;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.MIGRATION_REQUIRED;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.RUNNING;

public class DbMigrationJsonWriter {
@@ -29,21 +31,6 @@ public class DbMigrationJsonWriter {
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 STATUS_MIGRATION_REQUIRED = "MIGRATION_REQUIRED";

static final String NO_CONNECTION_TO_DB = "Cannot connect to Database.";
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_REQUIRED = "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
@@ -51,73 +38,43 @@ public class DbMigrationJsonWriter {

static void write(JsonWriter json, DatabaseMigrationState databaseMigrationState) {
json.beginObject()
.prop(FIELD_STATE, statusToJson(databaseMigrationState.getStatus()))
.prop(FIELD_MESSAGE, buildMessage(databaseMigrationState))
.prop(FIELD_STATE, databaseMigrationState.getStatus().toString())
.prop(FIELD_MESSAGE, writeMessageIncludingError(databaseMigrationState))
.propDateTime(FIELD_STARTED_AT, databaseMigrationState.getStartedAt())
.endObject();
}

private static String writeMessageIncludingError(DatabaseMigrationState state) {
if (state.getStatus() == FAILED) {
Throwable error = state.getError();
return String.format(state.getStatus().getMessage(), error != null ? error.getMessage() : "No failure error");
} else {
return state.getStatus().getMessage();
}
}

static void writeNotSupportedResponse(JsonWriter json) {
json.beginObject()
.prop(FIELD_STATE, STATUS_NOT_SUPPORTED)
.prop(FIELD_MESSAGE, MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE)
.prop(FIELD_STATE, DatabaseMigrationState.Status.STATUS_NOT_SUPPORTED.toString())
.prop(FIELD_MESSAGE, DatabaseMigrationState.Status.STATUS_NOT_SUPPORTED.getMessage())
.endObject();
}

static void writeJustStartedResponse(JsonWriter json, DatabaseMigrationState databaseMigrationState) {
json.beginObject()
.prop(FIELD_STATE, statusToJson(RUNNING))
.prop(FIELD_MESSAGE, MESSAGE_STATUS_RUNNING)
.prop(FIELD_STATE, RUNNING.toString())
.prop(FIELD_MESSAGE, RUNNING.getMessage())
.propDateTime(FIELD_STARTED_AT, databaseMigrationState.getStartedAt())
.endObject();
}

static void writeMigrationRequiredResponse(JsonWriter json) {
json.beginObject()
.prop(FIELD_STATE, STATUS_MIGRATION_REQUIRED)
.prop(FIELD_MESSAGE, MESSAGE_MIGRATION_REQUIRED)
.prop(FIELD_STATE, MIGRATION_REQUIRED.toString())
.prop(FIELD_MESSAGE, MIGRATION_REQUIRED.getMessage())
.endObject();
}

private static String statusToJson(DatabaseMigrationState.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(DatabaseMigrationState databaseMigrationState) {
switch (databaseMigrationState.getStatus()) {
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(databaseMigrationState));
default:
return UNSUPPORTED_DATABASE_MIGRATION_STATUS;
}
}

private static String failureMessage(DatabaseMigrationState databaseMigrationState) {
Throwable failureError = databaseMigrationState.getError();
if (failureError == null) {
return "No failure error";
}
return failureError.getMessage();
}

static String statusDescription() {
return "State values are:" +
"<ul>" +

+ 2
- 2
server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/DbMigrationStatusAction.java View File

@@ -30,8 +30,8 @@ import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;

import static com.google.common.base.Preconditions.checkState;
import static org.sonar.server.platform.ws.DbMigrationJsonWriter.NO_CONNECTION_TO_DB;
import static org.sonar.server.platform.ws.DbMigrationJsonWriter.UNSUPPORTED_DATABASE_MIGRATION_STATUS;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.NO_CONNECTION_TO_DB;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.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.writeMigrationRequiredResponse;

+ 2
- 2
server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/MigrateDbAction.java View File

@@ -31,8 +31,8 @@ import org.sonar.server.platform.db.migration.DatabaseMigration;
import org.sonar.server.platform.db.migration.DatabaseMigrationState;

import static com.google.common.base.Preconditions.checkState;
import static org.sonar.server.platform.ws.DbMigrationJsonWriter.NO_CONNECTION_TO_DB;
import static org.sonar.server.platform.ws.DbMigrationJsonWriter.UNSUPPORTED_DATABASE_MIGRATION_STATUS;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.NO_CONNECTION_TO_DB;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.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;

+ 9
- 19
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/DbMigrationStatusActionTest.java View File

@@ -47,20 +47,10 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.FAILED;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.MIGRATION_REQUIRED;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.NONE;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.RUNNING;
import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.SUCCEEDED;
import static org.sonar.server.platform.ws.DbMigrationJsonWriter.MESSAGE_MIGRATION_REQUIRED;
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_REQUIRED;
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;

@RunWith(DataProviderRunner.class)
@@ -111,7 +101,7 @@ public class DbMigrationStatusActionTest {

TestResponse response = tester.newRequest().execute();

assertJson(response.getInput()).isSimilarTo(expectedResponse(STATUS_NO_MIGRATION, MESSAGE_STATUS_NONE));
assertJson(response.getInput()).isSimilarTo(expectedResponse(NONE.toString(), NONE.getMessage()));
}

// this test will raise a IllegalArgumentException when an unsupported value is added to the Status enum
@@ -133,7 +123,7 @@ public class DbMigrationStatusActionTest {

TestResponse response = tester.newRequest().execute();

assertJson(response.getInput()).isSimilarTo(expectedResponse(STATUS_NO_MIGRATION, MESSAGE_STATUS_NONE));
assertJson(response.getInput()).isSimilarTo(expectedResponse(NONE.toString(), NONE.getMessage()));
}

@Test
@@ -144,7 +134,7 @@ public class DbMigrationStatusActionTest {

TestResponse response = tester.newRequest().execute();

assertJson(response.getInput()).isSimilarTo(expectedResponse(STATUS_NOT_SUPPORTED, MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE));
assertJson(response.getInput()).isSimilarTo(expectedResponse(Status.STATUS_NOT_SUPPORTED.toString(), Status.STATUS_NOT_SUPPORTED.getMessage()));
}

@Test
@@ -157,7 +147,7 @@ public class DbMigrationStatusActionTest {

TestResponse response = tester.newRequest().execute();

assertJson(response.getInput()).isSimilarTo(expectedResponse(STATUS_MIGRATION_RUNNING, MESSAGE_STATUS_RUNNING, SOME_DATE));
assertJson(response.getInput()).isSimilarTo(expectedResponse(RUNNING.toString(), RUNNING.getMessage(), SOME_DATE));
}

@Test
@@ -171,7 +161,7 @@ public class DbMigrationStatusActionTest {

TestResponse response = tester.newRequest().execute();

assertJson(response.getInput()).isSimilarTo(expectedResponse(STATUS_MIGRATION_FAILED, failedMsg(SOME_THROWABLE_MSG), SOME_DATE));
assertJson(response.getInput()).isSimilarTo(expectedResponse(FAILED.toString(), failedMsg(SOME_THROWABLE_MSG), SOME_DATE));
}

@Test
@@ -185,7 +175,7 @@ public class DbMigrationStatusActionTest {

TestResponse response = tester.newRequest().execute();

assertJson(response.getInput()).isSimilarTo(expectedResponse(STATUS_MIGRATION_FAILED, failedMsg(DEFAULT_ERROR_MSG), SOME_DATE));
assertJson(response.getInput()).isSimilarTo(expectedResponse(FAILED.toString(), failedMsg(DEFAULT_ERROR_MSG), SOME_DATE));
}

@Test
@@ -198,7 +188,7 @@ public class DbMigrationStatusActionTest {

TestResponse response = tester.newRequest().execute();

assertJson(response.getInput()).isSimilarTo(expectedResponse(STATUS_MIGRATION_SUCCEEDED, MESSAGE_STATUS_SUCCEEDED, SOME_DATE));
assertJson(response.getInput()).isSimilarTo(expectedResponse(SUCCEEDED.toString(), SUCCEEDED.getMessage(), SOME_DATE));
}

@Test
@@ -211,7 +201,7 @@ public class DbMigrationStatusActionTest {

TestResponse response = tester.newRequest().execute();

assertJson(response.getInput()).isSimilarTo(expectedResponse(STATUS_MIGRATION_REQUIRED, MESSAGE_MIGRATION_REQUIRED));
assertJson(response.getInput()).isSimilarTo(expectedResponse(MIGRATION_REQUIRED.toString(), MIGRATION_REQUIRED.getMessage()));
}

@DataProvider

+ 3
- 4
server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/StatusActionTest.java View File

@@ -32,7 +32,6 @@ import org.sonar.server.ws.WsActionTester;

import static com.google.common.base.Predicates.in;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.ImmutableSet.of;
import static com.google.common.collect.Iterables.filter;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
@@ -49,9 +48,9 @@ public class StatusActionTest {
private static final String STATUS_MIGRATION_NEEDED = "DB_MIGRATION_NEEDED";
private static final String STATUS_MIGRATION_RUNNING = "DB_MIGRATION_RUNNING";
private static final String STATUS_RESTARTING = "RESTARTING";
private static final Set<DatabaseMigrationState.Status> SUPPORTED_DATABASE_MIGRATION_STATUSES = of(DatabaseMigrationState.Status.FAILED, DatabaseMigrationState.Status.NONE,
DatabaseMigrationState.Status.SUCCEEDED, DatabaseMigrationState.Status.RUNNING);
private static final Set<Platform.Status> SUPPORTED_PLATFORM_STATUSES = of(Platform.Status.BOOTING, Platform.Status.SAFEMODE, Platform.Status.STARTING, Platform.Status.UP);
private static final Set<DatabaseMigrationState.Status> SUPPORTED_DATABASE_MIGRATION_STATUSES = Set.of(DatabaseMigrationState.Status.FAILED, DatabaseMigrationState.Status.NONE,
DatabaseMigrationState.Status.SUCCEEDED, DatabaseMigrationState.Status.RUNNING, DatabaseMigrationState.Status.STATUS_NOT_SUPPORTED, DatabaseMigrationState.Status.MIGRATION_REQUIRED);
private static final Set<Platform.Status> SUPPORTED_PLATFORM_STATUSES = Set.of(Platform.Status.BOOTING, Platform.Status.SAFEMODE, Platform.Status.STARTING, Platform.Status.UP);

private static Server server = new Dummy51Server();
private DatabaseMigrationState migrationState = mock(DatabaseMigrationState.class);

Loading…
Cancel
Save