1 package com.atlassian.plugin.manager;
2
3 import com.atlassian.plugin.ModuleDescriptorFactory;
4 import com.atlassian.plugin.Plugin;
5 import com.atlassian.plugin.PluginDependencies;
6 import com.atlassian.plugin.event.PluginEventManager;
7 import com.atlassian.plugin.loaders.PluginLoader;
8 import com.google.common.base.Predicates;
9 import com.google.common.collect.Collections2;
10 import com.google.common.collect.ImmutableList;
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.collect.ImmutableSet;
13 import com.google.common.collect.Maps;
14 import com.google.common.collect.Sets;
15 import org.junit.Assert;
16 import org.junit.Before;
17 import org.junit.Test;
18 import org.mockito.Mockito;
19
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.regex.Pattern;
25
26 import static com.atlassian.plugin.PluginDependencies.Type.DYNAMIC;
27 import static com.atlassian.plugin.PluginDependencies.Type.MANDATORY;
28 import static com.atlassian.plugin.PluginDependencies.Type.OPTIONAL;
29 import static com.atlassian.plugin.manager.PluginWithDeps.GET_KEY;
30
31 public class TestDefaultPluginManagerDependentPlugins {
32 private Collection<Plugin> enabledPlugins;
33 private ImmutableMap<String, Plugin> pluginsByKey;
34 private DefaultPluginManager pluginManager;
35
36 @Before
37 public void setUp() throws Exception {
38 enabledPlugins = ImmutableList.of(
39
40 new PluginWithDeps("root"),
41
42 new PluginWithDeps("a", "root"),
43 new PluginWithDeps("b", "root", "a"),
44 new PluginWithDeps("c", "root"),
45
46 new PluginWithDeps("aa", "a"),
47 new PluginWithDeps("ba", "b"),
48 new PluginWithDeps("bb", "b"),
49 new PluginWithDeps("ca", "c"),
50 new PluginWithDeps("cb", "c", "ca"),
51
52 new PluginWithDeps("aaa", "aa"),
53 new PluginWithDeps("caa", "c", "ca", "cb"),
54
55 new PluginWithDeps("disconnected.a"),
56 new PluginWithDeps("disconnected.b", "disconnected.a"),
57 new PluginWithDeps("disconnected.c", "disconnected.b")
58 );
59
60 pluginsByKey = Maps.uniqueIndex(enabledPlugins, GET_KEY);
61
62 pluginManager = new DefaultPluginManager(Mockito.mock(PluginPersistentStateStore.class), Collections.<PluginLoader>emptyList(),
63 Mockito.mock(ModuleDescriptorFactory.class), Mockito.mock(PluginEventManager.class));
64 }
65
66 private Set<String> getDependentPluginKeys(String parentKey) {
67 return getDependentPluginKeys(pluginsByKey.get(parentKey), enabledPlugins);
68 }
69
70 private Set<String> getDependentPluginKeys(Plugin root, Collection<Plugin> enabledPlugins) {
71 final DependentPlugins dependentPlugins = new DependentPlugins(ImmutableList.of(root.getKey()), enabledPlugins, ImmutableSet.of(MANDATORY, OPTIONAL, DYNAMIC));
72 return ImmutableSet.copyOf(Collections2.transform(dependentPlugins.get(), GET_KEY));
73 }
74
75 @Test
76 public void testNoDependencies() throws Exception {
77 Assert.assertEquals(ImmutableSet.of(), getDependentPluginKeys("aaa"));
78 }
79
80 @Test
81 public void testSingleDependency() throws Exception {
82 Assert.assertEquals(ImmutableSet.of("aaa"), getDependentPluginKeys("aa"));
83 }
84
85 @Test
86 public void testSimpleTransitiveDependency() throws Exception {
87 Assert.assertEquals(ImmutableSet.of("disconnected.b", "disconnected.c"), getDependentPluginKeys("disconnected.a"));
88 }
89
90 @Test
91 public void testTransitiveDependency() throws Exception {
92 Assert.assertEquals(ImmutableSet.of("aa", "aaa", "b", "ba", "bb"), getDependentPluginKeys("a"));
93 }
94
95 @Test
96 public void testCrossLayerDependency() throws Exception {
97 Assert.assertEquals(ImmutableSet.of("ca", "cb", "caa"), getDependentPluginKeys("c"));
98 }
99
100 @Test
101 public void testFullTreeDependency() throws Exception {
102 final Set<String> notDisconnected = Sets.filter(pluginsByKey.keySet(), Predicates.not(Predicates.contains(
103 Pattern.compile("disconnected|root"))));
104 Assert.assertEquals(notDisconnected, getDependentPluginKeys("root"));
105 }
106
107 @Test(timeout = 1000)
108 public void testCircularDependency() throws Exception {
109 final ImmutableList<Plugin> plugins = ImmutableList.of(
110 new PluginWithDeps("a", "c"),
111 new PluginWithDeps("b", "a"),
112 new PluginWithDeps("c", "b")
113 );
114 Assert.assertEquals(ImmutableSet.of("b", "c"), getDependentPluginKeys(plugins.get(0), plugins));
115 }
116
117 @Test(timeout = 1000)
118 public void testVeryDeepDependencyTreePerformance() throws Exception {
119 final Map<String, Plugin> plugins = Maps.newHashMap();
120 plugins.put("root", new PluginWithDeps("root"));
121
122 for (int lvl = 0; lvl < 10; lvl++) {
123 final Set<String> existingKeys = ImmutableSet.copyOf(plugins.keySet());
124 for (int i = 0; i < 10; i++) {
125 final String key = lvl + "." + i;
126 plugins.put(key, new PluginWithDeps(key, new PluginDependencies(existingKeys, null, null)));
127 }
128 }
129
130 final Set<String> allButRoot = Sets.difference(plugins.keySet(), ImmutableSet.of("root"));
131 Assert.assertEquals(allButRoot, getDependentPluginKeys(plugins.get("root"), plugins.values()));
132 }
133 }