Skip to content

Commit 05eb203

Browse files
committed
Test OOM handling: discover allocation counts at runtime
Replace hardcoded allocation counts in the sync OOM tests with runtime discovery loops. Each test section now iterates from 0 allocations upward until the operation succeeds, removing the need to manually find correct counts after any change to internal allocation patterns. Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
1 parent adb6e95 commit 05eb203

File tree

1 file changed

+73
-89
lines changed

1 file changed

+73
-89
lines changed

tests/ct_out_of_memory_handling.c

Lines changed: 73 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,9 @@
1111
* Tests will call a libvalkeycluster API-function while iterating on a number,
1212
* the number of successful allocations during the call before it hits an OOM.
1313
* The result and the error code is then checked to show "Out of memory".
14-
* As a last step the correct number of allocations is prepared to get a
15-
* successful API-function call.
16-
*
17-
* Tip:
18-
* When this testcase fails after code changes in the library, run the testcase
19-
* in `gdb` to find which API call that failed, and in which iteration.
20-
* - Go to the correct stack frame to find which API that triggered a failure.
21-
* - Use the gdb command `print i` to find which iteration.
22-
* - Investigate if a failure or a success is expected after the code change.
23-
* - Set correct `i` in for-loop and the `prepare_allocation_test()` for the test.
24-
* Correct `i` can be hard to know, finding the correct number might require trial
25-
* and error of running with increased/decreased `i` until the edge is found.
14+
* The required number of allocations for a successful call is discovered at
15+
* runtime rather than hardcoded, making the tests resilient to changes in
16+
* internal allocation patterns.
2617
*/
2718
#define _XOPEN_SOURCE 600 /* For strdup() */
2819
#include "adapters/libevent.h"
@@ -148,15 +139,16 @@ void test_alloc_failure_handling(void) {
148139
valkeyReply *reply;
149140
const char *cmd = "SET key value";
150141

151-
for (int i = 0; i < 33; ++i) {
152-
prepare_allocation_test(cc, i);
142+
/* Discover the number of allocations required for a successful call. */
143+
int n;
144+
for (n = 0; n < 1000; n++) {
145+
prepare_allocation_test(cc, n);
153146
reply = (valkeyReply *)valkeyClusterCommand(cc, cmd);
154-
assert(reply == NULL);
147+
if (reply != NULL)
148+
break;
155149
ASSERT_STR_EQ(cc->errstr, "Out of memory");
156150
}
157-
158-
prepare_allocation_test(cc, 33);
159-
reply = (valkeyReply *)valkeyClusterCommand(cc, cmd);
151+
assert(n < 1000);
160152
CHECK_REPLY_OK(cc, reply);
161153
freeReplyObject(reply);
162154
}
@@ -169,17 +161,15 @@ void test_alloc_failure_handling(void) {
169161
valkeyClusterNode *node = valkeyClusterGetNodeByKey(cc, (char *)"key");
170162
assert(node);
171163

172-
// OOM failing commands
173-
for (int i = 0; i < 32; ++i) {
174-
prepare_allocation_test(cc, i);
164+
int n;
165+
for (n = 0; n < 1000; n++) {
166+
prepare_allocation_test(cc, n);
175167
reply = valkeyClusterCommandToNode(cc, node, cmd);
176-
assert(reply == NULL);
168+
if (reply != NULL)
169+
break;
177170
ASSERT_STR_EQ(cc->errstr, "Out of memory");
178171
}
179-
180-
// Successful command
181-
prepare_allocation_test(cc, 32);
182-
reply = valkeyClusterCommandToNode(cc, node, cmd);
172+
assert(n < 1000);
183173
CHECK_REPLY_OK(cc, reply);
184174
freeReplyObject(reply);
185175
}
@@ -189,37 +179,35 @@ void test_alloc_failure_handling(void) {
189179
valkeyReply *reply;
190180
const char *cmd = "SET foo one";
191181

192-
for (int i = 0; i < 33; ++i) {
193-
prepare_allocation_test(cc, i);
182+
/* Discover allocations needed for a successful append. */
183+
int na;
184+
for (na = 0; na < 1000; na++) {
185+
prepare_allocation_test(cc, na);
194186
result = valkeyClusterAppendCommand(cc, cmd);
195-
assert(result == VALKEY_ERR);
187+
if (result == VALKEY_OK)
188+
break;
196189
ASSERT_STR_EQ(cc->errstr, "Out of memory");
197-
198190
valkeyClusterReset(cc);
199191
}
200-
201-
for (int i = 0; i < 4; ++i) {
202-
// Appended command lost when receiving error from valkey
203-
// during a GetReply, needs a new append for each test loop
204-
prepare_allocation_test(cc, 33);
192+
assert(na < 1000);
193+
194+
/* Discover allocations needed for a successful GetReply. */
195+
int ng;
196+
for (ng = 0; ng < 1000; ng++) {
197+
/* Appended command lost when receiving error during a GetReply,
198+
* needs a new append for each test loop. */
199+
prepare_allocation_test(cc, na);
205200
result = valkeyClusterAppendCommand(cc, cmd);
206201
assert(result == VALKEY_OK);
207202

208-
prepare_allocation_test(cc, i);
203+
prepare_allocation_test(cc, ng);
209204
result = valkeyClusterGetReply(cc, (void *)&reply);
210-
assert(result == VALKEY_ERR);
205+
if (result == VALKEY_OK)
206+
break;
211207
ASSERT_STR_EQ(cc->errstr, "Out of memory");
212-
213208
valkeyClusterReset(cc);
214209
}
215-
216-
prepare_allocation_test(cc, 34);
217-
result = valkeyClusterAppendCommand(cc, cmd);
218-
assert(result == VALKEY_OK);
219-
220-
prepare_allocation_test(cc, 4);
221-
result = valkeyClusterGetReply(cc, (void *)&reply);
222-
assert(result == VALKEY_OK);
210+
assert(ng < 1000);
223211
CHECK_REPLY_OK(cc, reply);
224212
freeReplyObject(reply);
225213
}
@@ -232,39 +220,33 @@ void test_alloc_failure_handling(void) {
232220
valkeyClusterNode *node = valkeyClusterGetNodeByKey(cc, (char *)"foo");
233221
assert(node);
234222

235-
// OOM failing appends
236-
for (int i = 0; i < 34; ++i) {
237-
prepare_allocation_test(cc, i);
223+
/* Discover allocations needed for a successful append to node. */
224+
int na;
225+
for (na = 0; na < 1000; na++) {
226+
prepare_allocation_test(cc, na);
238227
result = valkeyClusterAppendCommandToNode(cc, node, cmd);
239-
assert(result == VALKEY_ERR);
228+
if (result == VALKEY_OK)
229+
break;
240230
ASSERT_STR_EQ(cc->errstr, "Out of memory");
241-
242231
valkeyClusterReset(cc);
243232
}
233+
assert(na < 1000);
244234

245-
// OOM failing GetResults
246-
for (int i = 0; i < 4; ++i) {
247-
// First a successful append
248-
prepare_allocation_test(cc, 34);
235+
/* Discover allocations needed for a successful GetReply. */
236+
int ng;
237+
for (ng = 0; ng < 1000; ng++) {
238+
prepare_allocation_test(cc, na);
249239
result = valkeyClusterAppendCommandToNode(cc, node, cmd);
250240
assert(result == VALKEY_OK);
251241

252-
prepare_allocation_test(cc, i);
242+
prepare_allocation_test(cc, ng);
253243
result = valkeyClusterGetReply(cc, (void *)&reply);
254-
assert(result == VALKEY_ERR);
244+
if (result == VALKEY_OK)
245+
break;
255246
ASSERT_STR_EQ(cc->errstr, "Out of memory");
256-
257247
valkeyClusterReset(cc);
258248
}
259-
260-
// Successful append and GetReply
261-
prepare_allocation_test(cc, 35);
262-
result = valkeyClusterAppendCommandToNode(cc, node, cmd);
263-
assert(result == VALKEY_OK);
264-
265-
prepare_allocation_test(cc, 4);
266-
result = valkeyClusterGetReply(cc, (void *)&reply);
267-
assert(result == VALKEY_OK);
249+
assert(ng < 1000);
268250
CHECK_REPLY_OK(cc, reply);
269251
freeReplyObject(reply);
270252
}
@@ -318,19 +300,20 @@ void test_alloc_failure_handling(void) {
318300
freeReplyObject(reply);
319301

320302
/* Test ASK reply handling with OOM */
321-
for (int i = 0; i < 45; ++i) {
322-
prepare_allocation_test(cc, i);
323-
reply = valkeyClusterCommand(cc, "GET foo");
324-
assert(reply == NULL);
325-
ASSERT_STR_EQ(cc->errstr, "Out of memory");
303+
{
304+
int n;
305+
for (n = 0; n < 1000; n++) {
306+
prepare_allocation_test(cc, n);
307+
reply = valkeyClusterCommand(cc, "GET foo");
308+
if (reply != NULL)
309+
break;
310+
ASSERT_STR_EQ(cc->errstr, "Out of memory");
311+
}
312+
assert(n < 1000);
313+
CHECK_REPLY_STR(cc, reply, "one");
314+
freeReplyObject(reply);
326315
}
327316

328-
/* Test ASK reply handling without OOM */
329-
prepare_allocation_test(cc, 45);
330-
reply = valkeyClusterCommand(cc, "GET foo");
331-
CHECK_REPLY_STR(cc, reply, "one");
332-
freeReplyObject(reply);
333-
334317
/* Finalize the migration. Skip OOM testing during these steps by
335318
* allowing a high number of allocations. */
336319
prepare_allocation_test(cc, 1000);
@@ -347,19 +330,20 @@ void test_alloc_failure_handling(void) {
347330
freeReplyObject(reply);
348331

349332
/* Test MOVED reply handling with OOM */
350-
for (int i = 0; i < 32; ++i) {
351-
prepare_allocation_test(cc, i);
352-
reply = valkeyClusterCommand(cc, "GET foo");
353-
assert(reply == NULL);
354-
ASSERT_STR_EQ(cc->errstr, "Out of memory");
333+
{
334+
int n;
335+
for (n = 0; n < 1000; n++) {
336+
prepare_allocation_test(cc, n);
337+
reply = valkeyClusterCommand(cc, "GET foo");
338+
if (reply != NULL)
339+
break;
340+
ASSERT_STR_EQ(cc->errstr, "Out of memory");
341+
}
342+
assert(n < 1000);
343+
CHECK_REPLY_STR(cc, reply, "one");
344+
freeReplyObject(reply);
355345
}
356346

357-
/* Test MOVED reply handling without OOM */
358-
prepare_allocation_test(cc, 32);
359-
reply = valkeyClusterCommand(cc, "GET foo");
360-
CHECK_REPLY_STR(cc, reply, "one");
361-
freeReplyObject(reply);
362-
363347
/* MOVED triggers a slotmap update which currently replaces all cluster_node
364348
* objects. We can get the new objects by searching for its server ports.
365349
* This enables us to migrate the slot back to the original node. */

0 commit comments

Comments
 (0)