View Javadoc

1   package com.atlassian.plugin.manager;
2   
3   import com.atlassian.plugin.MockPlugin;
4   import com.atlassian.plugin.ModuleDescriptorFactory;
5   import com.atlassian.plugin.Plugin;
6   import com.atlassian.plugin.event.PluginEventManager;
7   import com.atlassian.plugin.loaders.PluginLoader;
8   import com.google.common.base.Function;
9   import com.google.common.base.Predicates;
10  import com.google.common.collect.Collections2;
11  import com.google.common.collect.ImmutableList;
12  import com.google.common.collect.ImmutableMap;
13  import com.google.common.collect.ImmutableSet;
14  import com.google.common.collect.Maps;
15  import com.google.common.collect.Sets;
16  import org.junit.Assert;
17  import org.junit.Before;
18  import org.junit.Test;
19  import org.mockito.Mockito;
20  
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.Map;
24  import java.util.Set;
25  import java.util.concurrent.Callable;
26  import java.util.concurrent.ExecutorService;
27  import java.util.concurrent.Executors;
28  import java.util.concurrent.Future;
29  import java.util.concurrent.TimeUnit;
30  import java.util.concurrent.TimeoutException;
31  import java.util.regex.Pattern;
32  
33  public class TestDefaultPluginManagerDependentPlugins
34  {
35  
36      private Collection<Plugin> enabledPlugins;
37      private ImmutableMap<String, Plugin> pluginsByKey;
38      private DefaultPluginManager pluginManager;
39  
40      private static Function<Plugin, String> GET_KEY = new Function<Plugin, String>()
41      {
42          @Override
43          public String apply(Plugin input)
44          {
45              return input.getKey();
46          }
47      };
48  
49      @Before
50      public void setUp() throws Exception
51      {
52          enabledPlugins = ImmutableList.<Plugin>of(
53                  // Draw it on paper first if you want to modify it, the more letters in the key the lower row
54                  new MockDepPlugin("root", Collections.<String>emptySet()),
55  
56                  new MockDepPlugin("a", ImmutableSet.of("root")),
57                  new MockDepPlugin("b", ImmutableSet.of("root", "a")),
58                  new MockDepPlugin("c", ImmutableSet.of("root")),
59  
60                  new MockDepPlugin("aa", ImmutableSet.of("a")),
61                  new MockDepPlugin("ba", ImmutableSet.of("b")),
62                  new MockDepPlugin("bb", ImmutableSet.of("b")),
63                  new MockDepPlugin("ca", ImmutableSet.of("c")),
64                  new MockDepPlugin("cb", ImmutableSet.of("c", "ca")),
65  
66                  new MockDepPlugin("aaa", ImmutableSet.of("aa")),
67                  new MockDepPlugin("caa", ImmutableSet.of("c", "ca", "cb")),
68  
69                  new MockDepPlugin("disconnected.a", ImmutableSet.<String>of()),
70                  new MockDepPlugin("disconnected.b", ImmutableSet.of("disconnected.a")),
71                  new MockDepPlugin("disconnected.c", ImmutableSet.of("disconnected.b"))
72          );
73  
74          pluginsByKey = Maps.uniqueIndex(enabledPlugins, GET_KEY);
75  
76          pluginManager = new DefaultPluginManager(Mockito.mock(PluginPersistentStateStore.class), Collections.<PluginLoader>emptyList(),
77                  Mockito.mock(ModuleDescriptorFactory.class), Mockito.mock(PluginEventManager.class));
78      }
79  
80      private Set<String> getDependentPluginKeys(String parentKey)
81      {
82          return getDependentPluginKeys(pluginsByKey.get(parentKey), enabledPlugins);
83      }
84  
85      private Set<String> getDependentPluginKeys(Plugin root, Collection<Plugin> enabledPlugins)
86      {
87          return ImmutableSet.copyOf(Collections2.transform(
88                  pluginManager.getDependentPlugins(root, enabledPlugins), GET_KEY));
89      }
90  
91      @Test
92      public void testNoDependencies() throws Exception
93      {
94          Assert.assertEquals(ImmutableSet.<String>of(), getDependentPluginKeys("aaa"));
95      }
96  
97      @Test
98      public void testSingleDependency() throws Exception
99      {
100         Assert.assertEquals(ImmutableSet.of("aaa"), getDependentPluginKeys("aa"));
101     }
102 
103     @Test
104     public void testSimpleTransitiveDependency() throws Exception
105     {
106         Assert.assertEquals(ImmutableSet.of("disconnected.b", "disconnected.c"), getDependentPluginKeys("disconnected.a"));
107     }
108 
109     @Test
110     public void testTransitiveDependency() throws Exception
111     {
112         Assert.assertEquals(ImmutableSet.of("aa", "aaa", "b", "ba", "bb"), getDependentPluginKeys("a"));
113     }
114 
115     @Test
116     public void testCrossLayerDependency() throws Exception
117     {
118         Assert.assertEquals(ImmutableSet.of("ca", "cb", "caa"), getDependentPluginKeys("c"));
119     }
120 
121     @Test
122     public void testFullTreeDependency() throws Exception
123     {
124         final Set<String> notDisconnected = Sets.filter(pluginsByKey.keySet(), Predicates.not(Predicates.contains(
125                 Pattern.compile("disconnected|root"))));
126         Assert.assertEquals(notDisconnected, getDependentPluginKeys("root"));
127     }
128 
129     @Test(timeout = 1000)
130     public void testCircularDependency() throws Exception
131     {
132         final ImmutableList<Plugin> plugins = ImmutableList.<Plugin>of(
133                 new MockDepPlugin("a", ImmutableSet.of("c")),
134                 new MockDepPlugin("b", ImmutableSet.of("a")),
135                 new MockDepPlugin("c", ImmutableSet.of("b"))
136         );
137         Assert.assertEquals(ImmutableSet.of("b", "c"), getDependentPluginKeys(plugins.get(0), plugins));
138     }
139 
140     @Test(timeout = 1000)
141     public void testVeryDeepDependencyTreePerformance() throws Exception
142     {
143         final Map<String, Plugin> plugins = Maps.newHashMap();
144         plugins.put("root", new MockDepPlugin("root", ImmutableSet.<String>of()));
145 
146         for (int lvl = 0; lvl < 10; lvl++)
147         {
148             final Set<String> existingKeys = ImmutableSet.copyOf(plugins.keySet());
149             for (int i = 0; i < 10; i++)
150             {
151                 final String key = lvl + "." + i;
152                 plugins.put(key, new MockDepPlugin(key, existingKeys));
153             }
154         }
155 
156         final Set<String> allButRoot = Sets.difference(plugins.keySet(), ImmutableSet.of("root"));
157         Assert.assertEquals(allButRoot, getDependentPluginKeys(plugins.get("root"), plugins.values()));
158     }
159 }
160 
161 class MockDepPlugin extends MockPlugin
162 {
163     final Set<String> requiredPlugins;
164 
165     public MockDepPlugin(String key, Set<String> requiredPlugins)
166     {
167         super(key, null);
168         this.requiredPlugins = requiredPlugins;
169     }
170 
171     @Override
172     public Set<String> getRequiredPlugins()
173     {
174         return requiredPlugins;
175     }
176 }