also, split state (which must be stored at platform level 2 because we need to keep state until SQ is shutdown) from migration code, which doesn't need to be kept in memory once Platform is out of safe mode
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.platform.db.migration;
+
+public interface DatabaseMigration {
+
+ /**
+ * Starts the migration status and returns immediately.
+ * <p>
+ * Migration can not be started twice but calling this method wont raise an error.
+ * </p>
+ * <p>
+ * <strong>This method should be named {@code start} but it can not be because it will be called by the pico container
+ * and this will cause unwanted behavior</strong>
+ * </p>
+ */
+ void startIt();
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.platform.db.migration;
+
+import java.util.Date;
+import javax.annotation.CheckForNull;
+
+public interface DatabaseMigrationState {
+
+ enum Status {
+ NONE, RUNNING, FAILED, SUCCEEDED
+ }
+
+ /**
+ * Current status of the migration.
+ */
+ Status getStatus();
+
+ /**
+ * The time and day the last migration was started.
+ * <p>
+ * If no migration was ever started, the returned date is {@code null}.
+ * </p>
+ *
+ * @return a {@link Date} or {@code null}
+ */
+ @CheckForNull
+ Date getStartedAt();
+
+ /**
+ * The error of the last migration if it failed.
+ *
+ * @return a {@link Throwable} or {@code null}
+ */
+ @CheckForNull
+ Throwable getError();
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.platform.db.migration;
+
+import java.util.Date;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+/**
+ * This implementation of {@link MutableDatabaseMigrationState} does not provide any thread safety.
+ */
+public class DatabaseMigrationStateImpl implements MutableDatabaseMigrationState {
+ private Status status = Status.NONE;
+ @Nullable
+ private Date startedAt;
+ @Nullable
+ private Throwable error;
+
+ @Override
+ public Status getStatus() {
+ return status;
+ }
+
+ @Override
+ public void setStatus(Status status) {
+ this.status = status;
+ }
+
+ @Override
+ @CheckForNull
+ public Date getStartedAt() {
+ return startedAt;
+ }
+
+ @Override
+ public void setStartedAt(@Nullable Date startedAt) {
+ this.startedAt = startedAt;
+ }
+
+ @Override
+ @CheckForNull
+ public Throwable getError() {
+ return error;
+ }
+
+ @Override
+ public void setError(@Nullable Throwable error) {
+ this.error = error;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.platform.db.migration;
+
+import java.util.Date;
+import javax.annotation.Nullable;
+
+public interface MutableDatabaseMigrationState extends DatabaseMigrationState {
+ void setStatus(Status status);
+
+ void setStartedAt(@Nullable Date startedAt);
+
+ void setError(@Nullable Throwable error);
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.platform.db.migration;
+
+/**
+ * Implementation of {@link DatabaseMigration} which performs no operation at all.
+ * It is meant to be used when the platform in NOT in safe mode, which means that the database is up to date
+ * and migration is neither required nor should be performed.
+ */
+public class NoopDatabaseMigrationImpl implements DatabaseMigration {
+
+ @Override
+ public void startIt() {
+ // do nothing
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.platform.db.migration;
+
+import java.util.Date;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DatabaseMigrationStateImplTest {
+ private DatabaseMigrationStateImpl underTest = new DatabaseMigrationStateImpl();
+
+ @Test
+ public void getStatus_returns_NONE_when_component_is_created() {
+ assertThat(underTest.getStatus()).isEqualTo(DatabaseMigrationState.Status.NONE);
+ }
+
+ @Test
+ public void getStatus_returns_argument_of_setStatus() {
+ for (DatabaseMigrationState.Status status : DatabaseMigrationState.Status.values()) {
+ underTest.setStatus(status);
+
+ assertThat(underTest.getStatus()).isEqualTo(status);
+ }
+
+ }
+
+ @Test
+ public void getStartedAt_returns_null_when_component_is_created() {
+ assertThat(underTest.getStartedAt()).isNull();
+ }
+
+ @Test
+ public void getStartedAt_returns_argument_of_setStartedAt() {
+ Date expected = new Date();
+ underTest.setStartedAt(expected);
+
+ assertThat(underTest.getStartedAt()).isSameAs(expected);
+ }
+
+ @Test
+ public void getError_returns_null_when_component_is_created() {
+ assertThat(underTest.getError()).isNull();
+ }
+
+ @Test
+ public void getError_returns_argument_of_setError() {
+ RuntimeException expected = new RuntimeException();
+ underTest.setError(expected);
+
+ assertThat(underTest.getError()).isSameAs(expected);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.platform.db.migration;
+
+import org.junit.Test;
+
+public class NoopDatabaseMigrationImplTest {
+ @Test
+ public void startIt_does_nothing() {
+ new NoopDatabaseMigrationImpl().startIt();
+ }
+}
import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.log.Profiler;
-import org.sonar.db.version.DatabaseMigration;
import org.sonar.server.platform.Platform;
+import org.sonar.server.platform.db.migration.DatabaseMigration;
+import org.sonar.server.platform.db.migration.MutableDatabaseMigrationState;
import org.sonar.server.ruby.RubyBridge;
+import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status;
+
/**
* Handles concurrency to make sure only one DB migration can run at a time.
*/
*/
private final PlatformDatabaseMigrationExecutorService executorService;
private final Platform platform;
+ private final MutableDatabaseMigrationState migrationState;
/**
* This lock implements thread safety from concurrent calls of method {@link #startIt()}
*/
* </p>
*/
private final AtomicBoolean running = new AtomicBoolean(false);
- private Status status = Status.NONE;
- @Nullable
- private Date startDate;
- @Nullable
- private Throwable failureError;
-
- public PlatformDatabaseMigration(RubyBridge rubyBridge,
- PlatformDatabaseMigrationExecutorService executorService, Platform platform) {
+
+ public PlatformDatabaseMigration(RubyBridge rubyBridge, PlatformDatabaseMigrationExecutorService executorService, Platform platform,
+ MutableDatabaseMigrationState migrationState) {
this.rubyBridge = rubyBridge;
this.executorService = executorService;
this.platform = platform;
+ this.migrationState = migrationState;
}
@Override
}
private void doDatabaseMigration() {
- status = Status.RUNNING;
- startDate = new Date();
- failureError = null;
+ migrationState.setStatus(Status.RUNNING);
+ migrationState.setStartedAt(new Date());
+ migrationState.setError(null);
Profiler profiler = Profiler.create(LOGGER);
try {
profiler.startInfo("Starting DB Migration");
doUpgradeDb();
doRestartContainer();
doRecreateWebRoutes();
- status = Status.SUCCEEDED;
+ migrationState.setStatus(Status.SUCCEEDED);
profiler.stopInfo("DB Migration ended successfully");
} catch (Throwable t) {
profiler.stopInfo("DB migration failed");
LOGGER.error("DB Migration or container restart failed. Process ended with an exception", t);
- status = Status.FAILED;
- failureError = t;
+ migrationState.setStatus(Status.FAILED);
+ migrationState.setError(t);
} finally {
running.getAndSet(false);
}
profiler.startTrace("Routes recreated successfully");
}
- @Override
- @CheckForNull
- public Date startedAt() {
- return this.startDate;
- }
-
- @Override
- public Status status() {
- return this.status;
- }
-
- @Override
- @CheckForNull
- public Throwable failureError() {
- return this.failureError;
- }
}
import org.sonar.server.platform.DefaultServerUpgradeStatus;
import org.sonar.server.platform.StartupMetadataProvider;
import org.sonar.server.platform.db.CheckDatabaseCharsetAtStartup;
+import org.sonar.server.platform.db.migration.DatabaseMigrationStateImpl;
import org.sonar.server.platform.db.migration.history.MigrationHistoryTableImpl;
import org.sonar.server.platform.db.migrations.DatabaseMigrator;
-import org.sonar.server.platform.db.migrations.PlatformDatabaseMigration;
import org.sonar.server.platform.db.migrations.PlatformDatabaseMigrationExecutorServiceImpl;
import org.sonar.server.platform.web.RailsAppsDeployer;
import org.sonar.server.plugins.InstalledPluginReferentialFactory;
// Full Java DB Migration framework and configuration
addIfStartupLeader(MigrationHistoryTableImpl.class);
- // platform DB migration (TODO remove call to Ruby's Active Record and use DbMigrationEngine instead)
- add(
- PlatformDatabaseMigrationExecutorServiceImpl.class,
- PlatformDatabaseMigration.class);
+ add(DatabaseMigrationStateImpl.class,
+ PlatformDatabaseMigrationExecutorServiceImpl.class);
// Ruby DB Migration
add(
DatabaseMigrator.class,
import org.sonar.server.platform.ServerIdManager;
import org.sonar.server.platform.ServerImpl;
import org.sonar.server.platform.StartupMetadataPersister;
+import org.sonar.server.platform.db.migration.NoopDatabaseMigrationImpl;
import org.sonar.server.setting.DatabaseSettingLoader;
import org.sonar.server.setting.DatabaseSettingsEnabler;
import org.sonar.server.startup.LogServerId;
protected void configureLevel() {
addIfStartupLeader(StartupMetadataPersister.class);
add(
+ NoopDatabaseMigrationImpl.class,
ServerIdManager.class,
ServerImpl.class,
DatabaseSettingLoader.class,
import org.sonar.server.organization.NoopDefaultOrganizationCache;
import org.sonar.server.platform.ServerImpl;
+import org.sonar.server.platform.db.migrations.PlatformDatabaseMigration;
import org.sonar.server.platform.web.WebPagesFilter;
import org.sonar.server.platform.ws.DbMigrationStatusAction;
import org.sonar.server.platform.ws.IndexAction;
WebServiceFilter.class,
NoopDefaultOrganizationCache.class);
+ add(PlatformDatabaseMigration.class);
}
}
package org.sonar.server.platform.ws;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.db.version.DatabaseMigration;
+import org.sonar.server.platform.db.migration.DatabaseMigrationState;
-import static org.sonar.db.version.DatabaseMigration.Status.RUNNING;
+import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status.RUNNING;
public class DbMigrationJsonWriter {
static final String FIELD_STATE = "state";
// static methods only
}
- static void write(JsonWriter json, DatabaseMigration databaseMigration) {
+ static void write(JsonWriter json, DatabaseMigrationState databaseMigrationState) {
json.beginObject()
- .prop(FIELD_STATE, statusToJson(databaseMigration.status()))
- .prop(FIELD_MESSAGE, buildMessage(databaseMigration))
- .propDateTime(FIELD_STARTED_AT, databaseMigration.startedAt())
+ .prop(FIELD_STATE, statusToJson(databaseMigrationState.getStatus()))
+ .prop(FIELD_MESSAGE, buildMessage(databaseMigrationState))
+ .propDateTime(FIELD_STARTED_AT, databaseMigrationState.getStartedAt())
.endObject();
}
.endObject();
}
- static void writeJustStartedResponse(JsonWriter json, DatabaseMigration databaseMigration) {
+ static void writeJustStartedResponse(JsonWriter json, DatabaseMigrationState databaseMigrationState) {
json.beginObject()
.prop(FIELD_STATE, statusToJson(RUNNING))
.prop(FIELD_MESSAGE, MESSAGE_STATUS_RUNNING)
- .propDateTime(FIELD_STARTED_AT, databaseMigration.startedAt())
+ .propDateTime(FIELD_STARTED_AT, databaseMigrationState.getStartedAt())
.endObject();
}
.endObject();
}
- private static String statusToJson(DatabaseMigration.Status status) {
+ private static String statusToJson(DatabaseMigrationState.Status status) {
switch (status) {
case NONE:
return STATUS_NO_MIGRATION;
}
}
- private static String buildMessage(DatabaseMigration databaseMigration) {
- switch (databaseMigration.status()) {
+ private static String buildMessage(DatabaseMigrationState databaseMigrationState) {
+ switch (databaseMigrationState.getStatus()) {
case NONE:
return MESSAGE_STATUS_NONE;
case RUNNING:
case SUCCEEDED:
return MESSAGE_STATUS_SUCCEEDED;
case FAILED:
- return String.format(MESSAGE_STATUS_FAILED, failureMessage(databaseMigration));
+ return String.format(MESSAGE_STATUS_FAILED, failureMessage(databaseMigrationState));
default:
return UNSUPPORTED_DATABASE_MIGRATION_STATUS;
}
}
- private static String failureMessage(DatabaseMigration databaseMigration) {
- Throwable failureError = databaseMigration.failureError();
+ private static String failureMessage(DatabaseMigrationState databaseMigrationState) {
+ Throwable failureError = databaseMigrationState.getError();
if (failureError == null) {
return "No failure error";
}
}
static String statusDescription() {
- return
- "State values are:" +
+ 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>" +
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 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;
public class DbMigrationStatusAction implements SystemWsAction {
private final DatabaseVersion databaseVersion;
- private final DatabaseMigration databaseMigration;
+ private final DatabaseMigrationState databaseMigrationState;
private final Database database;
- public DbMigrationStatusAction(DatabaseVersion databaseVersion, Database database, DatabaseMigration databaseMigration) {
+ public DbMigrationStatusAction(DatabaseVersion databaseVersion, Database database, DatabaseMigrationState databaseMigrationState) {
this.databaseVersion = databaseVersion;
this.database = database;
- this.databaseMigration = databaseMigration;
+ this.databaseMigrationState = databaseMigrationState;
}
@Override
JsonWriter json = response.newJsonWriter();
try {
if (currentVersion >= DatabaseVersion.LAST_VERSION) {
- write(json, databaseMigration);
+ write(json, databaseMigrationState);
} else if (!database.getDialect().supportsMigration()) {
writeNotSupportedResponse(json);
} else {
- switch (databaseMigration.status()) {
+ switch (databaseMigrationState.getStatus()) {
case RUNNING:
case FAILED:
case SUCCEEDED:
- write(json, databaseMigration);
+ write(json, databaseMigrationState);
break;
case NONE:
writeMigrationRequiredResponse(json);
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 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;
public class MigrateDbAction implements SystemWsAction {
private final DatabaseVersion databaseVersion;
+ private final DatabaseMigrationState migrationState;
private final DatabaseMigration databaseMigration;
private final Database database;
- public MigrateDbAction(DatabaseVersion databaseVersion, Database database, DatabaseMigration databaseMigration) {
+ public MigrateDbAction(DatabaseVersion databaseVersion, Database database,
+ DatabaseMigrationState migrationState, DatabaseMigration databaseMigration) {
this.databaseVersion = databaseVersion;
this.database = database;
+ this.migrationState = migrationState;
this.databaseMigration = databaseMigration;
}
JsonWriter json = response.newJsonWriter();
try {
if (currentVersion >= DatabaseVersion.LAST_VERSION) {
- write(json, databaseMigration);
+ write(json, migrationState);
} else if (!database.getDialect().supportsMigration()) {
writeNotSupportedResponse(json);
} else {
- switch (databaseMigration.status()) {
+ switch (migrationState.getStatus()) {
case RUNNING:
case FAILED:
case SUCCEEDED:
- write(json, databaseMigration);
+ write(json, migrationState);
break;
case NONE:
databaseMigration.startIt();
- writeJustStartedResponse(json, databaseMigration);
+ writeJustStartedResponse(json, migrationState);
break;
default:
throw new IllegalArgumentException(UNSUPPORTED_DATABASE_MIGRATION_STATUS);
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.IsAliveMapper;
-import org.sonar.db.version.DatabaseMigration;
import org.sonar.server.app.RestartFlagHolder;
import org.sonar.server.platform.Platform;
+import org.sonar.server.platform.db.migration.DatabaseMigrationState;
/**
* Implementation of the {@code status} action for the System WebService.
private static final Logger LOGGER = Loggers.get(StatusAction.class);
private final Server server;
- private final DatabaseMigration databaseMigration;
+ private final DatabaseMigrationState migrationState;
private final Platform platform;
private final DbClient dbClient;
private final RestartFlagHolder restartFlagHolder;
- public StatusAction(Server server, DatabaseMigration databaseMigration, Platform platform, DbClient dbClient, RestartFlagHolder restartFlagHolder) {
+ public StatusAction(Server server, DatabaseMigrationState migrationState,
+ Platform platform, DbClient dbClient, RestartFlagHolder restartFlagHolder) {
this.server = server;
- this.databaseMigration = databaseMigration;
+ this.migrationState = migrationState;
this.platform = platform;
this.dbClient = dbClient;
this.restartFlagHolder = restartFlagHolder;
}
private Status computeFromDbMigrationStatus() {
- DatabaseMigration.Status databaseMigrationStatus = databaseMigration.status();
+ DatabaseMigrationState.Status databaseMigrationStatus = migrationState.getStatus();
switch (databaseMigrationStatus) {
case NONE:
return Status.DB_MIGRATION_NEEDED;
import org.sonar.db.property.PropertiesDao;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.rule.RuleRepositoryDto;
-import org.sonar.db.version.DatabaseMigration;
import org.sonar.db.version.DatabaseVersion;
import org.sonar.process.ProcessProperties;
import org.sonar.server.authentication.IdentityProviderRepository;
import org.sonar.server.platform.PersistentSettings;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.db.migrations.DatabaseMigrator;
+import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.platform.ws.UpgradesAction;
import org.sonar.server.user.NewUserNotifier;
import static com.google.common.collect.Lists.newArrayList;
+import static org.sonar.server.platform.db.migration.DatabaseMigrationState.*;
public final class JRubyFacade {
*/
public boolean isSonarAccessAllowed() {
ComponentContainer container = Platform.getInstance().getContainer();
- DatabaseMigration databaseMigration = container.getComponentByType(DatabaseMigration.class);
- if (databaseMigration.status() == DatabaseMigration.Status.RUNNING
- || databaseMigration.status() == DatabaseMigration.Status.FAILED) {
+ DatabaseMigrationState databaseMigrationState = container.getComponentByType(DatabaseMigrationState.class);
+ Status status = databaseMigrationState.getStatus();
+ if (status == Status.RUNNING
+ || status == Status.FAILED) {
return false;
}
- if (databaseMigration.status() == DatabaseMigration.Status.SUCCEEDED) {
+ if (status == Status.SUCCEEDED) {
return true;
}
@Override
public void stop() {
+ try {
+ stopIt();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ private void stopIt() {
// Disable new tasks from being submitted
delegate.shutdown();
try {
import org.junit.Test;
import org.sonar.server.platform.Platform;
+import org.sonar.server.platform.db.migration.MutableDatabaseMigrationState;
import org.sonar.server.ruby.RubyBridge;
import static org.assertj.core.api.Assertions.assertThat;
* Implementation of execute wraps specified Runnable to add a delay of 200 ms before passing it
* to a SingleThread executor to execute asynchronously.
*/
- PlatformDatabaseMigrationExecutorService executorService = new PlatformDatabaseMigrationExecutorServiceAdaptor() {
+ private PlatformDatabaseMigrationExecutorService executorService = new PlatformDatabaseMigrationExecutorServiceAdaptor() {
@Override
public void execute(final Runnable command) {
taskSuppliedForAsyncProcess = true;
}
};
- RubyBridge rubyBridge = mock(RubyBridge.class);
- Platform platform = mock(Platform.class);
- PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform);
+ private RubyBridge rubyBridge = mock(RubyBridge.class);
+ private Platform platform = mock(Platform.class);
+ private MutableDatabaseMigrationState migrationState = mock(MutableDatabaseMigrationState.class);
+ private PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform, migrationState);
@Test
public void testName() throws Exception {
import org.junit.After;
import org.junit.Test;
import org.sonar.server.platform.Platform;
+import org.sonar.server.platform.db.migration.MutableDatabaseMigrationState;
import org.sonar.server.ruby.RubyBridge;
import org.sonar.server.ruby.RubyDatabaseMigration;
import org.sonar.server.ruby.RubyRailsRoutes;
/**
* Implementation of RubyDatabaseMigration which trigger method increments a thread-safe counter and add a delay of 200ms
*/
- RubyDatabaseMigration rubyDatabaseMigration = new RubyDatabaseMigration() {
+ private RubyDatabaseMigration rubyDatabaseMigration = new RubyDatabaseMigration() {
@Override
public void trigger() {
triggerCount.incrementAndGet();
}
}
};
- RubyBridge rubyBridge = mock(RubyBridge.class);
- Platform platform = mock(Platform.class);
- RubyRailsRoutes railsRoutes = mock(RubyRailsRoutes.class);
- PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform);
+ private RubyBridge rubyBridge = mock(RubyBridge.class);
+ private Platform platform = mock(Platform.class);
+ private RubyRailsRoutes railsRoutes = mock(RubyRailsRoutes.class);
+ private MutableDatabaseMigrationState migrationState = mock(MutableDatabaseMigrationState.class);
+ private PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform, migrationState);
@After
public void tearDown() {
import java.util.Date;
import org.junit.Test;
import org.mockito.InOrder;
-import org.sonar.db.version.DatabaseMigration;
import org.sonar.server.platform.Platform;
+import org.sonar.server.platform.db.migration.DatabaseMigrationState;
+import org.sonar.server.platform.db.migration.DatabaseMigrationStateImpl;
+import org.sonar.server.platform.db.migration.MutableDatabaseMigrationState;
import org.sonar.server.ruby.RubyBridge;
import org.sonar.server.ruby.RubyDatabaseMigration;
import org.sonar.server.ruby.RubyRailsRoutes;
/**
* Implementation of execute runs Runnable synchronously.
*/
- PlatformDatabaseMigrationExecutorService executorService = new PlatformDatabaseMigrationExecutorServiceAdaptor() {
+ private PlatformDatabaseMigrationExecutorService executorService = new PlatformDatabaseMigrationExecutorServiceAdaptor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
- RubyBridge rubyBridge = mock(RubyBridge.class);
- RubyDatabaseMigration rubyDatabaseMigration = mock(RubyDatabaseMigration.class);
- RubyRailsRoutes rubyRailsRoutes = mock(RubyRailsRoutes.class);
- Platform platform = mock(Platform.class);
- InOrder inOrder = inOrder(rubyDatabaseMigration, rubyBridge, rubyRailsRoutes, platform);
+ private RubyBridge rubyBridge = mock(RubyBridge.class);
+ private RubyDatabaseMigration rubyDatabaseMigration = mock(RubyDatabaseMigration.class);
+ private RubyRailsRoutes rubyRailsRoutes = mock(RubyRailsRoutes.class);
+ private Platform platform = mock(Platform.class);
+ private MutableDatabaseMigrationState migrationState = new DatabaseMigrationStateImpl();
+ private InOrder inOrder = inOrder(rubyDatabaseMigration, rubyBridge, rubyRailsRoutes, platform);
- PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform);
-
- @Test
- public void status_is_NONE_when_component_is_created() {
- assertThat(underTest.status()).isEqualTo(DatabaseMigration.Status.NONE);
- }
-
- @Test
- public void startedAt_is_null_when_component_is_created() {
- assertThat(underTest.startedAt()).isNull();
- }
-
- @Test
- public void failureError_is_null_when_component_is_created() {
- assertThat(underTest.failureError()).isNull();
- }
+ private PlatformDatabaseMigration underTest = new PlatformDatabaseMigration(rubyBridge, executorService, platform, migrationState);
@Test
public void startit_calls_databasemigration_trigger_in_a_separate_thread() {
underTest.startIt();
- assertThat(underTest.status()).isEqualTo(DatabaseMigration.Status.SUCCEEDED);
- assertThat(underTest.failureError()).isNull();
- assertThat(underTest.startedAt()).isNotNull();
+ assertThat(migrationState.getStatus()).isEqualTo(DatabaseMigrationState.Status.SUCCEEDED);
+ assertThat(migrationState.getError()).isNull();
+ assertThat(migrationState.getStartedAt()).isNotNull();
}
@Test
underTest.startIt();
- assertThat(underTest.status()).isEqualTo(DatabaseMigration.Status.FAILED);
- assertThat(underTest.failureError()).isSameAs(AN_ERROR);
- assertThat(underTest.startedAt()).isNotNull();
+ assertThat(migrationState.getStatus()).isEqualTo(DatabaseMigrationState.Status.FAILED);
+ assertThat(migrationState.getError()).isSameAs(AN_ERROR);
+ assertThat(migrationState.getStartedAt()).isNotNull();
}
@Test
underTest.startIt();
- assertThat(underTest.status()).isEqualTo(DatabaseMigration.Status.FAILED);
- assertThat(underTest.failureError()).isSameAs(AN_ERROR);
- Date firstStartDate = underTest.startedAt();
+ assertThat(migrationState.getStatus()).isEqualTo(DatabaseMigrationState.Status.FAILED);
+ assertThat(migrationState.getError()).isSameAs(AN_ERROR);
+ Date firstStartDate = migrationState.getStartedAt();
assertThat(firstStartDate).isNotNull();
mockTriggerDoesNothing();
underTest.startIt();
- assertThat(underTest.status()).isEqualTo(DatabaseMigration.Status.SUCCEEDED);
- assertThat(underTest.failureError()).isNull();
- assertThat(underTest.startedAt()).isNotSameAs(firstStartDate);
+ assertThat(migrationState.getStatus()).isEqualTo(DatabaseMigrationState.Status.SUCCEEDED);
+ assertThat(migrationState.getError()).isNull();
+ assertThat(migrationState.getStartedAt()).isNotSameAs(firstStartDate);
}
private void mockTriggerThrowsError() {
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.server.platform.db.migration.DatabaseMigrationState.Status;
import org.sonar.db.version.DatabaseVersion;
+import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.ws.WsTester;
import static com.google.common.base.Predicates.in;
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.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.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;
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);
+ private DatabaseVersion databaseVersion = mock(DatabaseVersion.class);
+ private Database database = mock(Database.class);
+ private Dialect dialect = mock(Dialect.class);
+ private DatabaseMigrationState migrationState = mock(DatabaseMigrationState.class);
+ private DbMigrationStatusAction underTest = new DbMigrationStatusAction(databaseVersion, database, migrationState);
- Request request = mock(Request.class);
- WsTester.TestResponse response = new WsTester.TestResponse();
+ private Request request = mock(Request.class);
+ private WsTester.TestResponse response = new WsTester.TestResponse();
@Before
public void wireMocksTogether() {
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"));
+ when(migrationState.getStatus()).thenReturn(RUNNING);
+ when(migrationState.getStartedAt()).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);
+ when(migrationState.getStatus()).thenReturn(NONE);
underTest.handle(request, response);
// 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))))) {
+ for (Status status : filter(Arrays.asList(DatabaseMigrationState.Status.values()), not(in(ImmutableList.of(NONE, RUNNING, FAILED, SUCCEEDED))))) {
when(databaseVersion.getVersion()).thenReturn(CURRENT_VERSION);
- when(databaseMigration.status()).thenReturn(status);
+ when(migrationState.getStatus()).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);
+ when(migrationState.getStatus()).thenReturn(NONE);
underTest.handle(request, response);
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);
+ when(migrationState.getStatus()).thenReturn(RUNNING);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
underTest.handle(request, response);
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));
+ when(migrationState.getStatus()).thenReturn(FAILED);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
+ when(migrationState.getError()).thenReturn(new UnsupportedOperationException(SOME_THROWABLE_MSG));
underTest.handle(request, response);
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
+ when(migrationState.getStatus()).thenReturn(FAILED);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
+ when(migrationState.getError()).thenReturn(null); // no failure throwable caught
underTest.handle(request, response);
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);
+ when(migrationState.getStatus()).thenReturn(SUCCEEDED);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
underTest.handle(request, response);
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);
+ when(migrationState.getStatus()).thenReturn(NONE);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
underTest.handle(request, response);
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.server.platform.db.migration.DatabaseMigration;
+import org.sonar.server.platform.db.migration.DatabaseMigrationState.Status;
import org.sonar.db.version.DatabaseVersion;
+import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.ws.WsTester;
import static com.google.common.base.Predicates.in;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
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.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.platform.db.migration.DatabaseMigrationState.Status.SUCCEEDED;
import static org.sonar.test.JsonAssert.assertJson;
public class MigrateDbActionTest {
private static final int OLD_VERSION = CURRENT_VERSION - 1;
private static final int NEWER_VERSION = CURRENT_VERSION + 1;
- 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";
+ 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";
- 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.";
+ private static final String MESSAGE_NO_MIGRATION_ON_EMBEDDED_DATABASE = "Upgrade is not supported on embedded database.";
+ 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.";
- DatabaseVersion databaseVersion = mock(DatabaseVersion.class);
- Database database = mock(Database.class);
- Dialect dialect = mock(Dialect.class);
- DatabaseMigration databaseMigration = mock(DatabaseMigration.class);
- MigrateDbAction underTest = new MigrateDbAction(databaseVersion, database, databaseMigration);
+ private DatabaseVersion databaseVersion = mock(DatabaseVersion.class);
+ private Database database = mock(Database.class);
+ private Dialect dialect = mock(Dialect.class);
+ private DatabaseMigration databaseMigration = mock(DatabaseMigration.class);
+ private DatabaseMigrationState migrationState = mock(DatabaseMigrationState.class);
+ private MigrateDbAction underTest = new MigrateDbAction(databaseVersion, database, migrationState, databaseMigration);
- Request request = mock(Request.class);
- WsTester.TestResponse response = new WsTester.TestResponse();
+ private Request request = mock(Request.class);
+ private WsTester.TestResponse response = new WsTester.TestResponse();
@Before
public void wireMocksTogether() {
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"));
+ when(migrationState.getStatus()).thenReturn(RUNNING);
+ when(migrationState.getStartedAt()).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_database_migration_when_database_version_is_equal_to_current_version() throws Exception {
when(databaseVersion.getVersion()).thenReturn(CURRENT_VERSION);
- when(databaseMigration.status()).thenReturn(NONE);
+ when(migrationState.getStatus()).thenReturn(NONE);
underTest.handle(request, response);
// 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))))) {
+ for (Status status : filter(Arrays.asList(DatabaseMigrationState.Status.values()), not(in(ImmutableList.of(NONE, RUNNING, FAILED, SUCCEEDED))))) {
when(databaseVersion.getVersion()).thenReturn(CURRENT_VERSION);
- when(databaseMigration.status()).thenReturn(status);
+ when(migrationState.getStatus()).thenReturn(status);
underTest.handle(request, response);
}
@Test
public void state_from_database_migration_when_databaseversion_greater_than_currentversion() throws Exception {
when(databaseVersion.getVersion()).thenReturn(NEWER_VERSION);
- when(databaseMigration.status()).thenReturn(NONE);
+ when(migrationState.getStatus()).thenReturn(NONE);
underTest.handle(request, response);
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);
- when(databaseMigration.startedAt()).thenReturn(SOME_DATE);
+ when(migrationState.getStatus()).thenReturn(RUNNING);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
underTest.handle(request, response);
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);
- when(databaseMigration.startedAt()).thenReturn(SOME_DATE);
- when(databaseMigration.failureError()).thenReturn(new UnsupportedOperationException(SOME_THROWABLE_MSG));
+ when(migrationState.getStatus()).thenReturn(FAILED);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
+ when(migrationState.getError()).thenReturn(new UnsupportedOperationException(SOME_THROWABLE_MSG));
underTest.handle(request, response);
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);
- when(databaseMigration.startedAt()).thenReturn(SOME_DATE);
- when(databaseMigration.failureError()).thenReturn(null); // no failure throwable caught
+ when(migrationState.getStatus()).thenReturn(FAILED);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
+ when(migrationState.getError()).thenReturn(null); // no failure throwable caught
underTest.handle(request, response);
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);
- when(databaseMigration.startedAt()).thenReturn(SOME_DATE);
+ when(migrationState.getStatus()).thenReturn(SUCCEEDED);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
underTest.handle(request, response);
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);
- when(databaseMigration.startedAt()).thenReturn(SOME_DATE);
+ when(migrationState.getStatus()).thenReturn(NONE);
+ when(migrationState.getStartedAt()).thenReturn(SOME_DATE);
underTest.handle(request, response);
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.IsAliveMapper;
-import org.sonar.db.version.DatabaseMigration;
import org.sonar.server.app.RestartFlagHolder;
import org.sonar.server.app.RestartFlagHolderImpl;
import org.sonar.server.platform.Platform;
+import org.sonar.server.platform.db.migration.DatabaseMigrationState;
import org.sonar.server.ws.WsTester;
import static com.google.common.base.Predicates.in;
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<DatabaseMigration.Status> SUPPORTED_DATABASE_MIGRATION_STATUSES = of(DatabaseMigration.Status.FAILED, DatabaseMigration.Status.NONE,
- DatabaseMigration.Status.SUCCEEDED, DatabaseMigration.Status.RUNNING);
+ 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.UP);
private static Server server = new Dummy51Server();
- private DatabaseMigration databaseMigration = mock(DatabaseMigration.class);
+ private DatabaseMigrationState migrationState = mock(DatabaseMigrationState.class);
private Platform platform = mock(Platform.class);
private DbClient dbClient = mock(DbClient.class);
private DbSession dbSession = mock(DbSession.class);
private IsAliveMapper isAliveMapper = mock(IsAliveMapper.class);
private RestartFlagHolder restartFlagHolder = new RestartFlagHolderImpl();
- private StatusAction underTest = new StatusAction(server, databaseMigration, platform, dbClient, restartFlagHolder);
+ private StatusAction underTest = new StatusAction(server, migrationState, platform, dbClient, restartFlagHolder);
private Request request = mock(Request.class);
@Test
public void status_is_UP_if_platform_is_UP_and_restartFlag_is_false_whatever_databaseMigration_status_is() throws Exception {
- for (DatabaseMigration.Status databaseMigrationStatus : DatabaseMigration.Status.values()) {
+ for (DatabaseMigrationState.Status databaseMigrationStatus : DatabaseMigrationState.Status.values()) {
verifyStatus(Platform.Status.UP, databaseMigrationStatus, STATUS_UP);
}
}
public void status_is_RESTARTING_if_platform_is_UP_and_restartFlag_is_true_whatever_databaseMigration_status_is() throws Exception {
restartFlagHolder.set();
- for (DatabaseMigration.Status databaseMigrationStatus : DatabaseMigration.Status.values()) {
+ for (DatabaseMigrationState.Status databaseMigrationStatus : DatabaseMigrationState.Status.values()) {
verifyStatus(Platform.Status.UP, databaseMigrationStatus, STATUS_RESTARTING);
}
}
@Test
public void status_is_DOWN_if_platform_is_BOOTING_whatever_databaseMigration_status_is() throws Exception {
- for (DatabaseMigration.Status databaseMigrationStatus : DatabaseMigration.Status.values()) {
+ for (DatabaseMigrationState.Status databaseMigrationStatus : DatabaseMigrationState.Status.values()) {
verifyStatus(Platform.Status.BOOTING, databaseMigrationStatus, STATUS_DOWN);
}
}
@Test
public void status_is_DB_MIGRATION_NEEDED_if_platform_is_SAFEMODE_and_databaseMigration_is_NONE() throws Exception {
- verifyStatus(Platform.Status.SAFEMODE, DatabaseMigration.Status.NONE, STATUS_MIGRATION_NEEDED);
+ verifyStatus(Platform.Status.SAFEMODE, DatabaseMigrationState.Status.NONE, STATUS_MIGRATION_NEEDED);
}
@Test
public void status_is_DB_MIGRATION_RUNNING_if_platform_is_SAFEMODE_and_databaseMigration_is_RUNNING() throws Exception {
- verifyStatus(Platform.Status.SAFEMODE, DatabaseMigration.Status.RUNNING, STATUS_MIGRATION_RUNNING);
+ verifyStatus(Platform.Status.SAFEMODE, DatabaseMigrationState.Status.RUNNING, STATUS_MIGRATION_RUNNING);
}
@Test
public void status_is_UP_if_platform_is_SAFEMODE_and_databaseMigration_is_SUCCEEDED() throws Exception {
- verifyStatus(Platform.Status.SAFEMODE, DatabaseMigration.Status.SUCCEEDED, STATUS_UP);
+ verifyStatus(Platform.Status.SAFEMODE, DatabaseMigrationState.Status.SUCCEEDED, STATUS_UP);
}
@Test
public void status_is_DOWN_if_platform_is_SAFEMODE_and_databaseMigration_is_FAILED() throws Exception {
- verifyStatus(Platform.Status.SAFEMODE, DatabaseMigration.Status.FAILED, STATUS_DOWN);
+ verifyStatus(Platform.Status.SAFEMODE, DatabaseMigrationState.Status.FAILED, STATUS_DOWN);
}
@Test
@Test
public void safety_test_for_new_platform_status() throws Exception {
for (Platform.Status platformStatus : filter(asList(Platform.Status.values()), not(in(SUPPORTED_PLATFORM_STATUSES)))) {
- for (DatabaseMigration.Status databaseMigrationStatus : DatabaseMigration.Status.values()) {
+ for (DatabaseMigrationState.Status databaseMigrationStatus : DatabaseMigrationState.Status.values()) {
verifyStatus(platformStatus, databaseMigrationStatus, STATUS_DOWN);
}
}
@Test
public void safety_test_for_new_databaseMigration_status_when_platform_is_SAFEMODE() throws Exception {
- for (DatabaseMigration.Status databaseMigrationStatus : filter(asList(DatabaseMigration.Status.values()), not(in(SUPPORTED_DATABASE_MIGRATION_STATUSES)))) {
+ for (DatabaseMigrationState.Status databaseMigrationStatus : filter(asList(DatabaseMigrationState.Status.values()), not(in(SUPPORTED_DATABASE_MIGRATION_STATUSES)))) {
when(platform.status()).thenReturn(Platform.Status.SAFEMODE);
- when(databaseMigration.status()).thenReturn(databaseMigrationStatus);
+ when(migrationState.getStatus()).thenReturn(databaseMigrationStatus);
WsTester.TestResponse response = new WsTester.TestResponse();
underTest.handle(request, response);
}
}
- private void verifyStatus(Platform.Status platformStatus, DatabaseMigration.Status databaseMigrationStatus, String expectedStatus) throws Exception {
+ private void verifyStatus(Platform.Status platformStatus, DatabaseMigrationState.Status databaseMigrationStatus, String expectedStatus) throws Exception {
when(isAliveMapper.isAlive()).thenReturn(IsAliveMapper.IS_ALIVE_RETURNED_VALUE);
when(platform.status()).thenReturn(platformStatus);
- when(databaseMigration.status()).thenReturn(databaseMigrationStatus);
+ when(migrationState.getStatus()).thenReturn(databaseMigrationStatus);
WsTester.TestResponse response = new WsTester.TestResponse();
underTest.handle(request, response);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact 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.db.version;
-
-import java.util.Date;
-import javax.annotation.CheckForNull;
-
-public interface DatabaseMigration {
- enum Status {
- NONE, RUNNING, FAILED, SUCCEEDED
- }
-
- /**
- * Starts the migration status and returns immediately.
- * <p>
- * Migration can not be started twice but calling this method wont raise an error.
- * On the other hand, calling this method when no migration is needed will start the process anyway.
- * </p>
- * <p>
- * <strong>This method should be named {@code start} but it can not be because it will be called by the pico container
- * and this will cause unwanted behavior</strong>
- * </p>
- */
- void startIt();
-
- /**
- * The time and day the last migration was started.
- * <p>
- * If no migration was ever started, the returned date is {@code null}. This value is reset when {@link #startIt()} is
- * called.
- * </p>
- *
- * @return a {@link Date} or {@code null}
- */
- @CheckForNull
- Date startedAt();
-
- /**
- * Current status of the migration.
- */
- Status status();
-
- /**
- * The error of the last migration if it failed.
- * <p>
- * This value is reset when {@link #startIt()} is called.
- * </p>
- * @return a {@link Throwable} or {@code null}
- */
- @CheckForNull
- Throwable failureError();
-
-}