github.com/go-graphite/carbonapi@v0.17.0/expr/helper/helper_test.go (about)

     1  package helper
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/go-graphite/carbonapi/expr/types"
    10  )
    11  
    12  func TestGCD(t *testing.T) {
    13  	tests := []struct {
    14  		arg1     int64
    15  		arg2     int64
    16  		expected int64
    17  	}{
    18  		{
    19  			13,
    20  			17,
    21  			1,
    22  		},
    23  		{
    24  			14,
    25  			21,
    26  			7,
    27  		},
    28  		{
    29  			12,
    30  			16,
    31  			4,
    32  		},
    33  	}
    34  	for _, tt := range tests {
    35  		t.Run(fmt.Sprintf("GDC(%v, %v)=>%v", tt.arg1, tt.arg2, tt.expected), func(t *testing.T) {
    36  			value := GCD(tt.arg1, tt.arg2)
    37  			if value != tt.expected {
    38  				t.Errorf("GCD of %v and %v != %v: %v", tt.arg1, tt.arg2, tt.expected, value)
    39  			}
    40  		})
    41  	}
    42  }
    43  
    44  func TestLCM(t *testing.T) {
    45  	tests := []struct {
    46  		args     []int64
    47  		expected int64
    48  	}{
    49  		{
    50  			[]int64{2, 3},
    51  			6,
    52  		},
    53  		{
    54  			[]int64{},
    55  			0,
    56  		},
    57  		{
    58  			[]int64{15},
    59  			15,
    60  		},
    61  		{
    62  			[]int64{10, 15, 20},
    63  			60,
    64  		},
    65  	}
    66  	for _, tt := range tests {
    67  		t.Run(fmt.Sprintf("LMC(%v)=>%v", tt.args, tt.expected), func(t *testing.T) {
    68  			value := LCM(tt.args...)
    69  			if value != tt.expected {
    70  				t.Errorf("LCM of %v != %v: %v", tt.args, tt.expected, value)
    71  			}
    72  		})
    73  	}
    74  }
    75  
    76  func TestGetCommonStep(t *testing.T) {
    77  	tests := []struct {
    78  		metrics    []*types.MetricData
    79  		commonStep int64
    80  		changed    bool
    81  	}{
    82  		// Different steps and start/stop time
    83  		{
    84  			[]*types.MetricData{
    85  				types.MakeMetricData("metric1", make([]float64, 15), 5, 5), // 5..80
    86  				types.MakeMetricData("metric2", make([]float64, 30), 2, 4), // 4..64
    87  				types.MakeMetricData("metric2", make([]float64, 25), 3, 6), // 6..81
    88  			},
    89  			30,
    90  			true,
    91  		},
    92  		// Same set of points
    93  		{
    94  			[]*types.MetricData{
    95  				types.MakeMetricData("metric1", make([]float64, 15), 5, 5), // 5..80
    96  				types.MakeMetricData("metric2", make([]float64, 15), 5, 5), // 5..80
    97  				types.MakeMetricData("metric3", make([]float64, 15), 5, 5), // 5..80
    98  			},
    99  			5,
   100  			false,
   101  		},
   102  		// Same step, different lengths
   103  		{
   104  			[]*types.MetricData{
   105  				types.MakeMetricData("metric1", make([]float64, 5), 5, 15), // 15..40
   106  				types.MakeMetricData("metric2", make([]float64, 8), 5, 30), // 30..70
   107  				types.MakeMetricData("metric3", make([]float64, 4), 5, 35), // 35..55
   108  			},
   109  			5,
   110  			false,
   111  		},
   112  	}
   113  	for i, tt := range tests {
   114  		t.Run(fmt.Sprintf("Set %v", i), func(t *testing.T) {
   115  			com, changed := GetCommonStep(tt.metrics)
   116  			if com != tt.commonStep {
   117  				t.Errorf("Result of GetCommonStep: %v; expected is %v", com, tt.commonStep)
   118  			}
   119  			if changed != tt.changed {
   120  				t.Errorf("GetCommonStep changed: %v; expected is %v", changed, tt.changed)
   121  			}
   122  		})
   123  	}
   124  }
   125  
   126  func TestScaleToCommonStep(t *testing.T) {
   127  	NaN := math.NaN()
   128  	tests := []struct {
   129  		name       string
   130  		metrics    []*types.MetricData
   131  		commonStep int64
   132  		expected   []*types.MetricData
   133  	}{
   134  		{
   135  			"Normal metrics",
   136  			[]*types.MetricData{
   137  				types.MakeMetricData("metric1", []float64{1, 3, 5, 7, 9, 11, 13, 15, 17}, 1, 4), // 4..13
   138  				types.MakeMetricData("metric2", []float64{1, 2, 3, 4, 5}, 2, 4),                 // 4..14
   139  				types.MakeMetricData("metric3", []float64{1, 2, 3, 4, 5, 6}, 3, 3),              // 3..21
   140  			},
   141  			0,
   142  			[]*types.MetricData{
   143  				types.MakeMetricData("metric1", []float64{2, 10, 17, NaN}, 6, 0), // 0..18
   144  				types.MakeMetricData("metric2", []float64{1, 3, 5, NaN}, 6, 0),   // 0..18
   145  				types.MakeMetricData("metric3", []float64{1, 2.5, 4.5, 6}, 6, 0), // 0..24
   146  			},
   147  		},
   148  
   149  		// Indx     |  0   |   1  |   2  |   3  |   4  |   5  |   6  |   7  |   8  |   9  |   10  |   11  |   12  |   13  |   14  |   15  |   20  |   21  |   22  |   23  |   24  |   25  |   26  |   27  |   28  |   29  |
   150  		// commonStep  6
   151  		// Start  0 (2 - 2 % 6)
   152  		//
   153  		// ConsolidationFunc = "sum", XFilesFactor = 0.45
   154  		//  metric1 |      |      |      |   N  |   3  |   5  |   7  |   9  |  11  |  13  |   15  |   17  |       |       |       |       |       |       |       |       |       |       |       |       |       |       |
   155  		//  metric1 |  N   |      |      |      |      |      |  72  |      |      |      |       |       |       |       |       |       |       |       |       |       |       |       |       |       |       |       |
   156  		//
   157  		// ConsolidationFunc = "min", XFilesFactor = 0.45
   158  		//  metric2 |      |      |      |      |   1  |      |   2  |      |   3  |      |    4  |       |    5  |       |       |       |       |       |       |       |       |       |       |       |       |       |
   159  		//  metric2 |  N   |      |      |      |      |      |   2  |      |      |      |       |       |    N  |       |       |       |       |       |       |       |       |       |       |       |       |       |
   160  		{
   161  			"xFilesFactor and custom aggregate function",
   162  			[]*types.MetricData{
   163  				types.MakeMetricData("metric1", []float64{NaN, 3, 5, 7, 9, 11, 13, 15, 17}, 1, 3).SetConsolidationFunc("sum").SetXFilesFactor(0.45),
   164  				types.MakeMetricData("metric2", []float64{1, 2, 3, 4, 5}, 2, 4).SetConsolidationFunc("min").SetXFilesFactor(0.45),
   165  				types.MakeMetricData("metric3", []float64{1, 2, 3, 4, 5, 6}, 3, 3).SetConsolidationFunc("max").SetXFilesFactor(0.51),
   166  				types.MakeMetricData("metric6", []float64{1, 2, 3, 4, 5}, 6, 0),
   167  			},
   168  			0,
   169  			[]*types.MetricData{
   170  				types.MakeMetricData("metric1", []float64{NaN, 72, NaN, NaN, NaN}, 6, 0), // 0..12
   171  				types.MakeMetricData("metric2", []float64{NaN, 2, NaN, NaN, NaN}, 6, 0),  // 0..18
   172  				types.MakeMetricData("metric3", []float64{NaN, 3, 5, NaN, NaN}, 6, 0),    // 0..24
   173  				types.MakeMetricData("metric6", []float64{1, 2, 3, 4, 5}, 6, 0),          // 0..30, unchanged
   174  			},
   175  		},
   176  		{
   177  			"Custom common step",
   178  			[]*types.MetricData{
   179  				types.MakeMetricData("metric1", []float64{NaN, 3, 5, 7, 9, 11, 13, 15, 17}, 1, 3), // 3..12
   180  				types.MakeMetricData("metric2", []float64{1, 2, 3, 4, 5}, 2, 4),                   // 4..14
   181  				types.MakeMetricData("metric3", []float64{1, 2, 3, 4, 5, 6}, 3, 3),                // 3..21
   182  				types.MakeMetricData("metric6", []float64{1, 2, 3, 4, 5}, 6, 0),                   // 0..30
   183  			},
   184  			12,
   185  			[]*types.MetricData{
   186  				types.MakeMetricData("metric1", []float64{10, NaN, NaN}, 12, 0), // 0..12
   187  				types.MakeMetricData("metric2", []float64{2.5, 5, NaN}, 12, 0),  // 0..18
   188  				types.MakeMetricData("metric3", []float64{2, 5, NaN}, 12, 0),    // 0..24
   189  				types.MakeMetricData("metric6", []float64{1.5, 3.5, 5}, 12, 0),  // 0..30, unchanged
   190  			},
   191  		},
   192  	}
   193  	for _, tt := range tests {
   194  		t.Run(tt.name, func(t *testing.T) {
   195  			result := ScaleToCommonStep(tt.metrics, tt.commonStep)
   196  			if len(result) != len(tt.expected) {
   197  				t.Errorf("Result has different length %v than expected %v", len(result), len(tt.expected))
   198  			}
   199  			for i, r := range result {
   200  				e := tt.expected[i]
   201  				if len(r.Values) != len(e.Values) {
   202  					t.Fatalf("Values of result[%v] has the different length %+v than expected %+v", i, r.Values, e.Values)
   203  				}
   204  				for v, rv := range r.Values {
   205  					ev := e.Values[v]
   206  					if math.IsNaN(rv) != math.IsNaN(ev) {
   207  						t.Errorf("One of result[%v][%v] is NaN, but not the second: result=%v, expected=%v", i, v, rv, ev)
   208  					} else if !math.IsNaN(rv) && (rv != ev) {
   209  						t.Errorf("result[%v][%v] %v != expected[%v][%v]: %v", i, v, rv, i, v, ev)
   210  					}
   211  				}
   212  				if r.StartTime != e.StartTime {
   213  					t.Errorf("result[%v].StartTime %v != expected[%v].StartTime %v", i, r.StartTime, i, e.StartTime)
   214  				}
   215  				if r.StopTime != e.StopTime {
   216  					t.Errorf("result[%v].StopTime %v != expected[%v].StopTime %v", i, r.StopTime, i, e.StopTime)
   217  				}
   218  				if r.StepTime != e.StepTime {
   219  					t.Errorf("result[%v].StepTime %v != expected[%v].StepTime %v", i, r.StepTime, i, e.StepTime)
   220  				}
   221  			}
   222  		})
   223  	}
   224  }
   225  
   226  func TestGetCommonTags(t *testing.T) {
   227  	first := map[string]string{"tag1": "value1", "tag2": "onevalue", "tag3": "value3"}
   228  	second := map[string]string{"tag1": "value1", "tag2": "differentvalue", "tag4": "value4"}
   229  
   230  	expected := map[string]string{"tag1": "value1"}
   231  	result := GetCommonTags([]*types.MetricData{{Tags: first}, {Tags: second}})
   232  
   233  	if !reflect.DeepEqual(expected, result) {
   234  		t.Errorf("expected %v, got %v", expected, result)
   235  	}
   236  }