source: josm/trunk/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTestIT.java@ 14778

Last change on this file since 14778 was 14778, checked in by Don-vip, 5 years ago

see #16912 - filter plugins requiring JavaFX on Java < 11 and headless mode

File size: 8.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins;
3
4import static org.junit.Assert.assertEquals;
5import static org.junit.Assert.assertFalse;
6import static org.junit.Assert.assertTrue;
7
8import java.awt.GraphicsEnvironment;
9import java.util.Arrays;
10import java.util.Collection;
11import java.util.HashMap;
12import java.util.Iterator;
13import java.util.List;
14import java.util.Map;
15import java.util.Set;
16import java.util.function.Consumer;
17import java.util.stream.Collectors;
18
19import org.apache.commons.lang3.exception.ExceptionUtils;
20import org.junit.Rule;
21import org.junit.Test;
22import org.openstreetmap.josm.data.Preferences;
23import org.openstreetmap.josm.data.gpx.GpxData;
24import org.openstreetmap.josm.data.osm.DataSet;
25import org.openstreetmap.josm.gui.MainApplication;
26import org.openstreetmap.josm.gui.layer.GpxLayer;
27import org.openstreetmap.josm.gui.layer.Layer;
28import org.openstreetmap.josm.gui.layer.OsmDataLayer;
29import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
30import org.openstreetmap.josm.spi.preferences.Config;
31import org.openstreetmap.josm.testutils.JOSMTestRules;
32import org.openstreetmap.josm.tools.Utils;
33
34import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35
36/**
37 * Integration tests of {@link PluginHandler} class.
38 */
39public class PluginHandlerTestIT {
40
41 /**
42 * Setup test.
43 */
44 @Rule
45 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
46 public JOSMTestRules test = new JOSMTestRules().main().projection().preferences().https().timeout(10*60*1000);
47
48 /**
49 * Test that available plugins rules can be loaded.
50 */
51 @Test
52 public void testValidityOfAvailablePlugins() {
53 loadAllPlugins();
54
55 Map<String, Throwable> loadingExceptions = PluginHandler.pluginLoadingExceptions.entrySet().stream()
56 .collect(Collectors.toMap(e -> e.getKey(), e -> ExceptionUtils.getRootCause(e.getValue())));
57
58 List<PluginInformation> loadedPlugins = PluginHandler.getPlugins();
59 Map<String, List<String>> invalidManifestEntries = loadedPlugins.stream().filter(pi -> !pi.invalidManifestEntries.isEmpty())
60 .collect(Collectors.toMap(pi -> pi.name, pi -> pi.invalidManifestEntries));
61
62 // Add/remove layers twice to test basic plugin good behaviour
63 Map<String, Throwable> layerExceptions = new HashMap<>();
64 for (int i = 0; i < 2; i++) {
65 OsmDataLayer layer = new OsmDataLayer(new DataSet(), "Layer "+i, null);
66 testPlugin(MainApplication.getLayerManager()::addLayer, layer, layerExceptions, loadedPlugins);
67 testPlugin(MainApplication.getLayerManager()::removeLayer, layer, layerExceptions, loadedPlugins);
68 }
69 for (int i = 0; i < 2; i++) {
70 GpxLayer layer = new GpxLayer(new GpxData(), "Layer "+i);
71 testPlugin(MainApplication.getLayerManager()::addLayer, layer, layerExceptions, loadedPlugins);
72 testPlugin(MainApplication.getLayerManager()::removeLayer, layer, layerExceptions, loadedPlugins);
73 }
74
75 debugPrint(invalidManifestEntries);
76 debugPrint(loadingExceptions);
77 debugPrint(layerExceptions);
78 String msg = Arrays.toString(invalidManifestEntries.entrySet().toArray()) + '\n' +
79 Arrays.toString(loadingExceptions.entrySet().toArray()) + '\n' +
80 Arrays.toString(layerExceptions.entrySet().toArray());
81 assertTrue(msg, invalidManifestEntries.isEmpty() && loadingExceptions.isEmpty() && layerExceptions.isEmpty());
82 }
83
84 private static void debugPrint(Map<String, ?> invalidManifestEntries) {
85 System.out.println(invalidManifestEntries.entrySet()
86 .stream()
87 .map(e -> e.getKey() + "=\"" + e.getValue() + "\"")
88 .collect(Collectors.joining(", ")));
89 }
90
91 /**
92 * Downloads and loads all JOSM plugins.
93 */
94 public static void loadAllPlugins() {
95 // Download complete list of plugins
96 ReadRemotePluginInformationTask pluginInfoDownloadTask = new ReadRemotePluginInformationTask(
97 Preferences.main().getOnlinePluginSites());
98 pluginInfoDownloadTask.run();
99 List<PluginInformation> plugins = pluginInfoDownloadTask.getAvailablePlugins();
100 System.out.println("Original plugin list contains " + plugins.size() + " plugins");
101 assertFalse(plugins.isEmpty());
102 PluginInformation info = plugins.get(0);
103 assertFalse(info.getName().isEmpty());
104 assertFalse(info.getClass().getName().isEmpty());
105
106 // Filter deprecated and unmaintained ones, or those not responsive enough to match our continuous integration needs
107 List<String> uncooperatingPlugins = Arrays.asList("ebdirigo", "scoutsigns", "josm-config");
108 Set<String> deprecatedPlugins = PluginHandler.getDeprecatedAndUnmaintainedPlugins();
109 for (Iterator<PluginInformation> it = plugins.iterator(); it.hasNext();) {
110 PluginInformation pi = it.next();
111 if (deprecatedPlugins.contains(pi.name) || uncooperatingPlugins.contains(pi.name)) {
112 System.out.println("Ignoring " + pi.name + " (deprecated, unmaintained, or uncooperative)");
113 it.remove();
114 }
115 }
116
117 // On Java < 11 and headless mode, filter plugins requiring JavaFX as Monocle is not available
118 int javaVersion = Utils.getJavaVersion();
119 if (GraphicsEnvironment.isHeadless() && javaVersion < 11) {
120 for (Iterator<PluginInformation> it = plugins.iterator(); it.hasNext();) {
121 PluginInformation pi = it.next();
122 if (pi.getRequiredPlugins().contains("openjfx")) {
123 System.out.println("Ignoring " + pi.name + " (requiring JavaFX and we're using Java < 11 in headless mode)");
124 it.remove();
125 }
126 }
127 }
128
129 System.out.println("Filtered plugin list contains " + plugins.size() + " plugins");
130
131 // Download plugins
132 downloadPlugins(plugins);
133
134 // Load early plugins
135 PluginHandler.loadEarlyPlugins(null, plugins, null);
136
137 // Load late plugins
138 PluginHandler.loadLatePlugins(null, plugins, null);
139 }
140
141 void testPlugin(Consumer<Layer> consumer, Layer layer,
142 Map<String, Throwable> layerExceptions, Collection<PluginInformation> loadedPlugins) {
143 try {
144 consumer.accept(layer);
145 } catch (Exception | LinkageError t) {
146 Throwable root = ExceptionUtils.getRootCause(t);
147 root.printStackTrace();
148 layerExceptions.put(findFaultyPlugin(loadedPlugins, root), root);
149 }
150 }
151
152 private static String findFaultyPlugin(Collection<PluginInformation> plugins, Throwable root) {
153 for (PluginInformation p : plugins) {
154 try {
155 ClassLoader cl = PluginHandler.getPluginClassLoader(p.getName());
156 String pluginPackage = cl.loadClass(p.className).getPackage().getName();
157 for (StackTraceElement e : root.getStackTrace()) {
158 try {
159 String stackPackage = cl.loadClass(e.getClassName()).getPackage().getName();
160 if (stackPackage.startsWith(pluginPackage)) {
161 return p.name;
162 }
163 } catch (ClassNotFoundException ex) {
164 System.err.println(ex.getMessage());
165 continue;
166 }
167 }
168 } catch (ClassNotFoundException ex) {
169 System.err.println(ex.getMessage());
170 continue;
171 }
172 }
173 return "<unknown>";
174 }
175
176 /**
177 * Download plugins
178 * @param plugins plugins to download
179 */
180 public static void downloadPlugins(Collection<PluginInformation> plugins) {
181 // Update the locally installed plugins
182 PluginDownloadTask pluginDownloadTask = new PluginDownloadTask(NullProgressMonitor.INSTANCE, plugins, null);
183 // Increase default timeout to avoid random network errors on big jar files
184 int defTimeout = Config.getPref().getInt("socket.timeout.read", 30);
185 Config.getPref().putInt("socket.timeout.read", 2 * defTimeout);
186 pluginDownloadTask.run();
187 // Restore default timeout
188 Config.getPref().putInt("socket.timeout.read", defTimeout);
189 assertTrue(pluginDownloadTask.getFailedPlugins().toString(), pluginDownloadTask.getFailedPlugins().isEmpty());
190 assertEquals(plugins.size(), pluginDownloadTask.getDownloadedPlugins().size());
191
192 // Update Plugin info for downloaded plugins
193 PluginHandler.refreshLocalUpdatedPluginInfo(pluginDownloadTask.getDownloadedPlugins());
194 }
195}
Note: See TracBrowser for help on using the repository browser.