mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 17:26:22 +01:00
Merged in feature/abort_plugin_installation (pull request #326)
Feature/abort plugin installation
This commit is contained in:
@@ -34,11 +34,8 @@ import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -74,12 +71,12 @@ class PendingPluginResourceTest {
|
||||
void mockMapper() {
|
||||
lenient().when(mapper.mapAvailable(any())).thenAnswer(invocation -> {
|
||||
PluginDto dto = new PluginDto();
|
||||
dto.setName(((AvailablePlugin)invocation.getArgument(0)).getDescriptor().getInformation().getName());
|
||||
dto.setName(((AvailablePlugin) invocation.getArgument(0)).getDescriptor().getInformation().getName());
|
||||
return dto;
|
||||
});
|
||||
lenient().when(mapper.mapInstalled(any(), any())).thenAnswer(invocation -> {
|
||||
PluginDto dto = new PluginDto();
|
||||
dto.setName(((InstalledPlugin)invocation.getArgument(0)).getDescriptor().getInformation().getName());
|
||||
dto.setName(((InstalledPlugin) invocation.getArgument(0)).getDescriptor().getInformation().getName());
|
||||
return dto;
|
||||
});
|
||||
}
|
||||
@@ -90,7 +87,7 @@ class PendingPluginResourceTest {
|
||||
@BeforeEach
|
||||
void bindSubject() {
|
||||
ThreadContext.bind(subject);
|
||||
doNothing().when(subject).checkPermission("plugin:manage");
|
||||
lenient().when(subject.isPermitted("plugin:manage")).thenReturn(true);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -113,7 +110,7 @@ class PendingPluginResourceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGetPendingAvailablePluginListWithInstallLink() throws URISyntaxException, UnsupportedEncodingException {
|
||||
void shouldGetPendingAvailablePluginListWithInstallAndCancelLink() throws URISyntaxException, UnsupportedEncodingException {
|
||||
AvailablePlugin availablePlugin = createAvailablePlugin("pending-available-plugin");
|
||||
when(availablePlugin.isPending()).thenReturn(true);
|
||||
when(pluginManager.getAvailable()).thenReturn(singletonList(availablePlugin));
|
||||
@@ -124,6 +121,7 @@ class PendingPluginResourceTest {
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
assertThat(response.getContentAsString()).contains("\"new\":[{\"name\":\"pending-available-plugin\"");
|
||||
assertThat(response.getContentAsString()).contains("\"execute\":{\"href\":\"/v2/plugins/pending/execute\"}");
|
||||
assertThat(response.getContentAsString()).contains("\"cancel\":{\"href\":\"/v2/plugins/pending/cancel\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -166,6 +164,17 @@ class PendingPluginResourceTest {
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
verify(pluginManager).executePendingAndRestart();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCancelPendingPlugins() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/pending/cancel");
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
verify(pluginManager).cancelPending();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -174,7 +183,7 @@ class PendingPluginResourceTest {
|
||||
@BeforeEach
|
||||
void bindSubject() {
|
||||
ThreadContext.bind(subject);
|
||||
doThrow(new ShiroException()).when(subject).checkPermission("plugin:manage");
|
||||
when(subject.isPermitted("plugin:manage")).thenReturn(false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -183,23 +192,18 @@ class PendingPluginResourceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotListPendingPlugins() throws URISyntaxException {
|
||||
void shouldGetPendingAvailablePluginListWithoutInstallAndCancelLink() throws URISyntaxException, UnsupportedEncodingException {
|
||||
AvailablePlugin availablePlugin = createAvailablePlugin("pending-available-plugin");
|
||||
when(availablePlugin.isPending()).thenReturn(true);
|
||||
when(pluginManager.getAvailable()).thenReturn(singletonList(availablePlugin));
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/pending");
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
verify(pluginManager, never()).executePendingAndRestart();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotExecutePendingPlugins() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/pending/execute");
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
verify(pluginManager, never()).executePendingAndRestart();
|
||||
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
|
||||
assertThat(response.getContentAsString()).contains("\"new\":[{\"name\":\"pending-available-plugin\"");
|
||||
assertThat(response.getContentAsString()).doesNotContain("\"execute\":{\"href\":\"/v2/plugins/pending/execute\"}");
|
||||
assertThat(response.getContentAsString()).doesNotContain("\"cancel\":{\"href\":\"/v2/plugins/pending/cancel\"}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,15 +10,19 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.plugin.AvailablePlugin;
|
||||
import sonia.scm.plugin.AvailablePluginDescriptor;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
import sonia.scm.plugin.InstalledPluginDescriptor;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginManager;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -34,6 +38,9 @@ class PluginDtoCollectionMapperTest {
|
||||
@InjectMocks
|
||||
PluginDtoMapperImpl pluginDtoMapper;
|
||||
|
||||
@Mock
|
||||
PluginManager manager;
|
||||
|
||||
Subject subject = mock(Subject.class);
|
||||
ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||
|
||||
@@ -43,6 +50,11 @@ class PluginDtoCollectionMapperTest {
|
||||
ThreadContext.bind(subject);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void mockPluginManager() {
|
||||
lenient().when(manager.getUpdatable()).thenReturn(new ArrayList<>());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void unbindSubject() {
|
||||
ThreadContext.unbindSubject();
|
||||
@@ -51,7 +63,7 @@ class PluginDtoCollectionMapperTest {
|
||||
|
||||
@Test
|
||||
void shouldMapInstalledPluginsWithoutUpdateWhenNoNewerVersionIsAvailable() {
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager);
|
||||
|
||||
HalRepresentation result = mapper.mapInstalled(
|
||||
singletonList(createInstalledPlugin("scm-some-plugin", "1")),
|
||||
@@ -66,7 +78,7 @@ class PluginDtoCollectionMapperTest {
|
||||
|
||||
@Test
|
||||
void shouldSetNewVersionInInstalledPluginWhenAvailableVersionIsNewer() {
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper,manager);
|
||||
|
||||
HalRepresentation result = mapper.mapInstalled(
|
||||
singletonList(createInstalledPlugin("scm-some-plugin", "1")),
|
||||
@@ -80,7 +92,7 @@ class PluginDtoCollectionMapperTest {
|
||||
@Test
|
||||
void shouldNotAddInstallLinkForNewVersionWhenNotPermitted() {
|
||||
when(subject.isPermitted("plugin:manage")).thenReturn(false);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager);
|
||||
|
||||
HalRepresentation result = mapper.mapInstalled(
|
||||
singletonList(createInstalledPlugin("scm-some-plugin", "1")),
|
||||
@@ -93,7 +105,7 @@ class PluginDtoCollectionMapperTest {
|
||||
@Test
|
||||
void shouldNotAddInstallLinkForNewVersionWhenInstallationIsPending() {
|
||||
when(subject.isPermitted("plugin:manage")).thenReturn(true);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager);
|
||||
|
||||
AvailablePlugin availablePlugin = createAvailablePlugin("scm-some-plugin", "2");
|
||||
when(availablePlugin.isPending()).thenReturn(true);
|
||||
@@ -108,7 +120,7 @@ class PluginDtoCollectionMapperTest {
|
||||
@Test
|
||||
void shouldAddInstallLinkForNewVersionWhenPermitted() {
|
||||
when(subject.isPermitted("plugin:manage")).thenReturn(true);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager);
|
||||
|
||||
HalRepresentation result = mapper.mapInstalled(
|
||||
singletonList(createInstalledPlugin("scm-some-plugin", "1")),
|
||||
@@ -121,7 +133,7 @@ class PluginDtoCollectionMapperTest {
|
||||
@Test
|
||||
void shouldSetInstalledPluginPendingWhenCorrespondingAvailablePluginIsPending() {
|
||||
when(subject.isPermitted("plugin:manage")).thenReturn(true);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper);
|
||||
PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper, manager);
|
||||
|
||||
AvailablePlugin availablePlugin = createAvailablePlugin("scm-some-plugin", "2");
|
||||
when(availablePlugin.isPending()).thenReturn(true);
|
||||
|
||||
@@ -20,6 +20,8 @@ import sonia.scm.ScmConstraintViolationException;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.lifecycle.RestartEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -30,11 +32,13 @@ import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static sonia.scm.plugin.PluginTestHelper.createAvailable;
|
||||
@@ -358,6 +362,24 @@ class DefaultPluginManagerTest {
|
||||
verify(mailPlugin).setMarkedForUninstall(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotChangeStateWhenUninstallFileCouldNotBeCreated() {
|
||||
InstalledPlugin mailPlugin = createInstalled("scm-mail-plugin");
|
||||
InstalledPlugin reviewPlugin = createInstalled("scm-review-plugin");
|
||||
when(reviewPlugin.getDescriptor().getDependencies()).thenReturn(singleton("scm-mail-plugin"));
|
||||
|
||||
when(reviewPlugin.getDirectory()).thenThrow(new PluginException("when the file could not be written an exception like this is thrown"));
|
||||
|
||||
when(loader.getInstalledPlugins()).thenReturn(asList(mailPlugin, reviewPlugin));
|
||||
|
||||
manager.computeInstallationDependencies();
|
||||
|
||||
assertThrows(PluginException.class, () -> manager.uninstall("scm-review-plugin", false));
|
||||
|
||||
verify(mailPlugin, never()).setMarkedForUninstall(true);
|
||||
assertThrows(ScmConstraintViolationException.class, () -> manager.uninstall("scm-mail-plugin", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionWhenUninstallingCorePlugin(@TempDirectory.TempDir Path temp) {
|
||||
InstalledPlugin mailPlugin = createInstalled("scm-mail-plugin");
|
||||
@@ -427,6 +449,71 @@ class DefaultPluginManagerTest {
|
||||
|
||||
verify(eventBus).post(any(RestartEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUndoPendingInstallations(@TempDirectory.TempDir Path temp) throws IOException {
|
||||
InstalledPlugin mailPlugin = createInstalled("scm-ssh-plugin");
|
||||
Path mailPluginPath = temp.resolve("scm-mail-plugin");
|
||||
Files.createDirectories(mailPluginPath);
|
||||
when(mailPlugin.getDirectory()).thenReturn(mailPluginPath);
|
||||
when(loader.getInstalledPlugins()).thenReturn(singletonList(mailPlugin));
|
||||
ArgumentCaptor<Boolean> uninstallCaptor = ArgumentCaptor.forClass(Boolean.class);
|
||||
doNothing().when(mailPlugin).setMarkedForUninstall(uninstallCaptor.capture());
|
||||
|
||||
AvailablePlugin git = createAvailable("scm-git-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(git));
|
||||
PendingPluginInstallation gitPendingPluginInformation = mock(PendingPluginInstallation.class);
|
||||
when(installer.install(git)).thenReturn(gitPendingPluginInformation);
|
||||
|
||||
manager.install("scm-git-plugin", false);
|
||||
manager.uninstall("scm-ssh-plugin", false);
|
||||
|
||||
manager.cancelPending();
|
||||
|
||||
assertThat(mailPluginPath.resolve("uninstall")).doesNotExist();
|
||||
verify(gitPendingPluginInformation).cancel();
|
||||
Boolean lasUninstallMarkerSet = uninstallCaptor.getAllValues().get(uninstallCaptor.getAllValues().size() - 1);
|
||||
assertThat(lasUninstallMarkerSet).isFalse();
|
||||
|
||||
Files.createFile(mailPluginPath.resolve("uninstall"));
|
||||
|
||||
manager.cancelPending();
|
||||
verify(gitPendingPluginInformation, times(1)).cancel();
|
||||
assertThat(mailPluginPath.resolve("uninstall")).exists();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUpdateAllPlugins() {
|
||||
InstalledPlugin mailPlugin = createInstalled("scm-mail-plugin");
|
||||
InstalledPlugin reviewPlugin = createInstalled("scm-review-plugin");
|
||||
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(mailPlugin, reviewPlugin));
|
||||
|
||||
AvailablePlugin newMailPlugin = createAvailable("scm-mail-plugin", "2.0.0");
|
||||
AvailablePlugin newReviewPlugin = createAvailable("scm-review-plugin", "2.0.0");
|
||||
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(newMailPlugin, newReviewPlugin));
|
||||
|
||||
manager.updateAll();
|
||||
|
||||
verify(installer).install(newMailPlugin);
|
||||
verify(installer).install(newReviewPlugin);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void shouldNotUpdateToOldPluginVersions() {
|
||||
InstalledPlugin scriptPlugin = createInstalled("scm-script-plugin");
|
||||
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(scriptPlugin));
|
||||
AvailablePlugin oldScriptPlugin = createAvailable("scm-script-plugin", "0.9");
|
||||
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(oldScriptPlugin));
|
||||
|
||||
manager.updateAll();
|
||||
|
||||
verify(installer, never()).install(oldScriptPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -482,5 +569,14 @@ class DefaultPluginManagerTest {
|
||||
assertThrows(AuthorizationException.class, () -> manager.executePendingAndRestart());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAuthorizationExceptionsForCancelPending() {
|
||||
assertThrows(AuthorizationException.class, () -> manager.cancelPending());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAuthorizationExceptionsForUpdateAll() {
|
||||
assertThrows(AuthorizationException.class, () -> manager.updateAll());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,13 @@ public class PluginTestHelper {
|
||||
return createAvailable(information);
|
||||
}
|
||||
|
||||
public static AvailablePlugin createAvailable(String name, String version) {
|
||||
PluginInformation information = new PluginInformation();
|
||||
information.setName(name);
|
||||
information.setVersion(version);
|
||||
return createAvailable(information);
|
||||
}
|
||||
|
||||
public static InstalledPlugin createInstalled(String name) {
|
||||
PluginInformation information = new PluginInformation();
|
||||
information.setName(name);
|
||||
|
||||
Reference in New Issue
Block a user