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