mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-07-02 21:18:05 +02:00
Add security notifications to inform about vulnerabilities (#1924)
Add security notifications in SCM-Manager to inform running instances about known security issues. These alerts can be core or plugin specific and will be shown to every user in the header. Co-authored-by: Matthias Thieroff <matthias.thieroff@cloudogu.com> Co-authored-by: Philipp Ahrendt <philipp.ahrendt@cloudogu.com> Co-authored-by: Sebastian Sdorra <sebastian.sdorra@cloudogu.com>
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.api.v2.resources.AlertsResource.AlertsRequest;
|
||||
import sonia.scm.api.v2.resources.AlertsResource.AlertsRequestBody;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.plugin.InstalledPlugin;
|
||||
import sonia.scm.plugin.InstalledPluginDescriptor;
|
||||
import sonia.scm.plugin.PluginInformation;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.util.SystemUtil;
|
||||
import sonia.scm.web.RestDispatcher;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
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 AlertsResourceTest {
|
||||
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Mock
|
||||
private PluginLoader pluginLoader;
|
||||
|
||||
@Mock
|
||||
private SCMContextProvider scmContextProvider;
|
||||
|
||||
private RestDispatcher restDispatcher;
|
||||
private ScmConfiguration scmConfiguration;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
restDispatcher = new RestDispatcher();
|
||||
scmConfiguration = new ScmConfiguration();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFailWithConflictIfAlertsUrlIsNull() throws Exception {
|
||||
scmConfiguration.setAlertsUrl(null);
|
||||
|
||||
MockHttpResponse response = invoke();
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(409);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnSelfUrl() throws Exception {
|
||||
MockHttpResponse response = invoke();
|
||||
JsonNode node = mapper.readTree(response.getContentAsString());
|
||||
assertThat(node.get("_links").get("self").get("href").asText()).isEqualTo("/v2/alerts");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnAlertsUrl() throws Exception {
|
||||
MockHttpResponse response = invoke();
|
||||
JsonNode node = mapper.readTree(response.getContentAsString());
|
||||
assertThat(node.get("_links").get("alerts").get("href").asText()).isEqualTo(ScmConfiguration.DEFAULT_ALERTS_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnVndMediaType() throws Exception {
|
||||
MockHttpResponse response = invoke();
|
||||
assertThat(response.getOutputHeaders().getFirst("Content-Type")).hasToString(VndMediaType.ALERTS_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnCustomAlertsUrl() throws Exception {
|
||||
scmConfiguration.setAlertsUrl("https://mycustom.alerts.io");
|
||||
|
||||
MockHttpResponse response = invoke();
|
||||
JsonNode node = mapper.readTree(response.getContentAsString());
|
||||
|
||||
assertThat(node.get("_links").get("alerts").get("href").asText()).isEqualTo("https://mycustom.alerts.io");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnAlertsRequest() throws Exception {
|
||||
String instanceId = UUID.randomUUID().toString();
|
||||
when(scmContextProvider.getInstanceId()).thenReturn(instanceId);
|
||||
when(scmContextProvider.getVersion()).thenReturn("2.28.0");
|
||||
|
||||
InstalledPlugin pluginA = createInstalledPlugin("some-scm-plugin", "1.0.0");
|
||||
InstalledPlugin pluginB = createInstalledPlugin("other-scm-plugin", "2.1.1");
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Arrays.asList(pluginA, pluginB));
|
||||
|
||||
MockHttpResponse response = invoke();
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
|
||||
AlertsRequest alertsRequest = unmarshal(response);
|
||||
AlertsRequestBody body = alertsRequest.getBody();
|
||||
assertThat(body.getInstanceId()).isEqualTo(instanceId);
|
||||
assertThat(body.getVersion()).isEqualTo("2.28.0");
|
||||
assertThat(body.getOs()).isEqualTo(SystemUtil.getOS());
|
||||
assertThat(body.getArch()).isEqualTo(SystemUtil.getArch());
|
||||
assertThat(body.getJre()).isEqualTo(SystemUtil.getJre());
|
||||
|
||||
List<AlertsResource.Plugin> plugins = body.getPlugins();
|
||||
assertThat(plugins.size()).isEqualTo(2);
|
||||
AlertsResource.Plugin somePlugin = findPlugin(plugins, "some-scm-plugin");
|
||||
assertThat(somePlugin.getVersion()).isEqualTo("1.0.0");
|
||||
AlertsResource.Plugin otherPlugin = findPlugin(plugins, "other-scm-plugin");
|
||||
assertThat(otherPlugin.getVersion()).isEqualTo("2.1.1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnSameChecksumIfNothingChanged() throws Exception {
|
||||
String instanceId = UUID.randomUUID().toString();
|
||||
when(scmContextProvider.getInstanceId()).thenReturn(instanceId);
|
||||
when(scmContextProvider.getVersion()).thenReturn("2.28.0");
|
||||
|
||||
InstalledPlugin plugin = createInstalledPlugin("some-scm-plugin", "1.0.0");
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Collections.singletonList(plugin));
|
||||
|
||||
MockHttpResponse response = invoke();
|
||||
String checksum = unmarshal(response).getChecksum();
|
||||
|
||||
MockHttpResponse secondResponse = invoke();
|
||||
|
||||
assertThat(unmarshal(secondResponse).getChecksum()).isEqualTo(checksum);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnDifferentChecksumIfCoreVersionChanges() throws Exception {
|
||||
when(scmContextProvider.getVersion()).thenReturn("2.28.0");
|
||||
|
||||
MockHttpResponse response = invoke();
|
||||
String checksum = unmarshal(response).getChecksum();
|
||||
|
||||
when(scmContextProvider.getVersion()).thenReturn("2.28.1");
|
||||
|
||||
MockHttpResponse secondResponse = invoke();
|
||||
|
||||
assertThat(unmarshal(secondResponse).getChecksum()).isNotEqualTo(checksum);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnDifferentChecksumIfPluginVersionChanges() throws Exception {
|
||||
InstalledPlugin plugin1_0_0 = createInstalledPlugin("some-scm-plugin", "1.0.0");
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Collections.singletonList(plugin1_0_0));
|
||||
|
||||
MockHttpResponse response = invoke();
|
||||
String checksum = unmarshal(response).getChecksum();
|
||||
|
||||
InstalledPlugin plugin1_0_1 = createInstalledPlugin("some-scm-plugin", "1.0.1");
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Collections.singletonList(plugin1_0_1));
|
||||
|
||||
MockHttpResponse secondResponse = invoke();
|
||||
|
||||
assertThat(unmarshal(secondResponse).getChecksum()).isNotEqualTo(checksum);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnDifferentChecksumIfDateChanges() throws Exception {
|
||||
MockHttpResponse response = invoke();
|
||||
String checksum = unmarshal(response).getChecksum();
|
||||
|
||||
InstalledPlugin plugin1_0_1 = createInstalledPlugin("some-scm-plugin", "1.0.1");
|
||||
when(pluginLoader.getInstalledPlugins()).thenReturn(Collections.singletonList(plugin1_0_1));
|
||||
|
||||
MockHttpResponse secondResponse = invoke("1979-10-12");
|
||||
|
||||
assertThat(unmarshal(secondResponse).getChecksum()).isNotEqualTo(checksum);
|
||||
}
|
||||
|
||||
private InstalledPlugin createInstalledPlugin(String name, String version) {
|
||||
PluginInformation pluginInformation = new PluginInformation();
|
||||
pluginInformation.setName(name);
|
||||
pluginInformation.setVersion(version);
|
||||
return createInstalledPlugin(pluginInformation);
|
||||
}
|
||||
|
||||
private InstalledPlugin createInstalledPlugin(PluginInformation pluginInformation) {
|
||||
InstalledPluginDescriptor descriptor = mock(InstalledPluginDescriptor.class);
|
||||
lenient().when(descriptor.getInformation()).thenReturn(pluginInformation);
|
||||
return new InstalledPlugin(descriptor, null, null, null, false);
|
||||
}
|
||||
|
||||
private MockHttpResponse invoke() throws Exception {
|
||||
return invoke(null);
|
||||
}
|
||||
|
||||
private MockHttpResponse invoke(String date) throws Exception {
|
||||
AlertsResource alertsResource;
|
||||
if (date != null) {
|
||||
alertsResource = new AlertsResource(scmContextProvider, scmConfiguration, pluginLoader, () -> date);
|
||||
} else {
|
||||
alertsResource = new AlertsResource(scmContextProvider, scmConfiguration, pluginLoader);
|
||||
}
|
||||
|
||||
restDispatcher.addSingletonResource(alertsResource);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest.get("/v2/alerts");
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
restDispatcher.invoke(request, response);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private AlertsRequest unmarshal(MockHttpResponse response) throws JsonProcessingException, UnsupportedEncodingException {
|
||||
return mapper.readValue(response.getContentAsString(), AlertsRequest.class);
|
||||
}
|
||||
|
||||
private AlertsResource.Plugin findPlugin(List<AlertsResource.Plugin> plugins, String name) {
|
||||
return plugins.stream()
|
||||
.filter(p -> name.equals(p.getName()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("plugin " + name + " not found in request"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,12 +39,8 @@ import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.security.AnonymousMode;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -106,6 +102,7 @@ class ScmConfigurationToConfigDtoMapperTest {
|
||||
assertThat(dto.isEnabledXsrfProtection()).isTrue();
|
||||
assertThat(dto.getNamespaceStrategy()).isEqualTo("username");
|
||||
assertThat(dto.getLoginInfoUrl()).isEqualTo("https://scm-manager.org/login-info");
|
||||
assertThat(dto.getAlertsUrl()).isEqualTo("https://alerts.scm-manager.org/api/v1/alerts");
|
||||
assertThat(dto.getReleaseFeedUrl()).isEqualTo("https://www.scm-manager.org/download/rss.xml");
|
||||
assertThat(dto.getMailDomainName()).isEqualTo("scm-manager.local");
|
||||
assertThat(dto.getEmergencyContacts()).contains(expectedUsers);
|
||||
@@ -169,6 +166,7 @@ class ScmConfigurationToConfigDtoMapperTest {
|
||||
config.setEnabledXsrfProtection(true);
|
||||
config.setNamespaceStrategy("username");
|
||||
config.setLoginInfoUrl("https://scm-manager.org/login-info");
|
||||
config.setAlertsUrl("https://alerts.scm-manager.org/api/v1/alerts");
|
||||
config.setReleaseFeedUrl("https://www.scm-manager.org/download/rss.xml");
|
||||
config.setEmergencyContacts(Sets.newSet(expectedUsers));
|
||||
return config;
|
||||
|
||||
@@ -21,166 +21,143 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.plugin;
|
||||
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.of;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
import sonia.scm.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.of;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
public class PluginTreeTest
|
||||
{
|
||||
public class PluginTreeTest {
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder tempFolder = new TemporaryFolder();
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test(expected = PluginConditionFailedException.class)
|
||||
public void testPluginConditionFailed() throws IOException
|
||||
{
|
||||
PluginCondition condition = new PluginCondition("999",
|
||||
new ArrayList<String>(), "hit");
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo("a", "1"), null, condition,
|
||||
false, null, null);
|
||||
public void testPluginConditionFailed() throws IOException {
|
||||
PluginCondition condition = new PluginCondition("999", new ArrayList<>(), "hit");
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo("a", "1"), null, condition,
|
||||
false, null, null);
|
||||
ExplodedSmp smp = createSmp(plugin);
|
||||
|
||||
new PluginTree(smp).getLeafLastNodes();
|
||||
new PluginTree(Stage.PRODUCTION, smp).getLeafLastNodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test(expected = PluginNotInstalledException.class)
|
||||
public void testPluginNotInstalled() throws IOException
|
||||
{
|
||||
new PluginTree(createSmpWithDependency("b", "a")).getLeafLastNodes();
|
||||
@Test(expected = PluginConditionFailedException.class)
|
||||
public void testPluginConditionFailedInDevelopmentStage() throws IOException {
|
||||
PluginCondition condition = new PluginCondition("999", new ArrayList<>(), "hit");
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo("a", "1"), null, condition,
|
||||
false, null, null);
|
||||
ExplodedSmp smp = createSmp(plugin);
|
||||
|
||||
new PluginTree(Stage.DEVELOPMENT, smp).getLeafLastNodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testNodes() throws IOException
|
||||
{
|
||||
public void testSkipCorePluginValidationOnDevelopment() throws IOException {
|
||||
PluginCondition condition = new PluginCondition("999", new ArrayList<>(), "hit");
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(2, createInfo("a", "1"), null, condition,
|
||||
false, null, null);
|
||||
|
||||
// make it core
|
||||
ExplodedSmp smp = createSmp(plugin);
|
||||
Path path = smp.getPath();
|
||||
Files.createFile(path.resolve(PluginConstants.FILE_CORE));
|
||||
|
||||
List<PluginNode> nodes = new PluginTree(Stage.DEVELOPMENT, smp).getLeafLastNodes();
|
||||
assertFalse(nodes.isEmpty());
|
||||
}
|
||||
|
||||
@Test(expected = PluginNotInstalledException.class)
|
||||
public void testPluginNotInstalled() throws IOException {
|
||||
new PluginTree(Stage.PRODUCTION, createSmpWithDependency("b", "a")).getLeafLastNodes();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNodes() throws IOException {
|
||||
List<ExplodedSmp> smps = createSmps("a", "b", "c");
|
||||
List<String> nodes = unwrapIds(new PluginTree(smps).getLeafLastNodes());
|
||||
List<String> nodes = unwrapIds(new PluginTree(Stage.PRODUCTION, smps).getLeafLastNodes());
|
||||
|
||||
assertThat(nodes, containsInAnyOrder("a", "b", "c"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test(expected = PluginException.class)
|
||||
public void testScmVersion() throws IOException
|
||||
{
|
||||
public void testScmVersion() throws IOException {
|
||||
InstalledPluginDescriptor plugin = new InstalledPluginDescriptor(1, createInfo("a", "1"), null, null, false,
|
||||
null, null);
|
||||
null, null);
|
||||
ExplodedSmp smp = createSmp(plugin);
|
||||
|
||||
new PluginTree(smp).getLeafLastNodes();
|
||||
new PluginTree(Stage.PRODUCTION, smp).getLeafLastNodes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Test
|
||||
public void testSimpleDependencies() throws IOException
|
||||
{
|
||||
//J-
|
||||
ExplodedSmp[] smps = new ExplodedSmp[] {
|
||||
public void testSimpleDependencies() throws IOException {
|
||||
ExplodedSmp[] smps = new ExplodedSmp[]{
|
||||
createSmpWithDependency("a"),
|
||||
createSmpWithDependency("b", "a"),
|
||||
createSmpWithDependency("c", "a", "b")
|
||||
};
|
||||
//J+
|
||||
|
||||
PluginTree tree = new PluginTree(smps);
|
||||
PluginTree tree = new PluginTree(Stage.PRODUCTION, smps);
|
||||
List<PluginNode> nodes = tree.getLeafLastNodes();
|
||||
|
||||
System.out.println(tree);
|
||||
|
||||
assertThat(unwrapIds(nodes), contains("a", "b", "c"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexDependencies() throws IOException
|
||||
{
|
||||
//J-
|
||||
public void testComplexDependencies() throws IOException {
|
||||
ExplodedSmp[] smps = new ExplodedSmp[]{
|
||||
createSmpWithDependency("a", "b", "c", "d"),
|
||||
createSmpWithDependency("b", "c"),
|
||||
createSmpWithDependency("c"),
|
||||
createSmpWithDependency("d")
|
||||
};
|
||||
//J+
|
||||
|
||||
PluginTree tree = new PluginTree(smps);
|
||||
PluginTree tree = new PluginTree(Stage.PRODUCTION, smps);
|
||||
List<PluginNode> nodes = tree.getLeafLastNodes();
|
||||
|
||||
System.out.println(tree);
|
||||
|
||||
assertThat(unwrapIds(nodes), contains("d", "c", "b", "a"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithOptionalDependency() throws IOException {
|
||||
ExplodedSmp[] smps = new ExplodedSmp[] {
|
||||
ExplodedSmp[] smps = new ExplodedSmp[]{
|
||||
createSmpWithDependency("a"),
|
||||
createSmpWithDependency("b", null, of("a")),
|
||||
createSmpWithDependency("c", null, of("a", "b"))
|
||||
};
|
||||
|
||||
PluginTree tree = new PluginTree(smps);
|
||||
PluginTree tree = new PluginTree(Stage.PRODUCTION, smps);
|
||||
List<PluginNode> nodes = tree.getLeafLastNodes();
|
||||
|
||||
System.out.println(tree);
|
||||
|
||||
assertThat(unwrapIds(nodes), contains("a", "b", "c"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRealWorldDependencies() throws IOException {
|
||||
//J-
|
||||
ExplodedSmp[] smps = new ExplodedSmp[]{
|
||||
createSmpWithDependency("scm-editor-plugin"),
|
||||
createSmpWithDependency("scm-ci-plugin"),
|
||||
@@ -206,7 +183,7 @@ public class PluginTreeTest
|
||||
createSmpWithDependency("scm-script-plugin"),
|
||||
createSmpWithDependency("scm-activity-plugin"),
|
||||
createSmpWithDependency("scm-mail-plugin"),
|
||||
createSmpWithDependency("scm-branchwp-plugin", of(), of("scm-editor-plugin", "scm-review-plugin", "scm-mail-plugin" )),
|
||||
createSmpWithDependency("scm-branchwp-plugin", of(), of("scm-editor-plugin", "scm-review-plugin", "scm-mail-plugin")),
|
||||
createSmpWithDependency("scm-notify-plugin", "scm-mail-plugin"),
|
||||
createSmpWithDependency("scm-redmine-plugin", "scm-issuetracker-plugin"),
|
||||
createSmpWithDependency("scm-jira-plugin", "scm-mail-plugin", "scm-issuetracker-plugin"),
|
||||
@@ -214,17 +191,10 @@ public class PluginTreeTest
|
||||
createSmpWithDependency("scm-pathwp-plugin", of(), of("scm-editor-plugin")),
|
||||
createSmpWithDependency("scm-cockpit-legacy-plugin", "scm-statistic-plugin", "scm-rest-legacy-plugin", "scm-activity-plugin")
|
||||
};
|
||||
//J+
|
||||
|
||||
Arrays.stream(smps)
|
||||
.forEach(smp -> System.out.println(smp.getPlugin()));
|
||||
|
||||
|
||||
PluginTree tree = new PluginTree(smps);
|
||||
PluginTree tree = new PluginTree(Stage.PRODUCTION, smps);
|
||||
List<PluginNode> nodes = tree.getLeafLastNodes();
|
||||
|
||||
System.out.println(tree);
|
||||
|
||||
assertEachParentHasChild(nodes, "scm-review-plugin", "scm-branchwp-plugin");
|
||||
}
|
||||
|
||||
@@ -239,18 +209,15 @@ public class PluginTreeTest
|
||||
assertEachParentHasChild(pluginNode.getChildren(), parentName, childName);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWithDeepOptionalDependency() throws IOException {
|
||||
ExplodedSmp[] smps = new ExplodedSmp[] {
|
||||
ExplodedSmp[] smps = new ExplodedSmp[]{
|
||||
createSmpWithDependency("a"),
|
||||
createSmpWithDependency("b", "a"),
|
||||
createSmpWithDependency("c", null, of("b"))
|
||||
};
|
||||
|
||||
PluginTree tree = new PluginTree(smps);
|
||||
|
||||
System.out.println(tree);
|
||||
PluginTree tree = new PluginTree(Stage.PRODUCTION, smps);
|
||||
|
||||
List<PluginNode> nodes = tree.getLeafLastNodes();
|
||||
|
||||
@@ -259,28 +226,18 @@ public class PluginTreeTest
|
||||
|
||||
@Test
|
||||
public void testWithNonExistentOptionalDependency() throws IOException {
|
||||
ExplodedSmp[] smps = new ExplodedSmp[] {
|
||||
ExplodedSmp[] smps = new ExplodedSmp[]{
|
||||
createSmpWithDependency("a", null, of("b"))
|
||||
};
|
||||
|
||||
PluginTree tree = new PluginTree(smps);
|
||||
PluginTree tree = new PluginTree(Stage.PRODUCTION, smps);
|
||||
List<PluginNode> nodes = tree.getLeafLastNodes();
|
||||
|
||||
assertThat(unwrapIds(nodes), containsInAnyOrder("a"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param version
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private PluginInformation createInfo(String name,
|
||||
String version)
|
||||
{
|
||||
String version) {
|
||||
PluginInformation info = new PluginInformation();
|
||||
|
||||
info.setName(name);
|
||||
@@ -289,58 +246,21 @@ public class PluginTreeTest
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param plugin
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private ExplodedSmp createSmp(InstalledPluginDescriptor plugin) throws IOException
|
||||
{
|
||||
return new ExplodedSmp(tempFolder.newFile().toPath(), plugin);
|
||||
private ExplodedSmp createSmp(InstalledPluginDescriptor plugin) throws IOException {
|
||||
return new ExplodedSmp(tempFolder.newFolder().toPath(), plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private ExplodedSmp createSmp(String name) throws IOException
|
||||
{
|
||||
private ExplodedSmp createSmp(String name) throws IOException {
|
||||
return createSmp(new InstalledPluginDescriptor(2, createInfo(name, "1.0.0"), null, null,
|
||||
false, null, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param name
|
||||
* @param dependencies
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private ExplodedSmp createSmpWithDependency(String name,
|
||||
String... dependencies)
|
||||
throws IOException
|
||||
{
|
||||
String... dependencies)
|
||||
throws IOException {
|
||||
Set<String> dependencySet = new HashSet<>();
|
||||
|
||||
for (String d : dependencies)
|
||||
{
|
||||
dependencySet.add(d);
|
||||
}
|
||||
Collections.addAll(dependencySet, dependencies);
|
||||
return createSmpWithDependency(name, dependencySet, null);
|
||||
}
|
||||
|
||||
@@ -357,52 +277,18 @@ public class PluginTreeTest
|
||||
return createSmp(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param names
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private List<ExplodedSmp> createSmps(String... names) throws IOException
|
||||
{
|
||||
private List<ExplodedSmp> createSmps(String... names) throws IOException {
|
||||
List<ExplodedSmp> smps = Lists.newArrayList();
|
||||
|
||||
for (String name : names)
|
||||
{
|
||||
for (String name : names) {
|
||||
smps.add(createSmp(name));
|
||||
}
|
||||
|
||||
return smps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param nodes
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private List<String> unwrapIds(List<PluginNode> nodes)
|
||||
{
|
||||
return Lists.transform(nodes, new Function<PluginNode, String>()
|
||||
{
|
||||
|
||||
@Override
|
||||
public String apply(PluginNode input)
|
||||
{
|
||||
return input.getId();
|
||||
}
|
||||
});
|
||||
private List<String> unwrapIds(List<PluginNode> nodes) {
|
||||
return nodes.stream().map(PluginNode::getId).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@Rule
|
||||
public TemporaryFolder tempFolder = new TemporaryFolder();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user