From 5ce0a708f31b3c19d8f332bbcada4655fd0518f1 Mon Sep 17 00:00:00 2001
From: Robert Scott <code@humanleg.org.uk>
Date: Sat, 2 Jun 2018 23:09:22 +0100
Subject: [PATCH v2 26/28] TestUtils: add syncEDTAndWorkerThreads

---
 test/unit/org/openstreetmap/josm/TestUtils.java | 32 +++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/test/unit/org/openstreetmap/josm/TestUtils.java b/test/unit/org/openstreetmap/josm/TestUtils.java
index 53e995a30..1817db0f8 100644
--- a/test/unit/org/openstreetmap/josm/TestUtils.java
+++ b/test/unit/org/openstreetmap/josm/TestUtils.java
@@ -25,6 +25,8 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.stream.Stream;
 
 import org.junit.Assume;
@@ -36,10 +38,12 @@ import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.progress.AbstractProgressMonitor;
 import org.openstreetmap.josm.gui.progress.CancelHandler;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressTaskId;
+import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.Compression;
 import org.openstreetmap.josm.testutils.FakeGraphics;
 import org.openstreetmap.josm.tools.JosmRuntimeException;
@@ -458,4 +462,32 @@ public final class TestUtils {
             fail(e.toString());
         }
     }
+
+    /**
+     * Waits until any asynchronous operations launched by the test on the EDT or worker threads have
+     * (almost certainly) completed.
+     */
+    public static void syncEDTAndWorkerThreads() {
+        boolean workerQueueEmpty = false;
+        while (!workerQueueEmpty) {
+            try {
+                // once our own task(s) have made it to the front of their respective queue(s),
+                // they're both executing at the same time and we know there aren't any outstanding
+                // worker tasks, then presumably the only way there could be incomplete operations
+                // is if the EDT had launched a deferred task to run on itself or perhaps set up a
+                // swing timer - neither are particularly common patterns in JOSM (?)
+                //
+                // there shouldn't be a risk of creating a deadlock in doing this as there shouldn't
+                // (...couldn't?) be EDT operations waiting on the results of a worker task.
+                workerQueueEmpty = MainApplication.worker.submit(
+                    () -> GuiHelper.runInEDTAndWaitAndReturn(
+                        () -> ((ThreadPoolExecutor) MainApplication.worker).getQueue().isEmpty()
+                    )
+                ).get();
+            } catch (InterruptedException | ExecutionException e) {
+                // inconclusive - retry...
+                workerQueueEmpty = false;
+            }
+        }
+    }
 }
-- 
2.11.0

