Skip to content

Commit 5bd76e0

Browse files
committed
test(qwp): pin the sf_sync_interval_millis config rejection paths
Both new user-visible rejection branches for sf_sync_interval_millis shipped untested: the out-of-range guard (<=0, or past the Long.MAX_VALUE/1_000_000 nanosecond-overflow boundary) and the non-WebSocket transport guard in the config-string parser. Add three cases to SfFromConfigTest: - testSfSyncIntervalRejectsZero: =0 is a realistic operator typo, rejected with "sf_sync_interval_millis is out of range". - testSfSyncIntervalOverflowBoundary: two-sided pin of the millis->nanos overflow guard -- Long.MAX_VALUE/1_000_000 is honored with exact nanos, one millisecond more is rejected -- so a later change to the operator or the divisor cannot regress silently. - testSfSyncIntervalRejectsOnNonWebSocketTransport: an http config is rejected with "sf_sync_interval_millis is only supported for WebSocket transport".
1 parent c5297f7 commit 5bd76e0

1 file changed

Lines changed: 72 additions & 0 deletions

File tree

core/src/test/java/io/questdb/client/test/cutlass/qwp/client/sf/SfFromConfigTest.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,78 @@ public void testSfSyncIntervalRequiresPeriodicMode() throws Exception {
276276
});
277277
}
278278

279+
@Test
280+
public void testSfSyncIntervalRejectsZero() throws Exception {
281+
// A realistic operator typo: sf_sync_interval_millis=0. The setter
282+
// rejects it at parse time (millis <= 0), before build() cross-checks
283+
// periodic mode, so the out-of-range message is what surfaces.
284+
TestUtils.assertMemoryLeak(() -> {
285+
String config = "ws::addr=localhost:1;sf_dir=" + sfDir
286+
+ ";sf_durability=periodic;sf_sync_interval_millis=0;";
287+
try (Sender ignored = Sender.fromConfig(config)) {
288+
Assert.fail("expected sf_sync_interval_millis=0 to be rejected");
289+
} catch (LineSenderException expected) {
290+
Assert.assertTrue(expected.getMessage(),
291+
expected.getMessage().contains("sf_sync_interval_millis is out of range"));
292+
}
293+
});
294+
}
295+
296+
@Test
297+
public void testSfSyncIntervalOverflowBoundary() throws Exception {
298+
// Pin the exact millis->nanos overflow guard: millis * 1_000_000 must
299+
// not overflow a long. The largest accepted value is
300+
// Long.MAX_VALUE / 1_000_000; one millisecond more must be rejected.
301+
// Both sides are asserted so a later change to the operator (> vs >=)
302+
// or the 1_000_000 divisor cannot regress silently.
303+
final long maxValidMillis = Long.MAX_VALUE / 1_000_000L;
304+
TestUtils.assertMemoryLeak(() -> {
305+
AckHandler handler = new AckHandler();
306+
try (TestWebSocketServer server = new TestWebSocketServer(handler)) {
307+
server.start();
308+
Assert.assertTrue(server.awaitStart(5, TimeUnit.SECONDS));
309+
310+
// Accept side: the boundary value is honored and converts to
311+
// nanos without overflow.
312+
String accepted = "ws::addr=localhost:" + server.getPort()
313+
+ ";sf_dir=" + sfDir + ";sf_durability=periodic"
314+
+ ";sf_sync_interval_millis=" + maxValidMillis + ";";
315+
try (Sender sender = Sender.fromConfig(accepted)) {
316+
QwpWebSocketSender ws = (QwpWebSocketSender) sender;
317+
Assert.assertEquals(maxValidMillis * 1_000_000L,
318+
ws.getCursorEngineForTesting().getSyncIntervalNanosForTesting());
319+
}
320+
}
321+
322+
// Reject side: one millisecond past the boundary is out of range.
323+
String rejected = "ws::addr=localhost:1;sf_dir=" + sfDir
324+
+ ";sf_durability=periodic;sf_sync_interval_millis="
325+
+ (maxValidMillis + 1) + ";";
326+
try (Sender ignored = Sender.fromConfig(rejected)) {
327+
Assert.fail("expected the overflow-boundary value to be rejected");
328+
} catch (LineSenderException expected) {
329+
Assert.assertTrue(expected.getMessage(),
330+
expected.getMessage().contains("sf_sync_interval_millis is out of range"));
331+
}
332+
});
333+
}
334+
335+
@Test
336+
public void testSfSyncIntervalRejectsOnNonWebSocketTransport() throws Exception {
337+
// The config-string parser rejects sf_sync_interval_millis on any
338+
// non-WebSocket schema before the value is parsed.
339+
TestUtils.assertMemoryLeak(() -> {
340+
String config = "http::addr=localhost:1;sf_sync_interval_millis=123;";
341+
try (Sender ignored = Sender.fromConfig(config)) {
342+
Assert.fail("expected sf_sync_interval_millis on http to be rejected");
343+
} catch (LineSenderException expected) {
344+
Assert.assertTrue(expected.getMessage(),
345+
expected.getMessage().contains(
346+
"sf_sync_interval_millis is only supported for WebSocket transport"));
347+
}
348+
});
349+
}
350+
279351
@Test
280352
public void testSfMaxBytesAcceptsSizeSuffixes() throws Exception {
281353
TestUtils.assertMemoryLeak(() -> {

0 commit comments

Comments
 (0)