--- /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.app;
+
+public interface ProcessCommandWrapper {
+ /**
+ * Requests to the main process that SQ be restarted.
+ */
+ void requestSQRestart();
+
+ /**
+ * Notifies any listening process that the WebServer is operational.
+ */
+ void notifyOperational();
+}
--- /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.app;
+
+import java.io.File;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.process.DefaultProcessCommands;
+import org.sonar.process.ProcessCommands;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH;
+
+public class ProcessCommandWrapperImpl implements ProcessCommandWrapper {
+ private static final Logger LOG = Loggers.get(ProcessCommandWrapperImpl.class);
+
+ private final Settings settings;
+
+ public ProcessCommandWrapperImpl(Settings settings) {
+ this.settings = settings;
+ }
+
+ @Override
+ public void requestSQRestart() {
+ call(VoidMethod.ASK_FOR_RESTART);
+ }
+
+ @Override
+ public void notifyOperational() {
+ call(VoidMethod.SET_OPERATIONAL);
+ }
+
+ private void call(VoidMethod command) {
+ File shareDir = nonNullValueAsFile(PROPERTY_SHARED_PATH);
+ int processNumber = nonNullAsInt(PROPERTY_PROCESS_INDEX);
+ try (ProcessCommands commands = new DefaultProcessCommands(shareDir, processNumber, false)) {
+ command.callOn(commands);
+ } catch (Exception e) {
+ LOG.warn("Failed to close ProcessCommands", e);
+ }
+ }
+
+ private enum VoidMethod {
+ SET_OPERATIONAL() {
+ @Override
+ void callOn(ProcessCommands processCommands) {
+ processCommands.setOperational();
+ }
+ },
+ ASK_FOR_RESTART() {
+ @Override
+ void callOn(ProcessCommands processCommands) {
+ processCommands.askForRestart();
+ }
+ };
+
+ abstract void callOn(ProcessCommands processCommands);
+ }
+
+ private int nonNullAsInt(String key) {
+ String s = settings.getString(key);
+ checkArgument(s != null, "Property %s is not set", key);
+ return Integer.parseInt(s);
+ }
+
+ public File nonNullValueAsFile(String key) {
+ String s = settings.getString(key);
+ checkArgument(s != null, "Property %s is not set", key);
+ return new File(s);
+ }
+}
import org.sonar.db.semaphore.SemaphoresImpl;
import org.sonar.db.version.DatabaseVersion;
import org.sonar.db.version.MigrationStepModule;
+import org.sonar.server.app.ProcessCommandWrapperImpl;
import org.sonar.server.computation.property.CePropertyDefinitions;
import org.sonar.server.db.EmbeddedDatabaseFactory;
import org.sonar.server.issue.index.IssueIndex;
addExtraRootComponents();
add(
new SonarQubeVersionProvider(),
+ ProcessCommandWrapperImpl.class,
ServerSettings.class,
ServerImpl.class,
UuidFactoryImpl.INSTANCE,
*/
package org.sonar.server.platform.ws;
-import java.io.File;
import org.sonar.api.config.Settings;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.web.UserRole;
-import org.sonar.process.DefaultProcessCommands;
-import org.sonar.process.ProcessCommands;
+import org.sonar.server.app.ProcessCommandWrapper;
import org.sonar.server.platform.Platform;
import org.sonar.server.user.UserSession;
-import static com.google.common.base.Preconditions.checkArgument;
-
/**
* Implementation of the {@code restart} action for the System WebService.
*/
public class RestartAction implements SystemWsAction {
private static final Logger LOGGER = Loggers.get(RestartAction.class);
- private static final String PROPERTY_SHARED_PATH = "process.sharedDir";
- private static final String PROPERTY_PROCESS_INDEX = "process.index";
private final UserSession userSession;
private final Settings settings;
private final Platform platform;
+ private final ProcessCommandWrapper processCommandWrapper;
- public RestartAction(UserSession userSession, Settings settings, Platform platform) {
+ public RestartAction(UserSession userSession, Settings settings, Platform platform, ProcessCommandWrapper processCommandWrapper) {
this.userSession = userSession;
this.settings = settings;
this.platform = platform;
+ this.processCommandWrapper = processCommandWrapper;
}
@Override
} else {
userSession.checkPermission(UserRole.ADMIN);
LOGGER.info("SonarQube restart requested by {}", userSession.getLogin());
-
- File shareDir = nonNullValueAsFile(PROPERTY_SHARED_PATH);
- int processNumber = nonNullAsInt(PROPERTY_PROCESS_INDEX);
- try (ProcessCommands commands = new DefaultProcessCommands(shareDir, processNumber, false)) {
- commands.askForRestart();
- } catch (Exception e) {
- LOGGER.warn("Failed to close ProcessCommands", e);
- }
+ processCommandWrapper.requestSQRestart();
}
response.noContent();
}
- private int nonNullAsInt(String key) {
- String s = settings.getString(key);
- checkArgument(s != null, "Property %s is not set", key);
- return Integer.parseInt(s);
- }
-
- public File nonNullValueAsFile(String key) {
- String s = settings.getString(key);
- checkArgument(s != null, "Property %s is not set", key);
- return new File(s);
- }
-
}
--- /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.app;
+
+import java.io.File;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.config.Settings;
+import org.sonar.process.DefaultProcessCommands;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH;
+
+public class ProcessCommandWrapperImplTest {
+ private static final int PROCESS_NUMBER = 2;
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private Settings settings = new Settings();
+
+ @Test
+ public void requestSQRestart_throws_IAE_if_process_sharedDir_property_not_set() throws Exception {
+ ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Property process.sharedDir is not set");
+
+ processCommandWrapper.requestSQRestart();
+ }
+
+ @Test
+ public void requestSQRestart_throws_IAE_if_process_index_property_not_set() throws Exception {
+ settings.setProperty(PROPERTY_SHARED_PATH, temp.newFolder().getAbsolutePath());
+ ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Property process.index is not set");
+
+ processCommandWrapper.requestSQRestart();
+ }
+
+ @Test
+ public void requestSQRestart_updates_shareMemory_file() throws Exception {
+ File tmpDir = temp.newFolder().getAbsoluteFile();
+ settings.setProperty(PROPERTY_SHARED_PATH, tmpDir.getAbsolutePath());
+ settings.setProperty(PROPERTY_PROCESS_INDEX, PROCESS_NUMBER);
+
+ ProcessCommandWrapperImpl underTest = new ProcessCommandWrapperImpl(settings);
+ underTest.requestSQRestart();
+
+ try (DefaultProcessCommands processCommands = new DefaultProcessCommands(tmpDir, PROCESS_NUMBER, false)) {
+ assertThat(processCommands.askedForRestart()).isTrue();
+ }
+ }
+
+ @Test
+ public void notifyOperational_throws_IAE_if_process_sharedDir_property_not_set() throws Exception {
+ ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Property process.sharedDir is not set");
+
+ processCommandWrapper.notifyOperational();
+ }
+
+ @Test
+ public void notifyOperational_throws_IAE_if_process_index_property_not_set() throws Exception {
+ settings.setProperty(PROPERTY_SHARED_PATH, temp.newFolder().getAbsolutePath());
+ ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Property process.index is not set");
+
+ processCommandWrapper.notifyOperational();
+ }
+
+ @Test
+ public void notifyOperational_updates_shareMemory_file() throws Exception {
+ File tmpDir = temp.newFolder().getAbsoluteFile();
+ settings.setProperty(PROPERTY_SHARED_PATH, tmpDir.getAbsolutePath());
+ settings.setProperty(PROPERTY_PROCESS_INDEX, PROCESS_NUMBER);
+
+ ProcessCommandWrapperImpl underTest = new ProcessCommandWrapperImpl(settings);
+ underTest.notifyOperational();
+
+ try (DefaultProcessCommands processCommands = new DefaultProcessCommands(tmpDir, PROCESS_NUMBER, false)) {
+ assertThat(processCommands.isOperational()).isTrue();
+ }
+ }
+
+}
*/
package org.sonar.server.platform.ws;
-import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.api.web.UserRole;
-import org.sonar.process.DefaultProcessCommands;
+import org.sonar.server.app.ProcessCommandWrapper;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.platform.Platform;
import org.sonar.server.tester.UserSessionRule;
@Rule
public LogTester logTester = new LogTester();
- Settings settings = new Settings();
- Platform platform = mock(Platform.class);
- RestartAction sut = new RestartAction(userSessionRule, settings, platform);
- WsActionTester actionTester = new WsActionTester(sut);
+ private Settings settings = new Settings();
+ private Platform platform = mock(Platform.class);
+ private ProcessCommandWrapper processCommandWrapper = mock(ProcessCommandWrapper.class);
+ private RestartAction sut = new RestartAction(userSessionRule, settings, platform, processCommandWrapper);
+ private WsActionTester actionTester = new WsActionTester(sut);
@Test
public void restart_if_dev_mode() throws Exception {
}
@Test
- public void fail_process_sharedDir_property_not_set_in_production_mode() throws Exception {
+ public void calls_ProcessCommandWrapper_requestForSQRestart_in_production_mode() throws Exception {
userSessionRule.login().setGlobalPermissions(UserRole.ADMIN);
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Property process.sharedDir is not set");
-
- actionTester.newRequest().execute();
- }
-
- @Test
- public void fail_process_index_property_not_set_in_production_mode() throws Exception {
- userSessionRule.login().setGlobalPermissions(UserRole.ADMIN);
- settings.setProperty("process.sharedDir", temp.newFolder().getAbsolutePath());
-
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Property process.index is not set");
-
- actionTester.newRequest().execute();
- }
-
- @Test
- public void askForRestart_in_shared_memory_in_production_mode() throws Exception {
- int processNumber = 2;
- File tempFolder = temp.newFolder().getAbsoluteFile();
-
- userSessionRule.login().setGlobalPermissions(UserRole.ADMIN);
- settings.setProperty("process.sharedDir", tempFolder.getAbsolutePath());
- settings.setProperty("process.index", processNumber);
-
- DefaultProcessCommands processCommands = new DefaultProcessCommands(tempFolder, processNumber);
-
actionTester.newRequest().execute();
- assertThat(processCommands.askedForRestart()).isTrue();
+ verify(processCommandWrapper).requestSQRestart();
}
@Test
String login = "BigBother";
userSessionRule.login(login).setGlobalPermissions(UserRole.ADMIN);
- settings.setProperty("process.sharedDir", temp.newFolder().getAbsoluteFile().getAbsolutePath());
- settings.setProperty("process.index", 2);
actionTester.newRequest().execute();
import org.junit.Test;
import org.sonar.api.config.Settings;
import org.sonar.api.server.ws.WebService;
+import org.sonar.server.app.ProcessCommandWrapper;
import org.sonar.server.platform.Platform;
import org.sonar.server.tester.AnonymousMockUserSession;
import org.sonar.server.user.UserSession;
@Test
public void define() {
- RestartAction action1 = new RestartAction(mock(UserSession.class), mock(Settings.class), mock(Platform.class));
+ RestartAction action1 = new RestartAction(mock(UserSession.class), mock(Settings.class), mock(Platform.class), mock(ProcessCommandWrapper.class));
InfoAction action2 = new InfoAction(new AnonymousMockUserSession());
SystemWs ws = new SystemWs(action1, action2);
WebService.Context context = new WebService.Context();