Ignore:
Timestamp:
2024-08-19T20:16:02+02:00 (6 months ago)
Author:
taylor.smock
Message:

Fix #23821: Ensure that remote control commands are processed in order

This reverts or partially reverts r19153 and r19196 in favour of forcing ordering
in the RequestProcessor#run method. This does not block the server thread, but
it can mean that we have a bunch of processor threads that are waiting on the
previous processor thread.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandlerTest.java

    r19153 r19200  
    1111import static org.junit.jupiter.api.Assertions.assertTrue;
    1212
     13import java.io.IOException;
     14import java.net.URI;
    1315import java.net.URLEncoder;
    1416import java.nio.charset.StandardCharsets;
     
    3133import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    3234import org.openstreetmap.josm.gui.util.GuiHelper;
     35import org.openstreetmap.josm.io.remotecontrol.RemoteControl;
    3336import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException;
     37import org.openstreetmap.josm.spi.preferences.Config;
    3438import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
    3539
     
    3943import org.openstreetmap.josm.testutils.annotations.Projection;
    4044import org.openstreetmap.josm.testutils.annotations.ThreadSync;
     45import org.openstreetmap.josm.tools.HttpClient;
    4146
    4247/**
     
    4752@ExtendWith(BasicWiremock.OsmApiExtension.class)
    4853class LoadAndZoomHandlerTest {
    49     private static final String DEFAULT_BBOX_URL = "https://localhost/load_and_zoom?left=0&bottom=0&right=0.001&top=0.001";
    50     private static final String DEFAULT_BBOX_URL_2 = "https://localhost/load_and_zoom?left=0.00025&bottom=0.00025&right=0.00075&top=0.00125";
     54    private static final String DEFAULT_BBOX_URL = "http://localhost/load_and_zoom?left=0&bottom=0&right=0.001&top=0.001";
     55    private static final String DEFAULT_BBOX_URL_2 = "http://localhost/load_and_zoom?left=0.00025&bottom=0.00025&right=0.00075&top=0.00125";
    5156    private static LoadAndZoomHandler newHandler(String url) throws RequestHandlerBadRequestException {
    5257        LoadAndZoomHandler req = new LoadAndZoomHandler();
     
    237242    /**
    238243     * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/23821">#23821</a>
    239      * @throws RequestHandlerBadRequestException If there is an issue with the handler
    240      */
    241     @Test
    242     void testNonRegression23821() throws RequestHandlerBadRequestException {
     244     * @param wireMockRuntimeInfo The runtime info
     245     */
     246    @Test
     247    void testNonRegression23821(WireMockRuntimeInfo wireMockRuntimeInfo) throws IOException {
     248        // Start remote control on a random port to avoid failing when JOSM is open.
     249        final int port = wireMockRuntimeInfo.getHttpPort() + 1;
     250        Config.getPref().putInt("remote.control.port", port);
    243251        final AtomicBoolean block = new AtomicBoolean(false);
    244252        final Runnable runnable = () -> {
     
    257265        MainApplication.getLayerManager().addLayer(new OsmDataLayer(wrongDataset,
    258266                "LoadAndZoomHandlerTest#testNonRegression23821", null));
    259         ForkJoinTask<?> task1;
    260         ForkJoinTask<?> task2;
    261267        try {
    262             GuiHelper.runInEDT(runnable);
    263             MainApplication.worker.submit(runnable);
    264             // The processor makes a new handler for each request
    265             // It is single-threaded, so blocking on one handler would fix the problem with the other handler.
    266             // But we might as well work on multi-threading, since it is easier to test. :)
    267             final LoadAndZoomHandler handler1 = newHandler(DEFAULT_BBOX_URL + "&new_layer=true&layer_name=OSMData");
    268             final LoadAndZoomHandler handler2 = newHandler(DEFAULT_BBOX_URL_2 + "&new_layer=false&layer_name=OSMData");
    269             // Use a separate threads to avoid blocking on this thread
    270             final ForkJoinPool pool = ForkJoinPool.commonPool();
    271             task1 = pool.submit(() -> assertDoesNotThrow(handler1::handle));
    272 
    273             // Make certain there is enough time for the first task to block
    274             Awaitility.await().until(() -> true);
    275             task2 = pool.submit(() -> assertDoesNotThrow(handler2::handle));
     268            ForkJoinTask<?> task1;
     269            ForkJoinTask<?> task2;
     270            try {
     271                GuiHelper.runInEDT(runnable);
     272                MainApplication.worker.submit(runnable);
     273                // The processor makes a new handler for each request
     274                // It is single-threaded, so blocking on one handler would fix the problem with the other handler.
     275                // But we might as well work on multi-threading, since it is easier to test. :)
     276                final HttpClient first = HttpClient.create(URI.create(DEFAULT_BBOX_URL.replace("localhost", "localhost:" + port)
     277                        + "&new_layer=true&layer_name=OSMData").toURL());
     278                final HttpClient second = HttpClient.create(URI.create(DEFAULT_BBOX_URL_2.replace("localhost", "localhost:" + port)
     279                        + "&new_layer=false&layer_name=OSMData").toURL());
     280                // Use a separate threads to avoid blocking on this thread.
     281                final ForkJoinPool pool = ForkJoinPool.commonPool();
     282                RemoteControl.start();
     283                task1 = pool.submit(() -> assertDoesNotThrow(() -> {
     284                    try {
     285                        assertEquals("OK\r\n", first.connect().fetchContent());
     286                    } finally {
     287                        first.disconnect();
     288                    }
     289                }));
     290                // Make certain there is enough time for the first task to block
     291                Awaitility.await().until(() -> true);
     292                task2 = pool.submit(() -> assertDoesNotThrow(() -> {
     293                    try {
     294                        assertEquals("OK\r\n", second.connect().fetchContent());
     295                    } finally {
     296                        second.disconnect();
     297                    }
     298                }));
     299            } finally {
     300                // Unblock UI/worker threads
     301                synchronized (block) {
     302                    block.set(true);
     303                    block.notifyAll();
     304                }
     305            }
     306
     307            task1.join();
     308            task2.join();
     309
     310            syncThreads();
    276311        } finally {
    277             // Unblock UI/worker threads
    278             synchronized (block) {
    279                 block.set(true);
    280                 block.notifyAll();
    281             }
     312            // We have to stop remote control _after_ we join the tasks and sync threads.
     313            RemoteControl.stop();
    282314        }
    283 
    284         task1.join();
    285         task2.join();
    286 
    287         syncThreads();
    288315        assertEquals(2, MainApplication.getLayerManager().getLayers().size());
    289316        final DataSet ds = MainApplication.getLayerManager().getEditDataSet();
Note: See TracChangeset for help on using the changeset viewer.