This is an automated email from the ASF dual-hosted git repository.

ifesdjeen pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/cassandra-simulator.git

commit 3f0abfbff5e8b4f15a90f94d357c65a4f216eac6
Author: Alex Petrov <[email protected]>
AuthorDate: Fri Jul 24 14:00:19 2026 +0000

    Use instrumented AQS for JDK CountDownLatch
---
 README.md                                          |  10 +-
 .../simulator_test/SchedulerIntegrationTest.java   |  19 +--
 .../org/apache/cassandra/simulator/Simulator.java  |  10 +-
 .../cassandra/simulator/step/ObservableAction.java |  24 ++++
 .../apache/cassandra/simulator/step/Session.java   |  22 +--
 .../simulator_test/CountDownLatchSimTest.java      | 160 +++++++++++++++------
 .../simulator_test/InstrumentedPrimitivesTest.java |  12 +-
 .../cassandra/simulator_test/ParkUnparkTest.java   |  25 ++--
 8 files changed, 187 insertions(+), 95 deletions(-)

diff --git a/README.md b/README.md
index 0b81abd..5201270 100644
--- a/README.md
+++ b/README.md
@@ -151,13 +151,17 @@ package matches the `GLOBAL_METHODS` or `MONITORS` 
patterns:
 |---|---|
 | `new Thread(...).start()` | 
`InterceptorOfGlobalMethods$Global.startThread()` — scheduled as a simulator 
action |
 
-### JDK synchronizers (constructor redirect)
+### JDK synchronizers and constructor redirects
 
-Constructors are rewritten at call sites so the simulator's subclass is 
instantiated instead:
+JDK synchronizers built on `AbstractQueuedSynchronizer`, including 
`CountDownLatch`, retain their
+JDK implementations. The agent instruments AQS calls to 
`LockSupport.park/unpark`, bringing their
+blocking and wakeup behavior under scheduler control. A caller can opt into a 
specialized latch
+with `sim.intercept(CountDownLatch.class, Replacement.class)`.
+
+The remaining default constructor redirects are:
 
 | Original | Simulator replacement |
 |---|---|
-| `new CountDownLatch(n)` | `InterceptingCountDownLatch` |
 | `new ConcurrentHashMap(...)` | `InterceptibleConcurrentHashMap` 
(deterministic hash codes) |
 | `new IdentityHashMap(...)` | `InterceptedIdentityHashMap` (deterministic 
hash codes) |
 
diff --git 
a/integration-test/src/test/java/org/apache/cassandra/simulator_test/SchedulerIntegrationTest.java
 
b/integration-test/src/test/java/org/apache/cassandra/simulator_test/SchedulerIntegrationTest.java
index 1295e2a..9de6588 100644
--- 
a/integration-test/src/test/java/org/apache/cassandra/simulator_test/SchedulerIntegrationTest.java
+++ 
b/integration-test/src/test/java/org/apache/cassandra/simulator_test/SchedulerIntegrationTest.java
@@ -47,8 +47,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
  * <ol>
  *   <li>A brand-new user-defined interface annotated with {@code @Intercept} 
can be registered
  *       and produces genuine scheduling points inside the simulator.
- *   <li>The built-in JDK {@code CountDownLatch} registration can be replaced 
with a custom
- *       implementation via {@link Simulator#intercept(Class, Class)}.
+ *   <li>A JDK {@code CountDownLatch} can be explicitly replaced with a custom 
implementation
+ *       via {@link Simulator#intercept(Class, Class)}.
  *   <li>A Cassandra factory-method interface can be overridden with a custom 
implementation.
  *   <li>The validator throws {@link IllegalArgumentException} when a custom 
implementation
  *       does not override every {@code @Intercept}-annotated instance method.
@@ -144,9 +144,8 @@ public class SchedulerIntegrationTest
     }
 
     // 
===========================================================================
-    // Custom JDK CountDownLatch replacement - overrides the built-in default 
so
-    // that the simulator uses MyJdkCountDownLatch instead of
-    // InterceptingCountDownLatch whenever simulation code calls new 
CountDownLatch(n).
+    // Custom JDK CountDownLatch replacement. JDK CountDownLatch uses 
instrumented
+    // AQS by default; this demonstrates opting into a specialized 
implementation.
     // 
===========================================================================
 
     @PerClassLoader
@@ -259,13 +258,13 @@ public class SchedulerIntegrationTest
     }
 
     // 
===========================================================================
-    // 2. JDK CountDownLatch override - replaces InterceptingCountDownLatch
-    //    with MyJdkCountDownLatch. The test verifies causal ordering to 
confirm
-    //    the custom class is functioning as a genuine scheduling point.
+    // 2. JDK CountDownLatch replacement - installs MyJdkCountDownLatch 
explicitly.
+    //    The test verifies causal ordering to confirm the custom class 
functions
+    //    as a genuine scheduling point.
     // 
===========================================================================
 
     @Test
-    void jdkCDLOverride_replacesDefaultAndPreservesScheduling()
+    void jdkCDLReplacement_installsCustomImplementationAndPreservesScheduling()
     {
         try (Simulator sim = new Simulator(42L, 1.0f))
         {
@@ -276,6 +275,8 @@ public class SchedulerIntegrationTest
                 // new CountDownLatch(1) is redirected to new 
MyJdkCountDownLatch(1)
                 var latch = new CountDownLatch(1);
                 var done  = cdl(2);
+                if (!(latch instanceof MyJdkCountDownLatch))
+                    throw new AssertionError("custom CountDownLatch 
replacement was not installed: " + latch.getClass());
 
                 new Thread(() -> {
                     log.add("A-before-await");
diff --git 
a/simulator-core/src/main/java/org/apache/cassandra/simulator/Simulator.java 
b/simulator-core/src/main/java/org/apache/cassandra/simulator/Simulator.java
index 2954e39..8787b9e 100644
--- a/simulator-core/src/main/java/org/apache/cassandra/simulator/Simulator.java
+++ b/simulator-core/src/main/java/org/apache/cassandra/simulator/Simulator.java
@@ -217,8 +217,6 @@ public class Simulator implements AutoCloseable
 
         // TODO: there are quite a few JDK primitives that are still not 
instrumented
         // Default JDK primitive redirects; can be overridden or supplemented 
by intercept() calls.
-        customRules.add(new 
InterceptRule.Constructor("java/util/concurrent/CountDownLatch",
-                                                      
"org/apache/cassandra/simulator/systems/InterceptingCountDownLatch"));
         customRules.add(new 
InterceptRule.Constructor("java/util/IdentityHashMap",
                                                       
"org/apache/cassandra/simulator/systems/InterceptedIdentityHashMap"));
         customRules.add(new 
InterceptRule.Constructor("java/util/concurrent/ConcurrentHashMap",
@@ -484,7 +482,7 @@ public class Simulator implements AutoCloseable
      * <p>Inside the bodies, standard Java concurrency primitives are 
transparently
      * intercepted by the ASM transformer:
      * <ul>
-     *   <li>{@code new CountDownLatch(n)} -> simulator-controlled latch</li>
+     *   <li>{@code CountDownLatch.await/countDown} -> scheduler-controlled 
through instrumented AQS</li>
      *   <li>{@code thread.start()} -> scheduler-controlled thread start</li>
      *   <li>{@code synchronized} blocks -> simulator-controlled monitor 
acquire/release</li>
      *   <li>{@code LockSupport.park/unpark} -> scheduler-controlled 
park/unpark</li>
@@ -607,17 +605,17 @@ public class Simulator implements AutoCloseable
         }
 
         @Override
-        public boolean stepUntil(Predicate<ObservableAction> predicate)
+        public Optional<ObservableAction> 
stepUntil(Predicate<ObservableAction> predicate)
         {
             while (step())
             {
                 for (ObservableAction action : drainObservedActions())
                 {
                     if (predicate.test(action))
-                        return true;
+                        return Optional.of(action);
                 }
             }
-            return false;
+            return Optional.empty();
         }
 
         @Override
diff --git 
a/simulator-core/src/main/java/org/apache/cassandra/simulator/step/ObservableAction.java
 
b/simulator-core/src/main/java/org/apache/cassandra/simulator/step/ObservableAction.java
index ad5f0c7..f9f8330 100644
--- 
a/simulator-core/src/main/java/org/apache/cassandra/simulator/step/ObservableAction.java
+++ 
b/simulator-core/src/main/java/org/apache/cassandra/simulator/step/ObservableAction.java
@@ -19,6 +19,8 @@
 package org.apache.cassandra.simulator.step;
 
 import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
 
 import javax.annotation.Nullable;
 
@@ -52,6 +54,28 @@ public interface ObservableAction
         CUSTOM
     }
 
+    /** Match actions of the supplied kind emitted by a thread whose name 
contains the fragment. */
+    static Predicate<ObservableAction> matcher(String threadNameFragment, Kind 
kind)
+    {
+        Objects.requireNonNull(threadNameFragment, "threadNameFragment");
+        Objects.requireNonNull(kind, "kind");
+        return action -> action.kind() == kind && 
action.threadName().contains(threadNameFragment);
+    }
+
+    /** Match actions targeting the thread that emitted the supplied action. */
+    static Predicate<ObservableAction> targetMatcher(ObservableAction 
targetThread)
+    {
+        long targetThreadId = Objects.requireNonNull(targetThread, 
"targetThread").threadId();
+        return action -> action.targetThreadId() != null && 
action.targetThreadId() == targetThreadId;
+    }
+
+    /** Match actions of the supplied kind targeting the thread that emitted 
the supplied action. */
+    static Predicate<ObservableAction> targetMatcher(ObservableAction 
targetThread, Kind kind)
+    {
+        Objects.requireNonNull(kind, "kind");
+        return targetMatcher(targetThread).and(action -> action.kind() == 
kind);
+    }
+
     /** Sequence number within the session, starting at zero. */
     long sequence();
 
diff --git 
a/simulator-core/src/main/java/org/apache/cassandra/simulator/step/Session.java 
b/simulator-core/src/main/java/org/apache/cassandra/simulator/step/Session.java
index 48d918e..6c630b3 100644
--- 
a/simulator-core/src/main/java/org/apache/cassandra/simulator/step/Session.java
+++ 
b/simulator-core/src/main/java/org/apache/cassandra/simulator/step/Session.java
@@ -63,9 +63,9 @@ public interface Session extends AutoCloseable {
      * Step until a captured action matches the supplied predicate.
      * Debug capture must be enabled before calling this method.
      *
-     * @return true on a match, or false if the schedule was exhausted first
+     * @return the matched action, or empty if the schedule was exhausted first
      */
-    boolean stepUntil(Predicate<ObservableAction> predicate);
+    Optional<ObservableAction> stepUntil(Predicate<ObservableAction> 
predicate);
 
     /**
      * Step until an action of the supplied kind is captured.
@@ -75,27 +75,13 @@ public interface Session extends AutoCloseable {
      */
     default Optional<ObservableAction> stepUntil(ObservableAction.Kind kind)
     {
-        ObservableAction[] matched = new ObservableAction[1];
-        boolean found = stepUntil(action -> {
-            if (action.kind() != kind)
-                return false;
-            matched[0] = action;
-            return true;
-        });
-        return found ? Optional.of(matched[0]) : Optional.empty();
+        return stepUntil(action -> action.kind() == kind);
     }
 
     /** Step until a custom action with the supplied stable name is captured. 
*/
     default Optional<ObservableAction> stepUntil(String name)
     {
-        ObservableAction[] matched = new ObservableAction[1];
-        boolean found = stepUntil(action -> {
-            if (action.kind() != ObservableAction.Kind.CUSTOM || 
!name.equals(action.name()))
-                return false;
-            matched[0] = action;
-            return true;
-        });
-        return found ? Optional.of(matched[0]) : Optional.empty();
+        return stepUntil(action -> action.kind() == 
ObservableAction.Kind.CUSTOM && name.equals(action.name()));
     }
 
     /**
diff --git 
a/simulator-core/src/test/java/org/apache/cassandra/simulator_test/CountDownLatchSimTest.java
 
b/simulator-core/src/test/java/org/apache/cassandra/simulator_test/CountDownLatchSimTest.java
index 0444d38..328b2ac 100644
--- 
a/simulator-core/src/test/java/org/apache/cassandra/simulator_test/CountDownLatchSimTest.java
+++ 
b/simulator-core/src/test/java/org/apache/cassandra/simulator_test/CountDownLatchSimTest.java
@@ -20,60 +20,134 @@ package org.apache.cassandra.simulator_test;
 
 import java.util.concurrent.CountDownLatch;
 
-import org.apache.cassandra.simulator.Simulator;
-import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import org.apache.cassandra.simulator.Simulator;
 import 
org.apache.cassandra.simulator.context.IIsolatedExecutor.SerializableRunnable;
+import org.apache.cassandra.simulator.context.SharedTestState;
+import org.apache.cassandra.simulator.step.ObservableAction;
+import org.apache.cassandra.simulator.step.Session;
+import org.apache.cassandra.simulator.systems.InterceptingCountDownLatch;
 
+import static 
org.apache.cassandra.simulator.step.ObservableAction.Kind.LATCH_AWAIT_CAPTURED;
+import static 
org.apache.cassandra.simulator.step.ObservableAction.Kind.LATCH_COUNTDOWN_CAPTURED;
+import static 
org.apache.cassandra.simulator.step.ObservableAction.Kind.PARK_CAPTURED;
+import static 
org.apache.cassandra.simulator.step.ObservableAction.Kind.UNPARK_CAPTURED;
+import static 
org.apache.cassandra.simulator.step.ObservableAction.Kind.WAKEUP_FIRED;
+import static org.apache.cassandra.simulator.step.ObservableAction.matcher;
+import static 
org.apache.cassandra.simulator.step.ObservableAction.targetMatcher;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * Verifies that JDK {@link CountDownLatch} is instrumented.
+ * Verifies both supported JDK {@link CountDownLatch} paths: explicit 
constructor
+ * replacement and the unmodified JDK implementation running through 
instrumented AQS.
  */
 public class CountDownLatchSimTest
 {
     @Test
-    void countDownLatchWakesWaiter()
+    void countDownLatchCanBeExplicitlyReplaced()
+    {
+        try (Simulator sim = new Simulator(42L))
+        {
+            sim.intercept(CountDownLatch.class, 
InterceptingCountDownLatch.class);
+            try (Session session = sim.byStep((SerializableRunnable) () -> {
+                CountDownLatch latch = new CountDownLatch(1);
+                CountDownLatch done = new CountDownLatch(1);
+                boolean[] waiterRan = { false };
+
+                assertTrue(latch instanceof InterceptingCountDownLatch,
+                           "the explicit constructor rule should install the 
requested replacement");
+
+                new Thread(() -> {
+                    try
+                    {
+                        latch.await();
+                    }
+                    catch (InterruptedException e)
+                    {
+                        Thread.currentThread().interrupt();
+                        return;
+                    }
+                    waiterRan[0] = true;
+                    done.countDown();
+                }, "waiter").start();
+
+                new Thread(latch::countDown, "decrementer").start();
+
+                try
+                {
+                    done.await();
+                }
+                catch (InterruptedException e)
+                {
+                    Thread.currentThread().interrupt();
+                }
+
+                assertTrue(waiterRan[0], "the replacement should wake the 
waiter");
+            }).enableDebug())
+            {
+                ObservableAction await = session.stepUntil(matcher("waiter", 
LATCH_AWAIT_CAPTURED))
+                                                .orElseThrow(() -> new 
AssertionError("the replacement should expose its await operation"));
+                assertEquals("1", await.detail());
+
+                ObservableAction countDown = 
session.stepUntil(matcher("decrementer", LATCH_COUNTDOWN_CAPTURED))
+                                                    .orElseThrow(() -> new 
AssertionError("the replacement should expose its countDown operation"));
+                assertEquals("1", countDown.detail());
+                assertTrue(await.sequence() < countDown.sequence());
+
+                session.runToEnd();
+            }
+        }
+    }
+
+    @Test
+    void jdkCountDownLatchBlocksThroughInstrumentedAqs()
     {
-        int steps = Simulator.simulate(42L, (SerializableRunnable) () -> {
-            CountDownLatch latch = new CountDownLatch(1);
-            CountDownLatch done  = new CountDownLatch(1);
-            boolean[] waiterRan  = { false };
-
-            new Thread(() -> {
-                try { latch.await(); }
-                catch (InterruptedException e) { 
Thread.currentThread().interrupt(); return; }
-                waiterRan[0] = true;
-                done.countDown();
-            }, "waiter").start();
-
-            new Thread(latch::countDown, "decrementer").start();
-
-            try { done.await(); }
-            catch (InterruptedException e) { 
Thread.currentThread().interrupt(); }
-
-            assertTrue(waiterRan[0], "waiter should have been woken by 
countDown() and completed");
-        });
-        // The step count is deterministic because buildSchedule() uses 
RunnableActionScheduler.Sequential,
-        // so actions are dequeued FIFO: waiter.start() is called before 
decrementer.start(), so the
-        // waiter always parks on the latch before the decrementer runs. With 
a random scheduler the
-        // decrementer could run first, the latch would already be 0 when the 
waiter called await(),
-        // and the whole thing would complete in 4 steps instead of 5.
-        Assertions.assertEquals(5, steps);
-        // Execution contains exactly 5 steps:
-        // * main thread starts and parks on done.await()
-        //    - [t]Thread[thread-0]
-        //    (its consequences: invoke waiter thread, invoke decrementer 
thread;
-        //     the thread itself suspends on done.await() — UNBOUNDED_WAIT 
adds no scheduled action,
-        //     so main will be woken later by a direct interceptWakeup from 
done.countDown())
-        // * waiter thread starts and parks on latch.await()
-        //    - [t]Invoke Thread[waiter,5,sim-896126964341291] with 
Thread[sim-896126964341291_waiter:1,5,sim-896126964341291]
-        // * decrementer thread starts, calls latch.countDown() (signals 
waiter), and exits
-        //    - [t]Invoke Thread[decrementer,5,sim-896126964341291] with 
Thread[sim-896126964341291_decrementer:1,5,sim-896126964341291]
-        // * waiter resumes, sets waiterRan, calls done.countDown() (signals 
main), and exits
-        //    - [tw]Wakeup 
Thread[sim-896126964341291_waiter:1,5,sim-896126964341291] 
parkedAt[org.apache.cassandra.simulator_test.CountDownLatchSimTest.lambda$countDownLatchWakesWaiter$0(CountDownLatchSimTest.java:45)]
-        // * main thread resumes and asserts
-        //    - [tw]Wakeup 
Thread[sim-896126964341291_thread-0:1,5,sim-896126964341291] 
parkedAt[org.apache.cassandra.simulator_test.CountDownLatchSimTest.lambda$countDownLatchWakesWaiter$1f753cc0$1(CountDownLatchSimTest.java:53)]
+        SharedTestState.reset();
+        try (Simulator sim = new Simulator(42L);
+             Session session = sim.byStep((SerializableRunnable) () -> {
+                 CountDownLatch latch = new CountDownLatch(1);
+                 if (latch.getClass() != CountDownLatch.class)
+                     throw new AssertionError("JDK CountDownLatch was 
unexpectedly replaced by " + latch.getClass());
+
+                 new Thread(() -> {
+                     try
+                     {
+                         latch.await();
+                     }
+                     catch (InterruptedException e)
+                     {
+                         Thread.currentThread().interrupt();
+                         return;
+                     }
+                     SharedTestState.threadRan.incrementAndGet();
+                 }, "jdk-cdl-waiter").start();
+
+                 new Thread(latch::countDown, "jdk-cdl-decrementer").start();
+             }).enableDebug())
+        {
+            ObservableAction park = 
session.stepUntil(matcher("jdk-cdl-waiter", PARK_CAPTURED))
+                                           .orElseThrow(() -> new 
AssertionError("CountDownLatch.await() should park in AQS"));
+            assertTrue(park.stackTrace().stream()
+                           .anyMatch(frame -> 
frame.getClassName().equals("java.util.concurrent.locks.AbstractQueuedSynchronizer")),
+                       "the intercepted park should originate in AQS");
+            assertEquals(0, SharedTestState.threadRan.get(), "the waiter must 
remain suspended");
+
+            ObservableAction unpark = 
session.stepUntil(matcher("jdk-cdl-decrementer", UNPARK_CAPTURED))
+                                             .orElseThrow(() -> new 
AssertionError("CountDownLatch.countDown() should unpark through AQS"));
+            assertTrue(unpark.stackTrace().stream()
+                               .anyMatch(frame -> 
frame.getClassName().equals("java.util.concurrent.locks.AbstractQueuedSynchronizer")),
+                       "the intercepted unpark should originate in AQS");
+            assertTrue(park.sequence() < unpark.sequence());
+            assertEquals(0, SharedTestState.threadRan.get(), "the wakeup has 
not run yet");
+
+            ObservableAction wakeup = session.stepUntil(targetMatcher(park, 
WAKEUP_FIRED)).orElseThrow();
+            assertEquals(Long.valueOf(park.threadId()), 
wakeup.targetThreadId());
+            assertTrue(unpark.sequence() < wakeup.sequence());
+
+            session.runToEnd();
+            assertEquals(1, SharedTestState.threadRan.get(), "the waiter 
should resume after countDown()");
+        }
     }
 }
diff --git 
a/simulator-core/src/test/java/org/apache/cassandra/simulator_test/InstrumentedPrimitivesTest.java
 
b/simulator-core/src/test/java/org/apache/cassandra/simulator_test/InstrumentedPrimitivesTest.java
index 77da2a5..b9fa202 100644
--- 
a/simulator-core/src/test/java/org/apache/cassandra/simulator_test/InstrumentedPrimitivesTest.java
+++ 
b/simulator-core/src/test/java/org/apache/cassandra/simulator_test/InstrumentedPrimitivesTest.java
@@ -82,8 +82,8 @@ import org.junit.jupiter.api.Test;
  *   <li>{@link Object#wait()} -- via ASM to {@code 
InterceptorOfSystemMethods.Global.wait}</li>
  *   <li>{@link Object#notify()} -- via ASM to {@code 
InterceptorOfSystemMethods.Global.notify}</li>
  *   <li>{@link Object#notifyAll()} -- via ASM to {@code 
InterceptorOfSystemMethods.Global.notifyAll}</li>
- *   <li>JDK {@link java.util.concurrent.CountDownLatch} (constructor 
rewritten to
- *       {@link 
org.apache.cassandra.simulator.systems.InterceptingCountDownLatch})</li>
+ *   <li>JDK {@link java.util.concurrent.CountDownLatch} -- blocking 
controlled through
+ *       instrumented AQS {@code LockSupport.park/unpark} calls</li>
  *   <li>{@link LockSupport#park()} -- via ASM to {@code 
InterceptibleThread.park}</li>
  *   <li>{@link LockSupport#parkNanos(long)} -- same</li>
  *   <li>{@link Thread#sleep(long)} -- via ASM to {@code 
InterceptorOfSystemMethods.Global.sleep}</li>
@@ -100,7 +100,7 @@ public class InstrumentedPrimitivesTest
 {
     // ---- Helpers 
--------------------------------------------------------------
 
-    /** JDK CDL -- constructor is rewritten to InterceptingCountDownLatch by 
default. */
+    /** JDK CDL -- its AQS park/unpark path is controlled by the simulator 
agent. */
     private static CountDownLatch cdl(int n)
     {
         return new CountDownLatch(n);
@@ -290,9 +290,9 @@ public class InstrumentedPrimitivesTest
     }
 
     // 
===========================================================================
-    // 5. JDK CountDownLatch  (NEW + <init> rewritten to 
InterceptingCountDownLatch)
-    //    The JDK type is transparently replaced with a simulator-controlled 
subclass.
-    //    No sim.intercept() call needed -- default Constructor rule fires 
automatically.
+    // 5. JDK CountDownLatch
+    //    The JDK implementation is retained. Its AQS blocking path reaches the
+    //    agent-instrumented LockSupport.park/unpark calls.
     // 
===========================================================================
 
     @Test
diff --git 
a/simulator-core/src/test/java/org/apache/cassandra/simulator_test/ParkUnparkTest.java
 
b/simulator-core/src/test/java/org/apache/cassandra/simulator_test/ParkUnparkTest.java
index 51e8184..4dcaaca 100644
--- 
a/simulator-core/src/test/java/org/apache/cassandra/simulator_test/ParkUnparkTest.java
+++ 
b/simulator-core/src/test/java/org/apache/cassandra/simulator_test/ParkUnparkTest.java
@@ -33,6 +33,11 @@ import org.junit.jupiter.api.Test;
 import 
org.apache.cassandra.simulator.context.IIsolatedExecutor.SerializableRunnable;
 import org.apache.cassandra.simulator.context.Shared;
 
+import static 
org.apache.cassandra.simulator.step.ObservableAction.Kind.PARK_CAPTURED;
+import static 
org.apache.cassandra.simulator.step.ObservableAction.Kind.UNPARK_CAPTURED;
+import static 
org.apache.cassandra.simulator.step.ObservableAction.Kind.WAKEUP_FIRED;
+import static org.apache.cassandra.simulator.step.ObservableAction.matcher;
+import static 
org.apache.cassandra.simulator.step.ObservableAction.targetMatcher;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -136,16 +141,16 @@ public class ParkUnparkTest
             session.enableDebug();
             assertEquals(Set.of(), SharedState.events);
 
-            
assertTrue(session.stepUntil(ObservableAction.Kind.PARK_CAPTURED).isPresent());
+            ObservableAction park = session.stepUntil(matcher("parker", 
PARK_CAPTURED)).orElseThrow();
             assertEquals(Set.of("parking"), SharedState.events, "park() was 
captured and the parker is suspended");
 
-            
assertTrue(session.stepUntil(ObservableAction.Kind.UNPARK_CAPTURED).isPresent());
+            session.stepUntil(matcher("unparker", 
UNPARK_CAPTURED).and(targetMatcher(park))).orElseThrow();
             assertEquals(Set.of("parking"), SharedState.events, "unpark() was 
captured but its wakeup has not fired");
 
-            
assertTrue(session.stepUntil(ObservableAction.Kind.WAKEUP_FIRED).isPresent());
+            session.stepUntil(targetMatcher(park, WAKEUP_FIRED)).orElseThrow();
             assertEquals(Set.of("parking", "unparked"), SharedState.events, 
"the scheduled wakeup resumed the parker");
 
-            
assertFalse(session.stepUntil(ObservableAction.Kind.PARK_CAPTURED).isPresent());
+            session.runToEnd();
             assertFalse(session.hasNext());
         }
     }
@@ -183,15 +188,15 @@ public class ParkUnparkTest
         {
             session.enableDebug();
 
-            
assertTrue(session.stepUntil(ObservableAction.Kind.PARK_CAPTURED).isPresent());
-            assertEquals(ObservableAction.Kind.PARK_CAPTURED, 
session.lastAction().orElseThrow().kind());
+            ObservableAction park = session.stepUntil(matcher("parker", 
PARK_CAPTURED)).orElseThrow();
+            assertEquals(PARK_CAPTURED, park.kind());
 
-            
assertTrue(session.stepUntil(ObservableAction.Kind.UNPARK_CAPTURED).isPresent());
-            assertNotEquals(ObservableAction.Kind.WAKEUP_FIRED, 
session.lastAction().orElseThrow().kind(),
+            ObservableAction unpark = session.stepUntil(matcher("unparker", 
UNPARK_CAPTURED).and(targetMatcher(park))).orElseThrow();
+            assertNotEquals(WAKEUP_FIRED, unpark.kind(),
                             "capturing unpark should not collapse with wakeup 
delivery");
 
-            
assertTrue(session.stepUntil(ObservableAction.Kind.WAKEUP_FIRED).isPresent());
-            
assertFalse(session.stepUntil(ObservableAction.Kind.PARK_CAPTURED).isPresent());
+            session.stepUntil(targetMatcher(park, WAKEUP_FIRED)).orElseThrow();
+            session.runToEnd();
         }
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to