@@ -24,7 +24,6 @@ import org.sonar.server.plugins.UpdateCenterClient; | |||
import org.sonar.server.plugins.UpdateCenterMatrixFactory; | |||
import org.sonar.server.updatecenter.ws.InstalledPluginsAction; | |||
import org.sonar.server.updatecenter.ws.UpdateCenterWs; | |||
import org.sonar.server.updatecenter.ws.UploadAction; | |||
public class UpdateCenterModule extends Module { | |||
@Override | |||
@@ -32,7 +31,6 @@ public class UpdateCenterModule extends Module { | |||
add( | |||
UpdateCenterClient.class, | |||
UpdateCenterMatrixFactory.class, | |||
UploadAction.class, | |||
InstalledPluginsAction.class, | |||
UpdateCenterWs.class); | |||
} |
@@ -21,6 +21,7 @@ package org.sonar.server.updatecenter.ws; | |||
import java.util.Arrays; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.server.ws.RemovedWebServiceHandler; | |||
public class UpdateCenterWs implements WebService { | |||
@@ -35,6 +36,11 @@ public class UpdateCenterWs implements WebService { | |||
NewController controller = context.createController("api/updatecenter") | |||
.setDescription("Get list of installed plugins") | |||
.setSince("2.10"); | |||
controller.createAction("upload") | |||
.setDescription("This web service is removed") | |||
.setSince("6.0") | |||
.setHandler(RemovedWebServiceHandler.INSTANCE) | |||
.setResponseExample(RemovedWebServiceHandler.INSTANCE.getResponseExample()); | |||
Arrays.stream(actions).forEach(action -> action.define(controller)); | |||
controller.done(); | |||
} |
@@ -1,78 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 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.updatecenter.ws; | |||
import java.io.File; | |||
import java.io.InputStream; | |||
import java.nio.file.Files; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.server.platform.ServerFileSystem; | |||
import org.sonar.server.user.UserSession; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; | |||
import static org.apache.commons.io.IOUtils.closeQuietly; | |||
import static org.sonar.api.server.ws.Request.Part; | |||
public class UploadAction implements UpdateCenterWsAction { | |||
public static final String PARAM_FILE = "file"; | |||
private final UserSession userSession; | |||
private final File downloadDir; | |||
public UploadAction(UserSession userSession, ServerFileSystem fileSystem) { | |||
this.userSession = userSession; | |||
this.downloadDir = fileSystem.getDownloadedPluginsDir(); | |||
} | |||
@Override | |||
public void define(WebService.NewController context) { | |||
WebService.NewAction action = context.createAction("upload") | |||
.setDescription("Upload a plugin.<br /> Requires 'Administer System' permission.") | |||
.setSince("6.0") | |||
.setPost(true) | |||
.setInternal(true) | |||
.setHandler(this); | |||
action.createParam(PARAM_FILE) | |||
.setDescription("The jar file of the plugin to install") | |||
.setRequired(true); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
userSession.checkIsSystemAdministrator(); | |||
Part part = request.mandatoryParamAsPart(PARAM_FILE); | |||
String fileName = part.getFileName(); | |||
checkArgument(fileName.endsWith(".jar"), "Only jar file is allowed"); | |||
InputStream inputStream = part.getInputStream(); | |||
try { | |||
File destPlugin = new File(downloadDir, fileName); | |||
Files.copy(inputStream, destPlugin.toPath(), REPLACE_EXISTING); | |||
response.noContent(); | |||
} finally { | |||
closeQuietly(inputStream); | |||
} | |||
} | |||
} |
@@ -29,6 +29,6 @@ public class UpdateCenterModuleTest { | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new UpdateCenterModule().configure(container); | |||
assertThat(container.size()).isEqualTo(2 + 5); | |||
assertThat(container.size()).isGreaterThan(2); | |||
} | |||
} |
@@ -22,11 +22,9 @@ package org.sonar.server.updatecenter.ws; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.server.platform.ServerFileSystem; | |||
import org.sonar.server.ws.WsTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
public class UpdateCenterWsTest { | |||
@@ -34,7 +32,7 @@ public class UpdateCenterWsTest { | |||
@Before | |||
public void setUp() { | |||
tester = new WsTester(new UpdateCenterWs(new UploadAction(null, mock(ServerFileSystem.class)))); | |||
tester = new WsTester(new UpdateCenterWs(new InstalledPluginsAction(null))); | |||
} | |||
@Test | |||
@@ -43,18 +41,18 @@ public class UpdateCenterWsTest { | |||
assertThat(controller).isNotNull(); | |||
assertThat(controller.since()).isEqualTo("2.10"); | |||
assertThat(controller.description()).isNotEmpty(); | |||
assertThat(controller.actions()).hasSize(1); | |||
assertThat(controller.actions()).hasSize(2); | |||
} | |||
@Test | |||
public void define_upload_action() { | |||
public void define_installed_plugins_action() { | |||
WebService.Controller controller = tester.controller("api/updatecenter"); | |||
WebService.Action action = controller.action("upload"); | |||
WebService.Action action = controller.action("installed_plugins"); | |||
assertThat(action).isNotNull(); | |||
assertThat(action.handler()).isNotNull(); | |||
assertThat(action.isInternal()).isTrue(); | |||
assertThat(action.isPost()).isTrue(); | |||
assertThat(action.isPost()).isFalse(); | |||
assertThat(action.params()).hasSize(1); | |||
} | |||
} |
@@ -1,147 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 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.updatecenter.ws; | |||
import java.io.File; | |||
import java.io.InputStream; | |||
import java.nio.channels.ClosedChannelException; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.platform.ServerFileSystem; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.TestResponse; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static java.nio.file.Files.newInputStream; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.test.ExceptionCauseMatcher.hasType; | |||
public class UploadActionTest { | |||
private static final String PLUGIN_NAME = "plugin.jar"; | |||
@Rule | |||
public TemporaryFolder folder = new TemporaryFolder(); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
private ServerFileSystem fileSystem = mock(ServerFileSystem.class); | |||
private File pluginDirectory; | |||
private File plugin = new File(getClass().getResource("UploadActionTest/plugin.jar").getFile()); | |||
private WsActionTester wsTester; | |||
@Before | |||
public void setUp() throws Exception { | |||
pluginDirectory = folder.newFolder(); | |||
when(fileSystem.getDownloadedPluginsDir()).thenReturn(pluginDirectory); | |||
wsTester = new WsActionTester(new UploadAction(userSession, fileSystem)); | |||
} | |||
@Test | |||
public void upload_plugin() throws Exception { | |||
logInAsSystemAdministrator(); | |||
TestResponse response = call(newInputStream(plugin.toPath()), PLUGIN_NAME); | |||
assertThat(response.getStatus()).isEqualTo(204); | |||
assertPluginIsUploaded(PLUGIN_NAME); | |||
} | |||
@Test | |||
public void erase_existing_plugin_if_already_exists() throws Exception { | |||
logInAsSystemAdministrator(); | |||
File plugin1 = new File(getClass().getResource("UploadActionTest/plugin.jar").getFile()); | |||
call(newInputStream(plugin1.toPath()), PLUGIN_NAME); | |||
File plugin2 = new File(getClass().getResource("UploadActionTest/anotherPlugin.jar").getFile()); | |||
call(newInputStream(plugin2.toPath()), PLUGIN_NAME); | |||
File result = new File(pluginDirectory, PLUGIN_NAME); | |||
assertThat(result.exists()).isTrue(); | |||
assertThat(result.length()).isNotEqualTo(plugin1.length()).isEqualTo(plugin2.length()); | |||
} | |||
@Test | |||
public void fail_when_plugin_extension_is_not_jar() throws Exception { | |||
logInAsSystemAdministrator(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Only jar file is allowed"); | |||
call(newInputStream(plugin.toPath()), "plugin.zip"); | |||
} | |||
@Test | |||
public void fail_when_no_files_param() { | |||
logInAsSystemAdministrator(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'file' parameter is missing"); | |||
wsTester.newRequest().execute(); | |||
} | |||
@Test | |||
public void input_stream_should_be_closed() throws Exception { | |||
logInAsSystemAdministrator(); | |||
InputStream inputStream = newInputStream(plugin.toPath()); | |||
call(inputStream, PLUGIN_NAME); | |||
// As the same InputStream is used, it will fail as it should have been called during the first execution of the WS | |||
expectedException.expectCause(hasType(ClosedChannelException.class)); | |||
call(inputStream, PLUGIN_NAME); | |||
} | |||
@Test | |||
public void throw_ForbiddenException_if_not_system_administrator() throws Exception { | |||
userSession.logIn().setNonSystemAdministrator(); | |||
expectedException.expect(ForbiddenException.class); | |||
expectedException.expectMessage("Insufficient privileges"); | |||
call(newInputStream(plugin.toPath()), PLUGIN_NAME); | |||
} | |||
private TestResponse call(InputStream inputStream, String fileName) { | |||
return wsTester.newRequest() | |||
.setPart("file", inputStream, fileName) | |||
.execute(); | |||
} | |||
private void logInAsSystemAdministrator() { | |||
userSession.logIn().setSystemAdministrator(); | |||
} | |||
private void assertPluginIsUploaded(String pluginName) { | |||
File result = new File(pluginDirectory, pluginName); | |||
assertThat(result.exists()).isTrue(); | |||
} | |||
} |