You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2023/06/21 21:45:11 UTC

[qpid-protonj2] branch main updated: PROTON-2739 Add API in performative expectations for capture and test

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

tabish pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-protonj2.git


The following commit(s) were added to refs/heads/main by this push:
     new a8aa6af2 PROTON-2739 Add API in performative expectations for capture and test
a8aa6af2 is described below

commit a8aa6af2b91c69553ccfabe0eb7f131e64f54f4b
Author: Timothy Bish <ta...@gmail.com>
AuthorDate: Wed Jun 21 17:44:57 2023 -0400

    PROTON-2739 Add API in performative expectations for capture and test
    
    Allow for user supplied Predicate types to provide custom validation
    Allow for user supplied Consumer types to capture incoming performatives
    in tests that want to see the payload to gather data such as dynamic
    node assigned addresses.
---
 .../driver/expectations/AbstractExpectation.java   | 64 +++++++++++++++++++++-
 .../driver/expectations/AttachExpectation.java     | 14 +++++
 .../test/driver/expectations/BeginExpectation.java | 14 +++++
 .../test/driver/expectations/CloseExpectation.java | 14 +++++
 .../driver/expectations/DetachExpectation.java     | 14 +++++
 .../expectations/DispositionExpectation.java       | 14 +++++
 .../test/driver/expectations/EndExpectation.java   | 14 +++++
 .../test/driver/expectations/FlowExpectation.java  | 14 +++++
 .../test/driver/expectations/OpenExpectation.java  | 14 +++++
 .../expectations/SaslChallengeExpectation.java     | 15 +++++
 .../driver/expectations/SaslInitExpectation.java   | 15 +++++
 .../expectations/SaslMechanismsExpectation.java    | 15 +++++
 .../expectations/SaslOutcomeExpectation.java       | 15 +++++
 .../expectations/SaslResponseExpectation.java      | 15 +++++
 .../driver/expectations/TransferExpectation.java   | 14 +++++
 .../protonj2/test/driver/ProtonTestClientTest.java | 41 +++++++++++++-
 16 files changed, 302 insertions(+), 4 deletions(-)

diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/AbstractExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/AbstractExpectation.java
index 38cd7e8b..915e9842 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/AbstractExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/AbstractExpectation.java
@@ -19,6 +19,8 @@ package org.apache.qpid.protonj2.test.driver.expectations;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import java.nio.ByteBuffer;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.ScriptedExpectation;
@@ -57,12 +59,15 @@ public abstract class AbstractExpectation<T extends ListDescribedType> implement
 
     public static int ANY_CHANNEL = -1;
 
-    protected int expectedChannel = ANY_CHANNEL;
     protected final AMQPTestDriver driver;
 
+    protected int expectedChannel = ANY_CHANNEL;
     private UnsignedInteger frameSize;
     private boolean optional;
 
+    private Predicate<T> verificationPredicate;
+    private Consumer<T> performativeCapture;
+
     public AbstractExpectation(AMQPTestDriver driver) {
         this.driver = driver;
     }
@@ -99,9 +104,42 @@ public abstract class AbstractExpectation<T extends ListDescribedType> implement
      *
      * @param frameSize
      * 		The expected size of the enclosing frame that carries the incoming data.
+     *
+     * @return this expectation instance.
      */
-    public void withFrameSize(int frameSize) {
+    public AbstractExpectation<T> withFrameSize(int frameSize) {
         this.frameSize = new UnsignedInteger(frameSize);
+        return this;
+    }
+
+    /**
+     * Allows a test to supply a {@link Predicate} that will be allowed to further test an
+     * incoming performative if all other tests verifications pass. If the predicate call
+     * throws any exceptions the verification process is failed.
+     *
+     * @param predicate
+     * 		The user supplied {@link Predicate} that will be called as a last stage verification.
+     *
+     * @return this expectation instance.
+     */
+    public AbstractExpectation<T> withPredicate(Predicate<T> predicate) {
+        this.verificationPredicate = predicate;
+        return this;
+    }
+
+    /**
+     * Allows the test to provide a capture {@link Consumer} that will be called to allow
+     * the test to capture the incoming performative instance for use in testing. Any errors
+     * that are thrown from the provided capture are ignored.
+     *
+     * @param capture
+     * 		The user supplied {@link Consumer} that will be provided the performative if verified.
+     *
+     * @return this expectation instance.
+     */
+    public AbstractExpectation<T> withCapture(Consumer<T> capture) {
+        this.performativeCapture = capture;
+        return this;
     }
 
     //------ Abstract classes use these methods to control validation
@@ -239,12 +277,34 @@ public abstract class AbstractExpectation<T extends ListDescribedType> implement
 
     //----- Internal implementation
 
+    @SuppressWarnings("unchecked")
     private void doVerification(int frameSize, Object performative, ByteBuffer payload, int channel, AMQPTestDriver driver) {
         if (getExpectedTypeClass().equals(performative.getClass())) {
             verifyFrameSize(frameSize);
             verifyPayload(payload);
             verifyChannel(channel);
             verifyPerformative(getExpectedTypeClass().cast(performative));
+
+            if (verificationPredicate != null) {
+                try {
+                    if (!verificationPredicate.test((T) performative)) {
+                        throw new AssertionError("Failed to pass user supplied performative verification predicate");
+                    }
+                } catch (AssertionError e) {
+                    throw e;
+                } catch (Throwable t) {
+                    throw new AssertionError("Performative should not have been sent with a payload: ");
+                }
+            }
+
+            if (performativeCapture != null) {
+                try {
+                    performativeCapture.accept((T) performative);
+                } catch (Exception e) {
+                    // Ignored
+                }
+            }
+
         } else {
             reportTypeExpectationError(performative, getExpectedTypeClass());
         }
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/AttachExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/AttachExpectation.java
index da77ea75..3b66894e 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/AttachExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/AttachExpectation.java
@@ -26,6 +26,8 @@ import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.UUID;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.LinkTracker;
@@ -83,6 +85,18 @@ public class AttachExpectation extends AbstractExpectation<Attach> {
         return this;
     }
 
+    @Override
+    public AttachExpectation withPredicate(Predicate<Attach> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public AttachExpectation withCapture(Consumer<Attach> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     /**
      * Creates a sufficient response for a simple {@link Attach} request for
      * simple test scripts. This response does not offer capabilities to the
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/BeginExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/BeginExpectation.java
index 3f7e4500..1521527e 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/BeginExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/BeginExpectation.java
@@ -24,6 +24,8 @@ import static org.hamcrest.collection.ArrayMatching.hasItemInArray;
 
 import java.nio.ByteBuffer;
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.actions.BeginInjectAction;
@@ -56,6 +58,18 @@ public class BeginExpectation extends AbstractExpectation<Begin> {
         withOutgoingWindow(notNullValue());
     }
 
+    @Override
+    public BeginExpectation withPredicate(Predicate<Begin> predicate) {
+        withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public BeginExpectation withCapture(Consumer<Begin> capture) {
+        withCapture(capture);
+        return this;
+    }
+
     @Override
     public BeginExpectation onChannel(int channel) {
         super.onChannel(channel);
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/CloseExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/CloseExpectation.java
index 9014ae59..1d53cd78 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/CloseExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/CloseExpectation.java
@@ -20,6 +20,8 @@ import static org.hamcrest.CoreMatchers.equalTo;
 
 import java.nio.ByteBuffer;
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.actions.BeginInjectAction;
@@ -51,6 +53,18 @@ public class CloseExpectation extends AbstractExpectation<Close> {
         return response;
     }
 
+    @Override
+    public CloseExpectation withPredicate(Predicate<Close> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public CloseExpectation withCapture(Consumer<Close> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     //----- Handle the performative and configure response is told to respond
 
     @Override
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/DetachExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/DetachExpectation.java
index 7eac73df..7f6bbd89 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/DetachExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/DetachExpectation.java
@@ -21,6 +21,8 @@ import static org.hamcrest.CoreMatchers.notNullValue;
 
 import java.nio.ByteBuffer;
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.LinkTracker;
@@ -65,6 +67,18 @@ public class DetachExpectation extends AbstractExpectation<Detach> {
         return response;
     }
 
+    @Override
+    public DetachExpectation withPredicate(Predicate<Detach> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public DetachExpectation withCapture(Consumer<Detach> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     //----- Handle the performative and configure response is told to respond
 
     @Override
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/DispositionExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/DispositionExpectation.java
index 994de96f..1e9b5936 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/DispositionExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/DispositionExpectation.java
@@ -21,6 +21,8 @@ import static org.hamcrest.CoreMatchers.notNullValue;
 
 import java.nio.ByteBuffer;
 import java.util.Random;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.SessionTracker;
@@ -64,6 +66,18 @@ public class DispositionExpectation extends AbstractExpectation<Disposition> {
         return this;
     }
 
+    @Override
+    public DispositionExpectation withPredicate(Predicate<Disposition> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public DispositionExpectation withCapture(Consumer<Disposition> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     //----- Handle the incoming Disposition validation and update local side if able
 
     @Override
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/EndExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/EndExpectation.java
index 891c5dcc..76f817c4 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/EndExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/EndExpectation.java
@@ -20,6 +20,8 @@ import static org.hamcrest.CoreMatchers.equalTo;
 
 import java.nio.ByteBuffer;
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.SessionTracker;
@@ -59,6 +61,18 @@ public class EndExpectation extends AbstractExpectation<End> {
         return response;
     }
 
+    @Override
+    public EndExpectation withPredicate(Predicate<End> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public EndExpectation withCapture(Consumer<End> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     //----- Handle the performative and configure response is told to respond
 
     @Override
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/FlowExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/FlowExpectation.java
index a68e7546..3a2cb410 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/FlowExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/FlowExpectation.java
@@ -23,6 +23,8 @@ import static org.hamcrest.CoreMatchers.nullValue;
 
 import java.nio.ByteBuffer;
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.LinkTracker;
@@ -67,6 +69,18 @@ public class FlowExpectation extends AbstractExpectation<Flow> {
         return response;
     }
 
+    @Override
+    public FlowExpectation withPredicate(Predicate<Flow> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public FlowExpectation withCapture(Consumer<Flow> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     //----- Handle the performative and configure response is told to respond
 
     @Override
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/OpenExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/OpenExpectation.java
index 87275b55..e3e446f9 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/OpenExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/OpenExpectation.java
@@ -23,6 +23,8 @@ import static org.hamcrest.collection.ArrayMatching.hasItemInArray;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.actions.BeginInjectAction;
@@ -57,6 +59,18 @@ public class OpenExpectation extends AbstractExpectation<Open> {
         onChannel(0);  // Open must used channel zero.
     }
 
+    @Override
+    public OpenExpectation withPredicate(Predicate<Open> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public OpenExpectation withCapture(Consumer<Open> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     /**
      * Creates a sufficient response for a simple {@link Open} request for
      * simple test scripts. This response does not offer capabilities to the
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslChallengeExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslChallengeExpectation.java
index ef8815f4..81b09579 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslChallengeExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslChallengeExpectation.java
@@ -18,6 +18,9 @@ package org.apache.qpid.protonj2.test.driver.expectations;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.actions.SaslResponseInjectAction;
 import org.apache.qpid.protonj2.test.driver.codec.ListDescribedType;
@@ -37,6 +40,18 @@ public class SaslChallengeExpectation extends AbstractExpectation<SaslChallenge>
         super(driver);
     }
 
+    @Override
+    public SaslChallengeExpectation withPredicate(Predicate<SaslChallenge> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public SaslChallengeExpectation withCapture(Consumer<SaslChallenge> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     public SaslResponseInjectAction respond() {
         SaslResponseInjectAction response = new SaslResponseInjectAction(driver);
         driver.addScriptedElement(response);
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslInitExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslInitExpectation.java
index 41422d8e..8a1b3fef 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslInitExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslInitExpectation.java
@@ -18,6 +18,9 @@ package org.apache.qpid.protonj2.test.driver.expectations;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.codec.ListDescribedType;
 import org.apache.qpid.protonj2.test.driver.codec.primitives.Binary;
@@ -37,6 +40,18 @@ public class SaslInitExpectation extends AbstractExpectation<SaslInit> {
         super(driver);
     }
 
+    @Override
+    public SaslInitExpectation withPredicate(Predicate<SaslInit> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public SaslInitExpectation withCapture(Consumer<SaslInit> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     //----- Type specific with methods that perform simple equals checks
 
     public SaslInitExpectation withMechanism(String mechanism) {
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslMechanismsExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslMechanismsExpectation.java
index 5848d549..e8f2903e 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslMechanismsExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslMechanismsExpectation.java
@@ -19,6 +19,9 @@ package org.apache.qpid.protonj2.test.driver.expectations;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.collection.ArrayMatching.hasItemInArray;
 
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.codec.ListDescribedType;
 import org.apache.qpid.protonj2.test.driver.codec.primitives.Symbol;
@@ -38,6 +41,18 @@ public class SaslMechanismsExpectation extends AbstractExpectation<SaslMechanism
         super(driver);
     }
 
+    @Override
+    public SaslMechanismsExpectation withPredicate(Predicate<SaslMechanisms> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public SaslMechanismsExpectation withCapture(Consumer<SaslMechanisms> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     //----- Type specific with methods that perform simple equals checks
 
     public SaslMechanismsExpectation withSaslServerMechanisms(String... mechanisms) {
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslOutcomeExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslOutcomeExpectation.java
index eecf87e2..65ff2435 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslOutcomeExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslOutcomeExpectation.java
@@ -18,6 +18,9 @@ package org.apache.qpid.protonj2.test.driver.expectations;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.ScriptedAction;
 import org.apache.qpid.protonj2.test.driver.codec.ListDescribedType;
@@ -39,6 +42,18 @@ public class SaslOutcomeExpectation extends AbstractExpectation<SaslOutcome> {
         super(driver);
     }
 
+    @Override
+    public SaslOutcomeExpectation withPredicate(Predicate<SaslOutcome> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public SaslOutcomeExpectation withCapture(Consumer<SaslOutcome> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     @Override
     public ScriptedAction performAfterwards() {
         return new ScriptedAction() {
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslResponseExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslResponseExpectation.java
index d137ed2a..b801e671 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslResponseExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/SaslResponseExpectation.java
@@ -18,6 +18,9 @@ package org.apache.qpid.protonj2.test.driver.expectations;
 
 import static org.hamcrest.CoreMatchers.equalTo;
 
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.codec.ListDescribedType;
 import org.apache.qpid.protonj2.test.driver.codec.primitives.Binary;
@@ -36,6 +39,18 @@ public class SaslResponseExpectation extends AbstractExpectation<SaslResponse> {
         super(driver);
     }
 
+    @Override
+    public SaslResponseExpectation withPredicate(Predicate<SaslResponse> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public SaslResponseExpectation withCapture(Consumer<SaslResponse> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     //----- Type specific with methods that perform simple equals checks
 
     public SaslResponseExpectation withResponse(byte[] response) {
diff --git a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/TransferExpectation.java b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/TransferExpectation.java
index 6e8675b0..6476a2ac 100644
--- a/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/TransferExpectation.java
+++ b/protonj2-test-driver/src/main/java/org/apache/qpid/protonj2/test/driver/expectations/TransferExpectation.java
@@ -21,6 +21,8 @@ import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.CoreMatchers.nullValue;
 
 import java.nio.ByteBuffer;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 import org.apache.qpid.protonj2.test.driver.AMQPTestDriver;
 import org.apache.qpid.protonj2.test.driver.LinkTracker;
@@ -64,6 +66,18 @@ public class TransferExpectation extends AbstractExpectation<Transfer> {
         withHandle(notNullValue());
     }
 
+    @Override
+    public TransferExpectation withPredicate(Predicate<Transfer> predicate) {
+        super.withPredicate(predicate);
+        return this;
+    }
+
+    @Override
+    public TransferExpectation withCapture(Consumer<Transfer> capture) {
+        super.withCapture(capture);
+        return this;
+    }
+
     public DispositionInjectAction respond() {
         response = new DispositionInjectAction(driver);
         driver.addScriptedElement(response);
diff --git a/protonj2-test-driver/src/test/java/org/apache/qpid/protonj2/test/driver/ProtonTestClientTest.java b/protonj2-test-driver/src/test/java/org/apache/qpid/protonj2/test/driver/ProtonTestClientTest.java
index 42fcf83c..cdefff5f 100644
--- a/protonj2-test-driver/src/test/java/org/apache/qpid/protonj2/test/driver/ProtonTestClientTest.java
+++ b/protonj2-test-driver/src/test/java/org/apache/qpid/protonj2/test/driver/ProtonTestClientTest.java
@@ -16,13 +16,16 @@
  */
 package org.apache.qpid.protonj2.test.driver;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.net.URI;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.qpid.protonj2.test.driver.codec.security.SaslCode;
 import org.apache.qpid.protonj2.test.driver.codec.transport.AMQPHeader;
+import org.apache.qpid.protonj2.test.driver.codec.transport.Open;
 import org.apache.qpid.protonj2.test.driver.utils.TestPeerTestsBase;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
@@ -196,9 +199,11 @@ class ProtonTestClientTest extends TestPeerTestsBase {
 
     @Test
     public void testClientCanConnectAndOpenExchanged() throws Exception {
+        final AtomicReference<Open> capturedOpen = new AtomicReference<>();
+
         try (ProtonTestServer peer = new ProtonTestServer()) {
             peer.expectAMQPHeader().respondWithAMQPHeader();
-            peer.expectOpen().respond();
+            peer.expectOpen().withCapture((o) -> capturedOpen.set(o)).respond();
             peer.expectClose().respond();
             peer.start();
 
@@ -219,6 +224,38 @@ class ProtonTestClientTest extends TestPeerTestsBase {
             LOG.info("Test started, peer listening on: {}", remoteURI);
 
             peer.waitForScriptToComplete(5, TimeUnit.SECONDS);
+
+            assertNotNull(capturedOpen.get());
+        }
+    }
+
+    @Test
+    public void testClientCanConnectAndOpenExchangedAndFailWithUserPredicate() throws Exception {
+        try (ProtonTestServer peer = new ProtonTestServer()) {
+            peer.expectAMQPHeader().respondWithAMQPHeader();
+            peer.expectOpen().respond();
+            peer.expectClose().respond();
+            peer.start();
+
+            URI remoteURI = peer.getServerURI();
+
+            ProtonTestClient client = new ProtonTestClient();
+
+            client.connect(remoteURI.getHost(), remoteURI.getPort());
+            client.expectAMQPHeader();
+            client.expectOpen();
+            client.expectClose().withPredicate((o) -> false);
+            client.remoteHeader(AMQPHeader.getAMQPHeader()).now();
+            client.remoteOpen().now();
+            client.remoteClose().later(10);
+
+            assertThrows(AssertionError.class, () -> client.waitForScriptToComplete(5, TimeUnit.SECONDS));
+
+            client.close();
+
+            LOG.info("Test started, peer listening on: {}", remoteURI);
+
+            peer.waitForScriptToComplete(5, TimeUnit.SECONDS);
         }
     }
 
@@ -285,7 +322,7 @@ class ProtonTestClientTest extends TestPeerTestsBase {
 
             URI remoteURI = peer.getServerURI();
 
-            ProtonTestClient client = new ProtonTestClient();
+            final ProtonTestClient client = new ProtonTestClient();
 
             client.remoteSASLHeader().queue();
             client.expectSASLHeader();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org