source: josm/trunk/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceHighLevelTest.java@ 18694

Last change on this file since 18694 was 18694, checked in by taylor.smock, 15 months ago

Fix #22381: Try to automatically install newly required plugins on plugin update

This additionally updates the plugin tests to JUnit 5 (see #16567). Some tests
required fixing (for example, MinimapDialogTest fails if the system of
measurement is metric).

  • Property svn:eol-style set to native
File size: 40.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.preferences.plugin;
3
4import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
5import static java.util.concurrent.TimeUnit.MILLISECONDS;
6import static org.junit.jupiter.api.Assertions.assertEquals;
7import static org.junit.jupiter.api.Assertions.assertFalse;
8import static org.junit.jupiter.api.Assertions.assertTrue;
9
10import java.awt.Component;
11import java.io.File;
12import java.nio.file.Files;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.Collections;
17import java.util.stream.Collectors;
18
19import javax.swing.JOptionPane;
20
21import com.github.tomakehurst.wiremock.client.WireMock;
22import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
23import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
24import mockit.MockUp;
25import org.awaitility.Awaitility;
26import org.junit.jupiter.api.AfterEach;
27import org.junit.jupiter.api.BeforeEach;
28import org.junit.jupiter.api.Test;
29import org.junit.jupiter.api.extension.RegisterExtension;
30import org.openstreetmap.josm.TestUtils;
31import org.openstreetmap.josm.data.Preferences;
32import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
33import org.openstreetmap.josm.gui.util.GuiHelper;
34import org.openstreetmap.josm.plugins.PluginHandler;
35import org.openstreetmap.josm.plugins.PluginInformation;
36import org.openstreetmap.josm.plugins.PluginProxy;
37import org.openstreetmap.josm.spi.preferences.Config;
38import org.openstreetmap.josm.testutils.PluginServer;
39import org.openstreetmap.josm.testutils.annotations.AssertionsInEDT;
40import org.openstreetmap.josm.testutils.annotations.AssumeRevision;
41import org.openstreetmap.josm.testutils.annotations.FullPreferences;
42import org.openstreetmap.josm.testutils.annotations.Main;
43import org.openstreetmap.josm.testutils.mockers.HelpAwareOptionPaneMocker;
44import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
45
46/**
47 * Higher level tests of {@link PluginPreference} class.
48 */
49@AssumeRevision("Revision: 10000\n")
50@AssertionsInEDT
51@FullPreferences
52@Main
53class PluginPreferenceHighLevelTest {
54 /**
55 * Plugin server mock.
56 */
57 @RegisterExtension
58 static WireMockExtension pluginServerRule = WireMockExtension.newInstance()
59 .options(options().dynamicPort().usingFilesUnderDirectory(TestUtils.getTestDataRoot()))
60 .build();
61
62 /**
63 * Setup test.
64 * @throws ReflectiveOperationException never
65 */
66 @BeforeEach
67 public void setUp() throws ReflectiveOperationException {
68
69 // some other tests actually go ahead and load plugins (notably at time of writing,
70 // MainApplicationTest$testUpdateAndLoadPlugins), which really isn't a reversible operation.
71 // it is, however, possible to pretend to our tests temporarily that they *aren't* loaded by
72 // setting the PluginHandler#pluginList to empty for the duration of this test. ideally these
73 // other tests wouldn't be so badly behaved or would at least do this from a separate batch
74 // but this works for now
75 @SuppressWarnings("unchecked")
76 final Collection<PluginProxy> pluginList = (Collection<PluginProxy>) TestUtils.getPrivateStaticField(
77 PluginHandler.class,
78 "pluginList"
79 );
80 this.originalPluginList = new ArrayList<>(pluginList);
81 pluginList.clear();
82
83 Config.getPref().putInt("pluginmanager.version", 999);
84 Config.getPref().put("pluginmanager.lastupdate", "999");
85 Config.getPref().putList("pluginmanager.sites",
86 Collections.singletonList(pluginServerRule.url("/plugins"))
87 );
88
89 this.referenceDummyJarOld = new File(TestUtils.getTestDataRoot(), "__files/plugin/dummy_plugin.v31701.jar");
90 this.referenceDummyJarNew = new File(TestUtils.getTestDataRoot(), "__files/plugin/dummy_plugin.v31772.jar");
91 this.referenceBazJarOld = new File(TestUtils.getTestDataRoot(), "__files/plugin/baz_plugin.v6.jar");
92 this.referenceBazJarNew = new File(TestUtils.getTestDataRoot(), "__files/plugin/baz_plugin.v7.jar");
93 this.pluginDir = Preferences.main().getPluginsDirectory();
94 this.targetDummyJar = new File(this.pluginDir, "dummy_plugin.jar");
95 this.targetDummyJarNew = new File(this.pluginDir, "dummy_plugin.jar.new");
96 this.targetBazJar = new File(this.pluginDir, "baz_plugin.jar");
97 this.targetBazJarNew = new File(this.pluginDir, "baz_plugin.jar.new");
98 this.pluginDir.mkdirs();
99 }
100
101 /**
102 * Tear down.
103 * @throws ReflectiveOperationException never
104 */
105 @AfterEach
106 public void tearDown() throws ReflectiveOperationException {
107 // restore actual PluginHandler#pluginList
108 @SuppressWarnings("unchecked")
109 final Collection<PluginProxy> pluginList = (Collection<PluginProxy>) TestUtils.getPrivateStaticField(
110 PluginHandler.class,
111 "pluginList"
112 );
113 pluginList.clear();
114 pluginList.addAll(this.originalPluginList);
115 }
116
117 private Collection<PluginProxy> originalPluginList;
118
119 private File pluginDir;
120 private File referenceDummyJarOld;
121 private File referenceDummyJarNew;
122 private File referenceBazJarOld;
123 private File referenceBazJarNew;
124 private File targetDummyJar;
125 private File targetDummyJarNew;
126 private File targetBazJar;
127 private File targetBazJarNew;
128
129 /**
130 * Tests choosing a new plugin to install without upgrading an already-installed plugin
131 * @throws Exception never
132 */
133 @Test
134 void testInstallWithoutUpdate(WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception {
135 final PluginServer pluginServer = new PluginServer(
136 new PluginServer.RemotePlugin(this.referenceDummyJarNew),
137 new PluginServer.RemotePlugin(this.referenceBazJarOld),
138 new PluginServer.RemotePlugin(null, Collections.singletonMap("Plugin-Version", "2"), "irrelevant_plugin")
139 );
140 pluginServer.applyToWireMockServer(wireMockRuntimeInfo);
141 Config.getPref().putList("plugins", Collections.singletonList("dummy_plugin"));
142
143 final HelpAwareOptionPaneMocker haMocker = new HelpAwareOptionPaneMocker(
144 Collections.singletonMap(
145 "<html>The following plugin has been downloaded <strong>successfully</strong>:"
146 + "<ul><li>baz_plugin (6)</li></ul>"
147 + "You have to restart JOSM for some settings to take effect."
148 + "<br/><br/>Would you like to restart now?</html>",
149 "Cancel"
150 )
151 );
152
153 Files.copy(this.referenceDummyJarOld.toPath(), this.targetDummyJar.toPath());
154
155 final PreferenceTabbedPane tabbedPane = new PreferenceTabbedPane();
156
157 tabbedPane.buildGui();
158 // PluginPreference is already added to PreferenceTabbedPane by default
159 tabbedPane.selectTabByPref(PluginPreference.class);
160
161 GuiHelper.runInEDTAndWait(
162 () -> ((javax.swing.JButton) TestUtils.getComponentByName(tabbedPane, "downloadListButton")).doClick()
163 );
164
165 Awaitility.await().atMost(2000, MILLISECONDS).until(() -> Config.getPref().getInt("pluginmanager.version", 999) != 999);
166
167 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
168 pluginServerRule.resetRequests();
169
170 final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
171 tabbedPane.getPluginPreference(),
172 "model"
173 );
174
175 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
176 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
177 // questionably correct
178 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
179 assertEquals(model.getDisplayedPlugins(), model.getAvailablePlugins());
180
181 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin", "irrelevant_plugin"),
182 model.getAvailablePlugins().stream().map(PluginInformation::getName).collect(Collectors.toList()));
183 assertEquals(Collections.singletonList("dummy_plugin"),
184 model.getSelectedPlugins().stream().map(PluginInformation::getName).collect(Collectors.toList()));
185 assertEquals(Arrays.asList("(null)", "31701", "(null)"), model.getAvailablePlugins().stream().map(
186 (pi) -> pi.localversion == null ? "(null)" : pi.localversion
187 ).collect(Collectors.toList()));
188 assertEquals(Arrays.asList("6", "31772", "2"),
189 model.getAvailablePlugins().stream().map((pi) -> pi.version).collect(Collectors.toList()));
190
191 // now we're going to choose to install baz_plugin
192 model.setPluginSelected("baz_plugin", true);
193
194 assertEquals(Collections.singletonList("baz_plugin"),
195 model.getNewlyActivatedPlugins().stream().map(PluginInformation::getName).collect(Collectors.toList()));
196 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
197 assertEquals(Collections.singletonList("baz_plugin"),
198 model.getPluginsScheduledForUpdateOrDownload().stream().map(PluginInformation::getName).collect(Collectors.toList()));
199
200 tabbedPane.savePreferences();
201
202 TestUtils.syncEDTAndWorkerThreads();
203
204 assertEquals(1, haMocker.getInvocationLog().size());
205 Object[] invocationLogEntry = haMocker.getInvocationLog().get(0);
206 assertEquals(1, (int) invocationLogEntry[0]);
207 assertEquals("Restart", invocationLogEntry[2]);
208
209 // dummy_plugin jar shouldn't have been updated
210 TestUtils.assertFileContentsEqual(this.referenceDummyJarOld, this.targetDummyJar);
211 // baz_plugin jar should have been installed
212 TestUtils.assertFileContentsEqual(this.referenceBazJarOld, this.targetBazJar);
213
214 // neither of these .jar.new files should have been left hanging round
215 assertFalse(targetDummyJarNew.exists());
216 assertFalse(targetBazJarNew.exists());
217
218 // the advertised version of dummy_plugin shouldn't have been fetched
219 pluginServerRule.verify(0, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/dummy_plugin.v31772.jar")));
220 // but the advertized version of baz_plugin *should* have
221 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/baz_plugin.v6.jar")));
222
223 // pluginmanager.version has been set to the current version
224 // questionably correct
225 assertEquals(10000, Config.getPref().getInt("pluginmanager.version", 111));
226 // however pluginmanager.lastupdate hasn't been updated
227 // questionably correct
228 assertEquals("999", Config.getPref().get("pluginmanager.lastupdate", "111"));
229
230 // baz_plugin should have been added to the plugins list
231 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"),
232 Config.getPref().getList("plugins", null).stream().sorted().collect(Collectors.toList()));
233 }
234
235 /**
236 * Tests a plugin being disabled without applying available upgrades
237 * @throws Exception never
238 */
239 @Test
240 void testDisablePluginWithUpdatesAvailable(WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception {
241 final PluginServer pluginServer = new PluginServer(
242 new PluginServer.RemotePlugin(this.referenceDummyJarNew),
243 new PluginServer.RemotePlugin(this.referenceBazJarNew),
244 new PluginServer.RemotePlugin(null, null, "irrelevant_plugin")
245 );
246 pluginServer.applyToWireMockServer(wireMockRuntimeInfo);
247 Config.getPref().putList("plugins", Arrays.asList("baz_plugin", "dummy_plugin"));
248
249 final HelpAwareOptionPaneMocker haMocker = new HelpAwareOptionPaneMocker(
250 Collections.singletonMap(
251 "<html>You have to restart JOSM for some settings to take effect."
252 + "<br/><br/>Would you like to restart now?</html>",
253 "Cancel"
254 )
255 );
256
257 Files.copy(this.referenceDummyJarOld.toPath(), this.targetDummyJar.toPath());
258 Files.copy(this.referenceBazJarOld.toPath(), this.targetBazJar.toPath());
259
260 final PreferenceTabbedPane tabbedPane = new PreferenceTabbedPane();
261
262 tabbedPane.buildGui();
263 // PluginPreference is already added to PreferenceTabbedPane by default
264 tabbedPane.selectTabByPref(PluginPreference.class);
265
266 GuiHelper.runInEDTAndWait(
267 () -> ((javax.swing.JButton) TestUtils.getComponentByName(tabbedPane, "downloadListButton")).doClick()
268 );
269
270 Awaitility.await().atMost(2000, MILLISECONDS).until(() -> Config.getPref().getInt("pluginmanager.version", 999) != 999);
271
272 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
273 pluginServerRule.resetRequests();
274
275 final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
276 tabbedPane.getPluginPreference(),
277 "model"
278 );
279
280 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
281 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
282 // questionably correct
283 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
284 assertEquals(model.getDisplayedPlugins(), model.getAvailablePlugins());
285
286 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin", "irrelevant_plugin"),
287 model.getAvailablePlugins().stream().map(PluginInformation::getName).collect(Collectors.toList()));
288 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"),
289 model.getSelectedPlugins().stream().map(PluginInformation::getName).collect(Collectors.toList()));
290 assertEquals(Arrays.asList("6", "31701", "(null)"), model.getAvailablePlugins().stream().map(
291 (pi) -> pi.localversion == null ? "(null)" : pi.localversion
292 ).collect(Collectors.toList()));
293 assertEquals(Arrays.asList("7", "31772", "(null)"), model.getAvailablePlugins().stream().map(
294 (pi) -> pi.version == null ? "(null)" : pi.version
295 ).collect(Collectors.toList()));
296
297 // now we're going to choose to disable baz_plugin
298 model.setPluginSelected("baz_plugin", false);
299
300 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
301 assertEquals(Collections.singletonList("baz_plugin"),
302 model.getNewlyDeactivatedPlugins().stream().map(PluginInformation::getName).collect(Collectors.toList()));
303 // questionably correct
304 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
305
306 tabbedPane.savePreferences();
307
308 TestUtils.syncEDTAndWorkerThreads();
309
310 assertEquals(1, haMocker.getInvocationLog().size());
311 Object[] invocationLogEntry = haMocker.getInvocationLog().get(0);
312 assertEquals(1, (int) invocationLogEntry[0]);
313 assertEquals("Restart", invocationLogEntry[2]);
314
315 // dummy_plugin jar shouldn't have been updated
316 TestUtils.assertFileContentsEqual(this.referenceDummyJarOld, this.targetDummyJar);
317 // baz_plugin jar shouldn't have been deleted
318 TestUtils.assertFileContentsEqual(this.referenceBazJarOld, this.targetBazJar);
319
320 // neither of these .jar.new files have a reason to be here
321 assertFalse(targetDummyJarNew.exists());
322 assertFalse(targetBazJarNew.exists());
323
324 // neither of the new jars have been fetched
325 pluginServerRule.verify(0, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/dummy_plugin.v31772.jar")));
326 pluginServerRule.verify(0, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/baz_plugin.v6.jar")));
327
328 // pluginmanager.version has been set to the current version
329 // questionably correct
330 assertEquals(10000, Config.getPref().getInt("pluginmanager.version", 111));
331 // however pluginmanager.lastupdate hasn't been updated
332 // questionably correct
333 assertEquals("999", Config.getPref().get("pluginmanager.lastupdate", "111"));
334
335 // baz_plugin should have been removed from the installed plugins list
336 assertEquals(Collections.singletonList("dummy_plugin"),
337 Config.getPref().getList("plugins", null).stream().sorted().collect(Collectors.toList()));
338 }
339
340 /**
341 * Demonstrates behaviour exhibited when attempting to update a single plugin when multiple updates
342 * are available by deselecting it before clicking the update button then reselecting it.
343 *
344 * This is probably NOT desirable and should be fixed, however this test documents the behaviour.
345 * @throws Exception never
346 */
347 @Test
348 void testUpdateOnlySelectedPlugin(WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception {
349 TestUtils.assumeWorkingJMockit();
350 final PluginServer pluginServer = new PluginServer(
351 new PluginServer.RemotePlugin(this.referenceDummyJarNew),
352 new PluginServer.RemotePlugin(this.referenceBazJarNew)
353 );
354 pluginServer.applyToWireMockServer(wireMockRuntimeInfo);
355 Config.getPref().putList("plugins", Arrays.asList("baz_plugin", "dummy_plugin"));
356
357 final HelpAwareOptionPaneMocker haMocker = new HelpAwareOptionPaneMocker();
358 final JOptionPaneSimpleMocker jopsMocker = new JOptionPaneSimpleMocker();
359
360 Files.copy(this.referenceDummyJarOld.toPath(), this.targetDummyJar.toPath());
361 Files.copy(this.referenceBazJarOld.toPath(), this.targetBazJar.toPath());
362
363 final PreferenceTabbedPane tabbedPane = new PreferenceTabbedPane();
364
365 tabbedPane.buildGui();
366 // PluginPreference is already added to PreferenceTabbedPane by default
367 tabbedPane.selectTabByPref(PluginPreference.class);
368
369 GuiHelper.runInEDTAndWait(
370 () -> ((javax.swing.JButton) TestUtils.getComponentByName(tabbedPane, "downloadListButton")).doClick()
371 );
372
373 TestUtils.syncEDTAndWorkerThreads();
374
375 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
376 pluginServerRule.resetRequests();
377
378 final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
379 tabbedPane.getPluginPreference(),
380 "model"
381 );
382
383 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
384 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
385 // questionably correct
386 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
387 assertEquals(model.getDisplayedPlugins(), model.getAvailablePlugins());
388
389 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"),
390 model.getAvailablePlugins().stream().map(PluginInformation::getName).collect(Collectors.toList()));
391 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"),
392 model.getSelectedPlugins().stream().map(PluginInformation::getName).collect(Collectors.toList()));
393 assertEquals(Arrays.asList("6", "31701"), model.getAvailablePlugins().stream().map(
394 (pi) -> pi.localversion == null ? "(null)" : pi.localversion
395 ).collect(Collectors.toList()));
396 assertEquals(Arrays.asList("7", "31772"), model.getAvailablePlugins().stream().map((pi) -> pi.version).collect(Collectors.toList()));
397
398 // now we're going to choose not to update baz_plugin
399 model.setPluginSelected("baz_plugin", false);
400
401 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
402 assertEquals(Collections.singletonList("baz_plugin"), model.getNewlyDeactivatedPlugins().stream()
403 .map(PluginInformation::getName).collect(Collectors.toList()));
404 // questionably correct
405 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
406
407 // prepare haMocker to handle this message
408 haMocker.getMockResultMap().put(
409 "<html>The following plugin has been downloaded <strong>successfully</strong>:"
410 + "<ul><li>dummy_plugin (31772)</li></ul>Please restart JOSM to activate the "
411 + "downloaded plugins.</html>",
412 "OK"
413 );
414
415 GuiHelper.runInEDTAndWait(
416 () -> ((javax.swing.JButton) TestUtils.getComponentByName(tabbedPane, "updatePluginsButton")).doClick()
417 );
418
419 TestUtils.syncEDTAndWorkerThreads();
420
421 assertTrue(jopsMocker.getInvocationLog().isEmpty());
422 assertEquals(1, haMocker.getInvocationLog().size());
423 Object[] invocationLogEntry = haMocker.getInvocationLog().get(0);
424 assertEquals(0, (int) invocationLogEntry[0]);
425 assertEquals("Update plugins", invocationLogEntry[2]);
426
427 // dummy_plugin jar should have been updated
428 TestUtils.assertFileContentsEqual(this.referenceDummyJarNew, this.targetDummyJar);
429 // but baz_plugin jar shouldn't have been
430 TestUtils.assertFileContentsEqual(this.referenceBazJarOld, this.targetBazJar);
431
432 // any .jar.new files should have been removed
433 assertFalse(targetDummyJarNew.exists());
434 assertFalse(targetBazJarNew.exists());
435
436 // the plugin list was rechecked
437 // questionably necessary
438 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
439 // dummy_plugin has been fetched
440 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/dummy_plugin.v31772.jar")));
441 // baz_plugin has not
442 pluginServerRule.verify(0, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/baz_plugin.v7.jar")));
443 pluginServerRule.resetRequests();
444
445 // pluginmanager.version has been set to the current version
446 // questionably correct
447 assertEquals(10000, Config.getPref().getInt("pluginmanager.version", 111));
448 // however pluginmanager.lastupdate hasn't been updated
449 // questionably correct
450 assertEquals("999", Config.getPref().get("pluginmanager.lastupdate", "111"));
451
452 // plugins list shouldn't have been altered, we haven't hit save yet
453 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"),
454 Config.getPref().getList("plugins", null).stream().sorted().collect(Collectors.toList()));
455
456 // the model's selection state should be largely as before
457 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
458 assertEquals(Collections.singletonList("baz_plugin"), model.getNewlyDeactivatedPlugins().stream()
459 .map(PluginInformation::getName).collect(Collectors.toList()));
460 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
461
462 // but now we re-select baz_plugin so that it isn't removed/disabled
463 model.setPluginSelected("baz_plugin", true);
464
465 // this has caused baz_plugin to be interpreted as a plugin "for download"
466 // questionably correct
467 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
468 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
469 assertEquals(Collections.singletonList("baz_plugin"), model.getPluginsScheduledForUpdateOrDownload().stream()
470 .map(PluginInformation::getName).collect(Collectors.toList()));
471
472 // prepare jopsMocker to handle this message
473 jopsMocker.getMockResultMap().put(
474 "<html>The following plugin has been downloaded <strong>successfully</strong>:"
475 + "<ul><li>baz_plugin (7)</li></ul></html>",
476 JOptionPane.OK_OPTION
477 );
478
479 tabbedPane.savePreferences();
480
481 TestUtils.syncEDTAndWorkerThreads();
482
483 // from previous haMocker invocation
484 assertEquals(1, haMocker.getInvocationLog().size());
485 // we've been alerted that (the new version of) baz_plugin was installed
486 // questionably correct
487 assertEquals(1, jopsMocker.getInvocationLog().size());
488 invocationLogEntry = jopsMocker.getInvocationLog().get(0);
489 assertEquals(JOptionPane.OK_OPTION, (int) invocationLogEntry[0]);
490 assertEquals("Warning", invocationLogEntry[2]);
491
492 // dummy_plugin jar is still the updated version
493 TestUtils.assertFileContentsEqual(this.referenceDummyJarNew, this.targetDummyJar);
494 // but now the baz_plugin jar has been too
495 // questionably correct
496 TestUtils.assertFileContentsEqual(this.referenceBazJarNew, this.targetBazJar);
497
498 // all .jar.new files have been deleted
499 assertFalse(targetDummyJarNew.exists());
500 assertFalse(targetBazJarNew.exists());
501
502 // dummy_plugin was not fetched
503 pluginServerRule.verify(0, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/dummy_plugin.v31772.jar")));
504 // baz_plugin however was fetched
505 // questionably correct
506 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/baz_plugin.v7.jar")));
507
508 assertEquals(10000, Config.getPref().getInt("pluginmanager.version", 111));
509 // questionably correct
510 assertEquals("999", Config.getPref().get("pluginmanager.lastupdate", "111"));
511 }
512
513 /**
514 * Tests the effect of requesting a "plugin update" when everything is up to date
515 * @throws Exception never
516 */
517 @Test
518 void testUpdateWithNoAvailableUpdates(WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception {
519 TestUtils.assumeWorkingJMockit();
520 final PluginServer pluginServer = new PluginServer(
521 new PluginServer.RemotePlugin(this.referenceDummyJarOld),
522 new PluginServer.RemotePlugin(this.referenceBazJarOld),
523 new PluginServer.RemotePlugin(null, Collections.singletonMap("Plugin-Version", "123"), "irrelevant_plugin")
524 );
525 pluginServer.applyToWireMockServer(wireMockRuntimeInfo);
526 Config.getPref().putList("plugins", Arrays.asList("baz_plugin", "dummy_plugin"));
527
528 final HelpAwareOptionPaneMocker haMocker = new HelpAwareOptionPaneMocker(
529 Collections.singletonMap(
530 "All installed plugins are up to date. JOSM does not have to download newer versions.",
531 "OK"
532 )
533 );
534 final JOptionPaneSimpleMocker jopsMocker = new JOptionPaneSimpleMocker();
535
536 Files.copy(this.referenceDummyJarOld.toPath(), this.targetDummyJar.toPath());
537 Files.copy(this.referenceBazJarOld.toPath(), this.targetBazJar.toPath());
538
539 final PreferenceTabbedPane tabbedPane = new PreferenceTabbedPane();
540
541 tabbedPane.buildGui();
542 // PluginPreference is already added to PreferenceTabbedPane by default
543 tabbedPane.selectTabByPref(PluginPreference.class);
544
545 GuiHelper.runInEDTAndWait(
546 () -> ((javax.swing.JButton) TestUtils.getComponentByName(tabbedPane, "downloadListButton")).doClick()
547 );
548
549 TestUtils.syncEDTAndWorkerThreads();
550
551 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
552 pluginServerRule.resetRequests();
553
554 final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
555 tabbedPane.getPluginPreference(),
556 "model"
557 );
558
559 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
560 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
561 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
562 assertEquals(model.getDisplayedPlugins(), model.getAvailablePlugins());
563
564 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin", "irrelevant_plugin"), model.getAvailablePlugins().stream()
565 .map(PluginInformation::getName).collect(Collectors.toList()));
566 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"), model.getSelectedPlugins().stream()
567 .map(PluginInformation::getName).collect(Collectors.toList()));
568 assertEquals(Arrays.asList("6", "31701", "(null)"), model.getAvailablePlugins().stream().map(
569 (pi) -> pi.localversion == null ? "(null)" : pi.localversion
570 ).collect(Collectors.toList()));
571 assertEquals(Arrays.asList("6", "31701", "123"), model.getAvailablePlugins()
572 .stream().map((pi) -> pi.version).collect(Collectors.toList()));
573
574 GuiHelper.runInEDTAndWait(
575 () -> ((javax.swing.JButton) TestUtils.getComponentByName(tabbedPane, "updatePluginsButton")).doClick()
576 );
577
578 TestUtils.syncEDTAndWorkerThreads();
579
580 assertTrue(jopsMocker.getInvocationLog().isEmpty());
581 assertEquals(1, haMocker.getInvocationLog().size());
582 Object[] invocationLogEntry = haMocker.getInvocationLog().get(0);
583 assertEquals(0, (int) invocationLogEntry[0]);
584 assertEquals("Plugins up to date", invocationLogEntry[2]);
585
586 // neither jar should have changed
587 TestUtils.assertFileContentsEqual(this.referenceDummyJarOld, this.targetDummyJar);
588 TestUtils.assertFileContentsEqual(this.referenceBazJarOld, this.targetBazJar);
589
590 // no reason for any .jar.new files
591 assertFalse(targetDummyJarNew.exists());
592 assertFalse(targetBazJarNew.exists());
593
594 // the plugin list was rechecked
595 // questionably necessary
596 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
597 // that should have been the only request to our PluginServer
598 assertEquals(1, pluginServerRule.getAllServeEvents().size());
599 pluginServerRule.resetRequests();
600
601 // pluginmanager.version has been set to the current version
602 assertEquals(10000, Config.getPref().getInt("pluginmanager.version", 111));
603 // pluginmanager.lastupdate hasn't been updated
604 // questionably correct
605 assertEquals("999", Config.getPref().get("pluginmanager.lastupdate", "111"));
606
607 // plugins list shouldn't have been altered
608 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"), Config.getPref().getList("plugins", null)
609 .stream().sorted().collect(Collectors.toList()));
610
611 // the model's selection state should be largely as before
612 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
613 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
614 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
615
616 tabbedPane.savePreferences();
617
618 TestUtils.syncEDTAndWorkerThreads();
619
620 assertTrue(jopsMocker.getInvocationLog().isEmpty());
621 assertEquals(1, haMocker.getInvocationLog().size());
622
623 // both jars are still the original version
624 TestUtils.assertFileContentsEqual(this.referenceDummyJarOld, this.targetDummyJar);
625 TestUtils.assertFileContentsEqual(this.referenceBazJarOld, this.targetBazJar);
626
627 // no reason for any .jar.new files
628 assertFalse(targetDummyJarNew.exists());
629 assertFalse(targetBazJarNew.exists());
630
631 // none of PluginServer's URLs should have been touched
632 assertEquals(0, pluginServerRule.getAllServeEvents().size());
633
634 // pluginmanager.version has been set to the current version
635 assertEquals(10000, Config.getPref().getInt("pluginmanager.version", 111));
636 // pluginmanager.lastupdate hasn't been updated
637 // questionably correct
638 assertEquals("999", Config.getPref().get("pluginmanager.lastupdate", "111"));
639 }
640
641 /**
642 * Tests installing a single plugin which is marked as "Canloadatruntime"
643 * @throws Exception never
644 */
645 @Test
646 void testInstallWithoutRestartRequired(WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception {
647 TestUtils.assumeWorkingJMockit();
648 final boolean[] loadPluginsCalled = new boolean[] {false};
649 new MockUp<PluginHandler>() {
650 @mockit.Mock
651 private void loadPlugins(
652 final Component parent,
653 final Collection<org.openstreetmap.josm.plugins.PluginInformation> plugins,
654 final org.openstreetmap.josm.gui.progress.ProgressMonitor monitor
655 ) {
656 assertEquals(1, plugins.size());
657 assertEquals("dummy_plugin", plugins.iterator().next().name);
658 assertEquals("31772", plugins.iterator().next().localversion);
659 loadPluginsCalled[0] = true;
660 }
661 };
662
663 final PluginServer pluginServer = new PluginServer(
664 new PluginServer.RemotePlugin(this.referenceDummyJarNew),
665 new PluginServer.RemotePlugin(this.referenceBazJarNew)
666 );
667 pluginServer.applyToWireMockServer(wireMockRuntimeInfo);
668 Config.getPref().putList("plugins", Collections.emptyList());
669
670 final HelpAwareOptionPaneMocker haMocker = new HelpAwareOptionPaneMocker();
671 final JOptionPaneSimpleMocker jopsMocker = new JOptionPaneSimpleMocker(Collections.singletonMap(
672 "<html>The following plugin has been downloaded <strong>successfully</strong>:"
673 + "<ul><li>dummy_plugin (31772)</li></ul></html>",
674 JOptionPane.OK_OPTION
675 ));
676
677 final PreferenceTabbedPane tabbedPane = new PreferenceTabbedPane();
678
679 tabbedPane.buildGui();
680 // PluginPreference is already added to PreferenceTabbedPane by default
681 tabbedPane.selectTabByPref(PluginPreference.class);
682
683 GuiHelper.runInEDTAndWait(
684 () -> ((javax.swing.JButton) TestUtils.getComponentByName(tabbedPane, "downloadListButton")).doClick()
685 );
686
687 TestUtils.syncEDTAndWorkerThreads();
688
689 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
690 pluginServerRule.resetRequests();
691
692 final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
693 tabbedPane.getPluginPreference(),
694 "model"
695 );
696
697 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
698 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
699 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
700 assertEquals(model.getDisplayedPlugins(), model.getAvailablePlugins());
701
702 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"), model.getAvailablePlugins().stream()
703 .map(PluginInformation::getName).collect(Collectors.toList()));
704 assertTrue(model.getSelectedPlugins().isEmpty());
705 assertEquals(Arrays.asList("(null)", "(null)"), model.getAvailablePlugins().stream().map(
706 (pi) -> pi.localversion == null ? "(null)" : pi.localversion
707 ).collect(Collectors.toList()));
708 assertEquals(Arrays.asList("7", "31772"), model.getAvailablePlugins().stream().map((pi) -> pi.version).collect(Collectors.toList()));
709
710 // now we select dummy_plugin
711 model.setPluginSelected("dummy_plugin", true);
712
713 // model should now reflect this
714 assertEquals(Collections.singletonList("dummy_plugin"), model.getNewlyActivatedPlugins().stream()
715 .map(PluginInformation::getName).collect(Collectors.toList()));
716 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
717
718 tabbedPane.savePreferences();
719
720 TestUtils.syncEDTAndWorkerThreads();
721
722 assertEquals(1, jopsMocker.getInvocationLog().size());
723 Object[] invocationLogEntry = jopsMocker.getInvocationLog().get(0);
724 assertEquals(JOptionPane.OK_OPTION, (int) invocationLogEntry[0]);
725 assertEquals("Warning", invocationLogEntry[2]);
726
727 assertTrue(haMocker.getInvocationLog().isEmpty());
728
729 // any .jar.new files should have been deleted
730 assertFalse(targetDummyJarNew.exists());
731 assertFalse(targetBazJarNew.exists());
732
733 // dummy_plugin was fetched
734 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/dummy_plugin.v31772.jar")));
735
736 // the dummy_plugin jar has been installed
737 TestUtils.assertFileContentsEqual(this.referenceDummyJarNew, this.targetDummyJar);
738 // the baz_plugin jar has not
739 assertFalse(this.targetBazJar.exists());
740
741 // loadPlugins(...) was called (with expected parameters)
742 assertTrue(loadPluginsCalled[0]);
743
744 // pluginmanager.version has been set to the current version
745 assertEquals(10000, Config.getPref().getInt("pluginmanager.version", 111));
746 // pluginmanager.lastupdate hasn't been updated
747 // questionably correct
748 assertEquals("999", Config.getPref().get("pluginmanager.lastupdate", "111"));
749 }
750
751 /**
752 * Tests installing a single plugin which has multiple versions advertised, with our JOSM version
753 * preventing us from using the latest version
754 * @throws Exception on failure
755 */
756 @AssumeRevision("Revision: 7000\n")
757 @Test
758 void testInstallMultiVersion(WireMockRuntimeInfo wireMockRuntimeInfo) throws Exception {
759 TestUtils.assumeWorkingJMockit();
760
761 final String bazOldServePath = "/baz/old.jar";
762 final PluginServer pluginServer = new PluginServer(
763 new PluginServer.RemotePlugin(this.referenceDummyJarNew),
764 new PluginServer.RemotePlugin(this.referenceBazJarNew, Collections.singletonMap(
765 "6800_Plugin-Url", "6;" + pluginServerRule.url(bazOldServePath)
766 ))
767 );
768 pluginServer.applyToWireMockServer(wireMockRuntimeInfo);
769 // need to actually serve this older jar from somewhere
770 pluginServerRule.stubFor(
771 WireMock.get(WireMock.urlEqualTo(bazOldServePath)).willReturn(
772 WireMock.aResponse().withStatus(200).withHeader("Content-Type", "application/java-archive").withBodyFile(
773 "plugin/baz_plugin.v6.jar"
774 )
775 )
776 );
777 Config.getPref().putList("plugins", Collections.emptyList());
778
779 final HelpAwareOptionPaneMocker haMocker = new HelpAwareOptionPaneMocker(Collections.singletonMap(
780 "<html>The following plugin has been downloaded <strong>successfully</strong>:"
781 + "<ul><li>baz_plugin (6)</li></ul>"
782 + "You have to restart JOSM for some settings to take effect.<br/><br/>"
783 + "Would you like to restart now?</html>",
784 "Cancel"
785 ));
786 final JOptionPaneSimpleMocker jopsMocker = new JOptionPaneSimpleMocker();
787
788 final PreferenceTabbedPane tabbedPane = new PreferenceTabbedPane();
789
790 tabbedPane.buildGui();
791 // PluginPreference is already added to PreferenceTabbedPane by default
792 tabbedPane.selectTabByPref(PluginPreference.class);
793
794 GuiHelper.runInEDTAndWait(
795 () -> ((javax.swing.JButton) TestUtils.getComponentByName(tabbedPane, "downloadListButton")).doClick()
796 );
797
798 TestUtils.syncEDTAndWorkerThreads();
799
800 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
801 pluginServerRule.resetRequests();
802
803 final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
804 tabbedPane.getPluginPreference(),
805 "model"
806 );
807
808 assertTrue(model.getNewlyActivatedPlugins().isEmpty());
809 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
810 assertTrue(model.getPluginsScheduledForUpdateOrDownload().isEmpty());
811 assertEquals(model.getDisplayedPlugins(), model.getAvailablePlugins());
812
813 assertEquals(Arrays.asList("baz_plugin", "dummy_plugin"), model.getAvailablePlugins().stream()
814 .map(PluginInformation::getName).collect(Collectors.toList()));
815 assertTrue(model.getSelectedPlugins().isEmpty());
816 assertEquals(Arrays.asList("(null)", "(null)"), model.getAvailablePlugins().stream().map(
817 (pi) -> pi.localversion == null ? "(null)" : pi.localversion
818 ).collect(Collectors.toList()));
819 assertEquals(Arrays.asList("6", "31772"), model.getAvailablePlugins().stream().map((pi) -> pi.version).collect(Collectors.toList()));
820
821 // now we select dummy_plugin
822 model.setPluginSelected("baz_plugin", true);
823
824 // model should now reflect this
825 assertEquals(Collections.singletonList("baz_plugin"), model.getNewlyActivatedPlugins().stream()
826 .map(PluginInformation::getName).collect(Collectors.toList()));
827 assertTrue(model.getNewlyDeactivatedPlugins().isEmpty());
828
829 tabbedPane.savePreferences();
830
831 TestUtils.syncEDTAndWorkerThreads();
832
833 assertEquals(1, haMocker.getInvocationLog().size());
834 Object[] invocationLogEntry = haMocker.getInvocationLog().get(0);
835 assertEquals(1, (int) invocationLogEntry[0]);
836 assertEquals("Restart", invocationLogEntry[2]);
837
838 assertTrue(jopsMocker.getInvocationLog().isEmpty());
839
840 // any .jar.new files should have been deleted
841 assertFalse(targetDummyJarNew.exists());
842 assertFalse(targetBazJarNew.exists());
843
844 // dummy_plugin was fetched
845 pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo(bazOldServePath)));
846
847 // the "old" baz_plugin jar has been installed
848 TestUtils.assertFileContentsEqual(this.referenceBazJarOld, this.targetBazJar);
849 // the dummy_plugin jar has not
850 assertFalse(this.targetDummyJar.exists());
851
852 // pluginmanager.version has been set to the current version
853 assertEquals(7000, Config.getPref().getInt("pluginmanager.version", 111));
854 // pluginmanager.lastupdate hasn't been updated
855 // questionably correct
856 assertEquals("999", Config.getPref().get("pluginmanager.lastupdate", "111"));
857 }
858}
Note: See TracBrowser for help on using the repository browser.