Changeset 19152 in josm for trunk/test/unit
- Timestamp:
- 2024-07-25T20:56:22+02:00 (4 months ago)
- Location:
- trunk/test/unit/org/openstreetmap/josm
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandlerTest.java
r18037 r19152 2 2 package org.openstreetmap.josm.io.remotecontrol.handler; 3 3 4 import static org.junit.jupiter.api.Assertions.assertAll; 4 5 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 5 6 import static org.junit.jupiter.api.Assertions.assertEquals; 7 import static org.junit.jupiter.api.Assertions.assertNotNull; 8 import static org.junit.jupiter.api.Assertions.assertNull; 6 9 import static org.junit.jupiter.api.Assertions.assertThrows; 7 10 import static org.junit.jupiter.api.Assertions.assertTrue; 11 12 import java.net.URLEncoder; 13 import java.nio.charset.StandardCharsets; 14 import java.util.Collection; 15 16 import com.github.tomakehurst.wiremock.client.WireMock; 17 import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; 18 import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; 19 import org.junit.jupiter.api.BeforeEach; 20 import org.junit.jupiter.api.extension.ExtendWith; 21 import org.openstreetmap.josm.data.osm.DataSet; 22 import org.openstreetmap.josm.data.osm.Node; 23 import org.openstreetmap.josm.data.osm.OsmPrimitive; 24 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 25 import org.openstreetmap.josm.gui.MainApplication; 8 26 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException; 9 27 import org.openstreetmap.josm.testutils.annotations.BasicPreferences; 10 28 11 29 import org.junit.jupiter.api.Test; 30 import org.openstreetmap.josm.testutils.annotations.BasicWiremock; 31 import org.openstreetmap.josm.testutils.annotations.Main; 32 import org.openstreetmap.josm.testutils.annotations.Projection; 33 import org.openstreetmap.josm.testutils.annotations.ThreadSync; 12 34 13 35 /** 14 36 * Unit tests of {@link LoadAndZoomHandler} class. 15 37 */ 38 @BasicPreferences 39 @BasicWiremock 40 @ExtendWith(BasicWiremock.OsmApiExtension.class) 16 41 class LoadAndZoomHandlerTest { 42 private static final String DEFAULT_BBOX_URL = "https://localhost/load_and_zoom?left=0&bottom=0&right=0.001&top=0.001"; 17 43 private static LoadAndZoomHandler newHandler(String url) throws RequestHandlerBadRequestException { 18 44 LoadAndZoomHandler req = new LoadAndZoomHandler(); 45 req.myCommand = LoadAndZoomHandler.command; 19 46 if (url != null) 20 47 req.setUrl(url); … … 22 49 } 23 50 51 private static void syncThreads() { 52 // There are calls to the worker thread and EDT 53 new ThreadSync.ThreadSyncExtension().threadSync(); 54 } 55 56 @BeforeEach 57 void setup(WireMockRuntimeInfo wireMockRuntimeInfo) { 58 String common = "visible=\"true\" version=\"1\" changeset=\"1\" timestamp=\"2000-01-01T00:00:00Z\" user=\"tsmock\" uid=\"1\""; 59 wireMockRuntimeInfo.getWireMock().register(WireMock.get("/api/0.6/map?bbox=0.0,0.0,0.001,0.001") 60 .willReturn(WireMock.aResponse().withBody("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 61 "<osm version=\"0.6\" generator=\"hand\" copyright=\"JOSM\" attribution=\"\" license=\"\">\n" + 62 " <bounds minlat=\"0\" minlon=\"0\" maxlat=\"0.001\" maxlon=\"0.001\"/>\n" + 63 " <node id=\"1\" " + common + " lat=\"0\" lon=\"0\"/>\n" + 64 " <node id=\"2\" " + common + " lat=\"0.0001\" lon=\"0.0001\"/>\n" + 65 " <node id=\"3\" " + common + " lat=\"0.0002\" lon=\"0.0002\"/>\n" + 66 "</osm>"))); 67 } 68 24 69 /** 25 70 * Unit test for bad request - no param. 26 * @throws Exception if any error occurs27 */28 @Test29 void testBadRequestNoParam() throws Exception {30 Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler(null).handle());71 */ 72 @Test 73 void testBadRequestNoParam() { 74 final LoadAndZoomHandler handler = assertDoesNotThrow(() -> newHandler(null)); 75 Exception e = assertThrows(RequestHandlerBadRequestException.class, handler::handle); 31 76 assertEquals("NumberFormatException (empty String)", e.getMessage()); 32 77 } … … 34 79 /** 35 80 * Unit test for bad request - invalid URL. 36 * @throws Exception if any error occurs37 */38 @Test39 void testBadRequestInvalidUrl() throws Exception {40 Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("invalid_url").handle());81 */ 82 @Test 83 void testBadRequestInvalidUrl() { 84 final LoadAndZoomHandler handler = assertDoesNotThrow(() -> newHandler("invalid_url")); 85 Exception e = assertThrows(RequestHandlerBadRequestException.class, handler::handle); 41 86 assertEquals("The following keys are mandatory, but have not been provided: bottom, top, left, right", e.getMessage()); 42 87 } … … 44 89 /** 45 90 * Unit test for bad request - incomplete URL. 46 * @throws Exception if any error occurs47 */48 @Test49 void testBadRequestIncompleteUrl() throws Exception {50 Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost").handle());91 */ 92 @Test 93 void testBadRequestIncompleteUrl() { 94 final LoadAndZoomHandler handler = assertDoesNotThrow(() -> newHandler("https://localhost")); 95 Exception e = assertThrows(RequestHandlerBadRequestException.class, handler::handle); 51 96 assertEquals("The following keys are mandatory, but have not been provided: bottom, top, left, right", e.getMessage()); 52 97 } 53 98 54 99 /** 55 * Unit test for nominal request - local data file. 56 * @throws Exception if any error occurs 57 */ 58 @Test 59 @BasicPreferences 60 void testNominalRequest() throws Exception { 61 assertDoesNotThrow(() -> newHandler("https://localhost?bottom=0&top=0&left=1&right=1").handle()); 100 * Ensure that a download is called and completed 101 * @param wireMockRuntimeInfo The wiremock information 102 * @throws RequestHandlerBadRequestException If there is an issue with the handler 103 */ 104 @Test 105 void testDownload(WireMockRuntimeInfo wireMockRuntimeInfo) throws RequestHandlerBadRequestException { 106 LoadAndZoomHandler handler = newHandler(DEFAULT_BBOX_URL); 107 assertDoesNotThrow(handler::handle); 108 syncThreads(); 109 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 110 assertNotNull(ds); 111 assertAll(() -> assertNotNull(ds.getPrimitiveById(1, OsmPrimitiveType.NODE)), 112 () -> assertNotNull(ds.getPrimitiveById(2, OsmPrimitiveType.NODE)), 113 () -> assertNotNull(ds.getPrimitiveById(3, OsmPrimitiveType.NODE)), 114 () -> assertNull(ds.getPrimitiveById(4, OsmPrimitiveType.NODE)), 115 () -> assertTrue(ds.selectionEmpty())); 116 wireMockRuntimeInfo.getWireMock().verifyThat(1, 117 RequestPatternBuilder.newRequestPattern().withUrl("/api/0.6/map?bbox=0.0,0.0,0.001,0.001")); 118 } 119 120 /** 121 * Ensure that an area isn't downloaded twice 122 * @param wireMockRuntimeInfo The wiremock information 123 * @throws RequestHandlerBadRequestException If there is an issue with the handler 124 */ 125 @Test 126 void testDoubleDownload(WireMockRuntimeInfo wireMockRuntimeInfo) throws RequestHandlerBadRequestException { 127 testDownload(wireMockRuntimeInfo); 128 testDownload(wireMockRuntimeInfo); 129 // testDownload checks that the URL has been called once. Since it doesn't reset anything, we don't need 130 // a specific test here. 131 } 132 133 /** 134 * Ensure that an overlapping area is trimmed before download 135 * @param wireMockRuntimeInfo The wiremock information 136 * @throws RequestHandlerBadRequestException If there is an issue with the handler 137 */ 138 @Test 139 void testOverlappingArea(WireMockRuntimeInfo wireMockRuntimeInfo) throws RequestHandlerBadRequestException { 140 LoadAndZoomHandler handler = newHandler(DEFAULT_BBOX_URL); 141 assertDoesNotThrow(handler::handle); 142 syncThreads(); 143 // The scientific notation is ok server-side. 144 final String mapCall = "/api/0.6/map?bbox=2.5E-4,0.001,7.5E-4,0.00125"; 145 final String commonNode = "visible=\"true\" version=\"1\" changeset=\"1\" timestamp=\"2000-01-01T00:00:00Z\" user=\"tsmock\" uid=\"1\""; 146 wireMockRuntimeInfo.getWireMock().register(WireMock.get(mapCall) 147 .willReturn(WireMock.aResponse().withBody("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 148 "<osm version=\"0.6\" generator=\"hand\" copyright=\"JOSM\" attribution=\"\" license=\"\">\n" + 149 " <bounds minlat=\"0.001\" minlon=\"0.00025\" maxlat=\"0.00125\" maxlon=\"0.00075\"/>\n" + 150 " <node id=\"4\" " + commonNode + " lat=\"0.00111\" lon=\"0.00026\"/>\n" + 151 " <node id=\"5\" " + commonNode + " lat=\"0.0011\" lon=\"0.00025\"/>\n" + 152 " <node id=\"6\" " + commonNode + " lat=\"0.0012\" lon=\"0.000251\"/>\n" + 153 "</osm>"))); 154 String request = "https://localhost/load_and_zoom?left=0.00025&bottom=0.00025&right=0.00075&top=0.00125"; 155 handler = newHandler(request); 156 assertDoesNotThrow(handler::handle); 157 syncThreads(); 158 wireMockRuntimeInfo.getWireMock().verifyThat(1, RequestPatternBuilder.newRequestPattern().withUrl(mapCall)); 159 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 160 assertNotNull(ds); 161 assertAll(() -> assertNotNull(ds.getPrimitiveById(1, OsmPrimitiveType.NODE)), 162 () -> assertNotNull(ds.getPrimitiveById(2, OsmPrimitiveType.NODE)), 163 () -> assertNotNull(ds.getPrimitiveById(3, OsmPrimitiveType.NODE)), 164 () -> assertNotNull(ds.getPrimitiveById(4, OsmPrimitiveType.NODE))); 165 } 166 167 /** 168 * Check search and zoom functionality 169 * @throws RequestHandlerBadRequestException If there is an issue with the handler 170 */ 171 @Main 172 @Projection 173 @Test 174 void testSearchAndZoom() throws RequestHandlerBadRequestException { 175 final LoadAndZoomHandler handler = newHandler(DEFAULT_BBOX_URL + "&search=id:1"); 176 assertDoesNotThrow(handler::handle); 177 syncThreads(); 178 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 179 Collection<OsmPrimitive> selected = ds.getSelected(); 180 assertEquals(1, selected.size()); 181 assertTrue(selected.contains(ds.getPrimitiveById(1, OsmPrimitiveType.NODE))); 182 assertTrue(ds.searchNodes(MainApplication.getMap().mapView.getRealBounds().toBBox()) 183 .contains((Node) ds.getPrimitiveById(1, OsmPrimitiveType.NODE))); 184 } 185 186 /** 187 * Check select and zoom functionality 188 * @throws RequestHandlerBadRequestException If there is an issue with the handler 189 */ 190 @Main 191 @Projection 192 @Test 193 void testSelectAndZoom() throws RequestHandlerBadRequestException { 194 final LoadAndZoomHandler handler = newHandler(DEFAULT_BBOX_URL + "&select=n1"); 195 assertDoesNotThrow(handler::handle); 196 syncThreads(); 197 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 198 Collection<OsmPrimitive> selected = ds.getSelected(); 199 assertEquals(1, selected.size()); 200 assertTrue(selected.contains(ds.getPrimitiveById(1, OsmPrimitiveType.NODE))); 201 assertTrue(ds.searchNodes(MainApplication.getMap().mapView.getRealBounds().toBBox()) 202 .contains((Node) ds.getPrimitiveById(1, OsmPrimitiveType.NODE))); 203 } 204 205 /** 206 * Check changeset tag functionality 207 * @throws RequestHandlerBadRequestException If there is an issue with the handler 208 */ 209 @Test 210 void testChangesetTags() throws RequestHandlerBadRequestException { 211 final String comment = "Add buildings, roads, and other random stuff"; 212 final String source = "This isn't Bing"; 213 final String hashtag = "#test-hashcodes"; 214 final String customTags = "custom=tag|is=here"; 215 final LoadAndZoomHandler handler = newHandler(DEFAULT_BBOX_URL 216 + "&changeset_comment=" + URLEncoder.encode(comment, StandardCharsets.UTF_8) 217 + "&changeset_source=" + URLEncoder.encode(source, StandardCharsets.UTF_8) 218 + "&changeset_hashtags=" + URLEncoder.encode(hashtag, StandardCharsets.UTF_8) 219 + "&changeset_tags=" + URLEncoder.encode(customTags, StandardCharsets.UTF_8)); 220 assertDoesNotThrow(handler::handle); 221 syncThreads(); 222 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 223 assertEquals(comment, ds.getChangeSetTags().get("comment")); 224 assertEquals(source, ds.getChangeSetTags().get("source")); 225 assertEquals(hashtag, ds.getChangeSetTags().get("hashtags")); 226 assertEquals("tag", ds.getChangeSetTags().get("custom")); 227 assertEquals("here", ds.getChangeSetTags().get("is")); 62 228 } 63 229 } -
trunk/test/unit/org/openstreetmap/josm/testutils/annotations/BasicWiremock.java
r19056 r19152 3 3 4 4 import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; 5 import static org.junit.jupiter.api.Assertions.assert True;5 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 6 6 import static org.junit.jupiter.api.Assertions.fail; 7 7 … … 19 19 import java.util.Arrays; 20 20 import java.util.List; 21 import java.util.stream.Collectors; 22 21 22 import com.github.tomakehurst.wiremock.core.WireMockConfiguration; 23 import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; 23 24 import org.junit.jupiter.api.extension.AfterAllCallback; 24 import org.junit.jupiter.api.extension.AfterEachCallback;25 25 import org.junit.jupiter.api.extension.BeforeAllCallback; 26 26 import org.junit.jupiter.api.extension.BeforeEachCallback; … … 29 29 import org.junit.jupiter.api.extension.ParameterContext; 30 30 import org.junit.jupiter.api.extension.ParameterResolutionException; 31 import org.junit.jupiter.api.extension.ParameterResolver;32 31 import org.junit.platform.commons.support.AnnotationSupport; 33 32 import org.openstreetmap.josm.TestUtils; 34 33 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 35 import org.openstreetmap.josm.gui.util.GuiHelper;36 34 import org.openstreetmap.josm.io.OsmApi; 37 35 import org.openstreetmap.josm.spi.preferences.Config; … … 43 41 import com.github.tomakehurst.wiremock.client.WireMock; 44 42 import com.github.tomakehurst.wiremock.extension.ResponseTransformerV2; 45 import com.github.tomakehurst.wiremock.verification.LoggedRequest;46 43 47 44 /** … … 81 78 * 82 79 */ 83 class WireMockExtension 84 implements AfterAllCallback, AfterEachCallback, BeforeAllCallback, BeforeEachCallback, ParameterResolver { 80 class WireMockExtension extends com.github.tomakehurst.wiremock.junit5.WireMockExtension { 81 protected WireMockExtension() { 82 this(defaultOptions()); 83 } 84 85 /** 86 * Create a new extension with options 87 * 88 * @param builder a {@link Builder} 89 * instance holding the initialisation parameters for the extension. 90 */ 91 protected WireMockExtension(Builder builder) { 92 super(builder); 93 } 94 85 95 /** 86 96 * Get the default wiremock server … … 98 108 new Pair<>(new Class<?>[] {ExtensionContext.class }, new Object[] {context }), 99 109 new Pair<>(new Class<?>[0], new Object[0]))) { 100 try { 101 Constructor<? extends ResponseTransformerV2> constructor = responseTransformer 102 .getConstructor(parameterMapping.a); 103 transformers.add(constructor.newInstance(parameterMapping.b)); 104 break; 105 } catch (ReflectiveOperationException e) { 106 fail(e); 107 } 110 Constructor<? extends ResponseTransformerV2> constructor = assertDoesNotThrow(() -> 111 responseTransformer.getConstructor(parameterMapping.a)); 112 ResponseTransformerV2 transformerV2 = assertDoesNotThrow(() -> constructor.newInstance(parameterMapping.b)); 113 transformers.add(transformerV2); 114 break; 108 115 } 109 116 } … … 114 121 } 115 122 123 static Builder defaultOptions() { 124 WireMockConfiguration options = WireMockConfiguration.options() 125 .usingFilesUnderDirectory(TestUtils.getTestDataRoot()) 126 .dynamicPort(); 127 return extensionOptions().options(options); 128 } 129 116 130 /** 117 131 * Replace URL servers with wiremock … … 120 134 * @param url The URL to fix 121 135 * @return A url that points at the wiremock server 136 * @deprecated since 19152 (not used in core; no known users) 122 137 */ 138 @Deprecated(forRemoval = true, since = "19152") 123 139 public static String replaceUrl(WireMockServer wireMockServer, String url) { 124 140 try { … … 132 148 133 149 @Override 134 public void afterAll(ExtensionContext context) throws Exception { 135 // Run in EDT to avoid stopping wiremock server before wiremock requests finish. 136 GuiHelper.runInEDTAndWait(getWiremock(context)::stop); 137 } 138 139 @Override 140 public void afterEach(ExtensionContext context) throws Exception { 141 List<LoggedRequest> missed = getWiremock(context).findUnmatchedRequests().getRequests(); 142 missed.forEach(r -> Logging.error(r.getAbsoluteUrl())); 143 try { 144 assertTrue(missed.isEmpty(), missed.stream().map(LoggedRequest::getUrl).collect(Collectors.joining("\n\n"))); 145 } finally { 146 getWiremock(context).resetRequests(); 147 getWiremock(context).resetToDefaultMappings(); 148 getWiremock(context).resetScenarios(); 149 if (AnnotationUtils.elementIsAnnotated(context.getElement(), BasicWiremock.class) 150 || getWiremock(context) == null) { 151 this.afterAll(context); 152 } 153 } 154 } 155 156 @Override 157 public void beforeAll(ExtensionContext context) throws Exception { 158 getWiremock(context).start(); 159 } 160 161 @Override 162 public void beforeEach(ExtensionContext context) throws Exception { 163 if (AnnotationUtils.elementIsAnnotated(context.getElement(), BasicWiremock.class) || getWiremock(context) == null) { 164 this.beforeAll(context); 165 } 150 protected void onBeforeAll(ExtensionContext extensionContext, WireMockRuntimeInfo wireMockRuntimeInfo) { 151 extensionContext.getStore(ExtensionContext.Namespace.create(BasicWiremock.WireMockExtension.class)) 152 .put(BasicWiremock.WireMockExtension.class, this); 153 } 154 155 @Override 156 protected void onAfterAll(ExtensionContext extensionContext, WireMockRuntimeInfo wireMockRuntimeInfo) { 157 // Sync threads to ensure that no further wiremock requests will be made 158 final ThreadSync.ThreadSyncExtension threadSyncExtension = new ThreadSync.ThreadSyncExtension(); 159 assertDoesNotThrow(() -> threadSyncExtension.afterEach(extensionContext)); 160 } 161 162 @Override 163 protected void onBeforeEach(ExtensionContext context, WireMockRuntimeInfo wireMockRuntimeInfo) { 166 164 if (context.getTestClass().isPresent()) { 167 165 List<Field> wireMockFields = AnnotationSupport.findAnnotatedFields(context.getRequiredTestClass(), BasicWiremock.class); … … 172 170 try { 173 171 field.set(context.getTestInstance().orElse(null), getWiremock(context)); 172 } catch (IllegalAccessException e) { 173 fail(e); 174 174 } finally { 175 175 field.setAccessible(isAccessible); … … 185 185 public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) 186 186 throws ParameterResolutionException { 187 if (super.supportsParameter(parameterContext, extensionContext)) { 188 return true; 189 } 190 if (WireMockRuntimeInfo.class.isAssignableFrom(parameterContext.getParameter().getType())) { 191 return true; 192 } 187 193 return parameterContext.getParameter().getAnnotation(BasicWiremock.class) != null 188 194 && parameterContext.getParameter().getType() == WireMockServer.class; … … 192 198 public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) 193 199 throws ParameterResolutionException { 200 if (super.supportsParameter(parameterContext, extensionContext)) { 201 return super.resolveParameter(parameterContext, extensionContext); 202 } 203 if (WireMockRuntimeInfo.class.isAssignableFrom(parameterContext.getParameter().getType())) { 204 return getRuntimeInfo(); 205 } 194 206 return getWiremock(extensionContext); 195 207 } … … 199 211 * A class specifically to mock OSM API calls 200 212 */ 201 class OsmApiExtension extends WireMockExtension { 202 @Override 203 public void afterAll(ExtensionContext context) throws Exception { 204 try { 205 super.afterAll(context); 206 } finally { 207 Config.getPref().put("osm-server.url", "https://invalid.url"); 208 } 213 class OsmApiExtension implements BeforeAllCallback, BeforeEachCallback, AfterAllCallback { 214 @Override 215 public void afterAll(ExtensionContext context) { 216 Config.getPref().put("osm-server.url", "https://invalid.url"); 209 217 } 210 218 … … 214 222 fail("OsmApiExtension requires @BasicPreferences"); 215 223 } 216 super.beforeAll(context); 217 Config.getPref().put("osm-server.url", getWiremock(context).baseUrl() + "/api"); 218 getWiremock(context).stubFor(WireMock.get("/api/0.6/capabilities") 224 this.beforeEach(context); 225 } 226 227 @Override 228 public void beforeEach(ExtensionContext extensionContext) throws Exception { 229 BasicWiremock.WireMockExtension extension = 230 extensionContext.getStore(ExtensionContext.Namespace.create(BasicWiremock.WireMockExtension.class)) 231 .get(BasicWiremock.WireMockExtension.class, BasicWiremock.WireMockExtension.class); 232 WireMockRuntimeInfo wireMockRuntimeInfo = extension.getRuntimeInfo(); 233 Config.getPref().put("osm-server.url", wireMockRuntimeInfo.getHttpBaseUrl() + "/api"); 234 wireMockRuntimeInfo.getWireMock().register(WireMock.get("/api/0.6/capabilities") 219 235 .willReturn(WireMock.aResponse().withBodyFile("api/0.6/capabilities"))); 220 getWiremock(context).stubFor(WireMock.get("/api/capabilities")236 wireMockRuntimeInfo.getWireMock().register(WireMock.get("/api/capabilities") 221 237 .willReturn(WireMock.aResponse().withBodyFile("api/capabilities"))); 222 OsmApi.getOsmApi().initialize(NullProgressMonitor.INSTANCE);238 assertDoesNotThrow(() -> OsmApi.getOsmApi().initialize(NullProgressMonitor.INSTANCE)); 223 239 } 224 240 }
Note:
See TracChangeset
for help on using the changeset viewer.