Skip to content

Commit 4bc8c84

Browse files
committed
feat(qwp): QWiP durable ack
1 parent 5d32bef commit 4bc8c84

1 file changed

Lines changed: 172 additions & 0 deletions

File tree

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*+*****************************************************************************
2+
* ___ _ ____ ____
3+
* / _ \ _ _ ___ ___| |_| _ \| __ )
4+
* | | | | | | |/ _ \/ __| __| | | | _ \
5+
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
6+
* \__\_\\__,_|\___||___/\__|____/|____/
7+
*
8+
* Copyright (c) 2014-2019 Appsicle
9+
* Copyright (c) 2019-2026 QuestDB
10+
*
11+
* Licensed under the Apache License, Version 2.0 (the "License");
12+
* you may not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing, software
18+
* distributed under the License is distributed on an "AS IS" BASIS,
19+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20+
* See the License for the specific language governing permissions and
21+
* limitations under the License.
22+
*
23+
******************************************************************************/
24+
25+
package io.questdb.client.test.cutlass.qwp.client;
26+
27+
import io.questdb.client.cutlass.qwp.client.WebSocketResponse;
28+
import io.questdb.client.std.MemoryTag;
29+
import io.questdb.client.std.Unsafe;
30+
import org.junit.Assert;
31+
import org.junit.Test;
32+
33+
import static io.questdb.client.test.tools.TestUtils.assertMemoryLeak;
34+
35+
public class WebSocketResponseTest {
36+
37+
@Test
38+
public void testDurableAckFactory() throws Exception {
39+
assertMemoryLeak(() -> {
40+
WebSocketResponse response = WebSocketResponse.durableAck(42L);
41+
Assert.assertTrue(response.isDurableAck());
42+
Assert.assertFalse(response.isSuccess());
43+
Assert.assertEquals(42L, response.getSequence());
44+
Assert.assertEquals(WebSocketResponse.STATUS_DURABLE_ACK, response.getStatus());
45+
Assert.assertEquals("DURABLE_ACK", response.getStatusName());
46+
Assert.assertNull(response.getErrorMessage());
47+
});
48+
}
49+
50+
@Test
51+
public void testDurableAckIsStructurallyValidExact9Bytes() throws Exception {
52+
assertMemoryLeak(() -> {
53+
WebSocketResponse response = WebSocketResponse.durableAck(7L);
54+
int size = response.serializedSize();
55+
Assert.assertEquals(WebSocketResponse.MIN_RESPONSE_SIZE, size);
56+
57+
long ptr = Unsafe.malloc(size, MemoryTag.NATIVE_DEFAULT);
58+
try {
59+
response.writeTo(ptr);
60+
Assert.assertTrue(WebSocketResponse.isStructurallyValid(ptr, size));
61+
// Extra bytes make it invalid
62+
Assert.assertFalse(WebSocketResponse.isStructurallyValid(ptr, size + 1));
63+
// Too few bytes also invalid
64+
Assert.assertFalse(WebSocketResponse.isStructurallyValid(ptr, size - 1));
65+
} finally {
66+
Unsafe.free(ptr, size, MemoryTag.NATIVE_DEFAULT);
67+
}
68+
});
69+
}
70+
71+
@Test
72+
public void testDurableAckRoundTripThroughNativeMemory() throws Exception {
73+
assertMemoryLeak(() -> {
74+
WebSocketResponse original = WebSocketResponse.durableAck(12345L);
75+
int size = original.serializedSize();
76+
long ptr = Unsafe.malloc(size, MemoryTag.NATIVE_DEFAULT);
77+
try {
78+
original.writeTo(ptr);
79+
80+
WebSocketResponse parsed = new WebSocketResponse();
81+
Assert.assertTrue(parsed.readFrom(ptr, size));
82+
Assert.assertTrue(parsed.isDurableAck());
83+
Assert.assertFalse(parsed.isSuccess());
84+
Assert.assertEquals(12345L, parsed.getSequence());
85+
Assert.assertNull(parsed.getErrorMessage());
86+
} finally {
87+
Unsafe.free(ptr, size, MemoryTag.NATIVE_DEFAULT);
88+
}
89+
});
90+
}
91+
92+
@Test
93+
public void testDurableAckDoesNotCarryErrorMessage() throws Exception {
94+
assertMemoryLeak(() -> {
95+
WebSocketResponse response = WebSocketResponse.durableAck(99L);
96+
int size = response.serializedSize();
97+
long ptr = Unsafe.malloc(size, MemoryTag.NATIVE_DEFAULT);
98+
try {
99+
response.writeTo(ptr);
100+
101+
WebSocketResponse parsed = new WebSocketResponse();
102+
Assert.assertTrue(parsed.readFrom(ptr, size));
103+
Assert.assertNull(parsed.getErrorMessage());
104+
} finally {
105+
Unsafe.free(ptr, size, MemoryTag.NATIVE_DEFAULT);
106+
}
107+
});
108+
}
109+
110+
@Test
111+
public void testSuccessIsNotDurableAck() throws Exception {
112+
assertMemoryLeak(() -> {
113+
WebSocketResponse response = WebSocketResponse.success(10L);
114+
Assert.assertTrue(response.isSuccess());
115+
Assert.assertFalse(response.isDurableAck());
116+
Assert.assertEquals("OK", response.getStatusName());
117+
});
118+
}
119+
120+
@Test
121+
public void testErrorIsNotDurableAck() throws Exception {
122+
assertMemoryLeak(() -> {
123+
WebSocketResponse response = WebSocketResponse.error(
124+
5L, WebSocketResponse.STATUS_PARSE_ERROR, "bad input");
125+
Assert.assertFalse(response.isDurableAck());
126+
Assert.assertFalse(response.isSuccess());
127+
Assert.assertEquals("PARSE_ERROR", response.getStatusName());
128+
});
129+
}
130+
131+
@Test
132+
public void testSuccessRoundTripUnchanged() throws Exception {
133+
assertMemoryLeak(() -> {
134+
WebSocketResponse original = WebSocketResponse.success(77L);
135+
int size = original.serializedSize();
136+
long ptr = Unsafe.malloc(size, MemoryTag.NATIVE_DEFAULT);
137+
try {
138+
original.writeTo(ptr);
139+
140+
WebSocketResponse parsed = new WebSocketResponse();
141+
Assert.assertTrue(parsed.readFrom(ptr, size));
142+
Assert.assertTrue(parsed.isSuccess());
143+
Assert.assertFalse(parsed.isDurableAck());
144+
Assert.assertEquals(77L, parsed.getSequence());
145+
} finally {
146+
Unsafe.free(ptr, size, MemoryTag.NATIVE_DEFAULT);
147+
}
148+
});
149+
}
150+
151+
@Test
152+
public void testErrorRoundTrip() throws Exception {
153+
assertMemoryLeak(() -> {
154+
WebSocketResponse original = WebSocketResponse.error(
155+
3L, WebSocketResponse.STATUS_INTERNAL_ERROR, "oops");
156+
int size = original.serializedSize();
157+
long ptr = Unsafe.malloc(size, MemoryTag.NATIVE_DEFAULT);
158+
try {
159+
original.writeTo(ptr);
160+
161+
WebSocketResponse parsed = new WebSocketResponse();
162+
Assert.assertTrue(parsed.readFrom(ptr, size));
163+
Assert.assertFalse(parsed.isSuccess());
164+
Assert.assertFalse(parsed.isDurableAck());
165+
Assert.assertEquals(3L, parsed.getSequence());
166+
Assert.assertEquals("oops", parsed.getErrorMessage());
167+
} finally {
168+
Unsafe.free(ptr, size, MemoryTag.NATIVE_DEFAULT);
169+
}
170+
});
171+
}
172+
}

0 commit comments

Comments
 (0)