]> arthur.barton.de Git - netdata.git/commitdiff
added more unit tests; fixed the issue where incremental values where gracefully...
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Wed, 20 Jan 2016 23:09:53 +0000 (01:09 +0200)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Wed, 20 Jan 2016 23:09:53 +0000 (01:09 +0200)
src/main.c
src/rrd.c
src/unit_test.c
src/unit_test.h

index be101dea6e6d0bb1bf7a8571f4fba038813ff3cc..8f3870bdc9e981ff3bae8e14be554fc00c1ab643 100755 (executable)
@@ -208,7 +208,7 @@ int main(int argc, char **argv)
                        }
                        i++;
                }
-               else if(strcmp(argv[i], "-df") == 0 && (i+1) < argc) { config_set("global", "debug flags",  argv[i+1]); i++; }
+               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++; }
                else if(strcmp(argv[i], "-p")  == 0 && (i+1) < argc) { config_set("global", "port",         argv[i+1]); i++; }
                else if(strcmp(argv[i], "-u")  == 0 && (i+1) < argc) { config_set("global", "run as user",  argv[i+1]); i++; }
                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)
                else if(strcmp(argv[i], "-ch") == 0 && (i+1) < argc) { config_set("global", "host access prefix", argv[i+1]); i++; }
                else if(strcmp(argv[i], "-nodeamon") == 0 || strcmp(argv[i], "-nd") == 0) dont_fork = 1;
                else if(strcmp(argv[i], "--unittest")  == 0) {
-                       if(unit_test_storage()) exit(1);
-                       exit(0);
                        rrd_update_every = 1;
-                       if(unit_test(1000000, 0)) exit(1);
-                       if(unit_test(1000000, 500000)) exit(1);
-                       if(unit_test(1000000, 100000)) exit(1);
-                       if(unit_test(1000000, 900000)) exit(1);
-                       if(unit_test(2000000, 0)) exit(1);
-                       if(unit_test(2000000, 500000)) exit(1);
-                       if(unit_test(2000000, 100000)) exit(1);
-                       if(unit_test(2000000, 900000)) exit(1);
-                       if(unit_test(500000, 500000)) exit(1);
-                       //if(unit_test(500000, 100000)) exit(1); // FIXME: the expected numbers are wrong
-                       //if(unit_test(500000, 900000)) exit(1); // FIXME: the expected numbers are wrong
-                       if(unit_test(500000, 0)) exit(1);
+                       if(run_all_mockup_tests()) exit(1);
+                       if(unit_test_storage()) exit(1);
                        fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
                        exit(0);
                }
index 6a08a149048103c24febdbcb7ad8532c44938a26..b9b20ee6a1866dab4e642d98b9c36c40ee015b4f 100755 (executable)
--- a/src/rrd.c
+++ b/src/rrd.c
@@ -804,6 +804,8 @@ void rrdset_next(RRDSET *st)
                gettimeofday(&now, NULL);
                microseconds = usecdiff(&now, &st->last_collected_time);
        }
+       // prevent infinite loop
+       else microseconds = st->update_every * 1000000ULL;
 
        rrdset_next_usec(st, microseconds);
 }
@@ -818,7 +820,8 @@ unsigned long long rrdset_done(RRDSET *st)
        debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
 
        RRDDIM *rd, *last;
-       int oldstate, store_this_entry = 1;
+       int oldstate, store_this_entry = 1, first_entry = 0, in_the_same_interpolation_point = 0;
+       unsigned long long last_ut, now_ut, next_ut;
 
        if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
                error("Cannot set pthread cancel state to DISABLE.");
@@ -829,11 +832,12 @@ unsigned long long rrdset_done(RRDSET *st)
        // enable the chart, if it was disabled
        st->enabled = 1;
 
-       // check if the chart has a long time to be refreshed
+       // check if the chart has a long time to be updated
        if(unlikely(st->usec_since_last_update > st->entries * st->update_every * 1000000ULL)) {
                info("%s: took too long to be updated (%0.3Lf secs). Reseting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
                rrdset_reset(st);
                st->usec_since_last_update = st->update_every * 1000000ULL;
+               first_entry = 1;
        }
        if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
 
@@ -845,15 +849,16 @@ unsigned long long rrdset_done(RRDSET *st)
 
                // the first entry should not be stored
                store_this_entry = 0;
+               first_entry = 1;
 
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_collected to now. Will not store the next entry.", st->name);
+               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);
        }
        else {
                // it is not the first entry
                // calculate the proper last_collected_time, using usec_since_last_update
                unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec + st->usec_since_last_update;
-               st->last_collected_time.tv_sec = (__time_t) (ut / 1000000ULL);
-               st->last_collected_time.tv_usec = (__suseconds_t) (ut % 1000000ULL);
+               st->last_collected_time.tv_sec = (time_t) (ut / 1000000ULL);
+               st->last_collected_time.tv_usec = (useconds_t) (ut % 1000000ULL);
        }
 
        // if this set has not been updated in the past
@@ -862,11 +867,12 @@ unsigned long long rrdset_done(RRDSET *st)
                // it has never been updated before
                // set a fake last_updated, in the past using usec_since_last_update
                unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
-               st->last_updated.tv_sec = (__time_t) (ut / 1000000ULL);
-               st->last_updated.tv_usec = (__suseconds_t) (ut % 1000000ULL);
+               st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
+               st->last_updated.tv_usec = (useconds_t) (ut % 1000000ULL);
 
                // the first entry should not be stored
                store_this_entry = 0;
+               first_entry = 1;
 
                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);
        }
@@ -881,20 +887,26 @@ unsigned long long rrdset_done(RRDSET *st)
                gettimeofday(&st->last_collected_time, NULL);
 
                unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
-               st->last_updated.tv_sec = (__time_t) (ut / 1000000ULL);
-               st->last_updated.tv_usec = (__suseconds_t) (ut % 1000000ULL);
+               st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
+               st->last_updated.tv_usec = (useconds_t) (ut % 1000000ULL);
 
                // the first entry should not be stored
                store_this_entry = 0;
+               first_entry = 1;
        }
 
        // these are the 3 variables that will help us in interpolation
        // last_ut = the last time we added a value to the storage
        //  now_ut = the time the current value is taken at
        // next_ut = the time of the next interpolation point
-       unsigned long long last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
-       unsigned long long now_ut  = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
-       unsigned long long next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;
+       last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
+       now_ut  = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
+       next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;
+
+       if(unlikely(!first_entry && now_ut < next_ut)) {
+               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
+               in_the_same_interpolation_point = 1;
+       }
 
        if(unlikely(st->debug)) {
                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)
        // at this stage we do not interpolate anything
        for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
 
-               if(unlikely(!rd->updated || rd->counter <= 1)) {
-                       rd->calculated_value = 0;
-                       continue;
-               }
-
-               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: "
+               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
                        " last_collected_value = " COLLECTED_NUMBER_FORMAT
                        " collected_value = " COLLECTED_NUMBER_FORMAT
                        " last_calculated_value = " CALCULATED_NUMBER_FORMAT
@@ -939,26 +946,24 @@ unsigned long long rrdset_done(RRDSET *st)
                        );
 
                switch(rd->algorithm) {
-                       case RRDDIM_PCENT_OVER_DIFF_TOTAL:
-                               // the percentage of the current increment
-                               // over the increment of all dimensions together
-                               if(unlikely(st->collected_total == st->last_collected_total)) rd->calculated_value = rd->last_calculated_value;
-                               else rd->calculated_value =
-                                         (calculated_number)100
-                                       * (calculated_number)(rd->collected_value - rd->last_collected_value)
-                                       / (calculated_number)(st->collected_total  - st->last_collected_total);
-
-                               if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
-                                               CALCULATED_NUMBER_FORMAT " = 100"
-                                               " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
-                                               " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
-                                               , st->id, rd->name
-                                               , rd->calculated_value
-                                               , rd->collected_value, rd->last_collected_value
-                                               , st->collected_total, st->last_collected_total
-                                               );
-                               break;
+               case RRDDIM_ABSOLUTE:
+                       rd->calculated_value = (calculated_number)rd->collected_value
+                               * (calculated_number)rd->multiplier
+                               / (calculated_number)rd->divisor;
+
+                       if(unlikely(st->debug))
+                               debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
+                                       CALCULATED_NUMBER_FORMAT " = "
+                                       COLLECTED_NUMBER_FORMAT
+                                       " * " CALCULATED_NUMBER_FORMAT
+                                       " / " CALCULATED_NUMBER_FORMAT
+                                       , st->id, rd->name
+                                       , rd->calculated_value
+                                       , rd->collected_value
+                                       , (calculated_number)rd->multiplier
+                                       , (calculated_number)rd->divisor
+                                       );
+                       break;
 
                        case RRDDIM_PCENT_OVER_ROW_TOTAL:
                                if(unlikely(!st->collected_total)) rd->calculated_value = 0;
@@ -983,6 +988,11 @@ unsigned long long rrdset_done(RRDSET *st)
                                break;
 
                        case RRDDIM_INCREMENTAL:
+                               if(unlikely(!rd->updated || rd->counter <= 1)) {
+                                       rd->calculated_value = 0;
+                                       continue;
+                               }
+
                                // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
                                // to reset the calculation (it will give zero as the calculation for this second)
                                if(unlikely(rd->last_collected_value > rd->collected_value)) {
@@ -994,17 +1004,21 @@ unsigned long long rrdset_done(RRDSET *st)
                                        rd->last_collected_value = rd->collected_value;
                                }
 
-                               rd->calculated_value += (calculated_number)(rd->collected_value - rd->last_collected_value)
+                               if(!in_the_same_interpolation_point) {
+                                       rd->last_calculated_value = rd->calculated_value;
+                               }
+
+                               rd->calculated_value = (calculated_number)(rd->collected_value - rd->last_collected_value)
                                        * (calculated_number)rd->multiplier
                                        / (calculated_number)rd->divisor;
 
                                if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: CALC INC "
-                                               CALCULATED_NUMBER_FORMAT " += ("
+                                       debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
+                                               CALCULATED_NUMBER_FORMAT " = ("
                                                COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
-                                               " * %ld"
-                                               " / %ld"
                                                ")"
+                                               " * " CALCULATED_NUMBER_FORMAT
+                                               " / " CALCULATED_NUMBER_FORMAT
                                                , st->id, rd->name
                                                , rd->calculated_value
                                                , rd->collected_value, rd->last_collected_value
@@ -1013,22 +1027,33 @@ unsigned long long rrdset_done(RRDSET *st)
                                                );
                                break;
 
-                       case RRDDIM_ABSOLUTE:
-                               rd->calculated_value = (calculated_number)rd->collected_value
-                                       * (calculated_number)rd->multiplier
-                                       / (calculated_number)rd->divisor;
+                       case RRDDIM_PCENT_OVER_DIFF_TOTAL:
+                               if(unlikely(!rd->updated || rd->counter <= 1)) {
+                                       rd->calculated_value = 0;
+                                       continue;
+                               }
+
+                               // the percentage of the current increment
+                               // over the increment of all dimensions together
+                               if(unlikely(st->collected_total == st->last_collected_total)) rd->calculated_value = rd->last_calculated_value;
+                               else rd->calculated_value =
+                                         (calculated_number)100
+                                       * (calculated_number)(rd->collected_value - rd->last_collected_value)
+                                       / (calculated_number)(st->collected_total  - st->last_collected_total);
+
+                               if(!in_the_same_interpolation_point) {
+                                       rd->last_calculated_value = rd->calculated_value;
+                               }
 
                                if(unlikely(st->debug))
-                                       debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
-                                               CALCULATED_NUMBER_FORMAT " = "
-                                               COLLECTED_NUMBER_FORMAT
-                                               " * %ld"
-                                               " / %ld"
+                                       debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
+                                               CALCULATED_NUMBER_FORMAT " = 100"
+                                               " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
+                                               " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
                                                , st->id, rd->name
                                                , rd->calculated_value
-                                               , rd->collected_value
-                                               , (calculated_number)rd->multiplier
-                                               , (calculated_number)rd->divisor
+                                               , rd->collected_value, rd->last_collected_value
+                                               , st->collected_total, st->last_collected_total
                                                );
                                break;
 
@@ -1045,6 +1070,19 @@ unsigned long long rrdset_done(RRDSET *st)
                                                );
                                break;
                }
+
+               if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
+                       " last_collected_value = " COLLECTED_NUMBER_FORMAT
+                       " collected_value = " COLLECTED_NUMBER_FORMAT
+                       " last_calculated_value = " CALCULATED_NUMBER_FORMAT
+                       " calculated_value = " CALCULATED_NUMBER_FORMAT
+                       , st->id, rd->name
+                       , rd->last_collected_value
+                       , rd->collected_value
+                       , rd->last_calculated_value
+                       , rd->calculated_value
+                       );
+
        }
 
        // at this point we have all the calculated values ready
@@ -1052,10 +1090,11 @@ unsigned long long rrdset_done(RRDSET *st)
 
        unsigned long long first_ut = last_ut;
        long long iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
+       if((now_ut % (st->update_every * 1000000ULL)) == 0) iterations++;
 
        for( ; likely(next_ut <= now_ut) ; next_ut += st->update_every * 1000000ULL, iterations-- ) {
 #ifdef NETDATA_INTERNAL_CHECKS
-               if(iterations <= 0) error("iterations calculation wrapped!");
+               if(iterations <= 0) { error("iterations calculation wrapped!"); }
 #endif
 
                if(unlikely(st->debug)) {
@@ -1063,7 +1102,7 @@ unsigned long long rrdset_done(RRDSET *st)
                        debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
                }
 
-               st->last_updated.tv_sec = (__time_t) (next_ut / 1000000ULL);
+               st->last_updated.tv_sec = (time_t) (next_ut / 1000000ULL);
                st->last_updated.tv_usec = 0;
 
                for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
@@ -1091,6 +1130,8 @@ unsigned long long rrdset_done(RRDSET *st)
                                                        );
 
                                        rd->calculated_value -= new_value;
+                                       new_value += rd->last_calculated_value;
+                                       rd->last_calculated_value = 0;
                                        new_value /= (calculated_number)st->update_every;
                                        break;
 
@@ -1198,10 +1239,29 @@ unsigned long long rrdset_done(RRDSET *st)
                last_ut = next_ut;
        }
 
+       // align next interpolation to last collection point
+       st->last_updated.tv_sec = st->last_collected_time.tv_sec;
+       st->last_updated.tv_usec = st->last_collected_time.tv_usec;
+
        for( rd = st->dimensions; likely(rd) ; rd = rd->next ) {
                if(unlikely(!rd->updated)) continue;
-               rd->last_collected_value = rd->collected_value;
-               rd->last_calculated_value = rd->calculated_value;
+
+               int is_incremental = 0;
+               if(rd->algorithm == RRDDIM_PCENT_OVER_DIFF_TOTAL || rd->algorithm == RRDDIM_INCREMENTAL)
+                       is_incremental = 1;
+
+               if((is_incremental && !in_the_same_interpolation_point) || !is_incremental || !store_this_entry) {
+                       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);
+                       rd->last_collected_value = rd->collected_value;
+
+                       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);
+                       rd->last_calculated_value = rd->calculated_value;
+               }
+               else {
+                       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);
+                       rd->calculated_value = 0;
+               }
+
                rd->collected_value = 0;
                rd->updated = 0;
 
index c3d1e8357a49d49f77baaa3c3192dcd884430f4f..0582819f0cd237a447c52eadeb5a61d54cc964ae 100755 (executable)
@@ -241,6 +241,426 @@ int unit_test_storage()
        return r;
 }
 
+
+// --------------------------------------------------------------------------------------------------------------------
+
+struct feed_values {
+               unsigned long long microseconds;
+               calculated_number value;
+};
+
+struct test {
+       char name[100];
+       char description[1024];
+
+       int update_every;
+       unsigned long long multiplier;
+       unsigned long long divisor;
+       int algorithm;
+
+       unsigned long feed_entries;
+       unsigned long result_entries;
+       struct feed_values *feed;
+       calculated_number *results;
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test1
+// test absolute values stored
+
+struct feed_values test1_feed[] = {
+               { 0, 10 },
+               { 1000000, 20 },
+               { 1000000, 30 },
+               { 1000000, 40 },
+               { 1000000, 50 },
+               { 1000000, 60 },
+               { 1000000, 70 },
+               { 1000000, 80 },
+               { 1000000, 90 },
+               { 1000000, 100 },
+};
+
+calculated_number test1_results[] = {
+               20, 30, 40, 50, 60, 70, 80, 90, 100
+};
+
+struct test test1 = {
+               "test1",                        // name
+               "test absolute values stored at exactly second boundaries",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_ABSOLUTE,        // algorithm
+               10,                                     // feed entries
+               9,                                      // result entries
+               test1_feed,                     // feed
+               test1_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test2
+// test absolute values stored in the middle of second boundaries
+
+struct feed_values test2_feed[] = {
+               { 500000, 10 },
+               { 1000000, 20 },
+               { 1000000, 30 },
+               { 1000000, 40 },
+               { 1000000, 50 },
+               { 1000000, 60 },
+               { 1000000, 70 },
+               { 1000000, 80 },
+               { 1000000, 90 },
+               { 1000000, 100 },
+};
+
+calculated_number test2_results[] = {
+               20, 30, 40, 50, 60, 70, 80, 90, 100
+};
+
+struct test test2 = {
+               "test2",                        // name
+               "test absolute values stored in the middle of second boundaries",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_ABSOLUTE,        // algorithm
+               10,                                     // feed entries
+               9,                                      // result entries
+               test2_feed,                     // feed
+               test2_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test3
+
+struct feed_values test3_feed[] = {
+               { 0, 10 },
+               { 1000000, 20 },
+               { 1000000, 30 },
+               { 1000000, 40 },
+               { 1000000, 50 },
+               { 1000000, 60 },
+               { 1000000, 70 },
+               { 1000000, 80 },
+               { 1000000, 90 },
+               { 1000000, 100 },
+};
+
+calculated_number test3_results[] = {
+               10, 10, 10, 10, 10, 10, 10, 10, 10
+};
+
+struct test test3 = {
+               "test3",                        // name
+               "test incremental values stored at exactly second boundaries",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_INCREMENTAL,     // algorithm
+               10,                                     // feed entries
+               9,                                      // result entries
+               test3_feed,                     // feed
+               test3_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test4
+
+struct feed_values test4_feed[] = {
+               { 500000, 10 },
+               { 1000000, 20 },
+               { 1000000, 30 },
+               { 1000000, 40 },
+               { 1000000, 50 },
+               { 1000000, 60 },
+               { 1000000, 70 },
+               { 1000000, 80 },
+               { 1000000, 90 },
+               { 1000000, 100 },
+};
+
+calculated_number test4_results[] = {
+               5, 10, 10, 10, 10, 10, 10, 10, 10
+};
+
+struct test test4 = {
+               "test4",                        // name
+               "test incremental values stored in the middle of second boundaries",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_INCREMENTAL,     // algorithm
+               10,                                     // feed entries
+               9,                                      // result entries
+               test4_feed,                     // feed
+               test4_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test5
+
+struct feed_values test5_feed[] = {
+               { 500000, 1000 },
+               { 1000000, 2000 },
+               { 1000000, 2000 },
+               { 1000000, 2000 },
+               { 1000000, 3000 },
+               { 1000000, 2000 },
+               { 1000000, 2000 },
+               { 1000000, 2000 },
+               { 1000000, 2000 },
+               { 1000000, 2000 },
+};
+
+calculated_number test5_results[] = {
+               500, 500, 0, 500, 500, 0, 0, 0, 0
+};
+
+struct test test5 = {
+               "test5",                        // name
+               "test incremental values ups and downs",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_INCREMENTAL,     // algorithm
+               10,                                     // feed entries
+               9,                                      // result entries
+               test5_feed,                     // feed
+               test5_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test6
+
+struct feed_values test6_feed[] = {
+               { 250000, 1000 },
+               { 250000, 2000 },
+               { 250000, 3000 },
+               { 250000, 4000 },
+               { 250000, 5000 },
+               { 250000, 6000 },
+               { 250000, 7000 },
+               { 250000, 8000 },
+               { 250000, 9000 },
+               { 250000, 10000 },
+               { 250000, 11000 },
+               { 250000, 12000 },
+               { 250000, 13000 },
+               { 250000, 14000 },
+               { 250000, 15000 },
+               { 250000, 16000 },
+};
+
+calculated_number test6_results[] = {
+               3000, 4000, 4000, 4000
+};
+
+struct test test6 = {
+               "test6",                        // name
+               "test incremental values updated within the same second",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_INCREMENTAL,     // algorithm
+               16,                                     // feed entries
+               4,                                      // result entries
+               test6_feed,                     // feed
+               test6_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test7
+
+struct feed_values test7_feed[] = {
+               { 500000, 1000 },
+               { 2000000, 2000 },
+               { 2000000, 3000 },
+               { 2000000, 4000 },
+               { 2000000, 5000 },
+               { 2000000, 6000 },
+               { 2000000, 7000 },
+               { 2000000, 8000 },
+               { 2000000, 9000 },
+               { 2000000, 10000 },
+};
+
+calculated_number test7_results[] = {
+               250, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500
+};
+
+struct test test7 = {
+               "test7",                        // name
+               "test incremental values updated in long durations",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_INCREMENTAL,     // algorithm
+               10,                                     // feed entries
+               18,                                     // result entries
+               test7_feed,                     // feed
+               test7_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test8
+
+struct feed_values test8_feed[] = {
+               { 500000, 1000 },
+               { 2000000, 2000 },
+               { 2000000, 3000 },
+               { 2000000, 4000 },
+               { 2000000, 5000 },
+               { 2000000, 6000 },
+};
+
+calculated_number test8_results[] = {
+               1250, 2000, 2250, 3000, 3250, 4000, 4250, 5000, 5250, 6000
+};
+
+struct test test8 = {
+               "test8",                        // name
+               "test absolute values updated in long durations",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_ABSOLUTE,        // algorithm
+               6,                                      // feed entries
+               10,                                     // result entries
+               test8_feed,                     // feed
+               test8_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+// test9
+
+struct feed_values test9_feed[] = {
+               { 250000, 1000 },
+               { 250000, 2000 },
+               { 250000, 3000 },
+               { 250000, 4000 },
+               { 250000, 5000 },
+               { 250000, 6000 },
+               { 250000, 7000 },
+               { 250000, 8000 },
+               { 250000, 9000 },
+               { 250000, 10000 },
+               { 250000, 11000 },
+               { 250000, 12000 },
+               { 250000, 13000 },
+               { 250000, 14000 },
+               { 250000, 15000 },
+               { 250000, 16000 },
+};
+
+calculated_number test9_results[] = {
+               4000, 8000, 12000, 16000
+};
+
+struct test test9 = {
+               "test9",                        // name
+               "test absolute values updated within the same second",
+               1,                                      // update_every
+               1,                                      // multiplier
+               1,                                      // divisor
+               RRDDIM_ABSOLUTE,        // algorithm
+               16,                                     // feed entries
+               4,                                      // result entries
+               test9_feed,                     // feed
+               test9_results           // results
+};
+
+// --------------------------------------------------------------------------------------------------------------------
+
+int run_test(struct test *test)
+{
+       fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
+
+       rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+       rrd_update_every = test->update_every;
+
+       char name[101];
+       snprintf(name, 100, "unittest-%s", test->name);
+
+       // create the chart
+       RRDSET *st = rrdset_create("netdata", name, name, "netdata", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
+       RRDDIM *rd = rrddim_add(st, "dimension", NULL, test->multiplier, test->divisor, test->algorithm);
+       st->debug = 1;
+
+       // feed it with the test data
+       unsigned long c;
+       for(c = 0; c < test->feed_entries; c++) {
+               if(debug_flags) fprintf(stderr, "\n\n");
+
+               if(c) {
+                       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);
+                       rrdset_next_usec(st, test->feed[c].microseconds);
+               }
+               else {
+                       fprintf(stderr, "    > %s: feeding position %lu with value " CALCULATED_NUMBER_FORMAT "\n", test->name, c+1, test->feed[c].value);
+               }
+
+               rrddim_set(st, "dimension", test->feed[c].value);
+               rrdset_done(st);
+
+               // align the first entry to second boundary
+               if(!c) {
+                       fprintf(stderr, "    > %s: fixing first collection time to be %llu microseconds to second boundary\n", test->name, test->feed[c].microseconds);
+                       rd->last_collected_time.tv_usec = st->last_collected_time.tv_usec = st->last_updated.tv_usec = test->feed[c].microseconds;
+               }
+       }
+
+       // check the result
+       int errors = 0;
+
+       if(st->counter != test->result_entries) {
+               fprintf(stderr, "    %s stored %lu entries, but we were expecting %lu, ### E R R O R ###\n", test->name, st->counter, test->result_entries);
+               errors++;
+       }
+
+       unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries;
+       for(c = 0 ; c < max ; c++) {
+               calculated_number v = unpack_storage_number(rd->values[c]), n = test->results[c];
+               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 ###");
+               if(v != n) errors++;
+       }
+
+       return errors;
+}
+
+int run_all_mockup_tests(void)
+{
+       if(run_test(&test1))
+               return 1;
+
+       if(run_test(&test2))
+               return 1;
+
+       if(run_test(&test3))
+               return 1;
+
+       if(run_test(&test4))
+               return 1;
+
+       if(run_test(&test5))
+               return 1;
+
+       if(run_test(&test6))
+               return 1;
+
+       if(run_test(&test7))
+               return 1;
+
+       if(run_test(&test8))
+               return 1;
+
+       if(run_test(&test9))
+               return 1;
+
+       return 0;
+}
+
 int unit_test(long delay, long shift)
 {
        static int repeat = 0;
@@ -249,14 +669,14 @@ int unit_test(long delay, long shift)
        char name[101];
        snprintf(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
 
-       debug_flags = 0xffffffff;
+       //debug_flags = 0xffffffff;
        rrd_memory_mode = RRD_MEMORY_MODE_RAM;
        rrd_update_every = 1;
 
        int do_abs = 1;
        int do_inc = 1;
-       int do_abst = 1;
-       int do_absi = 1;
+       int do_abst = 0;
+       int do_absi = 0;
 
        RRDSET *st = rrdset_create("netdata", name, name, "netdata", "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
        st->debug = 1;
@@ -296,7 +716,8 @@ int unit_test(long delay, long shift)
                }
 
                // prevent it from deleting the dimensions
-               for(rd = st->dimensions ; rd ; rd = rd->next) rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
+               for(rd = st->dimensions ; rd ; rd = rd->next)
+                       rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
 
                rrdset_done(st);
        }
@@ -306,27 +727,30 @@ int unit_test(long delay, long shift)
        fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %lu, DELAY %lu, SHIFT %lu\n", oincrement * 10, increment * 10, delay, shift);
 
        int ret = 0;
-       storage_number v;
+       storage_number sn;
+       calculated_number cn, v;
        for(c = 0 ; c < st->counter ; c++) {
-               fprintf(stderr, "\nPOSITION: c = %lu, VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
+               fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
 
                for(rd = st->dimensions ; rd ; rd = rd->next) {
-                       fprintf(stderr, "\t %s " STORAGE_NUMBER_FORMAT "   ->   ", rd->id, rd->values[c]);
+                       sn = rd->values[c];
+                       cn = unpack_storage_number(sn);
+                       fprintf(stderr, "\t %s " CALCULATED_NUMBER_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ")   ->   ", rd->id, cn, sn);
 
                        if(rd == rdabs) v =
                                (         oincrement
-                                       + (increment * (1000000 - shift) / 1000000)
-                                       + c * increment
-                               ) * 10;
+                                       // + (increment * (1000000 - shift) / 1000000)
+                                       + (c + 1) * increment
+                               );
 
-                       else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000)) * 10;
-                       else if(rd == rdabst) v = oincrement / dimensions;
-                       else if(rd == rdabsi) v = oincrement / dimensions;
+                       else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000));
+                       else if(rd == rdabst) v = oincrement / dimensions / 10;
+                       else if(rd == rdabsi) v = oincrement / dimensions / 10;
                        else v = 0;
 
-                       if(v == rd->values[c]) fprintf(stderr, "passed.\n");
+                       if(v == cn) fprintf(stderr, "passed.\n");
                        else {
-                               fprintf(stderr, "ERROR! (expected " STORAGE_NUMBER_FORMAT ")\n", v);
+                               fprintf(stderr, "ERROR! (expected " CALCULATED_NUMBER_FORMAT ")\n", v);
                                ret = 1;
                        }
                }
@@ -337,4 +761,3 @@ int unit_test(long delay, long shift)
 
        return ret;
 }
-
index c402d2cf164e42b491ae10dbb5cb6731042a249b..916ad71f231666054e4713f82edbb726f71dbb15 100755 (executable)
@@ -3,5 +3,6 @@
 
 extern int unit_test_storage(void);
 extern int unit_test(long delay, long shift);
+extern int run_all_mockup_tests(void);
 
 #endif /* NETDATA_UNIT_TEST_H */