@cryptotaxi247 / netdata-1 / commits / b475c5827

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 */