Ticket #18277: 18277.5.patch

File 18277.5.patch, 10.6 KB (added by taylor.smock, 4 years ago)

Add methods to ignore known failing plugins (see https://josm.openstreetmap.de/wiki/IntegrationTestIgnores?version=228 -- kenzi3d was consistently failing on my local machine)

  • src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java

     
    5555import org.openstreetmap.josm.gui.util.GuiHelper;
    5656import org.openstreetmap.josm.gui.widgets.FilterField;
    5757import org.openstreetmap.josm.plugins.PluginDownloadTask;
     58import org.openstreetmap.josm.plugins.PluginHandler;
    5859import org.openstreetmap.josm.plugins.PluginInformation;
    5960import org.openstreetmap.josm.plugins.ReadLocalPluginInformationTask;
    6061import org.openstreetmap.josm.plugins.ReadRemotePluginInformationTask;
     
    324325            List<String> l = new LinkedList<>(model.getSelectedPluginNames());
    325326            Collections.sort(l);
    326327            Config.getPref().putList("plugins", l);
    327             if (!model.getNewlyDeactivatedPlugins().isEmpty())
    328                 return true;
     328            List<PluginInformation> deactivatedPlugins = model.getNewlyDeactivatedPlugins();
     329            if (!deactivatedPlugins.isEmpty()) {
     330                boolean requiresRestart = PluginHandler.removePlugins(deactivatedPlugins);
     331                if (requiresRestart)
     332                    return requiresRestart;
     333            }
    329334            for (PluginInformation pi : model.getNewlyActivatedPlugins()) {
    330335                if (!pi.canloadatruntime)
    331336                    return true;
  • src/org/openstreetmap/josm/plugins/PluginHandler.java

     
    6868import org.openstreetmap.josm.io.OfflineAccessException;
    6969import org.openstreetmap.josm.io.OnlineResource;
    7070import org.openstreetmap.josm.spi.preferences.Config;
     71import org.openstreetmap.josm.tools.Destroyable;
    7172import org.openstreetmap.josm.tools.GBC;
    7273import org.openstreetmap.josm.tools.I18n;
    7374import org.openstreetmap.josm.tools.ImageProvider;
     
    11681169                        pluginsToDownload,
    11691170                        tr("Update plugins")
    11701171                );
    1171 
    11721172                try {
    11731173                    pluginDownloadTask.run();
    11741174                } catch (RuntimeException e) { // NOPMD
     
    13321332                    URL oldPluginURL = updatedPlugin.toURI().toURL();
    13331333                    pluginsToLoad.stream().filter(x -> x.libraries.contains(oldPluginURL)).forEach(
    13341334                            x -> Collections.replaceAll(x.libraries, oldPluginURL, newPluginURL));
     1335
     1336                    // Attempt to update loaded plugin (must implement Destroyable)
     1337                    PluginInformation tInfo = pluginsToLoad.parallelStream()
     1338                            .filter(x -> x.libraries.contains(newPluginURL)).findAny().orElse(null);
     1339                    if (tInfo != null) {
     1340                        Object tUpdatedPlugin = getPlugin(tInfo.name);
     1341                        if (tUpdatedPlugin instanceof Destroyable) {
     1342                            ((Destroyable) tUpdatedPlugin).destroy();
     1343                            PluginHandler.loadPlugins(getInfoPanel(), Collections.singleton(tInfo),
     1344                                    NullProgressMonitor.INSTANCE);
     1345                        }
     1346                    }
    13351347                } catch (MalformedURLException e) {
    13361348                    Logging.warn(e);
    13371349                }
     
    16431655            return cbDontShowAgain.isSelected();
    16441656        }
    16451657    }
     1658
     1659    /**
     1660     * Remove deactivated plugins, returning true if JOSM should restart
     1661     *
     1662     * @param deactivatedPlugins The plugins to deactivate
     1663     *
     1664     * @return true if there was a plugin that requires a restart
     1665     */
     1666    public static boolean removePlugins(List<PluginInformation> deactivatedPlugins) {
     1667        List<Destroyable> noRestart = deactivatedPlugins.parallelStream()
     1668                .map(info -> PluginHandler.getPlugin(info.name)).filter(Destroyable.class::isInstance)
     1669                .map(Destroyable.class::cast).collect(Collectors.toList());
     1670        boolean restartNeeded;
     1671        try {
     1672            noRestart.forEach(Destroyable::destroy);
     1673            new ArrayList<>(pluginList).stream().filter(proxy -> noRestart.contains(proxy.getPlugin()))
     1674                    .forEach(pluginList::remove);
     1675            restartNeeded = deactivatedPlugins.size() != noRestart.size();
     1676        } catch (Exception e) {
     1677            Logging.error(e);
     1678            restartNeeded = true;
     1679        }
     1680        return restartNeeded;
     1681    }
    16461682}
  • test/unit/org/openstreetmap/josm/plugins/PluginHandlerTestIT.java

     
    77
    88import java.awt.GraphicsEnvironment;
    99import java.awt.HeadlessException;
     10import java.io.IOException;
     11import java.util.ArrayList;
    1012import java.util.Arrays;
    1113import java.util.Collection;
    1214import java.util.HashMap;
     
    1315import java.util.Iterator;
    1416import java.util.List;
    1517import java.util.Map;
     18import java.util.Map.Entry;
    1619import java.util.Set;
    1720import java.util.function.Consumer;
    1821import java.util.stream.Collectors;
    1922
    2023import org.apache.commons.lang3.exception.ExceptionUtils;
    21 import org.junit.Rule;
     24import org.junit.BeforeClass;
     25import org.junit.ClassRule;
    2226import org.junit.Test;
     27import org.openstreetmap.josm.TestUtils;
    2328import org.openstreetmap.josm.data.Preferences;
    2429import org.openstreetmap.josm.data.gpx.GpxData;
    2530import org.openstreetmap.josm.data.osm.DataSet;
     
    3035import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
    3136import org.openstreetmap.josm.spi.preferences.Config;
    3237import org.openstreetmap.josm.testutils.JOSMTestRules;
     38import org.openstreetmap.josm.tools.Destroyable;
    3339import org.openstreetmap.josm.tools.Utils;
    3440
    3541import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     
    3945 */
    4046public class PluginHandlerTestIT {
    4147
     48    private static List<String> errorsToIgnore = new ArrayList<>();
    4249    /**
    4350     * Setup test.
    4451     */
    45     @Rule
     52    @ClassRule
    4653    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
    47     public JOSMTestRules test = new JOSMTestRules().main().projection().preferences().https().timeout(10*60*1000);
     54    public static JOSMTestRules test = new JOSMTestRules().main().projection().preferences().https()
     55            .timeout(10 * 60 * 1000);
    4856
    4957    /**
     58     * Setup test
     59     *
     60     * @throws IOException in case of I/O error
     61     */
     62    @BeforeClass
     63    public static void beforeClass() throws IOException {
     64        errorsToIgnore.addAll(TestUtils.getIgnoredErrorMessages(PluginHandlerTestIT.class));
     65    }
     66
     67    /**
    5068     * Test that available plugins rules can be loaded.
    5169     */
    5270    @Test
     
    7492            testPlugin(MainApplication.getLayerManager()::removeLayer, layer, layerExceptions, loadedPlugins);
    7593        }
    7694
     95        Map<String, Throwable> noRestartExceptions = new HashMap<>();
     96        testCompletelyRestartlessPlugins(loadedPlugins, noRestartExceptions);
     97
    7798        debugPrint(invalidManifestEntries);
    7899        debugPrint(loadingExceptions);
    79100        debugPrint(layerExceptions);
     101        debugPrint(noRestartExceptions);
     102
     103        invalidManifestEntries = filterKnownErrors(invalidManifestEntries);
     104        loadingExceptions = filterKnownErrors(loadingExceptions);
     105        layerExceptions = filterKnownErrors(layerExceptions);
     106        noRestartExceptions = filterKnownErrors(noRestartExceptions);
     107
    80108        String msg = Arrays.toString(invalidManifestEntries.entrySet().toArray()) + '\n' +
    81109                     Arrays.toString(loadingExceptions.entrySet().toArray()) + '\n' +
    82                      Arrays.toString(layerExceptions.entrySet().toArray());
     110                Arrays.toString(layerExceptions.entrySet().toArray()) + '\n'
     111                + Arrays.toString(noRestartExceptions.entrySet().toArray());
    83112        assertTrue(msg, invalidManifestEntries.isEmpty() && loadingExceptions.isEmpty() && layerExceptions.isEmpty());
    84113    }
    85114
     115    private static void testCompletelyRestartlessPlugins(List<PluginInformation> loadedPlugins,
     116            Map<String, Throwable> noRestartExceptions) {
     117        try {
     118            List<PluginInformation> restartable = loadedPlugins.parallelStream()
     119                    .filter(info -> PluginHandler.getPlugin(info.name) instanceof Destroyable)
     120                    .collect(Collectors.toList());
     121            // ensure good plugin behavior with regards to Destroyable (i.e., they can be
     122            // removed and readded)
     123            for (int i = 0; i < 2; i++) {
     124                assertFalse(PluginHandler.removePlugins(restartable));
     125                assertTrue(restartable.stream().noneMatch(info -> PluginHandler.getPlugins().contains(info)));
     126                loadPlugins(restartable);
     127            }
     128
     129            assertTrue(PluginHandler.removePlugins(loadedPlugins));
     130            assertTrue(restartable.parallelStream().noneMatch(info -> PluginHandler.getPlugins().contains(info)));
     131        } catch (Exception | LinkageError t) {
     132            Throwable root = ExceptionUtils.getRootCause(t);
     133            root.printStackTrace();
     134            noRestartExceptions.put(findFaultyPlugin(loadedPlugins, root), root);
     135        }
     136    }
     137
     138    private static <T> Map<String, T> filterKnownErrors(Map<String, T> errorMap) {
     139        return errorMap.entrySet().parallelStream()
     140                .filter(entry -> !errorsToIgnore.contains(convertEntryToString(entry)))
     141                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
     142    }
     143
    86144    private static void debugPrint(Map<String, ?> invalidManifestEntries) {
    87145        System.out.println(invalidManifestEntries.entrySet()
    88146                .stream()
    89                 .map(e -> e.getKey() + "=\"" + e.getValue() + "\"")
     147                .map(e -> convertEntryToString(e))
    90148                .collect(Collectors.joining(", ")));
    91149    }
    92150
     151    private static String convertEntryToString(Entry<String, ?> entry) {
     152        return entry.getKey() + "=\"" + entry.getValue() + "\"";
     153    }
     154
    93155    /**
    94156     * Downloads and loads all JOSM plugins.
    95157     */
     
    133195        // Download plugins
    134196        downloadPlugins(plugins);
    135197
     198        loadPlugins(plugins);
     199    }
     200
     201    static void loadPlugins(List<PluginInformation> plugins) {
    136202        // Load early plugins
    137203        PluginHandler.loadEarlyPlugins(null, plugins, null);
    138204