diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/InstalledPluginResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/InstalledPluginResource.java index bc9d4b397c..5b5d0f267b 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/InstalledPluginResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/InstalledPluginResource.java @@ -3,8 +3,8 @@ package sonia.scm.api.v2.resources; import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.StatusCodes; import com.webcohesion.enunciate.metadata.rs.TypeHint; +import sonia.scm.plugin.AvailablePlugin; import sonia.scm.plugin.InstalledPlugin; -import sonia.scm.plugin.InstalledPluginDescriptor; import sonia.scm.plugin.PluginManager; import sonia.scm.plugin.PluginPermissions; import sonia.scm.web.VndMediaType; @@ -50,7 +50,8 @@ public class InstalledPluginResource { public Response getInstalledPlugins() { PluginPermissions.read().check(); List plugins = pluginManager.getInstalled(); - return Response.ok(collectionMapper.mapInstalled(plugins)).build(); + List available = pluginManager.getAvailable(); + return Response.ok(collectionMapper.mapInstalled(plugins, available)).build(); } /** @@ -72,8 +73,9 @@ public class InstalledPluginResource { public Response getInstalledPlugin(@PathParam("name") String name) { PluginPermissions.read().check(); Optional pluginDto = pluginManager.getInstalled(name); + List available = pluginManager.getAvailable(); if (pluginDto.isPresent()) { - return Response.ok(mapper.mapInstalled(pluginDto.get())).build(); + return Response.ok(mapper.mapInstalled(pluginDto.get(), available)).build(); } else { throw notFound(entity("Plugin", name)); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDto.java index bf20d1b67e..41d285d59c 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDto.java @@ -1,5 +1,6 @@ package sonia.scm.api.v2.resources; +import com.fasterxml.jackson.annotation.JsonInclude; import de.otto.edison.hal.HalRepresentation; import de.otto.edison.hal.Links; import lombok.Getter; @@ -16,6 +17,8 @@ public class PluginDto extends HalRepresentation { private String name; private String version; + @JsonInclude(JsonInclude.Include.NON_NULL) + private String newVersion; private String displayName; private String description; private String author; diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapper.java index 7c1ee3d5a6..e8e85a0054 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapper.java @@ -26,8 +26,11 @@ public class PluginDtoCollectionMapper { this.mapper = mapper; } - public HalRepresentation mapInstalled(List plugins) { - List dtos = plugins.stream().map(mapper::mapInstalled).collect(toList()); + public HalRepresentation mapInstalled(List plugins, List availablePlugins) { + List dtos = plugins + .stream() + .map(i -> mapper.mapInstalled(i, availablePlugins)) + .collect(toList()); return new HalRepresentation(createInstalledPluginsLinks(), embedDtos(dtos)); } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java index 25faf0a101..00b363c6a3 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/PluginDtoMapper.java @@ -11,6 +11,9 @@ import sonia.scm.plugin.PluginPermissions; import javax.inject.Inject; +import java.util.List; +import java.util.Optional; + import static de.otto.edison.hal.Link.link; import static de.otto.edison.hal.Links.linkingTo; @@ -22,8 +25,8 @@ public abstract class PluginDtoMapper { public abstract void map(PluginInformation plugin, @MappingTarget PluginDto dto); - public PluginDto mapInstalled(InstalledPlugin plugin) { - PluginDto dto = createDtoForInstalled(plugin); + public PluginDto mapInstalled(InstalledPlugin plugin, List availablePlugins) { + PluginDto dto = createDtoForInstalled(plugin, availablePlugins); map(dto, plugin); return dto; } @@ -57,13 +60,33 @@ public abstract class PluginDtoMapper { return new PluginDto(links.build()); } - private PluginDto createDtoForInstalled(InstalledPlugin plugin) { + private PluginDto createDtoForInstalled(InstalledPlugin plugin, List availablePlugins) { PluginInformation information = plugin.getDescriptor().getInformation(); + Optional availablePlugin = checkForUpdates(plugin, availablePlugins); Links.Builder links = linkingTo() .self(resourceLinks.installedPlugin() .self(information.getName())); + if (availablePlugin.isPresent() + && !availablePlugin.get().isPending() + && PluginPermissions.manage().isPermitted() + ) { + links.single(link("update", resourceLinks.availablePlugin().install(information.getName()))); + } - return new PluginDto(links.build()); + PluginDto dto = new PluginDto(links.build()); + + availablePlugin.ifPresent(value -> { + dto.setNewVersion(value.getDescriptor().getInformation().getVersion()); + dto.setPending(value.isPending()); + }); + + return dto; + } + + private Optional checkForUpdates(InstalledPlugin plugin, List availablePlugins) { + return availablePlugins.stream() + .filter(a -> a.getDescriptor().getInformation().getName().equals(plugin.getDescriptor().getInformation().getName())) + .findAny(); } } diff --git a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java index 807eaac317..9334f87822 100644 --- a/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java +++ b/scm-webapp/src/main/java/sonia/scm/plugin/DefaultPluginManager.java @@ -42,6 +42,7 @@ import org.slf4j.LoggerFactory; import sonia.scm.NotFoundException; import sonia.scm.event.ScmEventBus; import sonia.scm.lifecycle.RestartEvent; +import sonia.scm.version.Version; //~--- JDK imports ------------------------------------------------------------ import javax.inject.Inject; @@ -83,7 +84,7 @@ public class DefaultPluginManager implements PluginManager { return center.getAvailable() .stream() .filter(filterByName(name)) - .filter(this::isNotInstalled) + .filter(this::isNotInstalledOrMoreUpToDate) .map(p -> getPending(name).orElse(p)) .findFirst(); } @@ -116,7 +117,7 @@ public class DefaultPluginManager implements PluginManager { PluginPermissions.read().check(); return center.getAvailable() .stream() - .filter(this::isNotInstalled) + .filter(this::isNotInstalledOrMoreUpToDate) .map(p -> getPending(p.getDescriptor().getInformation().getName()).orElse(p)) .collect(Collectors.toList()); } @@ -125,8 +126,14 @@ public class DefaultPluginManager implements PluginManager { return plugin -> name.equals(plugin.getDescriptor().getInformation().getName()); } - private boolean isNotInstalled(AvailablePlugin availablePlugin) { - return !getInstalled(availablePlugin.getDescriptor().getInformation().getName()).isPresent(); + private boolean isNotInstalledOrMoreUpToDate(AvailablePlugin availablePlugin) { + return getInstalled(availablePlugin.getDescriptor().getInformation().getName()) + .map(installedPlugin -> availableIsMoreUpToDateThanInstalled(availablePlugin, installedPlugin)) + .orElse(true); + } + + private boolean availableIsMoreUpToDateThanInstalled(AvailablePlugin availablePlugin, InstalledPlugin installed) { + return Version.parse(availablePlugin.getDescriptor().getInformation().getVersion()).isNewer(installed.getDescriptor().getInformation().getVersion()); } @Override diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java index 7fa0081c5c..84cd827932 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/InstalledPluginResourceTest.java @@ -29,6 +29,7 @@ import java.net.URISyntaxException; import java.util.Collections; import java.util.Optional; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -87,7 +88,7 @@ class InstalledPluginResourceTest { void getInstalledPlugins() throws URISyntaxException, UnsupportedEncodingException { InstalledPlugin installedPlugin = createPlugin(); when(pluginManager.getInstalled()).thenReturn(Collections.singletonList(installedPlugin)); - when(collectionMapper.mapInstalled(Collections.singletonList(installedPlugin))).thenReturn(new MockedResultDto()); + when(collectionMapper.mapInstalled(Collections.singletonList(installedPlugin), Collections.emptyList())).thenReturn(new MockedResultDto()); MockHttpRequest request = MockHttpRequest.get("/v2/plugins/installed"); request.accept(VndMediaType.PLUGIN_COLLECTION); @@ -110,7 +111,7 @@ class InstalledPluginResourceTest { PluginDto pluginDto = new PluginDto(); pluginDto.setName("pluginName"); - when(mapper.mapInstalled(installedPlugin)).thenReturn(pluginDto); + when(mapper.mapInstalled(installedPlugin, emptyList())).thenReturn(pluginDto); MockHttpRequest request = MockHttpRequest.get("/v2/plugins/installed/pluginName"); request.accept(VndMediaType.PLUGIN); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapperTest.java new file mode 100644 index 0000000000..fb368d12f2 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoCollectionMapperTest.java @@ -0,0 +1,171 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.HalRepresentation; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.subject.support.SubjectThreadState; +import org.apache.shiro.util.ThreadContext; +import org.apache.shiro.util.ThreadState; +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.InjectMocks; +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 java.net.URI; +import java.util.List; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class PluginDtoCollectionMapperTest { + + ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/")); + + @InjectMocks + PluginDtoMapperImpl pluginDtoMapper; + + Subject subject = mock(Subject.class); + ThreadState subjectThreadState = new SubjectThreadState(subject); + + @BeforeEach + void bindSubject() { + subjectThreadState.bind(); + ThreadContext.bind(subject); + } + + @AfterEach + public void unbindSubject() { + ThreadContext.unbindSubject(); + } + + + @Test + void shouldMapInstalledPluginsWithoutUpdateWhenNoNewerVersionIsAvailable() { + PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper); + + HalRepresentation result = mapper.mapInstalled( + singletonList(createInstalledPlugin("scm-some-plugin", "1")), + singletonList(createAvailablePlugin("scm-other-plugin", "2"))); + + List plugins = result.getEmbedded().getItemsBy("plugins"); + assertThat(plugins).hasSize(1); + PluginDto plugin = (PluginDto) plugins.get(0); + assertThat(plugin.getVersion()).isEqualTo("1"); + assertThat(plugin.getNewVersion()).isNull(); + } + + @Test + void shouldSetNewVersionInInstalledPluginWhenAvailableVersionIsNewer() { + PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper); + + HalRepresentation result = mapper.mapInstalled( + singletonList(createInstalledPlugin("scm-some-plugin", "1")), + singletonList(createAvailablePlugin("scm-some-plugin", "2"))); + + PluginDto plugin = getPluginDtoFromResult(result); + assertThat(plugin.getVersion()).isEqualTo("1"); + assertThat(plugin.getNewVersion()).isEqualTo("2"); + } + + @Test + void shouldNotAddInstallLinkForNewVersionWhenNotPermitted() { + when(subject.isPermitted("plugin:manage")).thenReturn(false); + PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper); + + HalRepresentation result = mapper.mapInstalled( + singletonList(createInstalledPlugin("scm-some-plugin", "1")), + singletonList(createAvailablePlugin("scm-some-plugin", "2"))); + + PluginDto plugin = getPluginDtoFromResult(result); + assertThat(plugin.getLinks().getLinkBy("update")).isEmpty(); + } + + @Test + void shouldNotAddInstallLinkForNewVersionWhenInstallationIsPending() { + when(subject.isPermitted("plugin:manage")).thenReturn(true); + PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper); + + AvailablePlugin availablePlugin = createAvailablePlugin("scm-some-plugin", "2"); + when(availablePlugin.isPending()).thenReturn(true); + HalRepresentation result = mapper.mapInstalled( + singletonList(createInstalledPlugin("scm-some-plugin", "1")), + singletonList(availablePlugin)); + + PluginDto plugin = getPluginDtoFromResult(result); + assertThat(plugin.getLinks().getLinkBy("update")).isEmpty(); + } + + @Test + void shouldAddInstallLinkForNewVersionWhenPermitted() { + when(subject.isPermitted("plugin:manage")).thenReturn(true); + PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper); + + HalRepresentation result = mapper.mapInstalled( + singletonList(createInstalledPlugin("scm-some-plugin", "1")), + singletonList(createAvailablePlugin("scm-some-plugin", "2"))); + + PluginDto plugin = getPluginDtoFromResult(result); + assertThat(plugin.getLinks().getLinkBy("update")).isNotEmpty(); + } + + @Test + void shouldSetInstalledPluginPendingWhenCorrespondingAvailablePluginIsPending() { + when(subject.isPermitted("plugin:manage")).thenReturn(true); + PluginDtoCollectionMapper mapper = new PluginDtoCollectionMapper(resourceLinks, pluginDtoMapper); + + AvailablePlugin availablePlugin = createAvailablePlugin("scm-some-plugin", "2"); + when(availablePlugin.isPending()).thenReturn(true); + HalRepresentation result = mapper.mapInstalled( + singletonList(createInstalledPlugin("scm-some-plugin", "1")), + singletonList(availablePlugin)); + + PluginDto plugin = getPluginDtoFromResult(result); + assertThat(plugin.isPending()).isTrue(); + } + + private PluginDto getPluginDtoFromResult(HalRepresentation result) { + assertThat(result.getEmbedded().getItemsBy("plugins")).hasSize(1); + List plugins = result.getEmbedded().getItemsBy("plugins"); + return (PluginDto) plugins.get(0); + } + + private InstalledPlugin createInstalledPlugin(String name, String version) { + PluginInformation information = new PluginInformation(); + information.setName(name); + information.setVersion(version); + return createInstalledPlugin(information); + } + + private InstalledPlugin createInstalledPlugin(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; + } + + private AvailablePlugin createAvailablePlugin(String name, String version) { + PluginInformation information = new PluginInformation(); + information.setName(name); + information.setVersion(version); + return createAvailablePlugin(information); + } + + private AvailablePlugin createAvailablePlugin(PluginInformation information) { + AvailablePlugin plugin = mock(AvailablePlugin.class); + AvailablePluginDescriptor descriptor = mock(AvailablePluginDescriptor.class); + lenient().when(descriptor.getInformation()).thenReturn(information); + lenient().when(plugin.getDescriptor()).thenReturn(descriptor); + return plugin; + } +} diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java index 5cf6bdd45a..1dc5e3d135 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PluginDtoMapperTest.java @@ -17,7 +17,9 @@ import sonia.scm.plugin.InstalledPlugin; import sonia.scm.plugin.PluginInformation; import java.net.URI; +import java.util.Collections; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -74,7 +76,7 @@ class PluginDtoMapperTest { void shouldAppendInstalledSelfLink() { InstalledPlugin plugin = createInstalled(); - PluginDto dto = mapper.mapInstalled(plugin); + PluginDto dto = mapper.mapInstalled(plugin, emptyList()); assertThat(dto.getLinks().getLinkBy("self").get().getHref()) .isEqualTo("https://hitchhiker.com/v2/plugins/installed/scm-cas-plugin"); } diff --git a/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java b/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java index 322163ee1a..705319f63f 100644 --- a/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/plugin/DefaultPluginManagerTest.java @@ -23,7 +23,6 @@ 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.*; @@ -71,8 +70,8 @@ class DefaultPluginManagerTest { @Test void shouldReturnInstalledPlugins() { - InstalledPlugin review = createInstalled("scm-review-plugin"); - InstalledPlugin git = createInstalled("scm-git-plugin"); + InstalledPlugin review = createInstalled("scm-review-plugin", "1"); + InstalledPlugin git = createInstalled("scm-git-plugin", "1"); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(review, git)); @@ -82,8 +81,8 @@ class DefaultPluginManagerTest { @Test void shouldReturnReviewPlugin() { - InstalledPlugin review = createInstalled("scm-review-plugin"); - InstalledPlugin git = createInstalled("scm-git-plugin"); + InstalledPlugin review = createInstalled("scm-review-plugin", "1"); + InstalledPlugin git = createInstalled("scm-git-plugin", "1"); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(review, git)); @@ -101,8 +100,8 @@ class DefaultPluginManagerTest { @Test void shouldReturnAvailablePlugins() { - AvailablePlugin review = createAvailable("scm-review-plugin"); - AvailablePlugin git = createAvailable("scm-git-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); + AvailablePlugin git = createAvailable("scm-git-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git)); @@ -111,22 +110,35 @@ class DefaultPluginManagerTest { } @Test - void shouldFilterOutAllInstalled() { - InstalledPlugin installedGit = createInstalled("scm-git-plugin"); + void shouldFilterOutAllInstalledWithSameVersion() { + InstalledPlugin installedGit = createInstalled("scm-git-plugin", "1"); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit)); - AvailablePlugin review = createAvailable("scm-review-plugin"); - AvailablePlugin git = createAvailable("scm-git-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); + AvailablePlugin git = createAvailable("scm-git-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git)); List available = manager.getAvailable(); assertThat(available).containsOnly(review); } + @Test + void shouldKeepInstalledWithOlderVersion() { + InstalledPlugin installedGit = createInstalled("scm-git-plugin", "1"); + when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit)); + + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); + AvailablePlugin git = createAvailable("scm-git-plugin", "1.1"); + when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git)); + + List available = manager.getAvailable(); + assertThat(available).contains(git, review); + } + @Test void shouldReturnAvailable() { - AvailablePlugin review = createAvailable("scm-review-plugin"); - AvailablePlugin git = createAvailable("scm-git-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); + AvailablePlugin git = createAvailable("scm-git-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git)); Optional available = manager.getAvailable("scm-git-plugin"); @@ -135,7 +147,7 @@ class DefaultPluginManagerTest { @Test void shouldReturnEmptyForNonExistingAvailable() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); Optional available = manager.getAvailable("scm-git-plugin"); @@ -144,10 +156,10 @@ class DefaultPluginManagerTest { @Test void shouldReturnEmptyForInstalledPlugin() { - InstalledPlugin installedGit = createInstalled("scm-git-plugin"); + InstalledPlugin installedGit = createInstalled("scm-git-plugin", "1"); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit)); - AvailablePlugin git = createAvailable("scm-git-plugin"); + AvailablePlugin git = createAvailable("scm-git-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(git)); Optional available = manager.getAvailable("scm-git-plugin"); @@ -156,7 +168,7 @@ class DefaultPluginManagerTest { @Test void shouldInstallThePlugin() { - AvailablePlugin git = createAvailable("scm-git-plugin"); + AvailablePlugin git = createAvailable("scm-git-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(git)); manager.install("scm-git-plugin", false); @@ -167,9 +179,9 @@ class DefaultPluginManagerTest { @Test void shouldInstallDependingPlugins() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin")); - AvailablePlugin mail = createAvailable("scm-mail-plugin"); + AvailablePlugin mail = createAvailable("scm-mail-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail)); manager.install("scm-review-plugin", false); @@ -180,12 +192,12 @@ class DefaultPluginManagerTest { @Test void shouldNotInstallAlreadyInstalledDependencies() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin")); - AvailablePlugin mail = createAvailable("scm-mail-plugin"); + AvailablePlugin mail = createAvailable("scm-mail-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail)); - InstalledPlugin installedMail = createInstalled("scm-mail-plugin"); + InstalledPlugin installedMail = createInstalled("scm-mail-plugin", "1"); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedMail)); manager.install("scm-review-plugin", false); @@ -198,11 +210,11 @@ class DefaultPluginManagerTest { @Test void shouldRollbackOnFailedInstallation() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin")); - AvailablePlugin mail = createAvailable("scm-mail-plugin"); + AvailablePlugin mail = createAvailable("scm-mail-plugin", "1"); when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin")); - AvailablePlugin notification = createAvailable("scm-notification-plugin"); + AvailablePlugin notification = createAvailable("scm-notification-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail, notification)); PendingPluginInstallation pendingNotification = mock(PendingPluginInstallation.class); @@ -221,9 +233,9 @@ class DefaultPluginManagerTest { @Test void shouldInstallNothingIfOneOfTheDependenciesIsNotAvailable() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin")); - AvailablePlugin mail = createAvailable("scm-mail-plugin"); + AvailablePlugin mail = createAvailable("scm-mail-plugin", "1"); when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin")); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail)); @@ -234,7 +246,7 @@ class DefaultPluginManagerTest { @Test void shouldSendRestartEventAfterInstallation() { - AvailablePlugin git = createAvailable("scm-git-plugin"); + AvailablePlugin git = createAvailable("scm-git-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(git)); manager.install("scm-git-plugin", true); @@ -245,7 +257,7 @@ class DefaultPluginManagerTest { @Test void shouldNotSendRestartEventIfNoPluginWasInstalled() { - InstalledPlugin gitInstalled = createInstalled("scm-git-plugin"); + InstalledPlugin gitInstalled = createInstalled("scm-git-plugin", "1"); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(gitInstalled)); manager.install("scm-git-plugin", true); @@ -254,7 +266,7 @@ class DefaultPluginManagerTest { @Test void shouldNotInstallAlreadyPendingPlugins() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); manager.install("scm-review-plugin", false); @@ -265,7 +277,7 @@ class DefaultPluginManagerTest { @Test void shouldSendRestartEvent() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); manager.install("scm-review-plugin", false); @@ -283,7 +295,7 @@ class DefaultPluginManagerTest { @Test void shouldReturnSingleAvailableAsPending() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); manager.install("scm-review-plugin", false); @@ -294,7 +306,7 @@ class DefaultPluginManagerTest { @Test void shouldReturnAvailableAsPending() { - AvailablePlugin review = createAvailable("scm-review-plugin"); + AvailablePlugin review = createAvailable("scm-review-plugin", "1"); when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); manager.install("scm-review-plugin", false); @@ -355,15 +367,17 @@ class DefaultPluginManagerTest { } - private AvailablePlugin createAvailable(String name) { + private AvailablePlugin createAvailable(String name, String version) { PluginInformation information = new PluginInformation(); information.setName(name); + information.setVersion(version); return createAvailable(information); } - private InstalledPlugin createInstalled(String name) { + private InstalledPlugin createInstalled(String name, String version) { PluginInformation information = new PluginInformation(); information.setName(name); + information.setVersion(version); return createInstalled(information); }