-
Notifications
You must be signed in to change notification settings - Fork 48
test(incarnation-sapere): harden LsaNode concurrency test #5325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
d1a0b8d
0f13ed4
e7545e6
edee5ff
58f6cfc
22643a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,13 +18,16 @@ | |
| import it.unibo.alchemist.model.positions.Euclidean2DPosition; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.concurrent.CountDownLatch; | ||
| import java.util.concurrent.ExecutorService; | ||
| import java.util.concurrent.Executors; | ||
| import java.util.concurrent.ExecutionException; | ||
| import java.util.concurrent.Future; | ||
| import java.util.concurrent.TimeUnit; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
| import java.util.concurrent.TimeoutException; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
|
@@ -52,11 +55,11 @@ void testConcurrentGetContentsAndModification() throws InterruptedException { | |
| final int numberOfOperations = 100; | ||
| final ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads); | ||
| final CountDownLatch latch = new CountDownLatch(numberOfThreads); | ||
| final AtomicBoolean exceptionOccurred = new AtomicBoolean(false); | ||
| final List<Future<?>> tasks = new ArrayList<>(numberOfThreads); | ||
| // Start threads that modify the node while others read from it | ||
| for (int i = 0; i < numberOfThreads; i++) { | ||
| final int threadId = i; | ||
| executor.submit(() -> { | ||
| tasks.add(executor.submit(() -> { | ||
| try { | ||
| for (int j = 0; j < numberOfOperations; j++) { | ||
| if (threadId % 2 == 0) { | ||
|
|
@@ -69,7 +72,7 @@ void testConcurrentGetContentsAndModification() throws InterruptedException { | |
| assertNotNull(lsaSpace); | ||
| } else { | ||
| // Writer threads | ||
| final ILsaMolecule newMolecule = new LsaMolecule("thread" + threadId + "_" + j); | ||
| final ILsaMolecule newMolecule = new LsaMolecule("thread" + threadId + "x" + j); | ||
| node.setConcentration(newMolecule); | ||
| // Sometimes remove molecules to simulate real concurrent modification | ||
| if (j % 10 == 0 && node.getMoleculeCount() > MIN_MOLECULES) { | ||
|
|
@@ -81,19 +84,39 @@ void testConcurrentGetContentsAndModification() throws InterruptedException { | |
| } | ||
| } | ||
| } | ||
| } catch (final IllegalStateException | java.util.ConcurrentModificationException e) { | ||
| exceptionOccurred.set(true); | ||
| e.printStackTrace(); | ||
| } finally { | ||
| latch.countDown(); | ||
| } | ||
| }); | ||
| return null; | ||
| })); | ||
| } | ||
| // Wait for all threads to complete | ||
| assertTrue(latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS), "Test should complete within 30 seconds"); | ||
| executor.shutdown(); | ||
| // No exceptions should have occurred (especially no ConcurrentModificationException) | ||
| assertFalse(exceptionOccurred.get(), "No exceptions should occur during concurrent access"); | ||
| try { | ||
| assertTrue(latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS), "Test should complete within " + TIMEOUT_SECONDS + " seconds"); | ||
| for (final Future<?> task : tasks) { | ||
| try { | ||
| task.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); | ||
| } catch (final InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| throw new AssertionError("Test interrupted while waiting for task", e); | ||
| } catch (final ExecutionException e) { | ||
| throw new AssertionError("Task failed with exception", e.getCause()); | ||
| } catch (final TimeoutException e) { | ||
| task.cancel(true); | ||
| throw new AssertionError("Task timed out after " + TIMEOUT_SECONDS + " seconds", e); | ||
| } | ||
| } | ||
| } finally { | ||
| executor.shutdownNow(); | ||
| try { | ||
| if (!executor.awaitTermination(TIMEOUT_SECONDS, TimeUnit.SECONDS)) { | ||
| throw new AssertionError("Executor did not terminate within " + TIMEOUT_SECONDS + " seconds"); | ||
| } | ||
| } catch (final InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| throw new AssertionError("Interrupted while waiting for executor termination", e); | ||
| } | ||
|
Comment on lines
+109
to
+118
|
||
| } | ||
| // Verify the node is still in a valid state | ||
| final Map<Molecule, List<ILsaMolecule>> finalContents = node.getContents(); | ||
| assertNotNull(finalContents); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.