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.PluginRestartState;
6   import com.atlassian.plugin.PluginState;
7   import com.atlassian.plugin.event.PluginEventManager;
8   import com.atlassian.plugin.loaders.PluginLoader;
9   import com.google.common.collect.ImmutableList;
10  import com.google.common.collect.ImmutableMap;
11  import com.google.common.collect.ImmutableSet;
12  import org.junit.Before;
13  import org.junit.Rule;
14  import org.junit.Test;
15  import org.junit.runner.RunWith;
16  import org.junit.runners.Parameterized;
17  import org.mockito.Mock;
18  import org.mockito.junit.MockitoJUnit;
19  import org.mockito.junit.MockitoRule;
20  
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.stream.Collectors;
28  
29  import static org.hamcrest.MatcherAssert.assertThat;
30  import static org.hamcrest.Matchers.is;
31  import static org.hamcrest.Matchers.notNullValue;
32  import static org.junit.Assert.fail;
33  import static org.mockito.ArgumentMatchers.any;
34  import static org.mockito.Mockito.when;
35  
36  @RunWith(Parameterized.class)
37  public class TestDefaultPluginManagerCycled extends TestDependentPlugins {
38      enum Result {
39          DISABLED(PluginState.DISABLED),
40          BOUNCED(PluginState.ENABLED),
41          UNTOUCHED(PluginState.ENABLED);
42  
43          final PluginState finalState;
44  
45          Result(final PluginState finalState) {
46              this.finalState = finalState;
47          }
48  
49          public PluginState getFinalState() {
50              return finalState;
51          }
52      }
53  
54      @Parameterized.Parameters(name = "{index}: {0}({1}): {2}")
55      public static Collection<Object[]> data() {
56          return Arrays.asList(new Object[][]{
57                  {PluginState.DISABLED, ImmutableList.of("G"), ImmutableMap.<Result, Set<String>>builder()
58                          .put(Result.DISABLED, ImmutableSet.of("C", "E", "H"))
59                          .put(Result.BOUNCED, ImmutableSet.of("D", "F", "A"))
60                          .put(Result.UNTOUCHED, ImmutableSet.of("B"))
61                          .build()
62                  },
63                  {PluginState.UNINSTALLED, ImmutableList.of("G"), ImmutableMap.<Result, Set<String>>builder()
64                          .put(Result.DISABLED, ImmutableSet.of("C", "E", "H"))
65                          .put(Result.BOUNCED, ImmutableSet.of("B", "D", "F", "A"))
66                          .build()
67                  },
68                  // circular deps
69                  {PluginState.DISABLED, ImmutableList.of("a"), ImmutableMap.<Result, Set<String>>builder()
70                          .put(Result.DISABLED, ImmutableSet.of("b", "c"))
71                          .build()
72                  },
73                  {PluginState.UNINSTALLED, ImmutableList.of("a"), ImmutableMap.<Result, Set<String>>builder()
74                          .put(Result.DISABLED, ImmutableSet.of("b", "c"))
75                          .build()
76                  },
77  
78                  // multiple plugins
79  
80                  {PluginState.UNINSTALLED, ImmutableList.of("G", "D", "E"), ImmutableMap.<Result, Set<String>>builder()
81                          .put(Result.DISABLED, ImmutableSet.of("C", "H", "F"))
82                          .put(Result.BOUNCED, ImmutableSet.of("A", "B"))
83                          .build()
84                  },
85  
86                  {PluginState.UNINSTALLED, ImmutableList.of("b", "c"), ImmutableMap.<Result, Set<String>>builder()
87                          .put(Result.DISABLED, ImmutableSet.of("a"))
88                          .build()
89                  },
90  
91                  {PluginState.UNINSTALLED, ImmutableList.of("mC", "mD"), ImmutableMap.<Result, Set<String>>builder()
92                          .put(Result.DISABLED, ImmutableSet.of("mX", "mA", "mE"))
93                          .put(Result.BOUNCED, ImmutableSet.of("mB"))
94                          .build()
95                  },
96          });
97      }
98  
99      @Parameterized.Parameter
100     public PluginState action;
101 
102     @Parameterized.Parameter(1)
103     public List<String> target;
104 
105     @Parameterized.Parameter(2)
106     public Map<Result, Set<String>> expectedResults;
107 
108     @Rule
109     public final MockitoRule mockito = MockitoJUnit.rule();
110 
111     @Mock
112     private PluginPersistentStateStore pluginPersistentStateStore;
113     @Mock
114     private ModuleDescriptorFactory moduleDescriptorFactory;
115     @Mock
116     private PluginEventManager pluginEventManager;
117     @Mock
118     private PluginPersistentState pluginPersistentState;
119     @Mock
120     private PluginLoader pluginLoader;
121 
122     private DefaultPluginManager pluginManager;
123 
124     @Before
125     public void setUp() throws Exception {
126         super.setUp();
127 
128         when(pluginLoader.loadAllPlugins(any(ModuleDescriptorFactory.class))).thenReturn(allPlugins);
129         when(pluginLoader.supportsRemoval()).thenReturn(true);
130 
131         pluginManager = new DefaultPluginManager(
132                 pluginPersistentStateStore,
133                 Arrays.<PluginLoader>asList(pluginLoader),
134                 moduleDescriptorFactory,
135                 pluginEventManager);
136         when(pluginPersistentStateStore.load()).thenReturn(pluginPersistentState);
137         when(pluginPersistentState.getPluginRestartState(any(String.class))).thenReturn(PluginRestartState.NONE);
138         pluginManager.init();
139 
140         pluginManager.enablePlugins(getKeys(allPlugins).toArray(new String[allPlugins.size()]));
141     }
142 
143     @Test
144     public void testAllOtherPluginsNotTouched() throws Exception {
145         final Set<Plugin> changed = new HashSet<>();
146 
147         run((p, result) -> changed.add(p));
148 
149         final Set<Plugin> allPlugins = new HashSet<>(pluginManager.getPlugins());
150         allPlugins.removeAll(changed);
151         target.stream().forEach(key -> allPlugins.remove(pluginManager.getPlugin(key)));
152 
153         allPlugins.stream().forEach(gp -> {
154             PluginWithDeps p = (PluginWithDeps) gp;
155             assertThat(p.getKey(), p.getTimesEnabled(), is(1));
156             assertThat(p.getKey(), p.getTimesDisabled(), is(0));
157         });
158     }
159 
160     @Test
161     public void testPluginsInDesiredStateAfterAction() throws Exception {
162         run((p, result) -> assertThat("Plugin '" + p + "' is not " + result.getFinalState(), p.getPluginState(), is(result.getFinalState())));
163     }
164 
165     @Test
166     public void testBouncedDisabledThenEnabled() throws Exception {
167         run((p, result) -> {
168             if (result == Result.BOUNCED) {
169                 assertThat(p.getKey(), p.getTimesEnabled(), is(2));
170                 assertThat(p.getKey(), p.getTimesDisabled(), is(1));
171             }
172         });
173     }
174 
175     @Test
176     public void testNotTouchedNotBounced() throws Exception {
177         run((p, result) -> {
178             if (result == Result.UNTOUCHED) {
179                 assertThat(p.getKey(), p.getTimesEnabled(), is(1));
180                 assertThat(p.getKey(), p.getTimesDisabled(), is(0));
181             }
182         });
183     }
184 
185     private void run(final AssertResult assertion) {
186         switch (action) {
187             case DISABLED:
188                 pluginManager.disablePlugin(target.get(0));
189                 break;
190             case UNINSTALLED:
191                 if (target.size()==1) {
192                     pluginManager.uninstall(pluginManager.getPlugin(target.get(0)));
193                 } else {
194                     pluginManager.uninstallPlugins(target.stream().map(pluginManager::getPlugin).collect(Collectors.toList()));
195                 }
196                 break;
197             default:
198                 fail("Unsupported action " + action);
199         }
200 
201         for (final Result result : expectedResults.keySet()) {
202             for (final String key : expectedResults.get(result)) {
203                 final Plugin p = pluginManager.getPlugin(key);
204                 assertThat("Plugin with key ='" + key + "' not found", p, is(notNullValue()));
205 
206                 assertion.assertResult((PluginWithDeps) p, result);
207             }
208         }
209     }
210 
211     private interface AssertResult {
212         void assertResult(final PluginWithDeps p, final Result result);
213     }
214 }