mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 17:26:22 +01:00
Merged in feature/install_plugins (pull request #299)
Feature/install plugins
This commit is contained in:
@@ -16,9 +16,11 @@ 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.PluginCondition;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginManager;
|
||||
import sonia.scm.plugin.PluginState;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Provider;
|
||||
@@ -27,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -87,10 +90,10 @@ class AvailablePluginResourceTest {
|
||||
|
||||
@Test
|
||||
void getAvailablePlugins() throws URISyntaxException, UnsupportedEncodingException {
|
||||
PluginInformation pluginInformation = new PluginInformation();
|
||||
pluginInformation.setState(PluginState.AVAILABLE);
|
||||
when(pluginManager.getAvailable()).thenReturn(Collections.singletonList(pluginInformation));
|
||||
when(collectionMapper.map(Collections.singletonList(pluginInformation))).thenReturn(new MockedResultDto());
|
||||
AvailablePlugin plugin = createPlugin();
|
||||
|
||||
when(pluginManager.getAvailable()).thenReturn(Collections.singletonList(plugin));
|
||||
when(collectionMapper.mapAvailable(Collections.singletonList(plugin))).thenReturn(new MockedResultDto());
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available");
|
||||
request.accept(VndMediaType.PLUGIN_COLLECTION);
|
||||
@@ -105,16 +108,18 @@ class AvailablePluginResourceTest {
|
||||
@Test
|
||||
void getAvailablePlugin() throws UnsupportedEncodingException, URISyntaxException {
|
||||
PluginInformation pluginInformation = new PluginInformation();
|
||||
pluginInformation.setState(PluginState.AVAILABLE);
|
||||
pluginInformation.setName("pluginName");
|
||||
pluginInformation.setVersion("2.0.0");
|
||||
when(pluginManager.getAvailable()).thenReturn(Collections.singletonList(pluginInformation));
|
||||
|
||||
AvailablePlugin plugin = createPlugin(pluginInformation);
|
||||
|
||||
when(pluginManager.getAvailable("pluginName")).thenReturn(Optional.of(plugin));
|
||||
|
||||
PluginDto pluginDto = new PluginDto();
|
||||
pluginDto.setName("pluginName");
|
||||
when(mapper.map(pluginInformation)).thenReturn(pluginDto);
|
||||
when(mapper.mapAvailable(plugin)).thenReturn(pluginDto);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available/pluginName/2.0.0");
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available/pluginName");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
@@ -126,15 +131,36 @@ class AvailablePluginResourceTest {
|
||||
|
||||
@Test
|
||||
void installPlugin() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/pluginName/2.0.0/install");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/pluginName/install");
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
verify(pluginManager).install("pluginName:2.0.0");
|
||||
verify(pluginManager).install("pluginName", false);
|
||||
assertThat(HttpServletResponse.SC_OK).isEqualTo(response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void installPendingPlugin() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/install-pending");
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
dispatcher.invoke(request, response);
|
||||
|
||||
verify(pluginManager).installPendingAndRestart();
|
||||
assertThat(HttpServletResponse.SC_OK).isEqualTo(response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
private AvailablePlugin createPlugin() {
|
||||
return createPlugin(new PluginInformation());
|
||||
}
|
||||
|
||||
private AvailablePlugin createPlugin(PluginInformation pluginInformation) {
|
||||
AvailablePluginDescriptor descriptor = new AvailablePluginDescriptor(
|
||||
pluginInformation, new PluginCondition(), Collections.emptySet(), "https://download.hitchhiker.com", null
|
||||
);
|
||||
return new AvailablePlugin(descriptor);
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -156,7 +182,7 @@ class AvailablePluginResourceTest {
|
||||
|
||||
@Test
|
||||
void shouldNotGetAvailablePluginIfMissingPermission() throws URISyntaxException {
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available/pluginName/2.0.0");
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/available/pluginName");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
@@ -166,7 +192,7 @@ class AvailablePluginResourceTest {
|
||||
@Test
|
||||
void shouldNotInstallPluginIfMissingPermission() throws URISyntaxException {
|
||||
ThreadContext.unbindSubject();
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/pluginName/2.0.0/install");
|
||||
MockHttpRequest request = MockHttpRequest.post("/v2/plugins/available/pluginName/install");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
|
||||
|
||||
@@ -16,11 +16,10 @@ 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.Plugin;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
import sonia.scm.plugin.InstalledPluginDescriptor;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.plugin.PluginState;
|
||||
import sonia.scm.plugin.PluginWrapper;
|
||||
import sonia.scm.plugin.PluginManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Provider;
|
||||
@@ -28,12 +27,12 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class InstalledPluginResourceTest {
|
||||
@@ -46,15 +45,15 @@ class InstalledPluginResourceTest {
|
||||
@Mock
|
||||
Provider<AvailablePluginResource> availablePluginResourceProvider;
|
||||
|
||||
@Mock
|
||||
private PluginLoader pluginLoader;
|
||||
|
||||
@Mock
|
||||
private PluginDtoCollectionMapper collectionMapper;
|
||||
|
||||
@Mock
|
||||
private PluginDtoMapper mapper;
|
||||
|
||||
@Mock
|
||||
private PluginManager pluginManager;
|
||||
|
||||
@InjectMocks
|
||||
InstalledPluginResource installedPluginResource;
|
||||
|
||||
@@ -86,9 +85,9 @@ class InstalledPluginResourceTest {
|
||||
|
||||
@Test
|
||||
void getInstalledPlugins() throws URISyntaxException, UnsupportedEncodingException {
|
||||
PluginWrapper pluginWrapper = new PluginWrapper(null, null, null, null);
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Collections.singletonList(pluginWrapper));
|
||||
when(collectionMapper.map(Collections.singletonList(pluginWrapper))).thenReturn(new MockedResultDto());
|
||||
InstalledPlugin installedPlugin = createPlugin();
|
||||
when(pluginManager.getInstalled()).thenReturn(Collections.singletonList(installedPlugin));
|
||||
when(collectionMapper.mapInstalled(Collections.singletonList(installedPlugin))).thenReturn(new MockedResultDto());
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/installed");
|
||||
request.accept(VndMediaType.PLUGIN_COLLECTION);
|
||||
@@ -105,14 +104,13 @@ class InstalledPluginResourceTest {
|
||||
PluginInformation pluginInformation = new PluginInformation();
|
||||
pluginInformation.setVersion("2.0.0");
|
||||
pluginInformation.setName("pluginName");
|
||||
pluginInformation.setState(PluginState.INSTALLED);
|
||||
Plugin plugin = new Plugin(2, pluginInformation, null, null, false, null);
|
||||
PluginWrapper pluginWrapper = new PluginWrapper(plugin, null, null, null);
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Collections.singletonList(pluginWrapper));
|
||||
InstalledPlugin installedPlugin = createPlugin(pluginInformation);
|
||||
|
||||
when(pluginManager.getInstalled("pluginName")).thenReturn(Optional.of(installedPlugin));
|
||||
|
||||
PluginDto pluginDto = new PluginDto();
|
||||
pluginDto.setName("pluginName");
|
||||
when(mapper.map(pluginWrapper)).thenReturn(pluginDto);
|
||||
when(mapper.mapInstalled(installedPlugin)).thenReturn(pluginDto);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/plugins/installed/pluginName");
|
||||
request.accept(VndMediaType.PLUGIN);
|
||||
@@ -125,6 +123,18 @@ class InstalledPluginResourceTest {
|
||||
}
|
||||
}
|
||||
|
||||
private InstalledPlugin createPlugin() {
|
||||
return createPlugin(new PluginInformation());
|
||||
}
|
||||
|
||||
private InstalledPlugin createPlugin(PluginInformation information) {
|
||||
InstalledPlugin plugin = mock(InstalledPlugin.class);
|
||||
InstalledPluginDescriptor descriptor = mock(InstalledPluginDescriptor.class);
|
||||
lenient().when(descriptor.getInformation()).thenReturn(information);
|
||||
lenient().when(plugin.getDescriptor()).thenReturn(descriptor);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithoutAuthorization {
|
||||
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.util.ThreadContext;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Answers;
|
||||
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.PluginInformation;
|
||||
import sonia.scm.plugin.PluginState;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PluginDtoMapperTest {
|
||||
@@ -21,11 +31,25 @@ class PluginDtoMapperTest {
|
||||
@InjectMocks
|
||||
private PluginDtoMapperImpl mapper;
|
||||
|
||||
@Mock
|
||||
private Subject subject;
|
||||
|
||||
@BeforeEach
|
||||
void bindSubject() {
|
||||
ThreadContext.bind(subject);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void unbindSubject() {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMapInformation() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
PluginDto dto = new PluginDto();
|
||||
mapper.map(information, dto);
|
||||
|
||||
assertThat(dto.getName()).isEqualTo("scm-cas-plugin");
|
||||
assertThat(dto.getVersion()).isEqualTo("1.0.0");
|
||||
@@ -48,41 +72,76 @@ class PluginDtoMapperTest {
|
||||
|
||||
@Test
|
||||
void shouldAppendInstalledSelfLink() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
information.setState(PluginState.INSTALLED);
|
||||
InstalledPlugin plugin = createInstalled();
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
PluginDto dto = mapper.mapInstalled(plugin);
|
||||
assertThat(dto.getLinks().getLinkBy("self").get().getHref())
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/installed/scm-cas-plugin");
|
||||
}
|
||||
|
||||
private InstalledPlugin createInstalled(PluginInformation information) {
|
||||
InstalledPlugin plugin = mock(InstalledPlugin.class, Answers.RETURNS_DEEP_STUBS);
|
||||
when(plugin.getDescriptor().getInformation()).thenReturn(information);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAppendAvailableSelfLink() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
information.setState(PluginState.AVAILABLE);
|
||||
AvailablePlugin plugin = createAvailable();
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
PluginDto dto = mapper.mapAvailable(plugin);
|
||||
assertThat(dto.getLinks().getLinkBy("self").get().getHref())
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin/1.0.0");
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotAppendInstallLinkWithoutPermissions() {
|
||||
AvailablePlugin plugin = createAvailable();
|
||||
|
||||
PluginDto dto = mapper.mapAvailable(plugin);
|
||||
assertThat(dto.getLinks().getLinkBy("install")).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAppendInstallLink() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
information.setState(PluginState.AVAILABLE);
|
||||
when(subject.isPermitted("plugin:manage")).thenReturn(true);
|
||||
AvailablePlugin plugin = createAvailable();
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
PluginDto dto = mapper.mapAvailable(plugin);
|
||||
assertThat(dto.getLinks().getLinkBy("install").get().getHref())
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin/1.0.0/install");
|
||||
.isEqualTo("https://hitchhiker.com/v2/plugins/available/scm-cas-plugin/install");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnMiscellaneousIfCategoryIsNull() {
|
||||
PluginInformation information = createPluginInformation();
|
||||
information.setCategory(null);
|
||||
|
||||
PluginDto dto = mapper.map(information);
|
||||
AvailablePlugin plugin = createAvailable(information);
|
||||
PluginDto dto = mapper.mapAvailable(plugin);
|
||||
assertThat(dto.getCategory()).isEqualTo("Miscellaneous");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAppendDependencies() {
|
||||
AvailablePlugin plugin = createAvailable();
|
||||
when(plugin.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("one", "two"));
|
||||
|
||||
PluginDto dto = mapper.mapAvailable(plugin);
|
||||
assertThat(dto.getDependencies()).containsOnly("one", "two");
|
||||
}
|
||||
|
||||
private InstalledPlugin createInstalled() {
|
||||
return createInstalled(createPluginInformation());
|
||||
}
|
||||
|
||||
private AvailablePlugin createAvailable() {
|
||||
return createAvailable(createPluginInformation());
|
||||
}
|
||||
|
||||
private AvailablePlugin createAvailable(PluginInformation information) {
|
||||
AvailablePluginDescriptor descriptor = mock(AvailablePluginDescriptor.class);
|
||||
when(descriptor.getInformation()).thenReturn(information);
|
||||
return new AvailablePlugin(descriptor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ public class UIRootResourceTest {
|
||||
assertTrue(response.getContentAsString().contains("/scm/my/bundle.js"));
|
||||
}
|
||||
|
||||
private void mockPlugins(PluginWrapper... plugins) {
|
||||
private void mockPlugins(InstalledPlugin... plugins) {
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Lists.newArrayList(plugins));
|
||||
}
|
||||
|
||||
@@ -180,16 +180,16 @@ public class UIRootResourceTest {
|
||||
return new PluginResources(scripts, styles);
|
||||
}
|
||||
|
||||
private PluginWrapper mockPlugin(String id) {
|
||||
private InstalledPlugin mockPlugin(String id) {
|
||||
return mockPlugin(id, id, null);
|
||||
}
|
||||
|
||||
private PluginWrapper mockPlugin(String id, String name, PluginResources pluginResources) {
|
||||
PluginWrapper wrapper = mock(PluginWrapper.class);
|
||||
private InstalledPlugin mockPlugin(String id, String name, PluginResources pluginResources) {
|
||||
InstalledPlugin wrapper = mock(InstalledPlugin.class);
|
||||
when(wrapper.getId()).thenReturn(id);
|
||||
|
||||
Plugin plugin = mock(Plugin.class);
|
||||
when(wrapper.getPlugin()).thenReturn(plugin);
|
||||
InstalledPluginDescriptor plugin = mock(InstalledPluginDescriptor.class);
|
||||
when(wrapper.getDescriptor()).thenReturn(plugin);
|
||||
when(plugin.getResources()).thenReturn(pluginResources);
|
||||
|
||||
PluginInformation information = mock(PluginInformation.class);
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.util.ThreadContext;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.lifecycle.RestartEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.in;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class DefaultPluginManagerTest {
|
||||
|
||||
@Mock
|
||||
private ScmEventBus eventBus;
|
||||
|
||||
@Mock
|
||||
private PluginLoader loader;
|
||||
|
||||
@Mock
|
||||
private PluginCenter center;
|
||||
|
||||
@Mock
|
||||
private PluginInstaller installer;
|
||||
|
||||
@InjectMocks
|
||||
private DefaultPluginManager manager;
|
||||
|
||||
@Mock
|
||||
private Subject subject;
|
||||
|
||||
@BeforeEach
|
||||
void mockInstaller() {
|
||||
lenient().when(installer.install(any())).then(ic -> {
|
||||
AvailablePlugin plugin = ic.getArgument(0);
|
||||
return new PendingPluginInstallation(plugin.install(), null);
|
||||
});
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithAdminPermissions {
|
||||
|
||||
@BeforeEach
|
||||
void setUpSubject() {
|
||||
ThreadContext.bind(subject);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clearThreadContext() {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnInstalledPlugins() {
|
||||
InstalledPlugin review = createInstalled("scm-review-plugin");
|
||||
InstalledPlugin git = createInstalled("scm-git-plugin");
|
||||
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(review, git));
|
||||
|
||||
List<InstalledPlugin> installed = manager.getInstalled();
|
||||
assertThat(installed).containsOnly(review, git);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnReviewPlugin() {
|
||||
InstalledPlugin review = createInstalled("scm-review-plugin");
|
||||
InstalledPlugin git = createInstalled("scm-git-plugin");
|
||||
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(review, git));
|
||||
|
||||
Optional<InstalledPlugin> plugin = manager.getInstalled("scm-review-plugin");
|
||||
assertThat(plugin).contains(review);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyForNonInstalledPlugin() {
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of());
|
||||
|
||||
Optional<InstalledPlugin> plugin = manager.getInstalled("scm-review-plugin");
|
||||
assertThat(plugin).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnAvailablePlugins() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
AvailablePlugin git = createAvailable("scm-git-plugin");
|
||||
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git));
|
||||
|
||||
List<AvailablePlugin> available = manager.getAvailable();
|
||||
assertThat(available).containsOnly(review, git);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFilterOutAllInstalled() {
|
||||
InstalledPlugin installedGit = createInstalled("scm-git-plugin");
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit));
|
||||
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
AvailablePlugin git = createAvailable("scm-git-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git));
|
||||
|
||||
List<AvailablePlugin> available = manager.getAvailable();
|
||||
assertThat(available).containsOnly(review);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnAvailable() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
AvailablePlugin git = createAvailable("scm-git-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git));
|
||||
|
||||
Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin");
|
||||
assertThat(available).contains(git);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyForNonExistingAvailable() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
|
||||
|
||||
Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin");
|
||||
assertThat(available).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptyForInstalledPlugin() {
|
||||
InstalledPlugin installedGit = createInstalled("scm-git-plugin");
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit));
|
||||
|
||||
AvailablePlugin git = createAvailable("scm-git-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(git));
|
||||
|
||||
Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin");
|
||||
assertThat(available).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInstallThePlugin() {
|
||||
AvailablePlugin git = createAvailable("scm-git-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(git));
|
||||
|
||||
manager.install("scm-git-plugin", false);
|
||||
|
||||
verify(installer).install(git);
|
||||
verify(eventBus, never()).post(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInstallDependingPlugins() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
|
||||
AvailablePlugin mail = createAvailable("scm-mail-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail));
|
||||
|
||||
manager.install("scm-review-plugin", false);
|
||||
|
||||
verify(installer).install(mail);
|
||||
verify(installer).install(review);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotInstallAlreadyInstalledDependencies() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
|
||||
AvailablePlugin mail = createAvailable("scm-mail-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail));
|
||||
|
||||
InstalledPlugin installedMail = createInstalled("scm-mail-plugin");
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedMail));
|
||||
|
||||
manager.install("scm-review-plugin", false);
|
||||
|
||||
ArgumentCaptor<AvailablePlugin> captor = ArgumentCaptor.forClass(AvailablePlugin.class);
|
||||
verify(installer).install(captor.capture());
|
||||
|
||||
assertThat(captor.getValue().getDescriptor().getInformation().getName()).isEqualTo("scm-review-plugin");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRollbackOnFailedInstallation() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
|
||||
AvailablePlugin mail = createAvailable("scm-mail-plugin");
|
||||
when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin"));
|
||||
AvailablePlugin notification = createAvailable("scm-notification-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail, notification));
|
||||
|
||||
PendingPluginInstallation pendingNotification = mock(PendingPluginInstallation.class);
|
||||
doReturn(pendingNotification).when(installer).install(notification);
|
||||
|
||||
PendingPluginInstallation pendingMail = mock(PendingPluginInstallation.class);
|
||||
doReturn(pendingMail).when(installer).install(mail);
|
||||
|
||||
doThrow(new PluginChecksumMismatchException("checksum does not match")).when(installer).install(review);
|
||||
|
||||
assertThrows(PluginInstallException.class, () -> manager.install("scm-review-plugin", false));
|
||||
|
||||
verify(pendingNotification).cancel();
|
||||
verify(pendingMail).cancel();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInstallNothingIfOneOfTheDependenciesIsNotAvailable() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
|
||||
AvailablePlugin mail = createAvailable("scm-mail-plugin");
|
||||
when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin"));
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail));
|
||||
|
||||
assertThrows(NotFoundException.class, () -> manager.install("scm-review-plugin", false));
|
||||
|
||||
verify(installer, never()).install(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendRestartEventAfterInstallation() {
|
||||
AvailablePlugin git = createAvailable("scm-git-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(git));
|
||||
|
||||
manager.install("scm-git-plugin", true);
|
||||
|
||||
verify(installer).install(git);
|
||||
verify(eventBus).post(any(RestartEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotSendRestartEventIfNoPluginWasInstalled() {
|
||||
InstalledPlugin gitInstalled = createInstalled("scm-git-plugin");
|
||||
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(gitInstalled));
|
||||
|
||||
manager.install("scm-git-plugin", true);
|
||||
verify(eventBus, never()).post(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotInstallAlreadyPendingPlugins() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
|
||||
|
||||
manager.install("scm-review-plugin", false);
|
||||
manager.install("scm-review-plugin", false);
|
||||
// only one interaction
|
||||
verify(installer).install(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSendRestartEvent() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
|
||||
|
||||
manager.install("scm-review-plugin", false);
|
||||
manager.installPendingAndRestart();
|
||||
|
||||
verify(eventBus).post(any(RestartEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotSendRestartEventWithoutPendingPlugins() {
|
||||
manager.installPendingAndRestart();
|
||||
|
||||
verify(eventBus, never()).post(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnSingleAvailableAsPending() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
|
||||
|
||||
manager.install("scm-review-plugin", false);
|
||||
|
||||
Optional<AvailablePlugin> available = manager.getAvailable("scm-review-plugin");
|
||||
assertThat(available.get().isPending()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnAvailableAsPending() {
|
||||
AvailablePlugin review = createAvailable("scm-review-plugin");
|
||||
when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
|
||||
|
||||
manager.install("scm-review-plugin", false);
|
||||
|
||||
List<AvailablePlugin> available = manager.getAvailable();
|
||||
assertThat(available.get(0).isPending()).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithoutReadPermissions {
|
||||
|
||||
@BeforeEach
|
||||
void setUpSubject() {
|
||||
ThreadContext.bind(subject);
|
||||
doThrow(AuthorizationException.class).when(subject).checkPermission("plugin:read");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clearThreadContext() {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAuthorizationExceptionsForReadMethods() {
|
||||
assertThrows(AuthorizationException.class, () -> manager.getInstalled());
|
||||
assertThrows(AuthorizationException.class, () -> manager.getInstalled("test"));
|
||||
assertThrows(AuthorizationException.class, () -> manager.getAvailable());
|
||||
assertThrows(AuthorizationException.class, () -> manager.getAvailable("test"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WithoutManagePermissions {
|
||||
|
||||
@BeforeEach
|
||||
void setUpSubject() {
|
||||
ThreadContext.bind(subject);
|
||||
doThrow(AuthorizationException.class).when(subject).checkPermission("plugin:manage");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clearThreadContext() {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAuthorizationExceptionsForInstallMethod() {
|
||||
assertThrows(AuthorizationException.class, () -> manager.install("test", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowAuthorizationExceptionsForInstallPendingAndRestart() {
|
||||
assertThrows(AuthorizationException.class, () -> manager.installPendingAndRestart());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private AvailablePlugin createAvailable(String name) {
|
||||
PluginInformation information = new PluginInformation();
|
||||
information.setName(name);
|
||||
return createAvailable(information);
|
||||
}
|
||||
|
||||
private InstalledPlugin createInstalled(String name) {
|
||||
PluginInformation information = new PluginInformation();
|
||||
information.setName(name);
|
||||
return createInstalled(information);
|
||||
}
|
||||
|
||||
private InstalledPlugin createInstalled(PluginInformation information) {
|
||||
InstalledPlugin plugin = mock(InstalledPlugin.class, Answers.RETURNS_DEEP_STUBS);
|
||||
returnInformation(plugin, information);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
private AvailablePlugin createAvailable(PluginInformation information) {
|
||||
AvailablePluginDescriptor descriptor = mock(AvailablePluginDescriptor.class);
|
||||
lenient().when(descriptor.getInformation()).thenReturn(information);
|
||||
return new AvailablePlugin(descriptor);
|
||||
}
|
||||
|
||||
private void returnInformation(Plugin mockedPlugin, PluginInformation information) {
|
||||
when(mockedPlugin.getDescriptor().getInformation()).thenReturn(information);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
|
||||
public void testGetResourceFromCache() {
|
||||
DefaultUberWebResourceLoader resourceLoader =
|
||||
new DefaultUberWebResourceLoader(servletContext,
|
||||
new ArrayList<PluginWrapper>(), Stage.PRODUCTION);
|
||||
new ArrayList<InstalledPlugin>(), Stage.PRODUCTION);
|
||||
|
||||
resourceLoader.getCache().put("/myresource", GITHUB);
|
||||
|
||||
@@ -131,8 +131,8 @@ public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
|
||||
{
|
||||
File directory = temp.newFolder();
|
||||
File file = file(directory, "myresource");
|
||||
PluginWrapper wrapper = createPluginWrapper(directory);
|
||||
List<PluginWrapper> plugins = Lists.newArrayList(wrapper);
|
||||
InstalledPlugin wrapper = createPluginWrapper(directory);
|
||||
List<InstalledPlugin> plugins = Lists.newArrayList(wrapper);
|
||||
WebResourceLoader resourceLoader =
|
||||
new DefaultUberWebResourceLoader(servletContext, plugins);
|
||||
|
||||
@@ -170,8 +170,8 @@ public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
|
||||
|
||||
File directory = temp.newFolder();
|
||||
File file = file(directory, "myresource");
|
||||
PluginWrapper wrapper = createPluginWrapper(directory);
|
||||
List<PluginWrapper> plugins = Lists.newArrayList(wrapper);
|
||||
InstalledPlugin wrapper = createPluginWrapper(directory);
|
||||
List<InstalledPlugin> plugins = Lists.newArrayList(wrapper);
|
||||
|
||||
UberWebResourceLoader resourceLoader =
|
||||
new DefaultUberWebResourceLoader(servletContext, plugins);
|
||||
@@ -197,11 +197,11 @@ public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
|
||||
WebResourceLoader loader = mock(WebResourceLoader.class);
|
||||
when(loader.getResource("/myresource")).thenReturn(url);
|
||||
|
||||
PluginWrapper pluginWrapper = mock(PluginWrapper.class);
|
||||
when(pluginWrapper.getWebResourceLoader()).thenReturn(loader);
|
||||
InstalledPlugin installedPlugin = mock(InstalledPlugin.class);
|
||||
when(installedPlugin.getWebResourceLoader()).thenReturn(loader);
|
||||
|
||||
WebResourceLoader resourceLoader =
|
||||
new DefaultUberWebResourceLoader(servletContext, Lists.newArrayList(pluginWrapper));
|
||||
new DefaultUberWebResourceLoader(servletContext, Lists.newArrayList(installedPlugin));
|
||||
|
||||
assertNull(resourceLoader.getResource("/myresource"));
|
||||
}
|
||||
@@ -214,11 +214,11 @@ public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
|
||||
WebResourceLoader loader = mock(WebResourceLoader.class);
|
||||
when(loader.getResource("/myresource")).thenReturn(url);
|
||||
|
||||
PluginWrapper pluginWrapper = mock(PluginWrapper.class);
|
||||
when(pluginWrapper.getWebResourceLoader()).thenReturn(loader);
|
||||
InstalledPlugin installedPlugin = mock(InstalledPlugin.class);
|
||||
when(installedPlugin.getWebResourceLoader()).thenReturn(loader);
|
||||
|
||||
UberWebResourceLoader resourceLoader =
|
||||
new DefaultUberWebResourceLoader(servletContext, Lists.newArrayList(pluginWrapper));
|
||||
new DefaultUberWebResourceLoader(servletContext, Lists.newArrayList(installedPlugin));
|
||||
|
||||
List<URL> resources = resourceLoader.getResources("/myresource");
|
||||
Assertions.assertThat(resources).isEmpty();
|
||||
@@ -232,7 +232,7 @@ public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private PluginWrapper createPluginWrapper(File directory)
|
||||
private InstalledPlugin createPluginWrapper(File directory)
|
||||
{
|
||||
return createPluginWrapper(directory.toPath());
|
||||
}
|
||||
@@ -245,9 +245,9 @@ public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private PluginWrapper createPluginWrapper(Path directory)
|
||||
private InstalledPlugin createPluginWrapper(Path directory)
|
||||
{
|
||||
return new PluginWrapper(null, null, new PathWebResourceLoader(directory),
|
||||
return new InstalledPlugin(null, null, new PathWebResourceLoader(directory),
|
||||
directory);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ public class ExplodedSmpTest
|
||||
info.setName(name);
|
||||
info.setVersion(version);
|
||||
|
||||
Plugin plugin = new Plugin(2, info, null, null, false,
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, info, null, null, false,
|
||||
Sets.newSet(dependencies));
|
||||
|
||||
return new ExplodedSmp(null, plugin);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junitpioneer.jupiter.TempDirectory;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith({MockitoExtension.class, TempDirectory.class})
|
||||
class PendingPluginInstallationTest {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private AvailablePlugin plugin;
|
||||
|
||||
@Test
|
||||
void shouldDeleteFileOnCancel(@TempDirectory.TempDir Path directory) throws IOException {
|
||||
Path file = directory.resolve("file");
|
||||
Files.write(file, "42".getBytes());
|
||||
|
||||
when(plugin.getDescriptor().getInformation().getName()).thenReturn("scm-awesome-plugin");
|
||||
|
||||
PendingPluginInstallation installation = new PendingPluginInstallation(plugin, file);
|
||||
installation.cancel();
|
||||
|
||||
assertThat(file).doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfCancelFailed(@TempDirectory.TempDir Path directory) {
|
||||
Path file = directory.resolve("file");
|
||||
when(plugin.getDescriptor().getInformation().getName()).thenReturn("scm-awesome-plugin");
|
||||
|
||||
PendingPluginInstallation installation = new PendingPluginInstallation(plugin, file);
|
||||
assertThrows(PluginFailedToCancelInstallationException.class, installation::cancel);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,13 @@
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -10,11 +17,19 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static sonia.scm.plugin.PluginCenterDto.Plugin;
|
||||
import static sonia.scm.plugin.PluginCenterDto.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PluginCenterDtoMapperTest {
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private PluginCenterDto dto;
|
||||
|
||||
@InjectMocks
|
||||
private PluginCenterDtoMapperImpl mapper;
|
||||
|
||||
@Test
|
||||
void shouldMapSinglePlugin() {
|
||||
Plugin plugin = new Plugin(
|
||||
@@ -27,19 +42,26 @@ class PluginCenterDtoMapperTest {
|
||||
"http://avatar.url",
|
||||
"555000444",
|
||||
new Condition(Collections.singletonList("linux"), "amd64","2.0.0"),
|
||||
new Dependency("scm-review-plugin"),
|
||||
new HashMap<>());
|
||||
ImmutableSet.of("scm-review-plugin"),
|
||||
ImmutableMap.of("download", new Link("http://download.hitchhiker.com"))
|
||||
);
|
||||
|
||||
PluginInformation result = PluginCenterDtoMapper.map(Collections.singletonList(plugin)).iterator().next();
|
||||
when(dto.getEmbedded().getPlugins()).thenReturn(Collections.singletonList(plugin));
|
||||
AvailablePluginDescriptor descriptor = mapper.map(dto).iterator().next().getDescriptor();
|
||||
PluginInformation information = descriptor.getInformation();
|
||||
PluginCondition condition = descriptor.getCondition();
|
||||
|
||||
assertThat(result.getAuthor()).isEqualTo(plugin.getAuthor());
|
||||
assertThat(result.getCategory()).isEqualTo(plugin.getCategory());
|
||||
assertThat(result.getVersion()).isEqualTo(plugin.getVersion());
|
||||
assertThat(result.getCondition().getArch()).isEqualTo(plugin.getConditions().getArch());
|
||||
assertThat(result.getCondition().getMinVersion()).isEqualTo(plugin.getConditions().getMinVersion());
|
||||
assertThat(result.getCondition().getOs().iterator().next()).isEqualTo(plugin.getConditions().getOs().iterator().next());
|
||||
assertThat(result.getDescription()).isEqualTo(plugin.getDescription());
|
||||
assertThat(result.getName()).isEqualTo(plugin.getName());
|
||||
assertThat(descriptor.getUrl()).isEqualTo("http://download.hitchhiker.com");
|
||||
assertThat(descriptor.getChecksum()).contains("555000444");
|
||||
|
||||
assertThat(information.getAuthor()).isEqualTo(plugin.getAuthor());
|
||||
assertThat(information.getCategory()).isEqualTo(plugin.getCategory());
|
||||
assertThat(information.getVersion()).isEqualTo(plugin.getVersion());
|
||||
assertThat(condition.getArch()).isEqualTo(plugin.getConditions().getArch());
|
||||
assertThat(condition.getMinVersion()).isEqualTo(plugin.getConditions().getMinVersion());
|
||||
assertThat(condition.getOs().iterator().next()).isEqualTo(plugin.getConditions().getOs().iterator().next());
|
||||
assertThat(information.getDescription()).isEqualTo(plugin.getDescription());
|
||||
assertThat(information.getName()).isEqualTo(plugin.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -54,8 +76,9 @@ class PluginCenterDtoMapperTest {
|
||||
"https://avatar.url",
|
||||
"12345678aa",
|
||||
new Condition(Collections.singletonList("linux"), "amd64","2.0.0"),
|
||||
new Dependency("scm-review-plugin"),
|
||||
new HashMap<>());
|
||||
ImmutableSet.of("scm-review-plugin"),
|
||||
ImmutableMap.of("download", new Link("http://download.hitchhiker.com/review"))
|
||||
);
|
||||
|
||||
Plugin plugin2 = new Plugin(
|
||||
"scm-hitchhiker-plugin",
|
||||
@@ -67,15 +90,16 @@ class PluginCenterDtoMapperTest {
|
||||
"http://avatar.url",
|
||||
"555000444",
|
||||
new Condition(Collections.singletonList("linux"), "amd64","2.0.0"),
|
||||
new Dependency("scm-review-plugin"),
|
||||
new HashMap<>());
|
||||
ImmutableSet.of("scm-review-plugin"),
|
||||
ImmutableMap.of("download", new Link("http://download.hitchhiker.com/hitchhiker"))
|
||||
);
|
||||
|
||||
Set<PluginInformation> resultSet = PluginCenterDtoMapper.map(Arrays.asList(plugin1, plugin2));
|
||||
when(dto.getEmbedded().getPlugins()).thenReturn(Arrays.asList(plugin1, plugin2));
|
||||
|
||||
List<PluginInformation> pluginsList = new ArrayList<>(resultSet);
|
||||
Set<AvailablePlugin> resultSet = mapper.map(dto);
|
||||
|
||||
PluginInformation pluginInformation1 = pluginsList.get(1);
|
||||
PluginInformation pluginInformation2 = pluginsList.get(0);
|
||||
PluginInformation pluginInformation1 = findPlugin(resultSet, plugin1.getName());
|
||||
PluginInformation pluginInformation2 = findPlugin(resultSet, plugin2.getName());
|
||||
|
||||
assertThat(pluginInformation1.getAuthor()).isEqualTo(plugin1.getAuthor());
|
||||
assertThat(pluginInformation1.getVersion()).isEqualTo(plugin1.getVersion());
|
||||
@@ -83,4 +107,14 @@ class PluginCenterDtoMapperTest {
|
||||
assertThat(pluginInformation2.getVersion()).isEqualTo(plugin2.getVersion());
|
||||
assertThat(resultSet.size()).isEqualTo(2);
|
||||
}
|
||||
|
||||
private PluginInformation findPlugin(Set<AvailablePlugin> resultSet, String name) {
|
||||
return resultSet
|
||||
.stream()
|
||||
.filter(p -> name.equals(p.getDescriptor().getInformation().getName()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("could not find plugin " + name))
|
||||
.getDescriptor()
|
||||
.getInformation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.net.ahc.AdvancedHttpClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PluginCenterLoaderTest {
|
||||
|
||||
private static final String PLUGIN_URL = "https://plugins.hitchhiker.com";
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private AdvancedHttpClient client;
|
||||
|
||||
@Mock
|
||||
private PluginCenterDtoMapper mapper;
|
||||
|
||||
@InjectMocks
|
||||
private PluginCenterLoader loader;
|
||||
|
||||
@Test
|
||||
void shouldFetch() throws IOException {
|
||||
Set<AvailablePlugin> plugins = Collections.emptySet();
|
||||
PluginCenterDto dto = new PluginCenterDto();
|
||||
when(client.get(PLUGIN_URL).request().contentFromJson(PluginCenterDto.class)).thenReturn(dto);
|
||||
when(mapper.map(dto)).thenReturn(plugins);
|
||||
|
||||
Set<AvailablePlugin> fetched = loader.load(PLUGIN_URL);
|
||||
assertThat(fetched).isSameAs(plugins);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnEmptySetIfPluginCenterNotBeReached() throws IOException {
|
||||
when(client.get(PLUGIN_URL).request()).thenThrow(new IOException("failed to fetch"));
|
||||
|
||||
Set<AvailablePlugin> fetch = loader.load(PLUGIN_URL);
|
||||
assertThat(fetch).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.cache.CacheManager;
|
||||
import sonia.scm.cache.MapCacheManager;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.net.ahc.AdvancedHttpClient;
|
||||
import sonia.scm.util.SystemUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class PluginCenterTest {
|
||||
|
||||
private static final String PLUGIN_URL_BASE = "https://plugins.hitchhiker.com/";
|
||||
private static final String PLUGIN_URL = PLUGIN_URL_BASE + "{version}";
|
||||
|
||||
@Mock
|
||||
private PluginCenterLoader loader;
|
||||
|
||||
@Mock
|
||||
private SCMContextProvider contextProvider;
|
||||
|
||||
private ScmConfiguration configuration;
|
||||
|
||||
private CacheManager cacheManager;
|
||||
|
||||
private PluginCenter pluginCenter;
|
||||
|
||||
@BeforeEach
|
||||
void setUpPluginCenter() {
|
||||
when(contextProvider.getVersion()).thenReturn("2.0.0");
|
||||
|
||||
cacheManager = new MapCacheManager();
|
||||
|
||||
configuration = new ScmConfiguration();
|
||||
configuration.setPluginUrl(PLUGIN_URL);
|
||||
|
||||
pluginCenter = new PluginCenter(contextProvider, cacheManager, configuration, loader);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFetchPlugins() {
|
||||
Set<AvailablePlugin> plugins = new HashSet<>();
|
||||
when(loader.load(PLUGIN_URL_BASE + "2.0.0")).thenReturn(plugins);
|
||||
|
||||
assertThat(pluginCenter.getAvailable()).isSameAs(plugins);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCache() {
|
||||
Set<AvailablePlugin> first = new HashSet<>();
|
||||
when(loader.load(anyString())).thenReturn(first, new HashSet<>());
|
||||
|
||||
assertThat(pluginCenter.getAvailable()).isSameAs(first);
|
||||
assertThat(pluginCenter.getAvailable()).isSameAs(first);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package sonia.scm.plugin;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junitpioneer.jupiter.TempDirectory;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.net.ahc.AdvancedHttpClient;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith({MockitoExtension.class, TempDirectory.class})
|
||||
class PluginInstallerTest {
|
||||
|
||||
@Mock
|
||||
private SCMContextProvider context;
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private AdvancedHttpClient client;
|
||||
|
||||
@InjectMocks
|
||||
private PluginInstaller installer;
|
||||
|
||||
private Path directory;
|
||||
|
||||
@BeforeEach
|
||||
void setUpContext(@TempDirectory.TempDir Path directory) {
|
||||
this.directory = directory;
|
||||
lenient().when(context.resolve(any())).then(ic -> {
|
||||
Path arg = ic.getArgument(0);
|
||||
return directory.resolve(arg);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDownloadPlugin() throws IOException {
|
||||
mockContent("42");
|
||||
|
||||
installer.install(createGitPlugin());
|
||||
|
||||
assertThat(directory.resolve("plugins").resolve("scm-git-plugin.smp")).hasContent("42");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnPendingPluginInstallation() throws IOException {
|
||||
mockContent("42");
|
||||
AvailablePlugin gitPlugin = createGitPlugin();
|
||||
|
||||
PendingPluginInstallation pending = installer.install(gitPlugin);
|
||||
|
||||
assertThat(pending).isNotNull();
|
||||
assertThat(pending.getPlugin().getDescriptor()).isEqualTo(gitPlugin.getDescriptor());
|
||||
assertThat(pending.getPlugin().isPending()).isTrue();
|
||||
}
|
||||
|
||||
private void mockContent(String content) throws IOException {
|
||||
when(client.get("https://download.hitchhiker.com").request().contentAsStream())
|
||||
.thenReturn(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
||||
private AvailablePlugin createGitPlugin() {
|
||||
return createPlugin(
|
||||
"scm-git-plugin",
|
||||
"https://download.hitchhiker.com",
|
||||
"73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049" // 42
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowPluginDownloadException() throws IOException {
|
||||
when(client.get("https://download.hitchhiker.com").request()).thenThrow(new IOException("failed to download"));
|
||||
|
||||
assertThrows(PluginDownloadException.class, () -> installer.install(createGitPlugin()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowPluginChecksumMismatchException() throws IOException {
|
||||
mockContent("21");
|
||||
|
||||
assertThrows(PluginChecksumMismatchException.class, () -> installer.install(createGitPlugin()));
|
||||
assertThat(directory.resolve("plugins").resolve("scm-git-plugin.smp")).doesNotExist();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowPluginDownloadExceptionAndCleanup() throws IOException {
|
||||
InputStream stream = mock(InputStream.class);
|
||||
when(stream.read(any(), anyInt(), anyInt())).thenThrow(new IOException("failed to read"));
|
||||
when(client.get("https://download.hitchhiker.com").request().contentAsStream()).thenReturn(stream);
|
||||
|
||||
assertThrows(PluginDownloadException.class, () -> installer.install(createGitPlugin()));
|
||||
assertThat(directory.resolve("plugins").resolve("scm-git-plugin.smp")).doesNotExist();
|
||||
}
|
||||
|
||||
|
||||
private AvailablePlugin createPlugin(String name, String url, String checksum) {
|
||||
PluginInformation information = new PluginInformation();
|
||||
information.setName(name);
|
||||
AvailablePluginDescriptor descriptor = new AvailablePluginDescriptor(
|
||||
information, null, Collections.emptySet(), url, checksum
|
||||
);
|
||||
return new AvailablePlugin(descriptor);
|
||||
}
|
||||
}
|
||||
@@ -129,7 +129,7 @@ public class PluginProcessorTest
|
||||
{
|
||||
copySmp(PLUGIN_A);
|
||||
|
||||
PluginWrapper plugin = collectAndGetFirst();
|
||||
InstalledPlugin plugin = collectAndGetFirst();
|
||||
|
||||
assertThat(plugin.getId(), is(PLUGIN_A.id));
|
||||
}
|
||||
@@ -145,15 +145,15 @@ public class PluginProcessorTest
|
||||
{
|
||||
copySmps(PLUGIN_A, PLUGIN_B);
|
||||
|
||||
Set<PluginWrapper> plugins = collectPlugins();
|
||||
Set<InstalledPlugin> plugins = collectPlugins();
|
||||
|
||||
assertThat(plugins, hasSize(2));
|
||||
|
||||
PluginWrapper a = findPlugin(plugins, PLUGIN_A.id);
|
||||
InstalledPlugin a = findPlugin(plugins, PLUGIN_A.id);
|
||||
|
||||
assertNotNull(a);
|
||||
|
||||
PluginWrapper b = findPlugin(plugins, PLUGIN_B.id);
|
||||
InstalledPlugin b = findPlugin(plugins, PLUGIN_B.id);
|
||||
|
||||
assertNotNull(b);
|
||||
}
|
||||
@@ -178,7 +178,7 @@ public class PluginProcessorTest
|
||||
{
|
||||
copySmp(PLUGIN_A);
|
||||
|
||||
PluginWrapper plugin = collectAndGetFirst();
|
||||
InstalledPlugin plugin = collectAndGetFirst();
|
||||
ClassLoader cl = plugin.getClassLoader();
|
||||
|
||||
// load parent class
|
||||
@@ -216,9 +216,9 @@ public class PluginProcessorTest
|
||||
{
|
||||
copySmps(PLUGIN_A, PLUGIN_B);
|
||||
|
||||
Set<PluginWrapper> plugins = collectPlugins();
|
||||
Set<InstalledPlugin> plugins = collectPlugins();
|
||||
|
||||
PluginWrapper plugin = findPlugin(plugins, PLUGIN_B.id);
|
||||
InstalledPlugin plugin = findPlugin(plugins, PLUGIN_B.id);
|
||||
ClassLoader cl = plugin.getClassLoader();
|
||||
|
||||
// load parent class
|
||||
@@ -247,7 +247,7 @@ public class PluginProcessorTest
|
||||
{
|
||||
copySmp(PLUGIN_A);
|
||||
|
||||
PluginWrapper plugin = collectAndGetFirst();
|
||||
InstalledPlugin plugin = collectAndGetFirst();
|
||||
WebResourceLoader wrl = plugin.getWebResourceLoader();
|
||||
|
||||
assertNotNull(wrl);
|
||||
@@ -269,7 +269,7 @@ public class PluginProcessorTest
|
||||
{
|
||||
copySmp(PLUGIN_F_1_0_0);
|
||||
|
||||
PluginWrapper plugin = collectAndGetFirst();
|
||||
InstalledPlugin plugin = collectAndGetFirst();
|
||||
|
||||
assertThat(plugin.getId(), is(PLUGIN_F_1_0_0.id));
|
||||
copySmp(PLUGIN_F_1_0_1);
|
||||
@@ -302,9 +302,9 @@ public class PluginProcessorTest
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private PluginWrapper collectAndGetFirst() throws IOException
|
||||
private InstalledPlugin collectAndGetFirst() throws IOException
|
||||
{
|
||||
Set<PluginWrapper> plugins = collectPlugins();
|
||||
Set<InstalledPlugin> plugins = collectPlugins();
|
||||
|
||||
assertThat(plugins, hasSize(1));
|
||||
|
||||
@@ -319,7 +319,7 @@ public class PluginProcessorTest
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private Set<PluginWrapper> collectPlugins() throws IOException
|
||||
private Set<InstalledPlugin> collectPlugins() throws IOException
|
||||
{
|
||||
return processor.collectPlugins(PluginProcessorTest.class.getClassLoader());
|
||||
}
|
||||
@@ -368,14 +368,14 @@ public class PluginProcessorTest
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private PluginWrapper findPlugin(Iterable<PluginWrapper> plugin,
|
||||
final String id)
|
||||
private InstalledPlugin findPlugin(Iterable<InstalledPlugin> plugin,
|
||||
final String id)
|
||||
{
|
||||
return Iterables.find(plugin, new Predicate<PluginWrapper>()
|
||||
return Iterables.find(plugin, new Predicate<InstalledPlugin>()
|
||||
{
|
||||
|
||||
@Override
|
||||
public boolean apply(PluginWrapper input)
|
||||
public boolean apply(InstalledPlugin input)
|
||||
{
|
||||
return id.equals(input.getId());
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class PluginTreeTest
|
||||
{
|
||||
PluginCondition condition = new PluginCondition("999",
|
||||
new ArrayList<String>(), "hit");
|
||||
Plugin plugin = new Plugin(2, createInfo("a", "1"), null, condition,
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo("a", "1"), null, condition,
|
||||
false, null);
|
||||
ExplodedSmp smp = createSmp(plugin);
|
||||
|
||||
@@ -114,7 +114,7 @@ public class PluginTreeTest
|
||||
@Test(expected = PluginException.class)
|
||||
public void testScmVersion() throws IOException
|
||||
{
|
||||
Plugin plugin = new Plugin(1, createInfo("a", "1"), null, null, false,
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(1, createInfo("a", "1"), null, null, false,
|
||||
null);
|
||||
ExplodedSmp smp = createSmp(plugin);
|
||||
|
||||
@@ -182,7 +182,7 @@ public class PluginTreeTest
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private ExplodedSmp createSmp(Plugin plugin) throws IOException
|
||||
private ExplodedSmp createSmp(InstalledPluginDescriptor plugin) throws IOException
|
||||
{
|
||||
return new ExplodedSmp(tempFolder.newFile().toPath(), plugin);
|
||||
}
|
||||
@@ -199,7 +199,7 @@ public class PluginTreeTest
|
||||
*/
|
||||
private ExplodedSmp createSmp(String name) throws IOException
|
||||
{
|
||||
return createSmp(new Plugin(2, createInfo(name, "1.0.0"), null, null,
|
||||
return createSmp(new InstalledPluginDescriptor(2, createInfo(name, "1.0.0"), null, null,
|
||||
false, null));
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ public class PluginTreeTest
|
||||
dependencySet.add(d);
|
||||
}
|
||||
|
||||
Plugin plugin = new Plugin(2, createInfo(name, "1"), null, null,
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo(name, "1"), null, null,
|
||||
false, dependencySet);
|
||||
|
||||
return createSmp(plugin);
|
||||
|
||||
Reference in New Issue
Block a user