test_trechist.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2/* Tests based on rechist tests */
3
4#include <assert.h>
5#include <inttypes.h>
6#include <limits.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#ifdef WIN32
12#include "vc_compat.h"
13#endif
14
15#include "lsquic_int_types.h"
16#include "lsquic_trechist.h"
17
18
19struct str_range_iter
20{
21    char                        *str;
22    struct lsquic_packno_range   range;
23};
24
25
26static const struct lsquic_packno_range *
27next_str_range (void *ctx)
28{
29    struct str_range_iter *const str_iter = ctx;
30
31    if (str_iter->str && str_iter->str[0] == '[')
32    {
33        str_iter->range.high = strtoul(str_iter->str + 1, &str_iter->str, 10);
34        assert('-' == *str_iter->str);
35        str_iter->range.low = strtoul(str_iter->str + 1, &str_iter->str, 10);
36        assert(']' == *str_iter->str);
37        ++str_iter->str;
38        return &str_iter->range;
39    }
40    else
41        return NULL;
42}
43
44
45static void
46test_clone (trechist_mask_t src_mask, struct trechist_elem *src_elems)
47{
48    trechist_mask_t       hist_mask;
49    struct trechist_elem *hist_elems;
50    const struct lsquic_packno_range *ranges[2];
51    struct trechist_iter iters[2];
52
53    hist_elems = malloc(sizeof(hist_elems[0]) * TRECHIST_MAX_RANGES);
54
55    lsquic_trechist_iter(&iters[0], src_mask, src_elems);
56    lsquic_trechist_copy_ranges(&hist_mask, hist_elems, &iters[0],
57                        lsquic_trechist_first, lsquic_trechist_next);
58
59    lsquic_trechist_iter(&iters[0], src_mask, src_elems);
60    lsquic_trechist_iter(&iters[1], hist_mask, hist_elems);
61
62    for (ranges[0] = lsquic_trechist_first(&iters[0]),
63         ranges[1] = lsquic_trechist_first(&iters[1]);
64
65         ranges[0] && ranges[1];
66
67         ranges[0] = lsquic_trechist_next(&iters[0]),
68         ranges[1] = lsquic_trechist_next(&iters[1]))
69    {
70        assert(ranges[0]->low == ranges[1]->low);
71        assert(ranges[0]->high == ranges[1]->high);
72    }
73
74    assert(!ranges[0] && !ranges[1]);
75
76    free(hist_elems);
77}
78
79
80static void
81test4 (void)
82{
83    trechist_mask_t       hist_mask;
84    struct trechist_elem *hist_elems;
85    const struct lsquic_packno_range *range;
86    struct trechist_iter iter;
87    lsquic_packno_t packno;
88
89    hist_elems = malloc(sizeof(hist_elems[0]) * TRECHIST_MAX_RANGES);
90    hist_mask = 0;
91    test_clone(hist_mask, hist_elems);
92
93    for (packno = 11917; packno <= 11941; ++packno)
94        lsquic_trechist_insert(&hist_mask, hist_elems, packno);
95    for (packno = 11946; packno <= 11994; ++packno)
96        lsquic_trechist_insert(&hist_mask, hist_elems, packno);
97
98    test_clone(hist_mask, hist_elems);
99    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
100    range = lsquic_trechist_first(&iter);
101    assert(range);
102    assert(range->high == 11994);
103    assert(range->low == 11946);
104    range = lsquic_trechist_next(&iter);
105    assert(range);
106    assert(range->high == 11941);
107    assert(range->low == 11917);
108    range = lsquic_trechist_next(&iter);
109    assert(!range);
110
111    lsquic_trechist_insert(&hist_mask, hist_elems, 11995);
112    lsquic_trechist_insert(&hist_mask, hist_elems, 11996);
113    test_clone(hist_mask, hist_elems);
114
115    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
116    range = lsquic_trechist_first(&iter);
117    assert(range);
118    assert(range->high == 11996);
119    assert(range->low == 11946);
120    range = lsquic_trechist_next(&iter);
121    assert(range);
122    assert(range->high == 11941);
123    assert(range->low == 11917);
124    range = lsquic_trechist_next(&iter);
125    assert(!range);
126    test_clone(hist_mask, hist_elems);
127
128    lsquic_trechist_insert(&hist_mask, hist_elems, 11912);
129
130    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
131    range = lsquic_trechist_first(&iter);
132    assert(range);
133    assert(range->high == 11996);
134    assert(range->low == 11946);
135    range = lsquic_trechist_next(&iter);
136    assert(range);
137    assert(range->high == 11941);
138    assert(range->low == 11917);
139    range = lsquic_trechist_next(&iter);
140    assert(range);
141    assert(range->high == 11912);
142    assert(range->low == 11912);
143    range = lsquic_trechist_next(&iter);
144    assert(!range);
145
146    for (packno = 12169; packno <= 12193; ++packno)
147        lsquic_trechist_insert(&hist_mask, hist_elems, packno);
148
149    test_clone(hist_mask, hist_elems);
150
151    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
152    range = lsquic_trechist_first(&iter);
153    assert(range);
154    assert(range->high == 12193);
155    assert(range->low == 12169);
156    range = lsquic_trechist_next(&iter);
157    assert(range);
158    assert(range->high == 11996);
159    assert(range->low == 11946);
160    range = lsquic_trechist_next(&iter);
161    assert(range);
162    assert(range->high == 11941);
163    assert(range->low == 11917);
164    range = lsquic_trechist_next(&iter);
165    assert(range);
166    assert(range->high == 11912);
167    assert(range->low == 11912);
168    range = lsquic_trechist_next(&iter);
169    assert(!range);
170
171    test_clone(hist_mask, hist_elems);
172
173    free(hist_elems);
174}
175
176
177static void
178rechist2str (trechist_mask_t hist_mask, const struct trechist_elem *hist_elems,
179                                                        char *buf, size_t bufsz)
180{
181    const struct lsquic_packno_range *range;
182    struct trechist_iter iter;
183    size_t off;
184    int n;
185
186    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
187    for (off = 0, range = lsquic_trechist_first(&iter);
188            range && off < bufsz;
189                off += n, range = lsquic_trechist_next(&iter))
190    {
191        n = snprintf(buf + off, bufsz - off, "[%"PRIu64"-%"PRIu64"]",
192                                                    range->high, range->low);
193        if (n < 0 || (size_t) n >= bufsz - off)
194            break;
195    }
196}
197
198
199static void
200test5 (void)
201{
202    trechist_mask_t       hist_mask;
203    struct trechist_elem *hist_elems;
204    char buf[100];
205
206    hist_elems = malloc(sizeof(hist_elems[0]) * TRECHIST_MAX_RANGES);
207    hist_mask = 0;
208
209    lsquic_trechist_insert(&hist_mask, hist_elems, 1);
210    /* Packet 2 omitted because it could not be decrypted */
211    lsquic_trechist_insert(&hist_mask, hist_elems, 3);
212    lsquic_trechist_insert(&hist_mask, hist_elems, 12);
213
214    rechist2str(hist_mask, hist_elems, buf, sizeof(buf));
215    assert(0 == strcmp(buf, "[12-12][3-3][1-1]"));
216
217    lsquic_trechist_insert(&hist_mask, hist_elems, 4);
218    rechist2str(hist_mask, hist_elems, buf, sizeof(buf));
219    assert(0 == strcmp(buf, "[12-12][4-3][1-1]"));
220
221    lsquic_trechist_insert(&hist_mask, hist_elems, 10);
222    rechist2str(hist_mask, hist_elems, buf, sizeof(buf));
223    assert(0 == strcmp(buf, "[12-12][10-10][4-3][1-1]"));
224
225    lsquic_trechist_insert(&hist_mask, hist_elems, 6);
226
227    rechist2str(hist_mask, hist_elems, buf, sizeof(buf));
228    assert(0 == strcmp(buf, "[12-12][10-10][6-6][4-3][1-1]"));
229
230    lsquic_trechist_insert(&hist_mask, hist_elems, 7);
231    lsquic_trechist_insert(&hist_mask, hist_elems, 8);
232
233    rechist2str(hist_mask, hist_elems, buf, sizeof(buf));
234    assert(0 == strcmp(buf, "[12-12][10-10][8-6][4-3][1-1]"));
235    test_clone(hist_mask, hist_elems);
236    assert(!(lsquic_trechist_contains(hist_mask, hist_elems, 0)));
237    assert(!(lsquic_trechist_contains(hist_mask, hist_elems, 9)));
238    assert(!(lsquic_trechist_contains(hist_mask, hist_elems, 20)));
239    assert(lsquic_trechist_contains(hist_mask, hist_elems, 4));
240    assert(lsquic_trechist_contains(hist_mask, hist_elems, 1));
241    assert(lsquic_trechist_contains(hist_mask, hist_elems, 7));
242    assert(lsquic_trechist_contains(hist_mask, hist_elems, 8));
243    assert(lsquic_trechist_contains(hist_mask, hist_elems, 6));
244
245    lsquic_trechist_insert(&hist_mask, hist_elems, 9);
246
247    rechist2str(hist_mask, hist_elems, buf, sizeof(buf));
248    assert(0 == strcmp(buf, "[12-12][10-6][4-3][1-1]"));
249    test_clone(hist_mask, hist_elems);
250
251    lsquic_trechist_insert(&hist_mask, hist_elems, 5);
252    lsquic_trechist_insert(&hist_mask, hist_elems, 11);
253
254    rechist2str(hist_mask, hist_elems, buf, sizeof(buf));
255    assert(0 == strcmp(buf, "[12-3][1-1]"));
256
257    free(hist_elems);
258}
259
260
261static void
262basic_test (void)
263{
264    trechist_mask_t       hist_mask;
265    struct trechist_elem *hist_elems;
266    const struct lsquic_packno_range *range;
267    struct trechist_iter iter;
268    unsigned i;
269    int s;
270
271    hist_elems = malloc(sizeof(hist_elems[0]) * TRECHIST_MAX_RANGES);
272    hist_mask = 0;
273
274    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
275    range = lsquic_trechist_first(&iter);
276    assert(!range);
277
278    s = lsquic_trechist_insert(&hist_mask, hist_elems, 1);
279    assert(("inserting packet number one is successful", 0 == s));
280
281    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
282    range = lsquic_trechist_first(&iter);
283    assert(("first range returned correctly", range));
284    assert(("first range low value checks out", range->low == 1));
285    assert(("first range high value checks out", range->high == 1));
286    range = lsquic_trechist_next(&iter);
287    assert(!range);
288    assert(("second range does not exist", !range));
289
290    for (i = 3; i <= 5; ++i)
291    {
292        s = lsquic_trechist_insert(&hist_mask, hist_elems, i);
293        assert(("inserting packet", s == 0));
294    }
295
296    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
297    range = lsquic_trechist_first(&iter);
298    assert(("first range returned correctly", range));
299    assert(("first range low value checks out", range->low == 3));
300    assert(("first range high value checks out", range->high == 5));
301    assert(!(lsquic_trechist_contains(hist_mask, hist_elems, 7)));
302    assert(!(lsquic_trechist_contains(hist_mask, hist_elems, 2)));
303    assert(lsquic_trechist_contains(hist_mask, hist_elems, 4));
304    range = lsquic_trechist_next(&iter);
305    assert(("second range returned correctly", range));
306    assert(("second range low value checks out", range->low == 1));
307    assert(("second range high value checks out", range->high == 1));
308    range = lsquic_trechist_next(&iter);
309    assert(("third range does not exist", !range));
310
311    assert(5 == lsquic_trechist_max(hist_mask, hist_elems));
312
313    s = lsquic_trechist_insert(&hist_mask, hist_elems, 10);
314    assert(("inserting packet", s == 0));
315
316    assert(10 == lsquic_trechist_max(hist_mask, hist_elems));
317
318    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
319    range = lsquic_trechist_first(&iter);
320    assert(("first range returned correctly", range));
321    assert(("first range low value checks out", range->low == 10));
322    assert(("first range high value checks out", range->high == 10));
323    test_clone(hist_mask, hist_elems);
324
325    s = lsquic_trechist_insert(&hist_mask, hist_elems, 8);
326    assert(("inserting packet", s == 0));
327    s = lsquic_trechist_insert(&hist_mask, hist_elems, 9);
328    assert(("inserting packet", s == 0));
329
330    /* Check merge */
331    lsquic_trechist_iter(&iter, hist_mask, hist_elems);
332    range = lsquic_trechist_first(&iter);
333    assert(("first range returned correctly", range));
334    assert(("first range low value checks out", range->low == 8));
335    assert(("first range high value checks out", range->high == 10));
336
337    free(hist_elems);
338}
339
340
341static void
342test_limits (void)
343{
344    trechist_mask_t       hist_mask;
345    struct trechist_elem *hist_elems;
346    unsigned i;
347    int s;
348
349    hist_elems = malloc(sizeof(hist_elems[0]) * TRECHIST_MAX_RANGES);
350    hist_mask = 0;
351
352    for (i = 1; i <= UCHAR_MAX; ++i)
353    {
354        s = lsquic_trechist_insert(&hist_mask, hist_elems, i);
355        assert(s == 0);
356    }
357
358    s = lsquic_trechist_insert(&hist_mask, hist_elems, i);
359    assert(s == -1);    /* Overflow */
360
361    /* Always successful inserting new entries: */
362    for (i = 0; i < TRECHIST_MAX_RANGES * 2; ++i)
363    {
364        s = lsquic_trechist_insert(&hist_mask, hist_elems, 1000 + 2 * i);
365        assert(s == 0);
366    }
367
368    /* Always successful inserting new entries in descending order, too: */
369    for (i = 0; i < TRECHIST_MAX_RANGES * 2; ++i)
370    {
371        s = lsquic_trechist_insert(&hist_mask, hist_elems, 10000 - 2 * i);
372        assert(s == 0);
373    }
374
375    /* Test merge where count exceeds max: */
376    hist_mask = 0;
377    lsquic_trechist_copy_ranges(&hist_mask, hist_elems,
378        & (struct str_range_iter) { .str = "[400-202][200-1]", },
379        next_str_range, next_str_range);
380    s = lsquic_trechist_insert(&hist_mask, hist_elems, 201);
381    assert(s == -1);
382
383    free(hist_elems);
384}
385
386
387static void
388test_overflow (void)
389{
390    trechist_mask_t       mask;
391    struct trechist_elem *elems;
392    int s;
393    char buf[0x1000];
394
395    struct str_range_iter str_iter = { .str =
396        "[395-390]"     /* 1 */
397        "[385-380]"
398        "[375-370]"
399        "[365-360]"
400        "[355-350]"     /* 5 */
401        "[345-340]"
402        "[335-330]"
403        "[325-320]"
404        "[315-310]"
405        "[305-300]"     /* 10 */
406        "[295-290]"
407        "[285-280]"
408        "[275-270]"
409        "[265-260]"
410        "[255-250]"     /* 15 */
411        "[245-240]"     /* 16 */
412        "[235-230]"     /* Overflow vvvvvv */
413        "[225-220]"
414        "[215-210]"
415        "[205-200]"
416        "[195-190]"
417        "[185-180]" };
418
419    elems = malloc(sizeof(elems[0]) * TRECHIST_MAX_RANGES);
420    lsquic_trechist_copy_ranges(&mask, elems, &str_iter, next_str_range,
421                                                         next_str_range);
422
423    rechist2str(mask, elems, buf, sizeof(buf));
424    assert(0 == strcmp(buf,
425        "[395-390]"     /* 1 */
426        "[385-380]"
427        "[375-370]"
428        "[365-360]"
429        "[355-350]"     /* 5 */
430        "[345-340]"
431        "[335-330]"
432        "[325-320]"
433        "[315-310]"
434        "[305-300]"     /* 10 */
435        "[295-290]"
436        "[285-280]"
437        "[275-270]"
438        "[265-260]"
439        "[255-250]"     /* 15 */
440        "[245-240]"     /* 16 */));
441
442    s = lsquic_trechist_insert(&mask, elems, 400);
443    assert(s == 0);
444    rechist2str(mask, elems, buf, sizeof(buf));
445    assert(0 == strcmp(buf,
446        "[400-400]"
447        "[395-390]"
448        "[385-380]"
449        "[375-370]"
450        "[365-360]"
451        "[355-350]"
452        "[345-340]"
453        "[335-330]"
454        "[325-320]"
455        "[315-310]"
456        "[305-300]"
457        "[295-290]"
458        "[285-280]"
459        "[275-270]"
460        "[265-260]"
461        "[255-250]"
462    ));
463
464    /* One more for a good measure */
465    s = lsquic_trechist_insert(&mask, elems, 402);
466    assert(s == 0);
467    rechist2str(mask, elems, buf, sizeof(buf));
468    assert(0 == strcmp(buf,
469        "[402-402]"
470        "[400-400]"
471        "[395-390]"
472        "[385-380]"
473        "[375-370]"
474        "[365-360]"
475        "[355-350]"
476        "[345-340]"
477        "[335-330]"
478        "[325-320]"
479        "[315-310]"
480        "[305-300]"
481        "[295-290]"
482        "[285-280]"
483        "[275-270]"
484        "[265-260]"
485    ));
486
487    s = lsquic_trechist_insert(&mask, elems, 401);
488    assert(s == 0);
489    s = lsquic_trechist_insert(&mask, elems, 500);
490    assert(s == 0);
491    s = lsquic_trechist_insert(&mask, elems, 200);
492    assert(s == 0);
493    s = lsquic_trechist_insert(&mask, elems, 267);
494    assert(s == 0);
495
496    /* One more for a good measure */
497    s = lsquic_trechist_insert(&mask, elems, 402);
498    assert(s == 0);
499    rechist2str(mask, elems, buf, sizeof(buf));
500    assert(0 == strcmp(buf,
501        "[500-500]"
502        "[402-400]"
503        "[395-390]"
504        "[385-380]"
505        "[375-370]"
506        "[365-360]"
507        "[355-350]"
508        "[345-340]"
509        "[335-330]"
510        "[325-320]"
511        "[315-310]"
512        "[305-300]"
513        "[295-290]"
514        "[285-280]"
515        "[275-270]"
516        "[267-267]"
517    ));
518
519    free(elems);
520}
521
522
523int
524main (void)
525{
526    basic_test();
527    test4();
528    test5();
529    test_limits();
530    test_overflow();
531
532    return 0;
533}
534