diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java index a0a1916..165237d 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java @@ -219,9 +219,7 @@ public class GetDataRunnable extends RecursiveTask { if (!monitor.isCanceled()) { if (bounds.size() == MAX_NUMBER_OF_BBOXES_TO_PROCESS) { final var temporaryDataSet = getDataReal(bounds.get(0), monitor); - synchronized (this.dataSet) { - dataSet.mergeFrom(temporaryDataSet); - } + this.dataSet.update(() -> dataSet.mergeFrom(temporaryDataSet)); } else { final Collection tasks = bounds.stream() .map(bound -> new GetDataRunnable(bound, dataSet, monitor.createSubTaskMonitor(0, true))) @@ -250,10 +248,10 @@ public class GetDataRunnable extends RecursiveTask { * @param info The information used to download the data */ public static void cleanup(DataSet dataSet, Bounds bounds, MapWithAIInfo info) { - realCleanup(dataSet, bounds, info); + dataSet.update(() -> realCleanup(dataSet, bounds, info)); } - private static synchronized void realCleanup(DataSet dataSet, Bounds bounds, MapWithAIInfo info) { + private static void realCleanup(DataSet dataSet, Bounds bounds, MapWithAIInfo info) { final Bounds boundsToUse; if (bounds == null && !dataSet.getDataSourceBounds().isEmpty()) { boundsToUse = new Bounds(dataSet.getDataSourceBounds().get(0)); diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/MapWithAILayerInfo.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/MapWithAILayerInfo.java index 529b157..491a219 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/MapWithAILayerInfo.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/MapWithAILayerInfo.java @@ -98,8 +98,10 @@ public class MapWithAILayerInfo { } // Avoid a deadlock in the EDT. if (!finished.get() && !SwingUtilities.isEventDispatchThread()) { + var count = 0; synchronized (MapWithAILayerInfo.class) { - while (!finished.get()) { + while (!finished.get() && count < 120) { + count++; try { MapWithAILayerInfo.class.wait(1000); } catch (InterruptedException e) { diff --git a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/actions/AddMapWithAILayerActionTest.java b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/actions/AddMapWithAILayerActionTest.java index d85cb44..ac816cd 100644 --- a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/actions/AddMapWithAILayerActionTest.java +++ b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/actions/AddMapWithAILayerActionTest.java @@ -4,14 +4,11 @@ package org.openstreetmap.josm.plugins.mapwithai.actions; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import javax.imageio.ImageIO; -import javax.swing.Action; -import javax.swing.ImageIcon; - import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -19,20 +16,22 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutionException; import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.stream.Collectors; -import org.awaitility.Awaitility; -import org.awaitility.Durations; +import javax.imageio.ImageIO; +import javax.swing.Action; +import javax.swing.ImageIcon; + +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.DataSource; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.layer.OsmDataLayer; -import org.openstreetmap.josm.gui.util.GuiHelper; import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils; import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer; import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIInfo; @@ -41,17 +40,19 @@ import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIType; import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.MapWithAISources; import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.NoExceptions; import org.openstreetmap.josm.testutils.annotations.BasicPreferences; +import org.openstreetmap.josm.testutils.annotations.BasicWiremock; import org.openstreetmap.josm.testutils.annotations.Projection; +import org.openstreetmap.josm.testutils.annotations.ThreadSync; import org.openstreetmap.josm.tools.ImageProvider; import org.openstreetmap.josm.tools.Logging; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import com.github.tomakehurst.wiremock.matching.AnythingPattern; import com.github.tomakehurst.wiremock.matching.EqualToPattern; import com.github.tomakehurst.wiremock.matching.StringValuePattern; import com.github.tomakehurst.wiremock.matching.UrlPathPattern; +import jakarta.json.Json; /** * Test class for {@link AddMapWithAILayerAction} @@ -63,11 +64,47 @@ import com.github.tomakehurst.wiremock.matching.UrlPathPattern; @MapWithAISources @Projection class AddMapWithAILayerActionTest { - @Test - void testAddMapWithAILayerActionTest() { - MapWithAIInfo info = MapWithAILayerInfo.getInstance().getLayers().stream() + + private static class ThreadSyncMWAI extends ThreadSync.ThreadSyncExtension { + public ThreadSyncMWAI() { + this.registerForkJoinPool(MapWithAIDataUtils.getForkJoinPool()); + } + } + + @RegisterExtension + static ThreadSyncMWAI threadSync = new ThreadSyncMWAI(); + + @BasicWiremock + WireMockServer wireMockServer; + + private static MapWithAIInfo info; + private static MapWithAIInfo backupInfo; + + @BeforeEach + void setup() { + final Map parameterMap = new HashMap<>(); + final AnythingPattern anythingPattern = new AnythingPattern(); + parameterMap.put("geometryType", anythingPattern); + parameterMap.put("geometry", anythingPattern); + parameterMap.put("inSR", new EqualToPattern("4326")); + parameterMap.put("f", new EqualToPattern("geojson")); + parameterMap.put("outfields", new EqualToPattern("*")); + parameterMap.put("result_type", new EqualToPattern("road_building_vector_xml")); + parameterMap.put("resultOffset", anythingPattern); + wireMockServer.stubFor( + WireMock.get(new UrlPathPattern(new EqualToPattern("/query"), false)).withQueryParams(parameterMap) + .willReturn(WireMock.aResponse() + .withBody(Json.createObjectBuilder().add("type", "FeatureCollection") + .add("features", Json.createArrayBuilder().build()).build().toString())) + .atPriority(Integer.MIN_VALUE)); + info = MapWithAILayerInfo.getInstance().getLayers().stream() .filter(i -> i.getName().equalsIgnoreCase("MapWithAI")).findAny().orElse(null); assertNotNull(info); + info = new MapWithAIInfo(info); + } + + @Test + void testAddMapWithAILayerActionTest() { AddMapWithAILayerAction action = new AddMapWithAILayerAction(info); assertDoesNotThrow(() -> action.actionPerformed(null)); OsmDataLayer osmLayer = new OsmDataLayer(new DataSet(), "TEST DATA", null); @@ -78,7 +115,7 @@ class AddMapWithAILayerActionTest { assertNull(MapWithAIDataUtils.getLayer(false)); action.updateEnabledState(); action.actionPerformed(null); - Awaitility.await().atMost(Durations.FIVE_SECONDS).until(() -> MapWithAIDataUtils.getLayer(false) != null); + threadSync.threadSync(); assertNotNull(MapWithAIDataUtils.getLayer(false)); MainApplication.getLayerManager().removeLayer(MapWithAIDataUtils.getLayer(false)); @@ -90,7 +127,7 @@ class AddMapWithAILayerActionTest { action.updateEnabledState(); action.actionPerformed(null); - Awaitility.await().atMost(Durations.FIVE_SECONDS).until(() -> !layer.getDataSet().isEmpty()); + threadSync.threadSync(); assertFalse(layer.getDataSet().isEmpty()); MainApplication.getLayerManager().removeLayer(MapWithAIDataUtils.getLayer(false)); @@ -100,69 +137,40 @@ class AddMapWithAILayerActionTest { mapwithaiLayer.getDataSet() .addDataSource(new DataSource(new Bounds(39.095376, -108.4495519, 39.0987811, -108.4422314), "")); action.actionPerformed(null); - Awaitility.await().atMost(Durations.FIVE_SECONDS).until(() -> !mapwithaiLayer.getDataSet().isEmpty()); + threadSync.threadSync(); assertFalse(mapwithaiLayer.getDataSet().isEmpty()); } @Test - void testRemoteIcon() throws IOException, ExecutionException, InterruptedException { + void testRemoteIcon() throws IOException { final ImageIcon blankImage = ImageProvider.createBlankIcon(ImageProvider.ImageSizes.LARGEICON); final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // BufferedImage is what the current implementation uses. Otherwise, we will // have to copy it into a BufferedImage. - assertTrue(blankImage.getImage() instanceof BufferedImage); - final BufferedImage bi = (BufferedImage) blankImage.getImage(); + final BufferedImage bi = assertInstanceOf(BufferedImage.class, blankImage.getImage()); ImageIO.write(bi, "png", byteArrayOutputStream); byte[] originalImage = byteArrayOutputStream.toByteArray(); - final WireMockServer wireMockServer = new WireMockServer(WireMockConfiguration.options().dynamicPort()); - try { - wireMockServer.start(); - wireMockServer.addStubMapping(wireMockServer - .stubFor(WireMock.get("/icon").willReturn(WireMock.aResponse().withBody(originalImage)))); - final MapWithAIInfo info = MapWithAILayerInfo.getInstance().getLayers().stream() - .filter(i -> i.getName().equalsIgnoreCase("MapWithAI")).findAny().orElse(null); - assertNotNull(info); - final MapWithAIInfo remoteInfo = new MapWithAIInfo(info); - remoteInfo.setIcon(wireMockServer.baseUrl() + "/icon"); - final AddMapWithAILayerAction action = new AddMapWithAILayerAction(remoteInfo); - GuiHelper.runInEDTAndWait(() -> { - /* Sync EDT */}); - MainApplication.worker.submit(() -> { - /* Sync worker thread */}).get(); - final Object image = action.getValue(Action.LARGE_ICON_KEY); - assertTrue(image instanceof ImageIcon); - final ImageIcon attachedIcon = (ImageIcon) image; - assertTrue(attachedIcon.getImage() instanceof BufferedImage); - byteArrayOutputStream.reset(); - ImageIO.write((BufferedImage) attachedIcon.getImage(), "png", byteArrayOutputStream); - final byte[] downloadedImage = byteArrayOutputStream.toByteArray(); - assertArrayEquals(originalImage, downloadedImage); - } finally { - wireMockServer.stop(); - } + wireMockServer.addStubMapping( + wireMockServer.stubFor(WireMock.get("/icon").willReturn(WireMock.aResponse().withBody(originalImage)))); + final MapWithAIInfo remoteInfo = new MapWithAIInfo(info); + remoteInfo.setIcon(wireMockServer.baseUrl() + "/icon"); + final AddMapWithAILayerAction action = new AddMapWithAILayerAction(remoteInfo); + threadSync.threadSync(); + final Object image = action.getValue(Action.LARGE_ICON_KEY); + final ImageIcon attachedIcon = assertInstanceOf(ImageIcon.class, image); + final BufferedImage bufferedImage = assertInstanceOf(BufferedImage.class, attachedIcon.getImage()); + byteArrayOutputStream.reset(); + ImageIO.write(bufferedImage, "png", byteArrayOutputStream); + final byte[] downloadedImage = byteArrayOutputStream.toByteArray(); + assertArrayEquals(originalImage, downloadedImage); } @Test - void testNonRegression22683() throws ExecutionException, InterruptedException { - final MapWithAIInfo info = MapWithAILayerInfo.getInstance().getLayers().stream() - .filter(i -> i.getName().equalsIgnoreCase("MapWithAI")).findAny().orElse(null); - assertNotNull(info); + void testNonRegression22683() { final OsmDataLayer layer = new OsmDataLayer(new DataSet(), "testNonRegression22683", null); layer.getDataSet().addDataSource(new DataSource(new Bounds(0, 0, 0.001, 0.001), "Area 1")); layer.getDataSet().addDataSource(new DataSource(new Bounds(-0.001, -0.001, 0, 0), "Area 2")); MainApplication.getLayerManager().addLayer(layer); - final WireMockServer server = new WireMockServer(WireMockConfiguration.options().dynamicPort()); - final Map parameterMap = new HashMap<>(); - final AnythingPattern anythingPattern = new AnythingPattern(); - parameterMap.put("geometryType", anythingPattern); - parameterMap.put("geometry", anythingPattern); - parameterMap.put("inSR", new EqualToPattern("4326")); - parameterMap.put("f", new EqualToPattern("geojson")); - parameterMap.put("outfields", new EqualToPattern("*")); - parameterMap.put("result_type", new EqualToPattern("road_building_vector_xml")); - parameterMap.put("resultOffset", anythingPattern); - server.stubFor(WireMock.get(new UrlPathPattern(new EqualToPattern("/query"), false)) - .withQueryParams(parameterMap).willReturn(WireMock.aResponse().withBody("{\"test\":0}"))); final List logs = new ArrayList<>(); Handler testHandler = new Handler() { @Override @@ -182,22 +190,16 @@ class AddMapWithAILayerActionTest { }; Logging.getLogger().addHandler(testHandler); try { - server.start(); - info.setUrl(server.baseUrl()); + info.setUrl(wireMockServer.baseUrl()); info.setSourceType(MapWithAIType.ESRI_FEATURE_SERVER); final AddMapWithAILayerAction action = new AddMapWithAILayerAction(info); Logging.clearLastErrorAndWarnings(); assertDoesNotThrow(() -> action.actionPerformed(null)); - GuiHelper.runInEDTAndWait(() -> { - /* Sync thread */ }); - MainApplication.worker.submit(() -> { - /* Sync thread */ }).get(); + threadSync.threadSync(); final List ides = logs.stream() - .filter(record -> record.getThrown() instanceof IllegalArgumentException) - .collect(Collectors.toList()); + .filter(record -> record.getThrown() instanceof IllegalArgumentException).toList(); assertTrue(ides.isEmpty(), ides.stream().map(LogRecord::getMessage).collect(Collectors.joining("\n"))); } finally { - server.stop(); Logging.getLogger().removeHandler(testHandler); } } diff --git a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayerTest.java b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayerTest.java index 519811e..4a73d4b 100644 --- a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayerTest.java +++ b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayerTest.java @@ -4,17 +4,13 @@ package org.openstreetmap.josm.plugins.mapwithai.backend; import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.openstreetmap.josm.tools.I18n.tr; -import javax.swing.Action; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; - import java.awt.Component; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; @@ -23,6 +19,11 @@ import java.util.Collections; import java.util.List; import java.util.stream.Stream; +import javax.swing.Action; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + import org.awaitility.Durations; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -53,6 +54,7 @@ import org.openstreetmap.josm.testutils.annotations.BasicPreferences; import org.openstreetmap.josm.testutils.annotations.Main; import org.openstreetmap.josm.testutils.annotations.OsmApi; import org.openstreetmap.josm.testutils.annotations.Projection; +import org.openstreetmap.josm.testutils.annotations.ResetUniquePrimitiveIdCounters; import org.openstreetmap.josm.testutils.annotations.Territories; /** @@ -124,9 +126,9 @@ class MapWithAILayerTest { @Test void testGetInfoComponent() { final Object tObject = layer.getInfoComponent(); - assertTrue(tObject instanceof JPanel, "The info component should be a JPanel instead of a string"); + JPanel jPanel = assertInstanceOf(JPanel.class, tObject, + "The info component should be a JPanel instead of a string"); - JPanel jPanel = (JPanel) tObject; final Component[] startComponents = jPanel.getComponents(); for (final Component comp : startComponents) { final JLabel label = (JLabel) comp; @@ -173,6 +175,7 @@ class MapWithAILayerTest { } } + @ResetUniquePrimitiveIdCounters @Test void testSelection() throws InvocationTargetException, InterruptedException { MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(true); @@ -186,10 +189,10 @@ class MapWithAILayerTest { SwingUtilities.invokeAndWait(() -> ds.setSelected(ds.allNonDeletedCompletePrimitives())); assertEquals(1, ds.getSelected().size()); OsmPrimitive prim = ds.getSelected().iterator().next(); - assertTrue(prim instanceof Way); - SwingUtilities.invokeAndWait(() -> ds.setSelected(((Way) prim).getNodes())); - assertEquals(((Way) prim).getNodes().size(), ds.getSelected().size()); - assertTrue(((Way) prim).getNodes().stream().allMatch(ds::isSelected)); + final Way way = assertInstanceOf(Way.class, prim); + SwingUtilities.invokeAndWait(() -> ds.setSelected(way.getNodes())); + assertEquals(way.getNodes().size(), ds.getSelected().size()); + assertTrue(way.getNodes().stream().allMatch(ds::isSelected)); } @Test diff --git a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/commands/MovePrimitiveDataSetCommandTest.java b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/commands/MovePrimitiveDataSetCommandTest.java index 3338a48..d303c83 100644 --- a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/commands/MovePrimitiveDataSetCommandTest.java +++ b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/commands/MovePrimitiveDataSetCommandTest.java @@ -49,8 +49,8 @@ class MovePrimitiveDataSetCommandTest { move.fillModifiedData(modified, deleted, added); final Collection participatingPrimitives = move.getParticipatingPrimitives(); assertAll(() -> assertEquals(0, deleted.size()), () -> assertEquals(0, added.size()), // the JOSM Add command - // doesn't add to this - // list + // doesn't add to this + // list () -> assertEquals(0, modified.size()), () -> assertEquals(1, from.allNonDeletedPrimitives().size()), () -> assertEquals(3, to.allNonDeletedPrimitives().size()), () -> assertNotNull(to.getPrimitiveById(way1)), () -> assertTrue(way1.isDeleted()), @@ -86,8 +86,8 @@ class MovePrimitiveDataSetCommandTest { move.fillModifiedData(modified, deleted, added); final List participatingPrimitives = new ArrayList<>(move.getParticipatingPrimitives()); assertAll(() -> assertEquals(0, deleted.size()), () -> assertEquals(0, added.size()), // the JOSM Add command - // doesn't add to this - // list + // doesn't add to this + // list () -> assertEquals(0, modified.size()), () -> assertEquals(1, from.allNonDeletedPrimitives().size()), () -> assertEquals(3, to.allNonDeletedPrimitives().size()), () -> assertNotNull(to.getPrimitiveById(way1)), diff --git a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/data/validation/tests/RoutingIslandsTestTest.java b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/data/validation/tests/RoutingIslandsTestTest.java index 8f5c9d3..f0e807d 100644 --- a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/data/validation/tests/RoutingIslandsTestTest.java +++ b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/data/validation/tests/RoutingIslandsTestTest.java @@ -157,6 +157,7 @@ class RoutingIslandsTestTest { /** * Test method for {@link RoutingIslandsTest#checkForUnconnectedWays}. */ + @BasicPreferences @Test void testCheckForUnconnectedWaysIncoming() { RoutingIslandsTest.checkForUnconnectedWays(Collections.emptySet(), Collections.emptySet(), null); diff --git a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/MapWithAITestRules.java b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/MapWithAITestRules.java deleted file mode 100644 index 6fc52b7..0000000 --- a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/MapWithAITestRules.java +++ /dev/null @@ -1,59 +0,0 @@ -// License: GPL. For details, see LICENSE file. -package org.openstreetmap.josm.plugins.mapwithai.testutils; - -import java.lang.Thread.UncaughtExceptionHandler; -import java.util.logging.Level; - -import org.junit.runners.model.InitializationError; -import org.openstreetmap.josm.testutils.JOSMTestRules; -import org.openstreetmap.josm.tools.Logging; - -import mockit.integration.TestRunnerDecorator; - -public class MapWithAITestRules extends JOSMTestRules { - - private boolean workerExceptions = true; - private UncaughtExceptionHandler currentExceptionHandler; - - public MapWithAITestRules() { - super(); - } - - public MapWithAITestRules noWorkerExceptions() { - this.workerExceptions = false; - return this; - } - - /** - * Set up before running a test - * - * @throws InitializationError If an error occurred while creating the - * required environment. - * @throws ReflectiveOperationException if a reflective access error occurs - */ - @Override - protected void before() throws InitializationError, ReflectiveOperationException { - TestRunnerDecorator.cleanUpAllMocks(); - super.before(); - Logging.getLogger().setFilter(record -> record.getLevel().intValue() >= Level.WARNING.intValue() - || record.getSourceClassName().startsWith("org.openstreetmap.josm.plugins.mapwithai")); - - if (workerExceptions) { - currentExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); - Thread.setDefaultUncaughtExceptionHandler((t, e) -> { - Logging.error(t.getClass().getSimpleName()); - Logging.error(e); - }); - } - } - - @Override - protected void after() throws ReflectiveOperationException { - super.after(); - - if (workerExceptions) { - Thread.setDefaultUncaughtExceptionHandler(currentExceptionHandler); - } - TestRunnerDecorator.cleanUpAllMocks(); - } -} diff --git a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/annotations/MapWithAISources.java b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/annotations/MapWithAISources.java index d1087ae..23cc457 100644 --- a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/annotations/MapWithAISources.java +++ b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/annotations/MapWithAISources.java @@ -20,5 +20,4 @@ import org.openstreetmap.josm.testutils.annotations.Territories; @Wiremock @Territories @ExtendWith(Wiremock.MapWithAILayerInfoExtension.class) -public @interface MapWithAISources { -} +public @interface MapWithAISources {} diff --git a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/annotations/Wiremock.java b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/annotations/Wiremock.java index 9f1bb99..88459e1 100644 --- a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/annotations/Wiremock.java +++ b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/testutils/annotations/Wiremock.java @@ -105,6 +105,8 @@ public @interface Wiremock { * Extension for {@link MapWithAILayerInfo} */ class MapWithAILayerInfoExtension extends WiremockExtension { + private static int hashCode; + @Override public void afterAll(ExtensionContext context) throws Exception { try { @@ -129,7 +131,7 @@ public @interface Wiremock { synchronized (MapWithAILayerInfo.class) { final var info = MapWithAILayerInfo.getInstance(); info.clear(); - if (false && AnnotationSupport.isAnnotated(context.getTestClass(), Territories.class)) { + if (AnnotationSupport.isAnnotated(context.getTestClass(), Territories.class)) { // This should probably only be run if territories is initialized info.getDefaultLayers().stream().filter(MapWithAIInfo::isDefaultEntry).forEach(info::add); } diff --git a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/tools/BlacklistUtilsTest.java b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/tools/BlacklistUtilsTest.java index 92c57eb..7ab3f15 100644 --- a/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/tools/BlacklistUtilsTest.java +++ b/src/test/unit/org/openstreetmap/josm/plugins/mapwithai/tools/BlacklistUtilsTest.java @@ -6,19 +6,23 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.noContent; import static com.github.tomakehurst.wiremock.client.WireMock.notFound; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.File; + import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.openstreetmap.josm.TestUtils; import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin; import org.openstreetmap.josm.plugins.mapwithai.testutils.MapWithAIPluginMock; +import org.openstreetmap.josm.spi.preferences.Config; -import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; /** * Tests for {@link BlacklistUtils} @@ -26,85 +30,90 @@ import com.github.tomakehurst.wiremock.WireMockServer; * @author Taylor Smock * */ +@WireMockTest class BlacklistUtilsTest { - private static WireMockServer wireMock; + private static String blacklistUrl; @BeforeAll - static void setup() { + static void setup(WireMockRuntimeInfo wireMockRuntimeInfo) { TestUtils.assumeWorkingJMockit(); - wireMock = new WireMockServer(options().dynamicPort()); - wireMock.start(); - BlacklistUtils.setBlacklistUrl(wireMock.baseUrl() + "/MapWithAI/json/blacklisted_versions.json"); + blacklistUrl = wireMockRuntimeInfo.getHttpBaseUrl() + "/MapWithAI/json/blacklisted_versions.json"; + BlacklistUtils.setBlacklistUrl(blacklistUrl); new MapWithAIPluginMock(); } @BeforeEach - void clear() { - wireMock.resetMappings(); + @AfterEach + void cleanup(WireMockRuntimeInfo wireMockRuntimeInfo) { + final var file = new File(Config.getDirs().getCacheDirectory(false), "mirror_http___localhost_" + + wireMockRuntimeInfo.getHttpPort() + "_MapWithAI_json_blacklisted_versions.json"); + // Ensure that we aren't reading a cached response from a different test + if (file.exists()) { + assertTrue(file.delete()); + } } @AfterAll static void tearDown() { BlacklistUtils.setBlacklistUrl(BlacklistUtils.DEFAULT_BLACKLIST_URL); - assertTrue(wireMock.findAllUnmatchedRequests().isEmpty()); - wireMock.stop(); + blacklistUrl = null; } @Test - void testArrayBad() { - wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")) - .willReturn(aResponse().withStatus(200).withBody("[\"" + MapWithAIPlugin.getVersionInfo() + "\"]")) - .build()); + void testArrayBad(WireMockRuntimeInfo wireMockRuntimeInfo) { + wireMockRuntimeInfo.getWireMock().register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")) + .willReturn(aResponse().withStatus(200).withBody("[\"" + MapWithAIPlugin.getVersionInfo() + "\"]"))); assertTrue(BlacklistUtils.isBlacklisted()); } @Test - void testArrayGood() { - wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")) - .willReturn(aResponse().withStatus(200).withBody("[null, 0, false]")).build()); + void testArrayGood(WireMockRuntimeInfo wireMockRuntimeInfo) { + wireMockRuntimeInfo.getWireMock().register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")) + .willReturn(aResponse().withStatus(200).withBody("[null, 0, false]"))); assertFalse(BlacklistUtils.isBlacklisted()); } @Test - void testObjectBad() { - wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(aResponse() - .withStatus(200).withBody("{ \"" + MapWithAIPlugin.getVersionInfo() + "\": \"reason here\"}")).build()); + void testObjectBad(WireMockRuntimeInfo wireMockRuntimeInfo) { + wireMockRuntimeInfo.getWireMock() + .register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(aResponse() + .withStatus(200).withBody("{ \"" + MapWithAIPlugin.getVersionInfo() + "\": \"reason here\"}"))); assertTrue(BlacklistUtils.isBlacklisted()); } @Test - void testObjectGood() { - wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")) - .willReturn(aResponse().withStatus(200).withBody("{ \"version\": \"reason here\"}")).build()); + void testObjectGood(WireMockRuntimeInfo wireMockRuntimeInfo) { + wireMockRuntimeInfo.getWireMock().register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")) + .willReturn(aResponse().withStatus(200).withBody("{ \"version\": \"reason here\"}"))); assertFalse(BlacklistUtils.isBlacklisted()); } @Test - void testNullJson() { - wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")) - .willReturn(aResponse().withStatus(200).withBody("null")).build()); + void testNullJson(WireMockRuntimeInfo wireMockRuntimeInfo) { + wireMockRuntimeInfo.getWireMock().register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")) + .willReturn(aResponse().withStatus(200).withBody("null"))); assertTrue(BlacklistUtils.isBlacklisted()); } @Test - void testBrokenJson() { - wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn( - aResponse().withStatus(200).withBody("{ \"" + MapWithAIPlugin.getVersionInfo() + "\": \"reason here\"")) - .build()); + void testBrokenJson(WireMockRuntimeInfo wireMockRuntimeInfo) { + wireMockRuntimeInfo.getWireMock() + .register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(aResponse() + .withStatus(200).withBody("{ \"" + MapWithAIPlugin.getVersionInfo() + "\": \"reason here\""))); assertTrue(BlacklistUtils.isBlacklisted()); } @Test - void testNoResponse() { - wireMock.addStubMapping( - get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(noContent()).build()); + void testNoResponse(WireMockRuntimeInfo wireMockRuntimeInfo) { + wireMockRuntimeInfo.getWireMock() + .register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(noContent())); assertTrue(BlacklistUtils.isBlacklisted()); } @Test - void testNotFound() { - wireMock.addStubMapping( - get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(notFound()).build()); + void testNotFound(WireMockRuntimeInfo wireMockRuntimeInfo) { + wireMockRuntimeInfo.getWireMock() + .register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(notFound())); assertTrue(BlacklistUtils.isBlacklisted()); } }