View Javadoc
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                  // Draw it on paper first if you want to modify it, the more letters in the key the lower row
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 }