added more unit tests; fixed the issue where incremental values where gracefully interpolated
Costa Tsaousis (ktsaou) committed
Jan 21, 2016 at 01:09 UTC
b475c58273d0f76e51ab43d30b5bc31249fdd0d7
4 files changed
+562
-90
src/main.c
+3
-15
@@ -208,7 +208,7 @@ int main(int argc, char **argv)
208
}
209
i++;
210
}
211
- else if(strcmp(argv[i], "-df") == 0 && (i+1) < argc) { config_set("global", "debug flags", argv[i+1]); i++; }
211
+ else if(strcmp(argv[i], "-df") == 0 && (i+1) < argc) { config_set("global", "debug flags", argv[i+1]); debug_flags = strtoull(argv[i+1], NULL, 0); i++; }
212
else if(strcmp(argv[i], "-p") == 0 && (i+1) < argc) { config_set("global", "port", argv[i+1]); i++; }
213
else if(strcmp(argv[i], "-u") == 0 && (i+1) < argc) { config_set("global", "run as user", argv[i+1]); i++; }
214
else if(strcmp(argv[i], "-l") == 0 && (i+1) < argc) { config_set("global", "history", argv[i+1]); i++; }
@@ -216,21 +216,9 @@ int main(int argc, char **argv)
216
else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) { config_set("global", "host access prefix", argv[i+1]); i++; }
217
else if(strcmp(argv[i], "-nodeamon") == 0 || strcmp(argv[i], "-nd") == 0) dont_fork = 1;
218
else if(strcmp(argv[i], "--unittest") == 0) {
219
- if(unit_test_storage()) exit(1);
220
- exit(0);
219
rrd_update_every = 1;
222
- if(unit_test(1000000, 0)) exit(1);
223
- if(unit_test(1000000, 500000)) exit(1);
224
- if(unit_test(1000000, 100000)) exit(1);
225
- if(unit_test(1000000, 900000)) exit(1);
226
- if(unit_test(2000000, 0)) exit(1);
227
- if(unit_test(2000000, 500000)) exit(1);
228
- if(unit_test(2000000, 100000)) exit(1);
229
- if(unit_test(2000000, 900000)) exit(1);
230
- if(unit_test(500000, 500000)) exit(1);
231
- //if(unit_test(500000, 100000)) exit(1); // FIXME: the expected numbers are wrong
232
- //if(unit_test(500000, 900000)) exit(1); // FIXME: the expected numbers are wrong
233
- if(unit_test(500000, 0)) exit(1);
220
+ if(run_all_mockup_tests()) exit(1);
221
+ if(unit_test_storage()) exit(1);
222
fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
223
exit(0);
224
}
src/rrd.c
+119
-59
@@ -804,6 +804,8 @@ void rrdset_next(RRDSET *st)
804
gettimeofday(&now, NULL);
805
microseconds = usecdiff(&now, &st->last_collected_time);
806
}
807
+ // prevent infinite loop
808
+ else microseconds = st->update_every * 1000000ULL;
809
810
rrdset_next_usec(st, microseconds);
811
}
@@ -818,7 +820,8 @@ unsigned long long rrdset_done(RRDSET *st)
820
debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
821
822
RRDDIM *rd, *last;
821
- int oldstate, store_this_entry = 1;
823
+ int oldstate, store_this_entry = 1, first_entry = 0, in_the_same_interpolation_point = 0;
824
+ unsigned long long last_ut, now_ut, next_ut;
825
826
if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
827
error("Cannot set pthread cancel state to DISABLE.");
@@ -829,11 +832,12 @@ unsigned long long rrdset_done(RRDSET *st)
832
// enable the chart, if it was disabled
833
st->enabled = 1;
834
832
- // check if the chart has a long time to be refreshed
835
+ // check if the chart has a long time to be updated
836
if(unlikely(st->usec_since_last_update > st->entries * st->update_every * 1000000ULL)) {
837
info("%s: took too long to be updated (%0.3Lf secs). Reseting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
838
rrdset_reset(st);
839
st->usec_since_last_update = st->update_every * 1000000ULL;
840
+ first_entry = 1;
841
}
842
if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
843
@@ -845,15 +849,16 @@ unsigned long long rrdset_done(RRDSET *st)
849
850
// the first entry should not be stored
851
store_this_entry = 0;
852
+ first_entry = 1;
853
849
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_collected to now. Will not store the next entry.", st->name);
854
+ if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
855
}
856
else {
857
// it is not the first entry
858
// calculate the proper last_collected_time, using usec_since_last_update
859
unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec + st->usec_since_last_update;
855
- st->last_collected_time.tv_sec = (__time_t) (ut / 1000000ULL);
856
- st->last_collected_time.tv_usec = (__suseconds_t) (ut % 1000000ULL);
860
+ st->last_collected_time.tv_sec = (time_t) (ut / 1000000ULL);
861
+ st->last_collected_time.tv_usec = (useconds_t) (ut % 1000000ULL);
862
}
863
864
// if this set has not been updated in the past
@@ -862,11 +867,12 @@ unsigned long long rrdset_done(RRDSET *st)
867
// it has never been updated before
868
// set a fake last_updated, in the past using usec_since_last_update
869
unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
865
- st->last_updated.tv_sec = (__time_t) (ut / 1000000ULL);
866
- st->last_updated.tv_usec = (__suseconds_t) (ut % 1000000ULL);
870
+ st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
871
+ st->last_updated.tv_usec = (useconds_t) (ut % 1000000ULL);
872
873
// the first entry should not be stored
874
store_this_entry = 0;
875
+ first_entry = 1;
876
877
if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_updated to now - %llu microseconds (%0.3Lf). Will not store the next entry.", st->name, st->usec_since_last_update, (long double)ut/1000000.0);
878
}
@@ -881,20 +887,26 @@ unsigned long long rrdset_done(RRDSET *st)
887
gettimeofday(&st->last_collected_time, NULL);
888
889
unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
884
- st->last_updated.tv_sec = (__time_t) (ut / 1000000ULL);
885
- st->last_updated.tv_usec = (__suseconds_t) (ut % 1000000ULL);
890
+ st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
891
+ st->last_updated.tv_usec = (useconds_t) (ut % 1000000ULL);
892
893
// the first entry should not be stored
894
store_this_entry = 0;
895
+ first_entry = 1;
896
}
897
898
// these are the 3 variables that will help us in interpolation
899
// last_ut = the last time we added a value to the storage
900
// now_ut = the time the current value is taken at
901
// next_ut = the time of the next interpolation point
895
- unsigned long long last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
896
- unsigned long long now_ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
897
- unsigned long long next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;
902
+ last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
903
+ now_ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
904
+ next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;
905
+
906
+ if(unlikely(!first_entry && now_ut < next_ut)) {
907
+ if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
908
+ in_the_same_interpolation_point = 1;
909
+ }
910
911
if(unlikely(st->debug)) {
912
debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
@@ -921,12 +933,7 @@ unsigned long long rrdset_done(RRDSET *st)
933
// at this stage we do not interpolate anything
934
for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
935
924
- if(unlikely(!rd->updated || rd->counter <= 1)) {
925
- rd->calculated_value = 0;
926
- continue;
927
- }
928
-
929
- if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: "
936
+ if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
937
" last_collected_value = " COLLECTED_NUMBER_FORMAT
938
" collected_value = " COLLECTED_NUMBER_FORMAT
939
" last_calculated_value = " CALCULATED_NUMBER_FORMAT
@@ -939,26 +946,24 @@ unsigned long long rrdset_done(RRDSET *st)
946
);
947
948
switch(rd->algorithm) {
942
- case RRDDIM_PCENT_OVER_DIFF_TOTAL:
943
- // the percentage of the current increment
944
- // over the increment of all dimensions together
945
- if(unlikely(st->collected_total == st->last_collected_total)) rd->calculated_value = rd->last_calculated_value;
946
- else rd->calculated_value =
947
- (calculated_number)100
948
- * (calculated_number)(rd->collected_value - rd->last_collected_value)
949
- / (calculated_number)(st->collected_total - st->last_collected_total);
950
-
951
- if(unlikely(st->debug))
952
- debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
953
- CALCULATED_NUMBER_FORMAT " = 100"
954
- " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
955
- " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
956
- , st->id, rd->name
957
- , rd->calculated_value
958
- , rd->collected_value, rd->last_collected_value
959
- , st->collected_total, st->last_collected_total
960
- );
961
- break;
949
+ case RRDDIM_ABSOLUTE:
950
+ rd->calculated_value = (calculated_number)rd->collected_value
951
+ * (calculated_number)rd->multiplier
952
+ / (calculated_number)rd->divisor;
953
+
954
+ if(unlikely(st->debug))
955
+ debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
956
+ CALCULATED_NUMBER_FORMAT " = "
957
+ COLLECTED_NUMBER_FORMAT
958
+ " * " CALCULATED_NUMBER_FORMAT
959
+ " / " CALCULATED_NUMBER_FORMAT
960
+ , st->id, rd->name
961
+ , rd->calculated_value
962
+ , rd->collected_value
963
+ , (calculated_number)rd->multiplier
964
+ , (calculated_number)rd->divisor
965
+ );
966
+ break;
967
968
case RRDDIM_PCENT_OVER_ROW_TOTAL:
969
if(unlikely(!st->collected_total)) rd->calculated_value = 0;
@@ -983,6 +988,11 @@ unsigned long long rrdset_done(RRDSET *st)
988
break;
989
990
case RRDDIM_INCREMENTAL:
991
+ if(unlikely(!rd->updated || rd->counter <= 1)) {
992
+ rd->calculated_value = 0;
993
+ continue;
994
+ }
995
+
996
// if the new is smaller than the old (an overflow, or reset), set the old equal to the new
997
// to reset the calculation (it will give zero as the calculation for this second)
998
if(unlikely(rd->last_collected_value > rd->collected_value)) {
@@ -994,17 +1004,21 @@ unsigned long long rrdset_done(RRDSET *st)
1004
rd->last_collected_value = rd->collected_value;
1005
}
1006
997
- rd->calculated_value += (calculated_number)(rd->collected_value - rd->last_collected_value)
1007
+ if(!in_the_same_interpolation_point) {
1008
+ rd->last_calculated_value = rd->calculated_value;
1009
+ }
1010
+
1011
+ rd->calculated_value = (calculated_number)(rd->collected_value - rd->last_collected_value)
1012
* (calculated_number)rd->multiplier
1013
/ (calculated_number)rd->divisor;
1014
1015
if(unlikely(st->debug))
1002
- debug(D_RRD_STATS, "%s/%s: CALC INC "
1003
- CALCULATED_NUMBER_FORMAT " += ("
1016
+ debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
1017
+ CALCULATED_NUMBER_FORMAT " = ("
1018
COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
1005
- " * %ld"
1006
- " / %ld"
1019
")"
1020
+ " * " CALCULATED_NUMBER_FORMAT
1021
+ " / " CALCULATED_NUMBER_FORMAT
1022
, st->id, rd->name
1023
, rd->calculated_value
1024
, rd->collected_value, rd->last_collected_value
@@ -1013,22 +1027,33 @@ unsigned long long rrdset_done(RRDSET *st)
1027
);
1028
break;
1029
1016
- case RRDDIM_ABSOLUTE:
1017
- rd->calculated_value = (calculated_number)rd->collected_value
1018
- * (calculated_number)rd->multiplier
1019
- / (calculated_number)rd->divisor;
1030
+ case RRDDIM_PCENT_OVER_DIFF_TOTAL:
1031
+ if(unlikely(!rd->updated || rd->counter <= 1)) {
1032
+ rd->calculated_value = 0;
1033
+ continue;
1034
+ }
1035
+
1036
+ // the percentage of the current increment
1037
+ // over the increment of all dimensions together
1038
+ if(unlikely(st->collected_total == st->last_collected_total)) rd->calculated_value = rd->last_calculated_value;
1039
+ else rd->calculated_value =
1040
+ (calculated_number)100
1041
+ * (calculated_number)(rd->collected_value - rd->last_collected_value)
1042
+ / (calculated_number)(st->collected_total - st->last_collected_total);
1043
+
1044
+ if(!in_the_same_interpolation_point) {
1045
+ rd->last_calculated_value = rd->calculated_value;
1046
+ }
1047
1048
if(unlikely(st->debug))
1022
- debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
1023
- CALCULATED_NUMBER_FORMAT " = "
1024
- COLLECTED_NUMBER_FORMAT
1025
- " * %ld"
1026
- " / %ld"
1049
+ debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
1050
+ CALCULATED_NUMBER_FORMAT " = 100"
1051
+ " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
1052
+ " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
1053
, st->id, rd->name
1054
, rd->calculated_value
1029
- , rd->collected_value
1030
- , (calculated_number)rd->multiplier
1031
- , (calculated_number)rd->divisor
1055
+ , rd->collected_value, rd->last_collected_value
1056
+ , st->collected_total, st->last_collected_total
1057
);
1058
break;
1059
@@ -1045,6 +1070,19 @@ unsigned long long rrdset_done(RRDSET *st)
1070
);
1071
break;
1072
}
1073
+
1074
+ if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
1075
+ " last_collected_value = " COLLECTED_NUMBER_FORMAT
1076
+ " collected_value = " COLLECTED_NUMBER_FORMAT
1077
+ " last_calculated_value = " CALCULATED_NUMBER_FORMAT
1078
+ " calculated_value = " CALCULATED_NUMBER_FORMAT
1079
+ , st->id, rd->name
1080
+ , rd->last_collected_value
1081
+ , rd->collected_value
1082
+ , rd->last_calculated_value
1083
+ , rd->calculated_value
1084
+ );
1085
+
1086
}
1087
1088
// at this point we have all the calculated values ready
@@ -1052,10 +1090,11 @@ unsigned long long rrdset_done(RRDSET *st)
1090
1091
unsigned long long first_ut = last_ut;
1092
long long iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
1093
+ if((now_ut % (st->update_every * 1000000ULL)) == 0) iterations++;
1094
1095
for( ; likely(next_ut <= now_ut) ; next_ut += st->update_every * 1000000ULL, iterations-- ) {
1096
#ifdef NETDATA_INTERNAL_CHECKS
1058
- if(iterations <= 0) error("iterations calculation wrapped!");
1097
+ if(iterations <= 0) { error("iterations calculation wrapped!"); }
1098
#endif
1099
1100
if(unlikely(st->debug)) {
@@ -1063,7 +1102,7 @@ unsigned long long rrdset_done(RRDSET *st)
1102
debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
1103
}
1104
1066
- st->last_updated.tv_sec = (__time_t) (next_ut / 1000000ULL);
1105
+ st->last_updated.tv_sec = (time_t) (next_ut / 1000000ULL);
1106
st->last_updated.tv_usec = 0;
1107
1108
for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
@@ -1091,6 +1130,8 @@ unsigned long long rrdset_done(RRDSET *st)
1130
);
1131
1132
rd->calculated_value -= new_value;
1133
+ new_value += rd->last_calculated_value;
1134
+ rd->last_calculated_value = 0;
1135
new_value /= (calculated_number)st->update_every;
1136
break;
1137
@@ -1198,10 +1239,29 @@ unsigned long long rrdset_done(RRDSET *st)
1239
last_ut = next_ut;
1240
}
1241
1242
+ // align next interpolation to last collection point
1243
+ st->last_updated.tv_sec = st->last_collected_time.tv_sec;
1244
+ st->last_updated.tv_usec = st->last_collected_time.tv_usec;
1245
+
1246
for( rd = st->dimensions; likely(rd) ; rd = rd->next ) {
1247
if(unlikely(!rd->updated)) continue;
1203
- rd->last_collected_value = rd->collected_value;
1204
- rd->last_calculated_value = rd->calculated_value;
1248
+
1249
+ int is_incremental = 0;
1250
+ if(rd->algorithm == RRDDIM_PCENT_OVER_DIFF_TOTAL || rd->algorithm == RRDDIM_INCREMENTAL)
1251
+ is_incremental = 1;
1252
+
1253
+ if((is_incremental && !in_the_same_interpolation_point) || !is_incremental || !store_this_entry) {
1254
+ if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
1255
+ rd->last_collected_value = rd->collected_value;
1256
+
1257
+ if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
1258
+ rd->last_calculated_value = rd->calculated_value;
1259
+ }
1260
+ else {
1261
+ if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: discarding calculated_value (old: " CALCULATED_NUMBER_FORMAT ") new: 0", st->id, rd->name, rd->calculated_value);
1262
+ rd->calculated_value = 0;
1263
+ }
1264
+
1265
rd->collected_value = 0;
1266
rd->updated = 0;
1267
src/unit_test.c
+439
-16
@@ -241,6 +241,426 @@ int unit_test_storage()
241
return r;
242
}
243
244
+
245
+// --------------------------------------------------------------------------------------------------------------------
246
+
247
+struct feed_values {
248
+ unsigned long long microseconds;
249
+ calculated_number value;
250
+};
251
+
252
+struct test {
253
+ char name[100];
254
+ char description[1024];
255
+
256
+ int update_every;
257
+ unsigned long long multiplier;
258
+ unsigned long long divisor;
259
+ int algorithm;
260
+
261
+ unsigned long feed_entries;
262
+ unsigned long result_entries;
263
+ struct feed_values *feed;
264
+ calculated_number *results;
265
+};
266
+
267
+// --------------------------------------------------------------------------------------------------------------------
268
+// test1
269
+// test absolute values stored
270
+
271
+struct feed_values test1_feed[] = {
272
+ { 0, 10 },
273
+ { 1000000, 20 },
274
+ { 1000000, 30 },
275
+ { 1000000, 40 },
276
+ { 1000000, 50 },
277
+ { 1000000, 60 },
278
+ { 1000000, 70 },
279
+ { 1000000, 80 },
280
+ { 1000000, 90 },
281
+ { 1000000, 100 },
282
+};
283
+
284
+calculated_number test1_results[] = {
285
+ 20, 30, 40, 50, 60, 70, 80, 90, 100
286
+};
287
+
288
+struct test test1 = {
289
+ "test1", // name
290
+ "test absolute values stored at exactly second boundaries",
291
+ 1, // update_every
292
+ 1, // multiplier
293
+ 1, // divisor
294
+ RRDDIM_ABSOLUTE, // algorithm
295
+ 10, // feed entries
296
+ 9, // result entries
297
+ test1_feed, // feed
298
+ test1_results // results
299
+};
300
+
301
+// --------------------------------------------------------------------------------------------------------------------
302
+// test2
303
+// test absolute values stored in the middle of second boundaries
304
+
305
+struct feed_values test2_feed[] = {
306
+ { 500000, 10 },
307
+ { 1000000, 20 },
308
+ { 1000000, 30 },
309
+ { 1000000, 40 },
310
+ { 1000000, 50 },
311
+ { 1000000, 60 },
312
+ { 1000000, 70 },
313
+ { 1000000, 80 },
314
+ { 1000000, 90 },
315
+ { 1000000, 100 },
316
+};
317
+
318
+calculated_number test2_results[] = {
319
+ 20, 30, 40, 50, 60, 70, 80, 90, 100
320
+};
321
+
322
+struct test test2 = {
323
+ "test2", // name
324
+ "test absolute values stored in the middle of second boundaries",
325
+ 1, // update_every
326
+ 1, // multiplier
327
+ 1, // divisor
328
+ RRDDIM_ABSOLUTE, // algorithm
329
+ 10, // feed entries
330
+ 9, // result entries
331
+ test2_feed, // feed
332
+ test2_results // results
333
+};
334
+
335
+// --------------------------------------------------------------------------------------------------------------------
336
+// test3
337
+
338
+struct feed_values test3_feed[] = {
339
+ { 0, 10 },
340
+ { 1000000, 20 },
341
+ { 1000000, 30 },
342
+ { 1000000, 40 },
343
+ { 1000000, 50 },
344
+ { 1000000, 60 },
345
+ { 1000000, 70 },
346
+ { 1000000, 80 },
347
+ { 1000000, 90 },
348
+ { 1000000, 100 },
349
+};
350
+
351
+calculated_number test3_results[] = {
352
+ 10, 10, 10, 10, 10, 10, 10, 10, 10
353
+};
354
+
355
+struct test test3 = {
356
+ "test3", // name
357
+ "test incremental values stored at exactly second boundaries",
358
+ 1, // update_every
359
+ 1, // multiplier
360
+ 1, // divisor
361
+ RRDDIM_INCREMENTAL, // algorithm
362
+ 10, // feed entries
363
+ 9, // result entries
364
+ test3_feed, // feed
365
+ test3_results // results
366
+};
367
+
368
+// --------------------------------------------------------------------------------------------------------------------
369
+// test4
370
+
371
+struct feed_values test4_feed[] = {
372
+ { 500000, 10 },
373
+ { 1000000, 20 },
374
+ { 1000000, 30 },
375
+ { 1000000, 40 },
376
+ { 1000000, 50 },
377
+ { 1000000, 60 },
378
+ { 1000000, 70 },
379
+ { 1000000, 80 },
380
+ { 1000000, 90 },
381
+ { 1000000, 100 },
382
+};
383
+
384
+calculated_number test4_results[] = {
385
+ 5, 10, 10, 10, 10, 10, 10, 10, 10
386
+};
387
+
388
+struct test test4 = {
389
+ "test4", // name
390
+ "test incremental values stored in the middle of second boundaries",
391
+ 1, // update_every
392
+ 1, // multiplier
393
+ 1, // divisor
394
+ RRDDIM_INCREMENTAL, // algorithm
395
+ 10, // feed entries
396
+ 9, // result entries
397
+ test4_feed, // feed
398
+ test4_results // results
399
+};
400
+
401
+// --------------------------------------------------------------------------------------------------------------------
402
+// test5
403
+
404
+struct feed_values test5_feed[] = {
405
+ { 500000, 1000 },
406
+ { 1000000, 2000 },
407
+ { 1000000, 2000 },
408
+ { 1000000, 2000 },
409
+ { 1000000, 3000 },
410
+ { 1000000, 2000 },
411
+ { 1000000, 2000 },
412
+ { 1000000, 2000 },
413
+ { 1000000, 2000 },
414
+ { 1000000, 2000 },
415
+};
416
+
417
+calculated_number test5_results[] = {
418
+ 500, 500, 0, 500, 500, 0, 0, 0, 0
419
+};
420
+
421
+struct test test5 = {
422
+ "test5", // name
423
+ "test incremental values ups and downs",
424
+ 1, // update_every
425
+ 1, // multiplier
426
+ 1, // divisor
427
+ RRDDIM_INCREMENTAL, // algorithm
428
+ 10, // feed entries
429
+ 9, // result entries
430
+ test5_feed, // feed
431
+ test5_results // results
432
+};
433
+
434
+// --------------------------------------------------------------------------------------------------------------------
435
+// test6
436
+
437
+struct feed_values test6_feed[] = {
438
+ { 250000, 1000 },
439
+ { 250000, 2000 },
440
+ { 250000, 3000 },
441
+ { 250000, 4000 },
442
+ { 250000, 5000 },
443
+ { 250000, 6000 },
444
+ { 250000, 7000 },
445
+ { 250000, 8000 },
446
+ { 250000, 9000 },
447
+ { 250000, 10000 },
448
+ { 250000, 11000 },
449
+ { 250000, 12000 },
450
+ { 250000, 13000 },
451
+ { 250000, 14000 },
452
+ { 250000, 15000 },
453
+ { 250000, 16000 },
454
+};
455
+
456
+calculated_number test6_results[] = {
457
+ 3000, 4000, 4000, 4000
458
+};
459
+
460
+struct test test6 = {
461
+ "test6", // name
462
+ "test incremental values updated within the same second",
463
+ 1, // update_every
464
+ 1, // multiplier
465
+ 1, // divisor
466
+ RRDDIM_INCREMENTAL, // algorithm
467
+ 16, // feed entries
468
+ 4, // result entries
469
+ test6_feed, // feed
470
+ test6_results // results
471
+};
472
+
473
+// --------------------------------------------------------------------------------------------------------------------
474
+// test7
475
+
476
+struct feed_values test7_feed[] = {
477
+ { 500000, 1000 },
478
+ { 2000000, 2000 },
479
+ { 2000000, 3000 },
480
+ { 2000000, 4000 },
481
+ { 2000000, 5000 },
482
+ { 2000000, 6000 },
483
+ { 2000000, 7000 },
484
+ { 2000000, 8000 },
485
+ { 2000000, 9000 },
486
+ { 2000000, 10000 },
487
+};
488
+
489
+calculated_number test7_results[] = {
490
+ 250, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500
491
+};
492
+
493
+struct test test7 = {
494
+ "test7", // name
495
+ "test incremental values updated in long durations",
496
+ 1, // update_every
497
+ 1, // multiplier
498
+ 1, // divisor
499
+ RRDDIM_INCREMENTAL, // algorithm
500
+ 10, // feed entries
501
+ 18, // result entries
502
+ test7_feed, // feed
503
+ test7_results // results
504
+};
505
+
506
+// --------------------------------------------------------------------------------------------------------------------
507
+// test8
508
+
509
+struct feed_values test8_feed[] = {
510
+ { 500000, 1000 },
511
+ { 2000000, 2000 },
512
+ { 2000000, 3000 },
513
+ { 2000000, 4000 },
514
+ { 2000000, 5000 },
515
+ { 2000000, 6000 },
516
+};
517
+
518
+calculated_number test8_results[] = {
519
+ 1250, 2000, 2250, 3000, 3250, 4000, 4250, 5000, 5250, 6000
520
+};
521
+
522
+struct test test8 = {
523
+ "test8", // name
524
+ "test absolute values updated in long durations",
525
+ 1, // update_every
526
+ 1, // multiplier
527
+ 1, // divisor
528
+ RRDDIM_ABSOLUTE, // algorithm
529
+ 6, // feed entries
530
+ 10, // result entries
531
+ test8_feed, // feed
532
+ test8_results // results
533
+};
534
+
535
+// --------------------------------------------------------------------------------------------------------------------
536
+// test9
537
+
538
+struct feed_values test9_feed[] = {
539
+ { 250000, 1000 },
540
+ { 250000, 2000 },
541
+ { 250000, 3000 },
542
+ { 250000, 4000 },
543
+ { 250000, 5000 },
544
+ { 250000, 6000 },
545
+ { 250000, 7000 },
546
+ { 250000, 8000 },
547
+ { 250000, 9000 },
548
+ { 250000, 10000 },
549
+ { 250000, 11000 },
550
+ { 250000, 12000 },
551
+ { 250000, 13000 },
552
+ { 250000, 14000 },
553
+ { 250000, 15000 },
554
+ { 250000, 16000 },
555
+};
556
+
557
+calculated_number test9_results[] = {
558
+ 4000, 8000, 12000, 16000
559
+};
560
+
561
+struct test test9 = {
562
+ "test9", // name
563
+ "test absolute values updated within the same second",
564
+ 1, // update_every
565
+ 1, // multiplier
566
+ 1, // divisor
567
+ RRDDIM_ABSOLUTE, // algorithm
568
+ 16, // feed entries
569
+ 4, // result entries
570
+ test9_feed, // feed
571
+ test9_results // results
572
+};
573
+
574
+// --------------------------------------------------------------------------------------------------------------------
575
+
576
+int run_test(struct test *test)
577
+{
578
+ fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
579
+
580
+ rrd_memory_mode = RRD_MEMORY_MODE_RAM;
581
+ rrd_update_every = test->update_every;
582
+
583
+ char name[101];
584
+ snprintf(name, 100, "unittest-%s", test->name);
585
+
586
+ // create the chart
587
+ RRDSET *st = rrdset_create("netdata", name, name, "netdata", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
588
+ RRDDIM *rd = rrddim_add(st, "dimension", NULL, test->multiplier, test->divisor, test->algorithm);
589
+ st->debug = 1;
590
+
591
+ // feed it with the test data
592
+ unsigned long c;
593
+ for(c = 0; c < test->feed_entries; c++) {
594
+ if(debug_flags) fprintf(stderr, "\n\n");
595
+
596
+ if(c) {
597
+ fprintf(stderr, " > %s: feeding position %lu, after %llu microseconds, with value " CALCULATED_NUMBER_FORMAT "\n", test->name, c+1, test->feed[c].microseconds, test->feed[c].value);
598
+ rrdset_next_usec(st, test->feed[c].microseconds);
599
+ }
600
+ else {
601
+ fprintf(stderr, " > %s: feeding position %lu with value " CALCULATED_NUMBER_FORMAT "\n", test->name, c+1, test->feed[c].value);
602
+ }
603
+
604
+ rrddim_set(st, "dimension", test->feed[c].value);
605
+ rrdset_done(st);
606
+
607
+ // align the first entry to second boundary
608
+ if(!c) {
609
+ fprintf(stderr, " > %s: fixing first collection time to be %llu microseconds to second boundary\n", test->name, test->feed[c].microseconds);
610
+ rd->last_collected_time.tv_usec = st->last_collected_time.tv_usec = st->last_updated.tv_usec = test->feed[c].microseconds;
611
+ }
612
+ }
613
+
614
+ // check the result
615
+ int errors = 0;
616
+
617
+ if(st->counter != test->result_entries) {
618
+ fprintf(stderr, " %s stored %lu entries, but we were expecting %lu, ### E R R O R ###\n", test->name, st->counter, test->result_entries);
619
+ errors++;
620
+ }
621
+
622
+ unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries;
623
+ for(c = 0 ; c < max ; c++) {
624
+ calculated_number v = unpack_storage_number(rd->values[c]), n = test->results[c];
625
+ fprintf(stderr, " %s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, c+1, n, v, (v == n)?"OK":"### E R R O R ###");
626
+ if(v != n) errors++;
627
+ }
628
+
629
+ return errors;
630
+}
631
+
632
+int run_all_mockup_tests(void)
633
+{
634
+ if(run_test(&test1))
635
+ return 1;
636
+
637
+ if(run_test(&test2))
638
+ return 1;
639
+
640
+ if(run_test(&test3))
641
+ return 1;
642
+
643
+ if(run_test(&test4))
644
+ return 1;
645
+
646
+ if(run_test(&test5))
647
+ return 1;
648
+
649
+ if(run_test(&test6))
650
+ return 1;
651
+
652
+ if(run_test(&test7))
653
+ return 1;
654
+
655
+ if(run_test(&test8))
656
+ return 1;
657
+
658
+ if(run_test(&test9))
659
+ return 1;
660
+
661
+ return 0;
662
+}
663
+
664
int unit_test(long delay, long shift)
665
{
666
static int repeat = 0;
@@ -249,14 +669,14 @@ int unit_test(long delay, long shift)
669
char name[101];
670
snprintf(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
671
252
- debug_flags = 0xffffffff;
672
+ //debug_flags = 0xffffffff;
673
rrd_memory_mode = RRD_MEMORY_MODE_RAM;
674
rrd_update_every = 1;
675
676
int do_abs = 1;
677
int do_inc = 1;
258
- int do_abst = 1;
259
- int do_absi = 1;
678
+ int do_abst = 0;
679
+ int do_absi = 0;
680
681
RRDSET *st = rrdset_create("netdata", name, name, "netdata", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
682
st->debug = 1;
@@ -296,7 +716,8 @@ int unit_test(long delay, long shift)
716
}
717
718
// prevent it from deleting the dimensions
299
- for(rd = st->dimensions ; rd ; rd = rd->next) rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
719
+ for(rd = st->dimensions ; rd ; rd = rd->next)
720
+ rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
721
722
rrdset_done(st);
723
}
@@ -306,27 +727,30 @@ int unit_test(long delay, long shift)
727
fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %lu, DELAY %lu, SHIFT %lu\n", oincrement * 10, increment * 10, delay, shift);
728
729
int ret = 0;
309
- storage_number v;
730
+ storage_number sn;
731
+ calculated_number cn, v;
732
for(c = 0 ; c < st->counter ; c++) {
311
- fprintf(stderr, "\nPOSITION: c = %lu, VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
733
+ fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
734
735
for(rd = st->dimensions ; rd ; rd = rd->next) {
314
- fprintf(stderr, "\t %s " STORAGE_NUMBER_FORMAT " -> ", rd->id, rd->values[c]);
736
+ sn = rd->values[c];
737
+ cn = unpack_storage_number(sn);
738
+ fprintf(stderr, "\t %s " CALCULATED_NUMBER_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ") -> ", rd->id, cn, sn);
739
740
if(rd == rdabs) v =
741
( oincrement
318
- + (increment * (1000000 - shift) / 1000000)
319
- + c * increment
320
- ) * 10;
742
+ // + (increment * (1000000 - shift) / 1000000)
743
+ + (c + 1) * increment
744
+ );
745
322
- else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000)) * 10;
323
- else if(rd == rdabst) v = oincrement / dimensions;
324
- else if(rd == rdabsi) v = oincrement / dimensions;
746
+ else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000));
747
+ else if(rd == rdabst) v = oincrement / dimensions / 10;
748
+ else if(rd == rdabsi) v = oincrement / dimensions / 10;
749
else v = 0;
750
327
- if(v == rd->values[c]) fprintf(stderr, "passed.\n");
751
+ if(v == cn) fprintf(stderr, "passed.\n");
752
else {
329
- fprintf(stderr, "ERROR! (expected " STORAGE_NUMBER_FORMAT ")\n", v);
753
+ fprintf(stderr, "ERROR! (expected " CALCULATED_NUMBER_FORMAT ")\n", v);
754
ret = 1;
755
}
756
}
@@ -337,4 +761,3 @@ int unit_test(long delay, long shift)
761
762
return ret;
763
}
340
-
src/unit_test.h
+1
@@ -3,5 +3,6 @@
3
4
extern int unit_test_storage(void);
5
extern int unit_test(long delay, long shift);
6
+extern int run_all_mockup_tests(void);
7
8
#endif /* NETDATA_UNIT_TEST_H */