1/**
2 * hdr_histogram_log_test.c
3 * Written by Michael Barker and released to the public domain,
4 * as explained at http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7#include <stdint.h>
8#include <stdbool.h>
9#include <stdlib.h>
10#include <math.h>
11#include <string.h>
12#include <errno.h>
13#include <inttypes.h>
14#include <time.h>
15
16#include <stdio.h>
17#include "hdr_time.h"
18#include <hdr_histogram.h>
19#include <hdr_histogram_log.h>
20#include <hdr_encoding.h>
21#include "minunit.h"
22
23#if defined(_MSC_VER)
24#pragma warning(push)
25#pragma warning(disable: 4996)
26#endif
27
28int tests_run = 0;
29
30static bool compare_int(int a, int b)
31{
32    if (a == b)
33    {
34        return true;
35    }
36
37    printf("%d != %d\n", a, b);
38    return false;
39}
40
41static long ns_to_ms(long ns)
42{
43    return (ns / 1000000) * 1000000;
44}
45
46static bool compare_timespec(hdr_timespec* a, hdr_timespec* b)
47{
48    char a_str[128];
49    char b_str[128];
50
51    long a_tv_msec = ns_to_ms(a->tv_nsec);
52    long b_tv_msec = ns_to_ms(b->tv_nsec);
53
54    // Allow off by 1 millisecond due to parsing and rounding.
55    if (a->tv_sec == b->tv_sec && labs(a_tv_msec - b_tv_msec) <= 1000000)
56    {
57        return true;
58    }
59
60    if (a->tv_sec != b->tv_sec)
61    {
62#if defined(_MSC_VER)
63        _ctime32_s(a_str, sizeof(a_str), &a->tv_sec);
64        _ctime32_s(b_str, sizeof(b_str), &b->tv_sec);
65        printf("tv_sec: %s != %s\n", a_str, b_str);
66#else
67        printf(
68            "tv_sec: %s != %s\n",
69            ctime_r(&a->tv_sec, a_str),
70            ctime_r(&b->tv_sec, b_str));
71#endif
72    }
73
74    if (a_tv_msec == b_tv_msec)
75    {
76        printf("%ld != %ld\n", a->tv_nsec, b->tv_nsec);
77    }
78
79    return false;
80}
81
82static bool compare_string(const char* a, const char* b, size_t len)
83{
84    if (strncmp(a, b, len) == 0)
85    {
86        return true;
87    }
88
89    printf("%s != %s\n", a, b);
90    return false;
91}
92
93static bool compare_histogram(struct hdr_histogram* a, struct hdr_histogram* b)
94{
95    if (a->counts_len != b->counts_len)
96    {
97        printf(
98            "a.counts_len = %"PRIu32", b.counts_len = %"PRIu32"\n",
99            a->counts_len, b->counts_len);
100        return false;
101    }
102
103    int64_t a_max = hdr_max(a);
104    int64_t b_max = hdr_max(b);
105
106    if (a_max != b_max)
107    {
108        printf("a.max = %"PRIu64", b.max = %"PRIu64"\n", a_max, b_max);
109//        return false;
110    }
111
112    int64_t a_min = hdr_min(a);
113    int64_t b_min = hdr_min(b);
114
115    if (a_min != b_min)
116    {
117        printf("a.min = %"PRIu64", b.min = %"PRIu64"\n", a_min, b_min);
118//        return false;
119    }
120
121    size_t a_size = hdr_get_memory_size(a);
122    size_t b_size = hdr_get_memory_size(b);
123
124    if (a_size != b_size)
125    {
126        printf("a.size: %zu, b.size: %zu\n", a_size, b_size);
127        return false;
128    }
129
130    size_t counts_size = a->counts_len * sizeof(int64_t);
131
132    if (memcmp(a->counts, b->counts, counts_size) == 0)
133    {
134        return true;
135    }
136
137    printf("%s\n", "Counts incorrect");
138
139    struct hdr_iter iter_a;
140    struct hdr_iter iter_b;
141
142    hdr_iter_init(&iter_a, a);
143    hdr_iter_init(&iter_b, b);
144
145    while (hdr_iter_next(&iter_a) && hdr_iter_next(&iter_b))
146    {
147        if (iter_a.count != iter_b.count ||
148            iter_a.value != iter_b.value)
149        {
150            printf(
151                "A - value: %"PRIu64", count: %"PRIu64", B - value: %"PRIu64", count: %"PRIu64"\n",
152                iter_a.value, iter_a.count,
153                iter_b.value, iter_b.count);
154        }
155    }
156
157    return false;
158}
159
160static struct hdr_histogram* raw_histogram = NULL;
161static struct hdr_histogram* cor_histogram = NULL;
162
163static void load_histograms()
164{
165    free(raw_histogram);
166    free(cor_histogram);
167
168    hdr_alloc(INT64_C(3600) * 1000 * 1000, 3, &raw_histogram);
169    hdr_alloc(INT64_C(3600) * 1000 * 1000, 3, &cor_histogram);
170
171    int i;
172    for (i = 0; i < 10000; i++)
173    {
174        hdr_record_value(raw_histogram, 1000);
175        hdr_record_corrected_value(cor_histogram, 1000, 10000);
176    }
177
178    hdr_record_value(raw_histogram, 100000000);
179    hdr_record_corrected_value(cor_histogram, 100000000, 10000);
180}
181
182static bool validate_return_code(int rc)
183{
184    if (rc == 0)
185    {
186        return true;
187    }
188
189    printf("%s\n", hdr_strerror(rc));
190    return false;
191}
192
193// Prototypes to avoid exporting in header file.
194void hdr_base64_encode_block(const uint8_t* input, char* output);
195
196void hdr_base64_decode_block(const char* input, uint8_t* output);
197int hdr_encode_compressed(struct hdr_histogram* h, uint8_t** buffer, size_t* length);
198int hdr_decode_compressed(
199    uint8_t* buffer, size_t length, struct hdr_histogram** histogram);
200void hex_dump (char *desc, void *addr, int len);
201
202static char* test_encode_and_decode_compressed()
203{
204    load_histograms();
205
206    uint8_t* buffer = NULL;
207    size_t len = 0;
208    int rc = 0;
209    struct hdr_histogram* actual = NULL;
210    struct hdr_histogram* expected = raw_histogram;
211
212    rc = hdr_encode_compressed(expected, &buffer, &len);
213    mu_assert("Did not encode", validate_return_code(rc));
214
215    rc = hdr_decode_compressed(buffer, len, &actual);
216    mu_assert("Did not decode", validate_return_code(rc));
217
218    mu_assert("Loaded histogram is null", actual != NULL);
219
220    mu_assert(
221        "Comparison did not match",
222        compare_histogram(expected, actual));
223
224    free(actual);
225
226    return 0;
227}
228
229static char* test_encode_and_decode_compressed2()
230{
231    load_histograms();
232
233    uint8_t* buffer = NULL;
234    size_t len = 0;
235    int rc = 0;
236    struct hdr_histogram* actual = NULL;
237    struct hdr_histogram* expected = cor_histogram;
238
239    rc = hdr_encode_compressed(expected, &buffer, &len);
240    mu_assert("Did not encode", validate_return_code(rc));
241
242    rc = hdr_decode_compressed(buffer, len, &actual);
243    mu_assert("Did not decode", validate_return_code(rc));
244
245    mu_assert("Loaded histogram is null", actual != NULL);
246
247    mu_assert(
248            "Comparison did not match",
249            compare_histogram(expected, actual));
250
251    free(actual);
252
253    return 0;
254}
255
256static char* test_bounds_check_on_decode()
257{
258    load_histograms();
259
260    uint8_t* buffer = NULL;
261    size_t len = 0;
262    int rc = 0;
263    struct hdr_histogram* actual = NULL;
264    struct hdr_histogram* expected = cor_histogram;
265
266    rc = hdr_encode_compressed(expected, &buffer, &len);
267    mu_assert("Did not encode", validate_return_code(rc));
268
269    rc = hdr_decode_compressed(buffer, len - 1, &actual);
270    mu_assert("Should have be invalid", compare_int64(EINVAL, rc));
271    mu_assert("Should not have built histogram", NULL == actual);
272
273    return 0;
274}
275
276static char* test_encode_and_decode_base64()
277{
278    load_histograms();
279
280    uint8_t* buffer = NULL;
281    uint8_t* decoded = NULL;
282    char* encoded = NULL;
283    size_t len = 0;
284    int rc = 0;
285
286    rc = hdr_encode_compressed(cor_histogram, &buffer, &len);
287    mu_assert("Did not encode", validate_return_code(rc));
288
289    size_t encoded_len = hdr_base64_encoded_len(len);
290    size_t decoded_len = hdr_base64_decoded_len(encoded_len);
291    encoded = calloc(encoded_len + 1, sizeof(char));
292    decoded = calloc(decoded_len, sizeof(uint8_t));
293
294    hdr_base64_encode(buffer, len, encoded, encoded_len);
295    hdr_base64_decode(encoded, encoded_len, decoded, decoded_len);
296
297    mu_assert("Should be same", memcmp(buffer, decoded, len) == 0);
298
299    return 0;
300}
301
302
303static char* test_encode_and_decode_compressed_large()
304{
305    const int64_t limit = INT64_C(3600) * 1000 * 1000;
306    struct hdr_histogram* actual = NULL;
307    struct hdr_histogram* expected = NULL;
308    uint8_t* buffer = NULL;
309    size_t len = 0;
310    int rc = 0;
311    hdr_init(1, limit, 4, &expected);
312    srand(5);
313
314    int i;
315    for (i = 0; i < 8070; i++)
316    {
317        hdr_record_value(expected, rand() % limit);
318    }
319
320    rc = hdr_encode_compressed(expected, &buffer, &len);
321    mu_assert("Did not encode", validate_return_code(rc));
322
323    rc = hdr_decode_compressed(buffer, len, &actual);
324    mu_assert("Did not decode", validate_return_code(rc));
325
326    mu_assert("Loaded histogram is null", actual != NULL);
327
328    mu_assert(
329        "Comparison did not match",
330        compare_histogram(expected, actual));
331
332    free(expected);
333    free(actual);
334
335    return 0;
336}
337
338
339static bool assert_base64_encode(const char* input, const char* expected)
340{
341    size_t input_len = strlen(input);
342    int output_len = (int) (ceil(input_len / 3.0) * 4.0);
343
344    char* output = calloc(sizeof(char), output_len);
345
346    int r = hdr_base64_encode((uint8_t*)input, input_len, output, output_len);
347    bool result = r == 0 && compare_string(expected, output, output_len);
348
349    free(output);
350
351    return result;
352}
353
354static char* base64_encode_encodes_without_padding()
355{
356    mu_assert(
357        "Encoding without padding",
358        assert_base64_encode(
359            "any carnal pleasur",
360            "YW55IGNhcm5hbCBwbGVhc3Vy"));
361
362    return 0;
363}
364
365static char* base64_encode_encodes_with_padding()
366{
367    mu_assert(
368        "Encoding with padding '='",
369        assert_base64_encode(
370            "any carnal pleasure.",
371            "YW55IGNhcm5hbCBwbGVhc3VyZS4="));
372    mu_assert(
373        "Encoding with padding '=='",
374        assert_base64_encode(
375            "any carnal pleasure",
376            "YW55IGNhcm5hbCBwbGVhc3VyZQ=="));
377
378    return 0;
379}
380
381static char* base64_encode_fails_with_invalid_lengths()
382{
383    mu_assert(
384        "Output length not 4/3 of input length",
385        hdr_base64_encode(NULL, 9, NULL, 11));
386
387    return 0;
388}
389
390static char* base64_encode_block_encodes_3_bytes()
391{
392    char output[5] = { 0 };
393
394    hdr_base64_encode_block((uint8_t*)"Man", output);
395    mu_assert("Encoding", compare_string("TWFu", output, 4));
396
397    return 0;
398}
399
400static char* base64_decode_block_decodes_4_chars()
401{
402    uint8_t output[4] = { 0 };
403
404    hdr_base64_decode_block("TWFu", output);
405    mu_assert("Decoding", compare_string("Man", (char*) output, 3));
406
407    return 0;
408}
409
410static bool assert_base64_decode(const char* base64_encoded, const char* expected)
411{
412    size_t encoded_len = strlen(base64_encoded);
413    size_t output_len = (encoded_len / 4) * 3;
414
415    uint8_t* output = calloc(sizeof(uint8_t), output_len);
416
417    int result = hdr_base64_decode(base64_encoded, encoded_len, output, output_len);
418
419    return result == 0 && compare_string(expected, (char*)output, output_len);
420}
421
422static char* base64_decode_decodes_strings_without_padding()
423{
424    mu_assert(
425        "Encoding without padding",
426        assert_base64_decode(
427            "YW55IGNhcm5hbCBwbGVhc3Vy",
428            "any carnal pleasur"));
429
430    return 0;
431}
432
433static char* base64_decode_decodes_strings_with_padding()
434{
435    mu_assert(
436        "Encoding with padding '='",
437        assert_base64_decode(
438            "YW55IGNhcm5hbCBwbGVhc3VyZS4=",
439            "any carnal pleasure."));
440
441    mu_assert(
442        "Encoding with padding '=='",
443        assert_base64_decode(
444            "YW55IGNhcm5hbCBwbGVhc3VyZQ==",
445            "any carnal pleasure"));
446
447    return 0;
448}
449
450static char* base64_decode_fails_with_invalid_lengths()
451{
452    mu_assert("Input length % 4 != 0", hdr_base64_decode(NULL, 5, NULL, 3) != 0);
453    mu_assert("Input length < 4", hdr_base64_decode(NULL, 3, NULL, 3) != 0);
454    mu_assert(
455        "Output length not 3/4 of input length",
456        hdr_base64_decode(NULL, 8, NULL, 7) != 0);
457
458    return 0;
459}
460
461static char* writes_and_reads_log()
462{
463    const char* file_name = "histogram.log";
464    hdr_timespec timestamp;
465    hdr_timespec interval;
466
467    hdr_gettime(&timestamp);
468
469    interval.tv_sec = 5;
470    interval.tv_nsec = 2000000;
471
472    struct hdr_log_writer writer;
473    struct hdr_log_reader reader;
474    hdr_log_writer_init(&writer);
475    hdr_log_reader_init(&reader);
476    int rc = 0;
477
478    FILE* log_file = fopen(file_name, "w+");
479
480    rc = hdr_log_write_header(&writer, log_file, "Test log", &timestamp);
481    mu_assert("Failed header write", validate_return_code(rc));
482    hdr_log_write(&writer, log_file, &timestamp, &interval, cor_histogram);
483    mu_assert("Failed corrected write", validate_return_code(rc));
484    hdr_log_write(&writer, log_file, &timestamp, &interval, raw_histogram);
485    mu_assert("Failed raw write", validate_return_code(rc));
486
487    fprintf(log_file, "\n");
488
489    fflush(log_file);
490    fclose(log_file);
491
492    log_file = fopen(file_name, "r");
493
494    struct hdr_histogram* read_cor_histogram = NULL;
495    struct hdr_histogram* read_raw_histogram = NULL;
496
497    rc = hdr_log_read_header(&reader, log_file);
498    mu_assert("Failed header read", validate_return_code(rc));
499    mu_assert("Incorrect major version", compare_int(reader.major_version, 1));
500    mu_assert("Incorrect minor version", compare_int(reader.minor_version, 2));
501    mu_assert(
502        "Incorrect start timestamp",
503        compare_timespec(&reader.start_timestamp, &timestamp));
504
505    hdr_timespec actual_timestamp;
506    hdr_timespec actual_interval;
507
508    rc = hdr_log_read(
509        &reader, log_file, &read_cor_histogram,
510        &actual_timestamp, &actual_interval);
511    mu_assert("Failed corrected read", validate_return_code(rc));
512    mu_assert(
513        "Incorrect first timestamp", compare_timespec(&actual_timestamp, &timestamp));
514    mu_assert(
515        "Incorrect first interval", compare_timespec(&actual_interval, &interval));
516
517    rc = hdr_log_read(&reader, log_file, &read_raw_histogram, NULL, NULL);
518    mu_assert("Failed raw read", validate_return_code(rc));
519
520    mu_assert(
521        "Histograms do not match",
522        compare_histogram(cor_histogram, read_cor_histogram));
523
524    mu_assert(
525        "Histograms do not match",
526        compare_histogram(raw_histogram, read_raw_histogram));
527
528    rc = hdr_log_read(&reader, log_file, &read_cor_histogram, NULL, NULL);
529    mu_assert("No EOF at end of file", rc == EOF);
530
531    fclose(log_file);
532    remove(file_name);
533
534    return 0;
535}
536
537static char* log_reader_aggregates_into_single_histogram()
538{
539    const char* file_name = "histogram.log";
540    hdr_timespec timestamp;
541    hdr_timespec interval;
542
543    hdr_gettime(&timestamp);
544    interval.tv_sec = 5;
545    interval.tv_nsec = 2000000;
546
547    struct hdr_log_writer writer;
548    struct hdr_log_reader reader;
549    hdr_log_writer_init(&writer);
550    hdr_log_reader_init(&reader);
551    int rc = 0;
552
553    FILE* log_file = fopen(file_name, "w+");
554
555    hdr_log_write_header(&writer, log_file, "Test log", &timestamp);
556    hdr_log_write(&writer, log_file, &timestamp, &interval, cor_histogram);
557    hdr_log_write(&writer, log_file, &timestamp, &interval, raw_histogram);
558    fflush(log_file);
559    fclose(log_file);
560
561    log_file = fopen(file_name, "r");
562
563    struct hdr_histogram* histogram;
564    hdr_alloc(INT64_C(3600) * 1000 * 1000, 3, &histogram);
565
566    rc = hdr_log_read_header(&reader, log_file);
567    mu_assert("Failed header read", validate_return_code(rc));
568    rc = hdr_log_read(&reader, log_file, &histogram, NULL, NULL);
569    mu_assert("Failed corrected read", validate_return_code(rc));
570    rc = hdr_log_read(&reader, log_file, &histogram, NULL, NULL);
571    mu_assert("Failed raw read", validate_return_code(rc));
572
573    struct hdr_iter iter;
574    hdr_iter_recorded_init(&iter, histogram);
575    int64_t expected_total_count =
576        raw_histogram->total_count + cor_histogram->total_count;
577
578    mu_assert(
579        "Total counts incorrect",
580        compare_int64(histogram->total_count, expected_total_count));
581
582    while (hdr_iter_next(&iter))
583    {
584        int64_t count = iter.count;
585        int64_t value = iter.value;
586
587        int64_t expected_count =
588            hdr_count_at_value(raw_histogram, value) +
589            hdr_count_at_value(cor_histogram, value);
590
591        mu_assert("Incorrect count", compare_int64(count, expected_count));
592    }
593
594    fclose(log_file);
595    remove(file_name);
596    free(histogram);
597
598    return 0;
599}
600
601static char* log_reader_fails_with_incorrect_version()
602{
603    const char* log_with_invalid_version =
604    "#[Test log]\n"
605    "#[Histogram log format version 1.04]\n"
606    "#[StartTime: 1404700005.222 (seconds since epoch), Mon Jul 02:26:45 GMT 2014]\n"
607    "StartTimestamp\",\"EndTimestamp\",\"Interval_Max\",\"Interval_Compressed_Histogram\"\n";
608    const char* file_name = "histogram_with_invalid_version.log";
609    struct hdr_log_reader reader;
610    FILE* log_file;
611
612    log_file = fopen(file_name, "w+");
613    fprintf(log_file, "%s", log_with_invalid_version);
614    fflush(log_file);
615    fclose(log_file);
616
617    log_file = fopen(file_name, "r");
618    hdr_log_reader_init(&reader);
619    int r = hdr_log_read_header(&reader, log_file);
620
621    mu_assert("Should error with incorrect version", r == HDR_LOG_INVALID_VERSION);
622
623    fclose(log_file);
624    remove(file_name);
625
626    return 0;
627}
628
629static char* test_encode_decode_empty()
630{
631    struct hdr_histogram *histogram, *hdr_new = NULL;
632    hdr_alloc(INT64_C(3600) * 1000 * 1000, 3, &histogram);
633
634    char *data;
635
636    mu_assert("Failed to encode histogram data", hdr_log_encode(histogram, &data) == 0);
637    mu_assert("Failed to decode histogram data", hdr_log_decode(&hdr_new, data, strlen(data)) == 0);
638    mu_assert("Histograms should be the same", compare_histogram(histogram, hdr_new));
639    // mu_assert("Mean different after encode/decode", compare_double(hdr_mean(histogram), hdr_mean(hdr_new), 0.001));
640    free(histogram);
641    free(hdr_new);
642    free(data);
643    return 0;
644}
645
646static char* test_string_encode_decode()
647{
648    struct hdr_histogram *histogram, *hdr_new = NULL;
649    hdr_alloc(INT64_C(3600) * 1000 * 1000, 3, &histogram);
650
651    int i;
652    for (i = 1; i < 100; i++)
653    {
654        hdr_record_value(histogram, i*i);
655    }
656
657    char *data;
658
659    mu_assert("Failed to encode histogram data", hdr_log_encode(histogram, &data) == 0);
660    mu_assert("Failed to decode histogram data", hdr_log_decode(&hdr_new, data, strlen(data)) == 0);
661    mu_assert("Histograms should be the same", compare_histogram(histogram, hdr_new));
662    mu_assert("Mean different after encode/decode", compare_double(hdr_mean(histogram), hdr_mean(hdr_new), 0.001));
663
664    return 0;
665}
666
667static char* test_string_encode_decode_2()
668{
669    struct hdr_histogram *histogram, *hdr_new = NULL;
670    hdr_alloc(1000, 3, &histogram);
671
672    int i;
673    for (i = 1; i < histogram->highest_trackable_value; i++)
674    {
675        hdr_record_value(histogram, i);
676    }
677
678    char *data;
679
680    mu_assert(
681        "Failed to encode histogram data", validate_return_code(hdr_log_encode(histogram, &data)));
682    mu_assert(
683        "Failed to decode histogram data", validate_return_code(hdr_log_decode(&hdr_new, data, strlen(data))));
684    mu_assert("Histograms should be the same", compare_histogram(histogram, hdr_new));
685    mu_assert("Mean different after encode/decode", compare_double(hdr_mean(histogram), hdr_mean(hdr_new), 0.001));
686
687    return 0;
688}
689
690
691static char* decode_v1_log()
692{
693    const char* v1_log = "jHiccup-2.0.6.logV1.hlog";
694
695    FILE* f = fopen(v1_log, "r");
696    mu_assert("Can not open v1 log file", f != NULL);
697
698    struct hdr_histogram* accum;
699    hdr_init(1, INT64_C(3600000000000), 3, &accum);
700
701    struct hdr_histogram* h = NULL;
702    struct hdr_log_reader reader;
703    hdr_timespec timestamp;
704    hdr_timespec interval;
705
706    hdr_log_reader_init(&reader);
707
708    int rc = hdr_log_read_header(&reader, f);
709    mu_assert("Failed to read header", rc == 0);
710
711    int histogram_count = 0;
712    int64_t total_count = 0;
713    while ((rc = hdr_log_read(&reader, f, &h, &timestamp, &interval)) != EOF)
714    {
715        mu_assert("Failed to read histogram", rc == 0);
716        histogram_count++;
717        total_count += h->total_count;
718        int64_t dropped = hdr_add(accum, h);
719        mu_assert("Dropped events", compare_int64(dropped, 0));
720
721        free(h);
722        h = NULL;
723    }
724
725    mu_assert("Wrong number of histograms", compare_int(histogram_count, 88));
726    mu_assert("Wrong total count", compare_int64(total_count, 65964));
727    mu_assert("99.9 percentile wrong", compare_int64(1829765119, hdr_value_at_percentile(accum, 99.9)));
728    mu_assert("max value wrong", compare_int64(1888485375, hdr_max(accum)));
729    mu_assert("Seconds wrong", compare_int64(1438867590, reader.start_timestamp.tv_sec));
730    mu_assert("Nanoseconds wrong", compare_int64(285000000, reader.start_timestamp.tv_nsec));
731
732    return 0;
733}
734
735
736static char* decode_v2_log()
737{
738    const char* v2_log = "jHiccup-2.0.7S.logV2.hlog";
739
740    FILE* f = fopen(v2_log, "r");
741    mu_assert("Can not open v2 log file", f != NULL);
742
743    struct hdr_histogram* accum;
744    hdr_init(1, INT64_C(3600000000000), 3, &accum);
745
746    struct hdr_histogram* h = NULL;
747    struct hdr_log_reader reader;
748    hdr_timespec timestamp;
749    hdr_timespec interval;
750
751    hdr_log_reader_init(&reader);
752
753    int rc = hdr_log_read_header(&reader, f);
754    mu_assert("Failed to read header", validate_return_code(rc));
755
756    int histogram_count = 0;
757    int64_t total_count = 0;
758    while ((rc = hdr_log_read(&reader, f, &h, &timestamp, &interval)) != EOF)
759    {
760        mu_assert("Failed to read histogram", validate_return_code(rc));
761        histogram_count++;
762        total_count += h->total_count;
763        int64_t dropped = hdr_add(accum, h);
764        mu_assert("Dropped events", compare_int64(dropped, 0));
765
766        free(h);
767        h = NULL;
768    }
769
770    mu_assert("Wrong number of histograms", compare_int(histogram_count, 62));
771    mu_assert("Wrong total count", compare_int64(total_count, 48761));
772    mu_assert("99.9 percentile wrong", compare_int64(1745879039, hdr_value_at_percentile(accum, 99.9)));
773    mu_assert("max value wrong", compare_int64(1796210687, hdr_max(accum)));
774    mu_assert("Seconds wrong", compare_int64(1441812279, reader.start_timestamp.tv_sec));
775    mu_assert("Nanoseconds wrong", compare_int64(474000000, reader.start_timestamp.tv_nsec));
776
777    return 0;
778}
779
780static char* decode_v3_log()
781{
782    const char* v3_log = "jHiccup-2.0.7S.logV3.hlog";
783
784    FILE* f = fopen(v3_log, "r");
785    mu_assert("Can not open v3 log file", f != NULL);
786
787    struct hdr_histogram* accum;
788    hdr_init(1, INT64_C(3600000000000), 3, &accum);
789
790    struct hdr_histogram* h = NULL;
791    struct hdr_log_reader reader;
792    hdr_timespec timestamp;
793    hdr_timespec interval;
794
795    hdr_log_reader_init(&reader);
796
797    int rc = hdr_log_read_header(&reader, f);
798    mu_assert("Failed to read header", validate_return_code(rc));
799
800    int histogram_count = 0;
801    int64_t total_count = 0;
802    while ((rc = hdr_log_read(&reader, f, &h, &timestamp, &interval)) != EOF)
803    {
804        mu_assert("Failed to read histogram", validate_return_code(rc));
805        histogram_count++;
806        total_count += h->total_count;
807        int64_t dropped = hdr_add(accum, h);
808        mu_assert("Dropped events", compare_int64(dropped, 0));
809
810        free(h);
811        h = NULL;
812    }
813
814    mu_assert("Wrong number of histograms", compare_int(histogram_count, 62));
815    mu_assert("Wrong total count", compare_int64(total_count, 48761));
816    mu_assert("99.9 percentile wrong", compare_int64(1745879039, hdr_value_at_percentile(accum, 99.9)));
817    mu_assert("max value wrong", compare_int64(1796210687, hdr_max(accum)));
818    mu_assert("Seconds wrong", compare_int64(1441812279, reader.start_timestamp.tv_sec));
819    mu_assert("Nanoseconds wrong", compare_int64(474000000, reader.start_timestamp.tv_nsec));
820
821    return 0;
822}
823
824static char* decode_v0_log()
825{
826    const char* v1_log = "jHiccup-2.0.1.logV0.hlog";
827
828    FILE* f = fopen(v1_log, "r");
829    mu_assert("Can not open v1 log file", f != NULL);
830
831    struct hdr_histogram* accum;
832    hdr_init(1, INT64_C(3600000000000), 3, &accum);
833
834    struct hdr_histogram* h = NULL;
835    struct hdr_log_reader reader;
836    hdr_timespec timestamp;
837    hdr_timespec interval;
838
839    hdr_log_reader_init(&reader);
840
841    int rc = hdr_log_read_header(&reader, f);
842    mu_assert("Failed to read header", rc == 0);
843
844    int histogram_count = 0;
845    int64_t total_count = 0;
846    while ((rc = hdr_log_read(&reader, f, &h, &timestamp, &interval)) != EOF)
847    {
848        mu_assert("Failed to read histogram", rc == 0);
849        histogram_count++;
850        total_count += h->total_count;
851        int64_t dropped = hdr_add(accum, h);
852        mu_assert("Dropped events", compare_int64(dropped, 0));
853
854        free(h);
855        h = NULL;
856    }
857
858    mu_assert("Wrong number of histograms", compare_int(histogram_count, 81));
859    mu_assert("Wrong total count", compare_int64(total_count, 61256));
860    mu_assert("99.9 percentile wrong", compare_int64(1510998015, hdr_value_at_percentile(accum, 99.9)));
861    mu_assert("max value wrong", compare_int64(1569718271, hdr_max(accum)));
862    mu_assert("Seconds wrong", compare_int64(1438869961, reader.start_timestamp.tv_sec));
863    mu_assert("Nanoseconds wrong", compare_int64(225000000, reader.start_timestamp.tv_nsec));
864
865    return 0;
866}
867
868static struct mu_result all_tests()
869{
870    tests_run = 0;
871
872    mu_run_test(test_encode_decode_empty);
873    mu_run_test(test_encode_and_decode_compressed);
874    mu_run_test(test_encode_and_decode_compressed2);
875    mu_run_test(test_encode_and_decode_compressed_large);
876    mu_run_test(test_encode_and_decode_base64);
877    mu_run_test(test_bounds_check_on_decode);
878
879    mu_run_test(base64_decode_block_decodes_4_chars);
880    mu_run_test(base64_decode_fails_with_invalid_lengths);
881    mu_run_test(base64_decode_decodes_strings_without_padding);
882    mu_run_test(base64_decode_decodes_strings_with_padding);
883
884    mu_run_test(base64_encode_block_encodes_3_bytes);
885    mu_run_test(base64_encode_fails_with_invalid_lengths);
886    mu_run_test(base64_encode_encodes_without_padding);
887    mu_run_test(base64_encode_encodes_with_padding);
888
889    mu_run_test(writes_and_reads_log);
890    mu_run_test(log_reader_aggregates_into_single_histogram);
891    mu_run_test(log_reader_fails_with_incorrect_version);
892
893    mu_run_test(test_string_encode_decode);
894    mu_run_test(test_string_encode_decode_2);
895
896    mu_run_test(decode_v3_log);
897    mu_run_test(decode_v2_log);
898    mu_run_test(decode_v1_log);
899    mu_run_test(decode_v0_log);
900
901    free(raw_histogram);
902    free(cor_histogram);
903
904    mu_ok;
905}
906
907static int hdr_histogram_log_run_tests()
908{
909    struct mu_result result = all_tests();
910
911    if (result.message != 0)
912    {
913        printf("hdr_histogram_log_test.%s(): %s\n", result.test, result.message);
914    }
915    else
916    {
917        printf("ALL TESTS PASSED\n");
918    }
919
920    printf("Tests run: %d\n", tests_run);
921
922    return result.message == NULL ? 0 : -1;
923}
924
925int main()
926{
927    return hdr_histogram_log_run_tests();
928}
929
930#if defined(_MSC_VER)
931#pragma warning(pop)
932#endif
933