Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test cleanup #524

Merged
merged 9 commits into from
Oct 17, 2024
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this instead of a regular MessageHeaderDecoder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is what the JsonPrinter.print method uses. I've just reproduced the issue and it happens when we run shouldDisconnectConnectionWhenOutOfRangeTemplateIdUsed() test with FIX_TEST log tag enabled.


public BinaryEntryPointClient(final int port, final TestSystem testSystem, final long serverAliveIntervalInMs)
throws IOException
Expand Down Expand Up @@ -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());
}
}
}

Expand Down Expand Up @@ -492,6 +501,7 @@ public void writeNewOrderSingle(final int clOrdId)

newOrderSingle
.clOrdID(clOrdId)
.selfTradePreventionInstruction(SelfTradePreventionInstruction.CANCEL_BOTH_ORDERS)
.securityID(SECURITY_ID)
.price().mantissa(3);
newOrderSingle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this fails you will lose the actual invokeCount.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I said privately I'd prefer refactoring this await method later on as it's being used in a bunch of tests - for now i'm just reusing it.

}

class FakeTimeoutHandler implements FixPCancelOnDisconnectTimeoutHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -192,6 +197,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutWithNoLogonOptionsButServerOpt

acquireAcceptingSession();

now = nanoClock.nanoTime();
disconnectSession(initiatingSession);

assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_DISCONNECT_ONLY, 0);
Expand All @@ -206,6 +212,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutWithNoLogonOptionsButServerOpt

acquireAcceptingSession();

now = nanoClock.nanoTime();
disconnectSession(initiatingSession);

assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_DISCONNECT_ONLY,
Expand All @@ -221,6 +228,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutForLogoutWithServerOption()

acquireAcceptingSession();

now = nanoClock.nanoTime();
logoutSession(initiatingSession);

assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_LOGOUT_ONLY, 0);
Expand All @@ -235,6 +243,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutForLogoutWithServerOptionAndTi

acquireAcceptingSession();

now = nanoClock.nanoTime();
logoutSession(initiatingSession);

assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_LOGOUT_ONLY,
Expand All @@ -249,6 +258,7 @@ public void shouldTriggerCancelOnDisconnectTimeoutForLogoutWithOptionsInsteadOfS

acquireAcceptingSession();

now = nanoClock.nanoTime();
logoutSession(initiatingSession);

assertTriggersCancelOnDisconnectFromDefaults(CancelOnDisconnectOption.CANCEL_ON_LOGOUT_ONLY,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
Expand All @@ -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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -99,6 +100,11 @@ public void shouldRoundTripMessagesViaExternalSystem()

assertNotNull(acceptingSessionWriter);

if (awaitsNewOrderSingle)
{
testSystem.awaitMessageOf(initiatingOtfAcceptor, "D");
}

messagesCanBeExchanged();

assertEquals(1, sessionProxyRequests);
Expand Down Expand Up @@ -135,6 +141,7 @@ public void shouldBeAbleToContinueProcessingAFollowersSession()

fakeSessionProxy.sequenceNumberAdjustment = 1;

awaitsNewOrderSingle = true;
shouldRoundTripMessagesViaExternalSystem();

assertEquals(acceptingSession.id(), writerSessionId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -148,7 +149,7 @@ public void shouldQuarantineThenDisconnectASlowConsumer() throws IOException
hasBecomeSlow = true;
}

sendMessage();
sendMessageWithRetry();
}

testSystem.poll();
Expand All @@ -173,16 +174,21 @@ private void sessionBecomesSlow()
assertTrue(session.isSlowConsumer());
}

private void sendMessage()
private void sendMessageWithRetry()
{
testSystem.awaitSend(this::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);
}
}

Expand All @@ -206,7 +212,7 @@ public void shouldRestoreConnectionFromSlowGroupWhenItCatchesUp() throws IOExcep
}
while (bytesRead > 0);

sendMessage();
sendMessageWithRetry();

testSystem.poll();
}
Expand Down Expand Up @@ -259,7 +265,7 @@ private ConnectedSessionInfo sessionBecomesSlow(final MessageTimingCaptor messag
{
for (int i = 0; i < 10; i++)
{
sendMessage();
sendMessageWithRetry();
}

testSystem.poll();
Expand Down
Loading