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