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
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
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 }