Bug 515941 - test for ExternalArchiveSourceContainer.dispose() behavior

Change-Id: I7b0b44d0df448b7951a7783fe98fe832568bfa3a
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/ExternalArchiveSourceContainerTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/ExternalArchiveSourceContainerTests.java
index 682c75f..746f545 100755
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/ExternalArchiveSourceContainerTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/ExternalArchiveSourceContainerTests.java
@@ -11,6 +11,10 @@
 package org.eclipse.jdt.debug.tests.sourcelookup;
 
 import java.io.File;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
@@ -151,4 +155,51 @@
 		storage = (ZipEntryStorage) objects[0];
 		assertEquals("Wrong file", "file-c.txt", storage.getName());
 	}
+
+	/**
+	 * Test for bug 515941 (ConcurrentModificationException on container dispose)
+	 */
+	public void testDisposed() throws Exception {
+		int threads = Math.min(Runtime.getRuntime().availableProcessors(), 4);
+		ExecutorService exec = Executors.newFixedThreadPool(threads);
+		AtomicReference<Throwable> err = new AtomicReference<>();
+		AtomicReference<ExternalArchiveSourceContainer> container = new AtomicReference<>();
+		AtomicReference<Boolean> stop = new AtomicReference<>(Boolean.FALSE);
+		CountDownLatch latch = new CountDownLatch(1);
+		for (int i = 0; i < threads; i++) {
+			exec.submit(() -> {
+				try {
+					latch.await();
+					while (!stop.get()) {
+						ExternalArchiveSourceContainer c = container.get();
+						if (c != null) {
+							c.dispose();
+						}
+					}
+				}
+				catch (Throwable e) {
+					err.set(e);
+				}
+			});
+		}
+		latch.countDown();
+		try {
+			for (int i = 0; i < 5_000; i++) {
+				ExternalArchiveSourceContainer cont = getContainer("testresources/source-test.zip", true, false);
+				try {
+					container.set(cont);
+					Thread.sleep(1);
+					cont.findSourceElements("one/two/Three.java");
+
+				}
+				finally {
+					cont.dispose();
+				}
+			}
+		}
+		finally {
+			stop.set(true);
+			exec.shutdownNow();
+		}
+	}
 }