From 6ac927f0ddf28e5f244aa43ca4eef778152dd2c5 Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Fri, 26 Jul 2024 14:41:38 -0300
Subject: [PATCH 1/9]  - using try-with-resources statement to initiate a
 FixConnection  - returning workCount and trySend result to improve debugging

---
 .../system_tests/MessageBasedAcceptorSystemTest.java | 12 +++++-------
 .../real_logic/artio/system_tests/OrderFactory.java  |  2 +-
 .../artio/system_tests/SlowConsumerTest.java         |  7 ++++---
 .../co/real_logic/artio/system_tests/TestSystem.java | 12 ++++++++----
 4 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/MessageBasedAcceptorSystemTest.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/MessageBasedAcceptorSystemTest.java
index b6c35b2d87..a652417deb 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/MessageBasedAcceptorSystemTest.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/MessageBasedAcceptorSystemTest.java
@@ -1146,12 +1146,10 @@ private void sendInvalidMessage(final FixConnection connection, final Encoder en
 
     private void logonThenLogout() throws IOException
     {
-        final FixConnection connection = FixConnection.initiate(port);
-
-        logon(connection);
-
-        connection.logoutAndAwaitReply();
-
-        connection.close();
+        try (FixConnection connection = FixConnection.initiate(port))
+        {
+            logon(connection);
+            connection.logoutAndAwaitReply();
+        }
     }
 }
diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/OrderFactory.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/OrderFactory.java
index 28938c5b80..d5402e4e22 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/OrderFactory.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/OrderFactory.java
@@ -27,7 +27,7 @@
 
 final class OrderFactory
 {
-    private static NewOrderSingleEncoder makeOrder()
+    public static NewOrderSingleEncoder makeOrder()
     {
         final NewOrderSingleEncoder newOrderSingle = new NewOrderSingleEncoder();
         final DecimalFloat price = new DecimalFloat(100);
diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SlowConsumerTest.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SlowConsumerTest.java
index 85a3151940..4aa6e4165d 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SlowConsumerTest.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SlowConsumerTest.java
@@ -25,6 +25,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
+
 import uk.co.real_logic.artio.Timing;
 import uk.co.real_logic.artio.builder.Encoder;
 import uk.co.real_logic.artio.builder.LogonEncoder;
@@ -173,16 +174,16 @@ private void sessionBecomesSlow()
         assertTrue(session.isSlowConsumer());
     }
 
-    private void sendMessage()
+    private long sendMessage()
     {
         if (sendMetadata)
         {
             metadata.putInt(0, session.lastSentMsgSeqNum() + 1);
-            session.trySend(testRequest, metadata, 0);
+            return session.trySend(testRequest, metadata, 0);
         }
         else
         {
-            session.trySend(testRequest);
+            return session.trySend(testRequest);
         }
     }
 
diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/TestSystem.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/TestSystem.java
index 81c9a75f13..c3742cb94b 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/TestSystem.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/TestSystem.java
@@ -80,15 +80,19 @@ public TestSystem awaitTimeoutInMs(final long awaitTimeoutInMs)
         return this;
     }
 
-    public void poll()
+    public int poll()
     {
+        int result = 0;
         if (scheduler != null)
         {
-            scheduler.invokeFramer();
-            scheduler.invokeFramer();
+            result = scheduler.invokeFramer();
+        }
+        for (final FixLibrary library : libraries)
+        {
+            result += library.poll(LIBRARY_LIMIT);
         }
-        libraries.forEach((library) -> library.poll(LIBRARY_LIMIT));
         operations.forEach(Runnable::run);
+        return result;
     }
 
     public void addOperation(final Runnable operation)

From 1e292ff66727127388b8ecca6ec8402b93a771fa Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Mon, 29 Jul 2024 07:38:31 -0300
Subject: [PATCH 2/9] applying retry in sendMessage: -
 SlowConsumerTest.sendMessage call is now protected against back pressure as
 it's now wrapped around a awaitSend call.

---
 .../artio/system_tests/SlowConsumerTest.java          | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SlowConsumerTest.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SlowConsumerTest.java
index 4aa6e4165d..36b7879404 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SlowConsumerTest.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SlowConsumerTest.java
@@ -149,7 +149,7 @@ public void shouldQuarantineThenDisconnectASlowConsumer() throws IOException
                     hasBecomeSlow = true;
                 }
 
-                sendMessage();
+                sendMessageWithRetry();
             }
 
             testSystem.poll();
@@ -174,6 +174,11 @@ private void sessionBecomesSlow()
         assertTrue(session.isSlowConsumer());
     }
 
+    private void sendMessageWithRetry()
+    {
+        testSystem.awaitSend(this::sendMessage);
+    }
+
     private long sendMessage()
     {
         if (sendMetadata)
@@ -207,7 +212,7 @@ public void shouldRestoreConnectionFromSlowGroupWhenItCatchesUp() throws IOExcep
             }
             while (bytesRead > 0);
 
-            sendMessage();
+            sendMessageWithRetry();
 
             testSystem.poll();
         }
@@ -260,7 +265,7 @@ private ConnectedSessionInfo sessionBecomesSlow(final MessageTimingCaptor messag
         {
             for (int i = 0; i < 10; i++)
             {
-                sendMessage();
+                sendMessageWithRetry();
             }
 
             testSystem.poll();

From 3f9004344892ddd9543e04d186bcface590a27a8 Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Tue, 3 Sep 2024 18:04:37 +0200
Subject: [PATCH 3/9] renaming library publications descriptions in log

---
 .../java/uk/co/real_logic/artio/library/LibraryTransport.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/artio-core/src/main/java/uk/co/real_logic/artio/library/LibraryTransport.java b/artio-core/src/main/java/uk/co/real_logic/artio/library/LibraryTransport.java
index 2d2a564974..c8fe1e0245 100644
--- a/artio-core/src/main/java/uk/co/real_logic/artio/library/LibraryTransport.java
+++ b/artio-core/src/main/java/uk/co/real_logic/artio/library/LibraryTransport.java
@@ -30,7 +30,7 @@
 
 class LibraryTransport
 {
-    private static final String OUTBOUND_PUBLICATION = "outboundPublication";
+    private static final String OUTBOUND_PUBLICATION = "library outboundPublication";
 
     private final LibraryConfiguration configuration;
     private final FixCounters fixCounters;
@@ -87,7 +87,7 @@ void initStreams(final String aeronChannel)
             idleStrategy, outboundDataPublication(aeronChannel));
 
         final ExclusivePublication publication = aeron.addExclusivePublication(aeronChannel, inboundLibraryStream);
-        StreamInformation.print("inboundPublication", publication, printAeronStreamIdentifiers);
+        StreamInformation.print("library inboundPublication", publication, printAeronStreamIdentifiers);
         inboundPublication = new GatewayPublication(
             publication,
             fixCounters.failedInboundPublications(),

From 11468927a3aca67336d6efa75aeb53031ae5601f Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Thu, 12 Sep 2024 17:11:28 +0200
Subject: [PATCH 4/9] fixing undeterminism in ExternallyControlledSystemTest as
 sometimes it receives D replay before live msg

---
 .../artio/system_tests/ExternallyControlledSystemTest.java | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/ExternallyControlledSystemTest.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/ExternallyControlledSystemTest.java
index 3a50389305..3c78e518e6 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/ExternallyControlledSystemTest.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/ExternallyControlledSystemTest.java
@@ -53,6 +53,7 @@
 
 public class ExternallyControlledSystemTest extends AbstractGatewayToGatewaySystemTest
 {
+    private boolean awaitsNewOrderSingle = false;
     private final FakeSessionProxy fakeSessionProxy = new FakeSessionProxy();
     private SessionWriter acceptingSessionWriter = null;
     private final FakeHandler acceptingHandler = new FakeHandler(acceptingOtfAcceptor)
@@ -99,6 +100,11 @@ public void shouldRoundTripMessagesViaExternalSystem()
 
         assertNotNull(acceptingSessionWriter);
 
+        if (awaitsNewOrderSingle)
+        {
+            testSystem.awaitMessageOf(initiatingOtfAcceptor, "D");
+        }
+
         messagesCanBeExchanged();
 
         assertEquals(1, sessionProxyRequests);
@@ -135,6 +141,7 @@ public void shouldBeAbleToContinueProcessingAFollowersSession()
 
         fakeSessionProxy.sequenceNumberAdjustment = 1;
 
+        awaitsNewOrderSingle = true;
         shouldRoundTripMessagesViaExternalSystem();
 
         assertEquals(acceptingSession.id(), writerSessionId);

From 93abd19c5dbebfd938ca2d3930d586396a67f0ed Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Fri, 27 Sep 2024 11:56:30 +0200
Subject: [PATCH 5/9] creating one single executor to be used by every call to
 awaitBlocking

---
 .../artio/system_tests/TestSystem.java        | 57 +++++++++----------
 1 file changed, 26 insertions(+), 31 deletions(-)

diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/TestSystem.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/TestSystem.java
index c3742cb94b..a5d4ca31b0 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/TestSystem.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/TestSystem.java
@@ -53,6 +53,7 @@
 
 public class TestSystem
 {
+    private final ExecutorService executor = Executors.newSingleThreadExecutor();
     public static final long LONG_AWAIT_TIMEOUT_IN_MS = 600_000_000;
 
     private final List<FixLibrary> libraries;
@@ -315,48 +316,42 @@ public void awaitLongBlocking(final Runnable operation)
 
     public <T> T awaitBlocking(final Callable<T> operation)
     {
-        final ExecutorService executor = Executors.newSingleThreadExecutor();
-        try
-        {
-            final Future<T> future = executor.submit(operation);
-
-            final long deadlineInMs = System.currentTimeMillis() + awaitTimeoutInMs;
-
-            while (!future.isDone())
-            {
-                poll();
+        final Future<T> future = executor.submit(operation);
 
-                Thread.yield();
+        final long deadlineInMs = System.currentTimeMillis() + awaitTimeoutInMs;
 
-                if (System.currentTimeMillis() > deadlineInMs)
-                {
-                    Exceptions.printStackTracesForAllThreads();
+        while (!future.isDone())
+        {
+            poll();
 
-                    throw new TimeoutException(operation + " failed: timed out");
-                }
-            }
+            Thread.yield();
 
-            try
-            {
-                return future.get();
-            }
-            catch (final InterruptedException | ExecutionException e)
+            if (System.currentTimeMillis() > deadlineInMs)
             {
-                if (e.getCause() instanceof TimeoutException ||
-                    e.getCause() instanceof java.util.concurrent.TimeoutException)
-                {
-                    Exceptions.printStackTracesForAllThreads();
-                }
+                Exceptions.printStackTracesForAllThreads();
 
-                LangUtil.rethrowUnchecked(e);
+                throw new TimeoutException(String.format(" %s failed: timed out after [%s]ms",
+                    operation,
+                    awaitTimeoutInMs));
             }
+        }
 
-            return null;
+        try
+        {
+            return future.get();
         }
-        finally
+        catch (final InterruptedException | ExecutionException e)
         {
-            executor.shutdown();
+            if (e.getCause() instanceof TimeoutException ||
+                e.getCause() instanceof java.util.concurrent.TimeoutException)
+            {
+                Exceptions.printStackTracesForAllThreads();
+            }
+
+            LangUtil.rethrowUnchecked(e);
         }
+
+        return null;
     }
 
     public void awaitUnbind(final ILink3Connection session)

From 27e0caf217518d4c6bfa9612c3aec28227317956 Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Mon, 14 Oct 2024 11:10:27 +0200
Subject: [PATCH 6/9] setting selfTradePreventionInstruction in FIXP test so
 the test does not fail when FIXP logtag is enabled

---
 .../co/real_logic/artio/system_tests/BinaryEntryPointClient.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/BinaryEntryPointClient.java b/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/BinaryEntryPointClient.java
index 0a5abe7844..db3a2d186b 100644
--- a/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/BinaryEntryPointClient.java
+++ b/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/BinaryEntryPointClient.java
@@ -492,6 +492,7 @@ public void writeNewOrderSingle(final int clOrdId)
 
         newOrderSingle
             .clOrdID(clOrdId)
+            .selfTradePreventionInstruction(SelfTradePreventionInstruction.CANCEL_BOTH_ORDERS)
             .securityID(SECURITY_ID)
             .price().mantissa(3);
         newOrderSingle

From 086b4bfc5493fd3666a01d8d459c31f896349a7e Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Wed, 4 Sep 2024 16:11:30 +0200
Subject: [PATCH 7/9] -making
 PersistentSequenceNumberGatewayToGatewaySystemTest deterministic -fixing
 BinaryEntryPointClient call to jsonPrint when FIX_TEST is enabled
 -cancelOnDisconnect test was using wrong assumption on logout time

---
 .../system_tests/BinaryEntryPointClient.java  | 15 ++++++--
 .../CancelOnDisconnectSystemTest.java         | 38 ++++++++++++-------
 ...uenceNumberGatewayToGatewaySystemTest.java | 30 +++++++++++++--
 .../artio/system_tests/SystemTestUtil.java    | 14 +++++++
 4 files changed, 78 insertions(+), 19 deletions(-)

diff --git a/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/BinaryEntryPointClient.java b/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/BinaryEntryPointClient.java
index db3a2d186b..f2935dee3d 100644
--- a/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/BinaryEntryPointClient.java
+++ b/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/BinaryEntryPointClient.java
@@ -28,6 +28,7 @@
 import uk.co.real_logic.artio.DebugLogger;
 import uk.co.real_logic.artio.binary_entrypoint.BinaryEntryPointProtocol;
 import uk.co.real_logic.sbe.json.JsonPrinter;
+import uk.co.real_logic.sbe.otf.OtfHeaderDecoder;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
@@ -89,6 +90,8 @@ public final class BinaryEntryPointClient implements AutoCloseable
     private long keepAliveIntervalInMs = KEEP_ALIVE_INTERVAL_IN_MS;
     private CancelOnDisconnectType cancelOnDisconnectType = DO_NOT_CANCEL_ON_DISCONNECT_OR_TERMINATE;
     private long codTimeoutWindow = DeltaInMillisEncoder.timeNullValue();
+    private static final OtfHeaderDecoder OTF_HEADER_DECODER = new OtfHeaderDecoder(
+        BinaryEntryPointProtocol.loadSbeIr().headerStructure());
 
     public BinaryEntryPointClient(final int port, final TestSystem testSystem, final long serverAliveIntervalInMs)
         throws IOException
@@ -331,9 +334,15 @@ private void print(final UnsafeBuffer unsafeReadBuffer, final String prefixStrin
     {
         if (DebugLogger.isEnabled(FIX_TEST))
         {
-            final StringBuilder sb = new StringBuilder();
-            jsonPrinter.print(sb, unsafeReadBuffer, SOFH_LENGTH);
-            DebugLogger.log(FIX_TEST, prefixString, sb.toString());
+            // when templateId == 1000 the call to jsonPrinter.print throws an exception as it does not recognize
+            // this as a valid templateId
+            final int templateId = OTF_HEADER_DECODER.getTemplateId(unsafeReadBuffer, SOFH_LENGTH);
+            if (templateId != OUT_OF_RANGE_TEMPLATE_ID)
+            {
+                final StringBuilder sb = new StringBuilder();
+                jsonPrinter.print(sb, unsafeReadBuffer, SOFH_LENGTH);
+                DebugLogger.log(FIX_TEST, prefixString, sb.toString());
+            }
         }
     }
 
diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/CancelOnDisconnectSystemTest.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/CancelOnDisconnectSystemTest.java
index 3c0d061fa0..3847f5621f 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/CancelOnDisconnectSystemTest.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/CancelOnDisconnectSystemTest.java
@@ -51,6 +51,7 @@ public class CancelOnDisconnectSystemTest extends AbstractGatewayToGatewaySystem
     public static final int COD_TEST_TIMEOUT_IN_MS = 500;
     public static final int LONG_COD_TEST_TIMEOUT_IN_MS = RUNNING_ON_WINDOWS ? 3_000 : COD_TEST_TIMEOUT_IN_MS;
     public static final Class<FixDictionaryImpl> FIX_DICTIONARY_WITHOUT_COD = FixDictionaryImpl.class;
+    private long now;
 
     private final FakeTimeoutHandler timeoutHandler = new FakeTimeoutHandler();
 
@@ -119,9 +120,10 @@ public void shouldTriggerCancelOnDisconnectTimeoutForLogout()
         launch();
         setup(CANCEL_ON_LOGOUT_ONLY.representation(), COD_TEST_TIMEOUT_IN_MS);
 
+        now = nanoClock.nanoTime();
         logoutSession(initiatingSession);
 
-        assertTriggersCancelOnDisconnect(CANCEL_ON_LOGOUT_ONLY);
+        assertTriggersCancelOnDisconnect(CANCEL_ON_LOGOUT_ONLY, now);
     }
 
     @Test(timeout = TEST_TIMEOUT_IN_MS)
@@ -130,9 +132,10 @@ public void shouldTriggerCancelOnDisconnectTimeoutForDisconnect()
         launch();
         setup(CANCEL_ON_DISCONNECT_ONLY.representation(), COD_TEST_TIMEOUT_IN_MS);
 
+        now = nanoClock.nanoTime();
         testSystem.awaitRequestDisconnect(initiatingSession);
 
-        assertTriggersCancelOnDisconnect(CANCEL_ON_DISCONNECT_ONLY);
+        assertTriggersCancelOnDisconnect(CANCEL_ON_DISCONNECT_ONLY, now);
     }
 
     @Test(timeout = TEST_TIMEOUT_IN_MS)
@@ -143,9 +146,10 @@ public void shouldTriggerCancelOnDisconnectTimeoutForLogoutLibrary()
 
         acquireAcceptingSession();
 
+        now = nanoClock.nanoTime();
         logoutSession(initiatingSession);
 
-        assertTriggersCancelOnDisconnect(CANCEL_ON_LOGOUT_ONLY);
+        assertTriggersCancelOnDisconnect(CANCEL_ON_LOGOUT_ONLY, now);
     }
 
     @Test(timeout = TEST_TIMEOUT_IN_MS)
@@ -154,9 +158,10 @@ public void shouldTriggerCancelOnDisconnectTimeoutForDisconnectLibrary()
         launch();
         setup(CANCEL_ON_DISCONNECT_ONLY.representation(), COD_TEST_TIMEOUT_IN_MS);
 
+        now = nanoClock.nanoTime();
         testSystem.awaitRequestDisconnect(initiatingSession);
 
-        assertTriggersCancelOnDisconnect(CANCEL_ON_DISCONNECT_ONLY);
+        assertTriggersCancelOnDisconnect(CANCEL_ON_DISCONNECT_ONLY, now);
     }
 
     @Test(timeout = TEST_TIMEOUT_IN_MS)
@@ -192,6 +197,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutWithNoLogonOptionsButServerOpt
 
         acquireAcceptingSession();
 
+        now = nanoClock.nanoTime();
         disconnectSession(initiatingSession);
 
         assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_DISCONNECT_ONLY, 0);
@@ -206,6 +212,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutWithNoLogonOptionsButServerOpt
 
         acquireAcceptingSession();
 
+        now = nanoClock.nanoTime();
         disconnectSession(initiatingSession);
 
         assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_DISCONNECT_ONLY,
@@ -221,6 +228,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutForLogoutWithServerOption()
 
         acquireAcceptingSession();
 
+        now = nanoClock.nanoTime();
         logoutSession(initiatingSession);
 
         assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_LOGOUT_ONLY, 0);
@@ -235,6 +243,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutForLogoutWithServerOptionAndTi
 
         acquireAcceptingSession();
 
+        now = nanoClock.nanoTime();
         logoutSession(initiatingSession);
 
         assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_LOGOUT_ONLY,
@@ -249,6 +258,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutForLogoutWithOptionsInsteadOfS
 
         acquireAcceptingSession();
 
+        now = nanoClock.nanoTime();
         logoutSession(initiatingSession);
 
         assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_LOGOUT_ONLY,
@@ -292,8 +302,9 @@ public void shouldTriggerCancelOnDisconnectFromGatewayAfterReacquiring()
         acquireAcceptingSession();
         testSystem.awaitCompletedReply(acceptingLibrary.releaseToGateway(acceptingSession, 5_000));
 
+        now = nanoClock.nanoTime();
         testSystem.awaitRequestDisconnect(initiatingSession);
-        assertTriggersCancelOnDisconnect(CANCEL_ON_DISCONNECT_ONLY);
+        assertTriggersCancelOnDisconnect(CANCEL_ON_DISCONNECT_ONLY, now);
     }
 
     private void assertDisconnectWithHandlerNotInvoked()
@@ -321,16 +332,18 @@ private void assertHandlerNotInvoked(final int codTestTimeoutInMs)
         assertEquals(0, timeoutHandler.invokeCount());
     }
 
-    private void assertTriggersCancelOnDisconnect(final CancelOnDisconnectType type)
+    private void assertTriggersCancelOnDisconnect(final CancelOnDisconnectType type, final long initiatorLogoutTime)
     {
-        assertTriggersCancelOnDisconnect(type, COD_TEST_TIMEOUT_IN_MS);
+        assertTriggersCancelOnDisconnect(type, COD_TEST_TIMEOUT_IN_MS, initiatorLogoutTime);
     }
 
-    private void assertTriggersCancelOnDisconnect(final CancelOnDisconnectType type, final int codTestTimeoutInMs)
+    private void assertTriggersCancelOnDisconnect(final CancelOnDisconnectType type,
+        final int codTestTimeoutInMs,
+        final long initiatorLogoutTime)
     {
         final long codTimeoutInNs = MILLISECONDS.toNanos(codTestTimeoutInMs);
 
-        assertAcceptorCodTriggered(codTimeoutInNs);
+        assertAcceptorCodTriggered(codTimeoutInNs, initiatorLogoutTime);
 
         assertInitiatorCodState(type, codTimeoutInNs, codTestTimeoutInMs);
     }
@@ -354,12 +367,11 @@ private void assertTriggersCancelOnDisconnectFromDefaults(final CancelOnDisconne
         assertEquals(initiatorOption, initiatingSession.cancelOnDisconnectOption());
         assertEquals(initiatorCodTestTimeoutInNs, initiatingSession.cancelOnDisconnectTimeoutWindowInNs());
 
-        assertAcceptorCodTriggered(acceptorCodTimeoutInNs);
+        assertAcceptorCodTriggered(acceptorCodTimeoutInNs, now);
     }
 
-    private void assertAcceptorCodTriggered(final long codTimeoutInNs)
+    private void assertAcceptorCodTriggered(final long codTimeoutInNs, final long initiatorLogoutTime)
     {
-        final long logoutTimeInNs = nanoClock.nanoTime();
         assertSessionDisconnected(initiatingSession);
 
         testSystem.await("timeout not triggered", () -> timeoutHandler.result() != null);
@@ -368,7 +380,7 @@ private void assertAcceptorCodTriggered(final long codTimeoutInNs)
         final TimeoutResult result = timeoutHandler.result();
         assertEquals(onlySession.sessionId(), result.surrogateId);
         assertEquals(onlySession.sessionKey(), result.compositeId);
-        final long timeoutTakenInNs = result.timeInNs - logoutTimeInNs;
+        final long timeoutTakenInNs = result.timeInNs - initiatorLogoutTime;
         assertThat(timeoutTakenInNs, greaterThanOrEqualTo(codTimeoutInNs));
         assertEquals(1, timeoutHandler.invokeCount());
     }
diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/PersistentSequenceNumberGatewayToGatewaySystemTest.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/PersistentSequenceNumberGatewayToGatewaySystemTest.java
index 50758dd97b..5721ec7553 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/PersistentSequenceNumberGatewayToGatewaySystemTest.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/PersistentSequenceNumberGatewayToGatewaySystemTest.java
@@ -216,9 +216,8 @@ public void shouldCopeWithResendRequestOfMissingMessagesWithHighInitialSequenceN
             HIGH_INITIAL_SEQUENCE_NUMBER,
             4,
             HIGH_INITIAL_SEQUENCE_NUMBER,
-            5);
-
-        receivesGapfill(acceptingOtfAcceptor, greaterThan(HIGH_INITIAL_SEQUENCE_NUMBER));
+            5,
+            greaterThan(HIGH_INITIAL_SEQUENCE_NUMBER));
 
         // Test that we don't accidentally send another resend request
         // Reproduction of reported bug
@@ -1094,6 +1093,20 @@ private void exchangeMessagesAroundARestart(
         final int initialReceivedSequenceNumber,
         final int expectedInitToAccSeqNum,
         final int expectedAccToInitSeqNum)
+    {
+        exchangeMessagesAroundARestart(initialSentSequenceNumber,
+            initialReceivedSequenceNumber,
+            expectedInitToAccSeqNum,
+            expectedAccToInitSeqNum,
+            null);
+    }
+
+    private void exchangeMessagesAroundARestart(
+        final int initialSentSequenceNumber,
+        final int initialReceivedSequenceNumber,
+        final int expectedInitToAccSeqNum,
+        final int expectedAccToInitSeqNum,
+        final Matcher<Integer> gapFillMatcher)
     {
         launch(this::nothing);
         connectPersistingSessions(AUTOMATIC_INITIAL_SEQUENCE_NUMBER, resetSequenceNumbersOnLogon);
@@ -1134,6 +1147,17 @@ private void exchangeMessagesAroundARestart(
             assertSequenceFromInitToAcceptAt(expectedInitToAccSeqNum, expectedAccToInitSeqNum);
         }
 
+        // this means a resend request will be sent by the acceptor
+        if (initialReceivedSequenceNumber != AUTOMATIC_INITIAL_SEQUENCE_NUMBER &&
+            initialReceivedSequenceNumber < expectedAccToInitSeqNum)
+        {
+            assertReceivedResendRequest(testSystem, initiatingOtfAcceptor, expectedAccToInitSeqNum);
+        }
+        if (gapFillMatcher != null)
+        {
+            receivesGapfill(acceptingOtfAcceptor, gapFillMatcher);
+        }
+
         assertTestRequestSentAndReceived(initiatingSession, testSystem, acceptingOtfAcceptor);
     }
 
diff --git a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SystemTestUtil.java b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SystemTestUtil.java
index f3e6c62f6e..31a362818b 100644
--- a/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SystemTestUtil.java
+++ b/artio-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/SystemTestUtil.java
@@ -538,6 +538,20 @@ static void assertReceivedSingleHeartbeat(
             });
     }
 
+    static void assertReceivedResendRequest(
+        final TestSystem testSystem, final FakeOtfAcceptor acceptor, final int msgSeqNo)
+    {
+        assertEventuallyTrue("Failed to receive resend request",
+            () ->
+            {
+                testSystem.poll();
+
+                return acceptor
+                    .receivedMessage("2")
+                    .anyMatch((message) -> msgSeqNo == Integer.parseInt(message.get(Constants.MSG_SEQ_NUM)));
+            });
+    }
+
     static LibraryInfo gatewayLibraryInfo(final FixEngine engine)
     {
         return libraries(engine)

From 2e945179175354c47bd466e75eb9b5cd0ec69793 Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Mon, 14 Oct 2024 11:32:57 +0200
Subject: [PATCH 8/9] adding await in
 CancelOnDisconnectBinaryEntrypointSystemTest for timeoutHandler.invokeCount
 set

---
 .../CancelOnDisconnectBinaryEntrypointSystemTest.java           | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/CancelOnDisconnectBinaryEntrypointSystemTest.java b/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/CancelOnDisconnectBinaryEntrypointSystemTest.java
index 03c6e67e65..744b1f7b51 100644
--- a/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/CancelOnDisconnectBinaryEntrypointSystemTest.java
+++ b/artio-binary-entrypoint-system-tests/src/test/java/uk/co/real_logic/artio/system_tests/CancelOnDisconnectBinaryEntrypointSystemTest.java
@@ -216,7 +216,7 @@ private void assertTriggersCancelOnDisconnect(final long logoutTimeInNs)
         assertEquals(onlySession.key(), result.context.key());
         final long timeoutTakenInNs = result.timeInNs - logoutTimeInNs;
         assertThat(timeoutTakenInNs, greaterThanOrEqualTo(codTimeoutInNs));
-        assertEquals(1, timeoutHandler.invokeCount());
+        testSystem.await("timeoutHandler.invokeCount() is not 1", () -> 1 == timeoutHandler.invokeCount());
     }
 
     class FakeTimeoutHandler implements FixPCancelOnDisconnectTimeoutHandler

From ef019e9ed1837637d6fe8cff39322dc8825308f8 Mon Sep 17 00:00:00 2001
From: Luciano Viana <luciano@weareadaptive.com>
Date: Mon, 14 Oct 2024 16:21:28 +0200
Subject: [PATCH 9/9] adding a Dockerfile to run artio build in a container

---
 Dockerfile | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 Dockerfile

diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000..8f32d942c4
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,6 @@
+# the idea of this dockerfile is to allow running artio build in multiple containers in order to increase the chances of a failing test locally
+FROM alpine/java:21-jdk as artio-image
+ENV GRADLE_OPTS="-Dorg.gradle.daemon=false -Dfix.core.debug=STATE_CLEANUP,FIX_MESSAGE,REPLAY,FIXP_SESSION,FIXP_BUSINESS -Dfix.core.ci=true"
+ADD . artio-src
+WORKDIR artio-src
+ENTRYPOINT ./gradlew clean test