Skip to content

Commit 735b6f2

Browse files
authored
Merge pull request #1220 from quickfix-j/copilot/fix-timeout-issue-when-connecting
Stabilize external-DTD dictionary loading in `MessageTest` with short timeouts and bounded retries
2 parents db6fbab + a2fa570 commit 735b6f2

1 file changed

Lines changed: 47 additions & 1 deletion

File tree

quickfixj-core/src/test/java/quickfix/MessageTest.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@
143143
* message classes that are generated later in the compile process.
144144
*/
145145
public class MessageTest {
146+
private static final String DEFAULT_CONNECT_TIMEOUT_PROPERTY = "sun.net.client.defaultConnectTimeout";
147+
private static final String DEFAULT_READ_TIMEOUT_PROPERTY = "sun.net.client.defaultReadTimeout";
148+
private static final int EXTERNAL_DTD_TIMEOUT_MILLIS = 5000;
149+
private static final int EXTERNAL_DTD_LOAD_RETRIES = 3;
150+
private static final int EXTERNAL_DTD_RETRY_DELAY_MILLIS = 250;
146151

147152
@Rule
148153
public ExpectedException expectedException = ExpectedException.none();
@@ -1265,14 +1270,55 @@ public void testIfMessageHeaderIsOverwritten() {
12651270

12661271
@Test
12671272
public void shouldConvertToXmlWhenDataDictionaryLoadedWithExternalDTD() throws ConfigError {
1268-
DataDictionary dataDictionary = new DataDictionary("FIX_External_DTD.xml", DocumentBuilderFactory::newInstance);
1273+
DataDictionary dataDictionary = loadDataDictionaryWithExternalDtdRetry();
12691274
Message message = new Message();
12701275
message.setString(Account.FIELD, "test-account");
12711276

12721277
String xml = message.toXML(dataDictionary);
12731278
xml = xml.replace("\r", "").replace("\n", "").replaceAll(">\\s+<", "><");
12741279
assertEquals("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\"?><message><header/><body><field name=\"Account\" tag=\"1\"><![CDATA[test-account]]></field></body><trailer/></message>", xml);
12751280
}
1281+
1282+
private DataDictionary loadDataDictionaryWithExternalDtdRetry() throws ConfigError {
1283+
final String previousConnectTimeout = System.getProperty(DEFAULT_CONNECT_TIMEOUT_PROPERTY);
1284+
final String previousReadTimeout = System.getProperty(DEFAULT_READ_TIMEOUT_PROPERTY);
1285+
try {
1286+
final String timeout = String.valueOf(EXTERNAL_DTD_TIMEOUT_MILLIS);
1287+
System.setProperty(DEFAULT_CONNECT_TIMEOUT_PROPERTY, timeout);
1288+
System.setProperty(DEFAULT_READ_TIMEOUT_PROPERTY, timeout);
1289+
1290+
ConfigError lastError = new ConfigError("Could not parse data dictionary file");
1291+
for (int attempt = 1; attempt <= EXTERNAL_DTD_LOAD_RETRIES; attempt++) {
1292+
try {
1293+
return new DataDictionary("FIX_External_DTD.xml", DocumentBuilderFactory::newInstance);
1294+
} catch (ConfigError e) {
1295+
lastError = e;
1296+
if (attempt < EXTERNAL_DTD_LOAD_RETRIES) {
1297+
try {
1298+
Thread.sleep((1L << (attempt - 1)) * EXTERNAL_DTD_RETRY_DELAY_MILLIS);
1299+
} catch (InterruptedException interruptedException) {
1300+
Thread.currentThread().interrupt();
1301+
throw new ConfigError("Interrupted while retrying FIX_External_DTD.xml load", interruptedException);
1302+
}
1303+
}
1304+
}
1305+
}
1306+
throw new ConfigError("Failed to load FIX_External_DTD.xml after "
1307+
+ EXTERNAL_DTD_LOAD_RETRIES + " attempts", lastError);
1308+
} finally {
1309+
restoreSystemProperty(DEFAULT_CONNECT_TIMEOUT_PROPERTY, previousConnectTimeout);
1310+
restoreSystemProperty(DEFAULT_READ_TIMEOUT_PROPERTY, previousReadTimeout);
1311+
}
1312+
}
1313+
1314+
private static void restoreSystemProperty(String key, String value) {
1315+
if (value == null) {
1316+
System.clearProperty(key);
1317+
} else {
1318+
System.setProperty(key, value);
1319+
}
1320+
}
1321+
12761322
@Test
12771323
public void shouldConvertToXMLWithoutIndent() {
12781324
Message message = new Message();

0 commit comments

Comments
 (0)