Beispiel #1
0
func TestCommand_Describe(t *testing.T) {
	fakeApi := mocks.NewFakeApi()
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("dc=west,env=production,host=a")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("dc=west,env=staging,host=b")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("dc=east,env=production,host=c")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("dc=east,env=staging,host=d")}, emptyGraphiteName)

	for _, test := range []struct {
		query    string
		backend  api.API
		expected map[string][]string
	}{
		{"describe series_0", fakeApi, map[string][]string{"dc": {"east", "west"}, "env": {"production", "staging"}, "host": {"a", "b", "c", "d"}}},
		{"describe`series_0`", fakeApi, map[string][]string{"dc": {"east", "west"}, "env": {"production", "staging"}, "host": {"a", "b", "c", "d"}}},
		{"describe series_0 where dc='west'", fakeApi, map[string][]string{"dc": {"west"}, "env": {"production", "staging"}, "host": {"a", "b"}}},
		{"describe`series_0`where(dc='west')", fakeApi, map[string][]string{"dc": {"west"}, "env": {"production", "staging"}, "host": {"a", "b"}}},
		{"describe series_0 where dc='west' or env = 'production'", fakeApi, map[string][]string{"dc": {"east", "west"}, "env": {"production", "staging"}, "host": {"a", "b", "c"}}},
		{"describe series_0 where`dc`='west'or`env`='production'", fakeApi, map[string][]string{"dc": {"east", "west"}, "env": {"production", "staging"}, "host": {"a", "b", "c"}}},
		{"describe series_0 where dc='west' or env = 'production' and doesnotexist = ''", fakeApi, map[string][]string{"dc": {"west"}, "env": {"production", "staging"}, "host": {"a", "b"}}},
		{"describe series_0 where env = 'production' and doesnotexist = '' or dc = 'west'", fakeApi, map[string][]string{"dc": {"west"}, "env": {"production", "staging"}, "host": {"a", "b"}}},
		{"describe series_0 where (dc='west' or env = 'production') and doesnotexist = ''", fakeApi, map[string][]string{}},
		{"describe series_0 where(dc='west' or env = 'production')and`doesnotexist` = ''", fakeApi, map[string][]string{}},
	} {
		a := assert.New(t).Contextf("query=%s", test.query)
		command, err := Parse(test.query)
		if err != nil {
			a.Errorf("Unexpected error while parsing")
			continue
		}

		a.EqString(command.Name(), "describe")
		rawResult, _ := command.Execute(ExecutionContext{Backend: nil, API: test.backend, FetchLimit: 1000, Timeout: 0})
		a.Eq(rawResult, test.expected)
	}
}
func TestCommand_Describe(t *testing.T) {
	fakeApi := mocks.NewFakeApi()
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("dc=west,env=production,host=a")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("dc=west,env=staging,host=b")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("dc=east,env=production,host=c")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("dc=east,env=staging,host=d")}, emptyGraphiteName)

	for _, test := range []struct {
		query   string
		backend api.API
		length  int // expected length of the result.
	}{
		{"describe series_0", fakeApi, 4},
		{"describe`series_0`", fakeApi, 4},
		{"describe series_0 where dc='west'", fakeApi, 2},
		{"describe`series_0`where(dc='west')", fakeApi, 2},
		{"describe series_0 where dc='west' or env = 'production'", fakeApi, 3},
		{"describe series_0 where`dc`='west'or`env`='production'", fakeApi, 3},
		{"describe series_0 where dc='west' or env = 'production' and doesnotexist = ''", fakeApi, 2},
		{"describe series_0 where env = 'production' and doesnotexist = '' or dc = 'west'", fakeApi, 2},
		{"describe series_0 where (dc='west' or env = 'production') and doesnotexist = ''", fakeApi, 0},
		{"describe series_0 where(dc='west' or env = 'production')and`doesnotexist` = ''", fakeApi, 0},
	} {
		a := assert.New(t).Contextf("query=%s", test.query)
		command, err := Parse(test.query)
		if err != nil {
			a.Errorf("Unexpected error while parsing")
			continue
		}
		a.EqString(command.Name(), "describe")
		rawResult, _ := command.Execute(ExecutionContext{Backend: nil, API: test.backend, FetchLimit: 1000, Timeout: 0})
		parsedResult := rawResult.([]string)
		a.EqInt(len(parsedResult), test.length)
	}
}
Beispiel #3
0
func TestCommand_DescribeAll(t *testing.T) {
	fakeApi := mocks.NewFakeApi()
	fakeApi.AddPair(api.TaggedMetric{"series_0", api.ParseTagSet("")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_1", api.ParseTagSet("")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_2", api.ParseTagSet("")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_3", api.ParseTagSet("")}, emptyGraphiteName)

	for _, test := range []struct {
		query    string
		backend  api.API
		expected []api.MetricKey
	}{
		{"describe all", fakeApi, []api.MetricKey{"series_0", "series_1", "series_2", "series_3"}},
		{"describe all match '_0'", fakeApi, []api.MetricKey{"series_0"}},
		{"describe all match '_5'", fakeApi, []api.MetricKey{}},
	} {
		a := assert.New(t).Contextf("query=%s", test.query)
		command, err := Parse(test.query)
		if err != nil {
			a.Errorf("Unexpected error while parsing")
			continue
		}

		a.EqString(command.Name(), "describe all")
		rawResult, err := command.Execute(ExecutionContext{Backend: nil, API: test.backend, FetchLimit: 1000, Timeout: 0})
		a.CheckError(err)
		a.Eq(rawResult, test.expected)
	}
}
func Test_TagIndex(t *testing.T) {
	a := assert.New(t)
	db := newDatabase(t)
	if db == nil {
		return
	}
	defer cleanDatabase(t, db)
	if db == nil {
		return
	}
	if rows, err := db.GetMetricKeys("environment", "production"); err != nil {
		a.CheckError(err)
	} else {
		a.EqInt(len(rows), 0)
	}
	a.CheckError(db.AddToTagIndex("environment", "production", "a.b.c"))
	a.CheckError(db.AddToTagIndex("environment", "production", "d.e.f"))
	if rows, err := db.GetMetricKeys("environment", "production"); err != nil {
		a.CheckError(err)
	} else {
		a.EqInt(len(rows), 2)
	}

	a.CheckError(db.RemoveFromTagIndex("environment", "production", "a.b.c"))
	if rows, err := db.GetMetricKeys("environment", "production"); err != nil {
		a.CheckError(err)
	} else {
		a.EqInt(len(rows), 1)
		a.EqString(string(rows[0]), "d.e.f")
	}
}
Beispiel #5
0
func TestFunctionName(t *testing.T) {
	a := assert.New(t)
	a.EqString(functionName(0), "TestFunctionName")
	first, second := testFunction1()
	a.EqString(first, "testFunction1")
	a.EqString(second, "TestFunctionName")
}
Beispiel #6
0
func TestCompile_Good(t *testing.T) {
	a := assert.New(t)
	_, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
}
Beispiel #7
0
func checkConversionErrorCode(t *testing.T, err error, expected ConversionErrorCode) {
	casted, ok := err.(ConversionError)
	if !ok {
		t.Errorf("Invalid Error type")
		return
	}
	a := assert.New(t)
	a.EqInt(int(casted.Code()), int(expected))
}
Beispiel #8
0
func TestCompile(t *testing.T) {
	for _, row := range inputs {
		a := assert.New(t).Contextf(row)
		p := Parser{Buffer: row}
		p.Init()
		a.CheckError(p.Parse())
		p.Execute()
		testParserResult(a, p)
	}
}
Beispiel #9
0
func TestUnescapeLiteral(t *testing.T) {
	a := assert.New(t)
	a.EqString(unescapeLiteral("'foo'"), "foo")
	a.EqString(unescapeLiteral("foo"), "foo")
	a.EqString(unescapeLiteral("nodes.cpu.io"), "nodes.cpu.io")
	a.EqString(unescapeLiteral(`"hello"`), `hello`)
	a.EqString(unescapeLiteral(`"\"hello\""`), `"hello"`)
	a.EqString(unescapeLiteral(`'\"hello\"'`), `"hello"`)
	a.EqString(unescapeLiteral("\"\\`\""), "`")
}
Beispiel #10
0
func Test_Registry_Default(t *testing.T) {
	a := assert.New(t)
	sr := StandardRegistry{mapping: make(map[string]function.MetricFunction)}
	a.Eq(sr.All(), []string{})
	if err := sr.Register(function.MetricFunction{Name: "foo", Compute: dummyCompute}); err != nil {
		a.CheckError(err)
	}
	if err := sr.Register(function.MetricFunction{Name: "bar", Compute: dummyCompute}); err != nil {
		a.CheckError(err)
	}
	a.Eq(sr.All(), []string{"bar", "foo"})
}
Beispiel #11
0
func TestRandom(t *testing.T) {
	a := assert.New(t)
	expected := []string{"Apple", "apple", "file2", "file22", "file90", "file99", "file100", "Zoo", "zoo"}
	test := []string{"Apple", "apple", "file2", "file22", "file90", "file99", "file100", "Zoo", "zoo"}
	Sort(test)
	a.Eq(test, expected)
	for i := 0; i < 1000; i++ {
		testShuffle(test)
		a := a.Contextf("input: %+v", test)
		Sort(test)
		a.Eq(test, expected)
	}
}
Beispiel #12
0
func TestLoadYAML_Invalid(t *testing.T) {
	a := assert.New(t)
	rawYAML := `
rules
  -
    pattern: foo.bar.baz.%tag%
    metric_key: abc
    regex: {}
  `
	ruleSet, err := LoadYAML([]byte(rawYAML))
	checkRuleErrorCode(a, err, InvalidYaml)
	a.EqInt(len(ruleSet.rules), 0)
}
Beispiel #13
0
func TestNaturalSort(t *testing.T) {
	a := assert.New(t)
	expected := []string{"Apple", "apple", "file2", "file22", "file90", "file99", "file100", "Zoo", "zoo"}
	tests := [][]string{
		{"Apple", "apple", "file2", "file90", "file99", "file100", "Zoo", "zoo", "file22"},
		{"Zoo", "Apple", "apple", "file100", "file2", "file90", "file99", "zoo", "file22"},
		{"file2", "file90", "apple", "Zoo", "file100", "file22", "file99", "zoo", "Apple"},
	}
	Sort([]string{}) // check that no panic occurs
	for _, test := range tests {
		Sort(test)
		a.Eq(test, expected)
	}
}
Beispiel #14
0
func Test_FetchCounter(t *testing.T) {
	c := NewFetchCounter(10)
	a := assert.New(t)
	a.EqInt(c.Current(), 0)
	a.EqInt(c.Limit(), 10)
	a.EqBool(c.Consume(5), true)
	a.EqInt(c.Current(), 5)
	a.EqBool(c.Consume(4), true)
	a.EqInt(c.Current(), 9)
	a.EqBool(c.Consume(1), true)
	a.EqInt(c.Current(), 10)
	a.EqBool(c.Consume(1), false)
	a.EqInt(c.Current(), 11)
}
Beispiel #15
0
func TestLoadYAML(t *testing.T) {
	a := assert.New(t)
	rawYAML := `
rules:
  -
    pattern: foo.bar.baz.%tag%
    metric_key: abc
    regex: {}
  `
	ruleSet, err := LoadYAML([]byte(rawYAML))
	a.CheckError(err)
	a.EqInt(len(ruleSet.rules), 1)
	a.EqString(string(ruleSet.rules[0].raw.MetricKeyPattern), "abc")
	a.Eq(ruleSet.rules[0].graphitePatternTags, []string{"tag"})
}
Beispiel #16
0
func Test_ParallelMultiBackend_Success(t *testing.T) {
	a := assert.New(t)
	suite := newSuite()
	defer suite.cleanup()
	go func() {
		_, err := suite.multiBackend.FetchMultipleSeries(api.FetchMultipleRequest{
			Metrics:     []api.TaggedMetric{api.TaggedMetric{"a", api.NewTagSet()}},
			Cancellable: suite.cancellable,
		})
		a.CheckError(err)
		suite.waitGroup.Done()
	}()
	suite.backend.tickets <- struct{}{}
	suite.waitGroup.Wait()
}
Beispiel #17
0
func TestToGraphiteName(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
	tm := api.TaggedMetric{
		MetricKey: "test-metric",
		TagSet:    api.ParseTagSet("foo=fooValue"),
	}
	reversed, err := rule.ToGraphiteName(tm)
	a.CheckError(err)
	a.EqString(string(reversed), "prefix.fooValue")
}
Beispiel #18
0
func TestCompile_Error(t *testing.T) {
	for _, test := range []struct {
		rawRule      RawRule
		expectedCode RuleErrorCode
	}{
		{RawRule{Pattern: "prefix.%foo%", MetricKeyPattern: ""}, InvalidMetricKey},
		{RawRule{Pattern: "prefix.%foo%abc%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%.%foo%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%.abc.%%", MetricKeyPattern: "test-metric"}, InvalidPattern},
		{RawRule{Pattern: "prefix.%foo%", MetricKeyPattern: "test-metric", Regex: map[string]string{"foo": "(bar)"}}, InvalidCustomRegex},
	} {
		_, err := Compile(test.rawRule)
		a := assert.New(t).Contextf("%s", test.rawRule.Pattern)
		checkRuleErrorCode(a, err, test.expectedCode)
	}
}
Beispiel #19
0
func TestTimeseries_Downsample(t *testing.T) {
	a := assert.New(t)
	for _, suite := range []struct {
		input      []float64
		inputRange Timerange
		newRange   Timerange
		sampler    func([]float64) float64
		expected   []float64
	}{
		{[]float64{1, 2, 3, 4, 5}, Timerange{0, 4, 1}, Timerange{0, 4, 2}, max, []float64{2, 4, 5}},
	} {
		tagset := ParseTagSet("key=value")
		ts := Timeseries{suite.input, tagset}
		sampled, err := ts.downsample(suite.inputRange, suite.newRange, suite.sampler)
		a.CheckError(err)
		a.Eq(sampled.Values, suite.expected)
	}
}
Beispiel #20
0
func Test_ScalarExpression(t *testing.T) {
	timerangeA, err := api.NewTimerange(0, 10, 2)
	if err != nil {
		t.Fatalf("invalid timerange used for testcase")
		return
	}
	for _, test := range []struct {
		expr           scalarExpression
		timerange      api.Timerange
		expectedSeries []api.Timeseries
	}{
		{
			scalarExpression{5},
			timerangeA,
			[]api.Timeseries{
				api.Timeseries{
					[]float64{5.0, 5.0, 5.0, 5.0, 5.0, 5.0},
					api.NewTagSet(),
				},
			},
		},
	} {
		a := assert.New(t).Contextf("%+v", test)
		result, err := evaluateToSeriesList(test.expr, function.EvaluationContext{
			MultiBackend: backend.NewSequentialMultiBackend(FakeBackend{}),
			Timerange:    test.timerange,
			SampleMethod: api.SampleMean,
			FetchLimit:   function.NewFetchCounter(1000),
			Registry:     registry.Default(),
		})

		if err != nil {
			t.Fatalf("failed to convert number into serieslist")
		}

		a.EqInt(len(result.Series), len(test.expectedSeries))

		for i := 0; i < len(result.Series); i += 1 {
			a.Eq(result.Series[i].Values, test.expectedSeries[i].Values)
		}
	}
}
func Test_GetAllMetrics(t *testing.T) {
	a := assert.New(t)
	db := newDatabase(t)
	if db == nil {
		return
	}
	defer cleanDatabase(t, db)
	a.CheckError(db.AddMetricName("metric.a", api.ParseTagSet("foo=a")))
	a.CheckError(db.AddMetricName("metric.a", api.ParseTagSet("foo=b")))
	keys, err := db.GetAllMetrics()
	a.CheckError(err)
	sort.Sort(api.MetricKeys(keys))
	a.Eq(keys, []api.MetricKey{"metric.a"})
	a.CheckError(db.AddMetricName("metric.b", api.ParseTagSet("foo=c")))
	a.CheckError(db.AddMetricName("metric.b", api.ParseTagSet("foo=c")))
	keys, err = db.GetAllMetrics()
	a.CheckError(err)
	sort.Sort(api.MetricKeys(keys))
	a.Eq(keys, []api.MetricKey{"metric.a", "metric.b"})
}
Beispiel #22
0
func TestMatchRule_FilterTag(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%.%bar%",
		MetricKeyPattern: "test-metric.%bar%",
	})
	a.CheckError(err)
	originalName := "prefix.fooValue.barValue"
	matcher, matched := rule.MatchRule(originalName)
	if !matched {
		t.Errorf("Expected matching but didn't occur")
		return
	}
	a.EqString(string(matcher.MetricKey), "test-metric.barValue")
	a.Eq(matcher.TagSet, api.TagSet(map[string]string{"foo": "fooValue"}))
	// perform the reverse.
	reversed, err := rule.ToGraphiteName(matcher)
	a.CheckError(err)
	a.EqString(string(reversed), originalName)
}
Beispiel #23
0
func TestToGraphiteName_Error(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)
	reversed, err := rule.ToGraphiteName(api.TaggedMetric{
		MetricKey: "test-metric",
		TagSet:    api.ParseTagSet(""),
	})
	checkConversionErrorCode(t, err, MissingTag)
	a.EqString(string(reversed), "")

	reversed, err = rule.ToGraphiteName(api.TaggedMetric{
		MetricKey: "test-metric-foo",
		TagSet:    api.ParseTagSet("foo=fooValue"),
	})
	checkConversionErrorCode(t, err, CannotInterpolate)
	a.EqString(string(reversed), "")
}
Beispiel #24
0
func Test_Registry_Error(t *testing.T) {
	for _, suite := range []struct {
		Name     string
		Function function.MetricFunction
	}{
		{"empty name", function.MetricFunction{Name: "", Compute: dummyCompute}},
		{"duplicate name", function.MetricFunction{Name: "existing", Compute: dummyCompute}},
		{"no compute", function.MetricFunction{Name: "notexisting", Compute: nil}},
	} {
		a := assert.New(t).Contextf("%s", suite.Name)
		// set up the standard registry
		sr := StandardRegistry{mapping: make(map[string]function.MetricFunction)}
		if err := sr.Register(function.MetricFunction{Name: "existing", Compute: dummyCompute}); err != nil {
			a.CheckError(err)
			return
		}
		if err := sr.Register(suite.Function); err == nil {
			a.Errorf("Expected error, but got none.")
		}
	}
}
Beispiel #25
0
func TestMatchRule_Simple(t *testing.T) {
	a := assert.New(t)
	rule, err := Compile(RawRule{
		Pattern:          "prefix.%foo%",
		MetricKeyPattern: "test-metric",
	})
	a.CheckError(err)

	_, matches := rule.MatchRule("")
	if matches {
		t.Errorf("Unexpected matching")
	}
	matcher, matches := rule.MatchRule("prefix.abc")
	if !matches {
		t.Errorf("Expected matching but didn't occur")
	}
	a.EqString(string(matcher.MetricKey), "test-metric")
	a.EqString(matcher.TagSet["foo"], "abc")

	_, matches = rule.MatchRule("prefix.abc.def")
	if matches {
		t.Errorf("Unexpected matching")
	}
}
Beispiel #26
0
func TestMatchRule_CustomRegex(t *testing.T) {
	a := assert.New(t)
	regex := make(map[string]string)
	regex["name"] = "[a-z]+"
	regex["shard"] = "[0-9]+"
	rule, err := Compile(RawRule{
		Pattern:          "feed.%name%-shard-%shard%",
		MetricKeyPattern: "test-feed-metric",
		Regex:            regex,
	})
	a.CheckError(err)

	_, matches := rule.MatchRule("")
	if matches {
		t.Errorf("Unexpected matching")
	}
	matcher, matches := rule.MatchRule("feed.feedname-shard-12")
	if !matches {
		t.Errorf("Expected matching but didn't occur")
	}
	a.EqString(string(matcher.MetricKey), "test-feed-metric")
	a.EqString(matcher.TagSet["name"], "feedname")
	a.EqString(matcher.TagSet["shard"], "12")
}
Beispiel #27
0
func Test_ParallelMultiBackend_Timeout(t *testing.T) {
	a := assert.New(t)
	suite := newSuite()
	defer suite.cleanup()
	go func() {
		_, err := suite.multiBackend.FetchMultipleSeries(api.FetchMultipleRequest{
			Metrics:     []api.TaggedMetric{api.TaggedMetric{"a", api.NewTagSet()}},
			Cancellable: suite.cancellable,
		})
		if err == nil {
			t.Errorf("Error expected, but got nil")
		} else {
			casted, ok := err.(api.BackendError)
			if !ok {
				t.Errorf("Invalid error type")
			} else {
				a.Eq(casted.Code, api.FetchTimeoutError)
			}
		}
		suite.waitGroup.Done()
	}()
	close(suite.cancellable.Done())
	suite.waitGroup.Wait()
}
func Test_MetricName_GetTagSet(t *testing.T) {
	a := assert.New(t)
	db := newDatabase(t)
	if db == nil {
		return
	}
	defer cleanDatabase(t, db)
	if db == nil {
		return
	}
	if tags, err := db.GetTagSet("sample"); err != nil {
		t.Errorf("Error fetching tags from Cassandra")
	} else {
		a.EqInt(len(tags), 0)
	}

	metricNamesTests := []struct {
		addTest      bool
		metricName   string
		tagString    string
		expectedTags map[string][]string // { metricName: [ tags ] }
	}{
		{true, "sample", "foo=bar1", map[string][]string{
			"sample": []string{"foo=bar1"},
		}},
		{true, "sample", "foo=bar2", map[string][]string{
			"sample": []string{"foo=bar1", "foo=bar2"},
		}},
		{true, "sample2", "foo=bar2", map[string][]string{
			"sample":  []string{"foo=bar1", "foo=bar2"},
			"sample2": []string{"foo=bar2"},
		}},
		{false, "sample2", "foo=bar2", map[string][]string{
			"sample": []string{"foo=bar1", "foo=bar2"},
		}},
		{false, "sample", "foo=bar1", map[string][]string{
			"sample": []string{"foo=bar2"},
		}},
	}

	for _, c := range metricNamesTests {
		if c.addTest {
			a.CheckError(db.AddMetricName(api.MetricKey(c.metricName), api.ParseTagSet(c.tagString)))
		} else {
			a.CheckError(db.RemoveMetricName(api.MetricKey(c.metricName), api.ParseTagSet(c.tagString)))
		}

		for k, v := range c.expectedTags {
			if tags, err := db.GetTagSet(api.MetricKey(k)); err != nil {
				t.Errorf("Error fetching tags")
			} else {
				stringTags := make([]string, len(tags))
				for i, tag := range tags {
					stringTags[i] = tag.Serialize()
				}

				a.EqInt(len(stringTags), len(v))
				sort.Sort(sort.StringSlice(stringTags))
				sort.Sort(sort.StringSlice(v))
				a.Eq(stringTags, v)
			}
		}
	}
}
Beispiel #29
0
func TestTag(t *testing.T) {
	fakeApi := mocks.NewFakeApi()
	fakeBackend := backend.NewSequentialMultiBackend(fakeApiBackend{})
	tests := []struct {
		query    string
		expected api.SeriesList
	}{
		{
			query: "select series_2 | tag.drop('dc') from 0  to 120",
			expected: api.SeriesList{
				Series: []api.Timeseries{
					{
						Values: []float64{1, 2, 3, 4, 5},
						TagSet: api.TagSet{},
					},
					{
						Values: []float64{3, 0, 3, 6, 2},
						TagSet: api.TagSet{},
					},
				},
			},
		},
		{
			query: "select series_2 | tag.drop('none') from 0  to 120",
			expected: api.SeriesList{
				Series: []api.Timeseries{
					{
						Values: []float64{1, 2, 3, 4, 5},
						TagSet: api.TagSet{"dc": "west"},
					},
					{
						Values: []float64{3, 0, 3, 6, 2},
						TagSet: api.TagSet{"dc": "east"},
					},
				},
			},
		},
		{
			query: "select series_2 | tag.set('dc', 'north') from 0  to 120",
			expected: api.SeriesList{
				Series: []api.Timeseries{
					{
						Values: []float64{1, 2, 3, 4, 5},
						TagSet: api.TagSet{"dc": "north"},
					},
					{
						Values: []float64{3, 0, 3, 6, 2},
						TagSet: api.TagSet{"dc": "north"},
					},
				},
			},
		},
		{
			query: "select series_2 | tag.set('none', 'north') from 0  to 120",
			expected: api.SeriesList{
				Series: []api.Timeseries{
					{
						Values: []float64{1, 2, 3, 4, 5},
						TagSet: api.TagSet{"dc": "west", "none": "north"},
					},
					{
						Values: []float64{3, 0, 3, 6, 2},
						TagSet: api.TagSet{"dc": "east", "none": "north"},
					},
				},
			},
		},
	}
	for _, test := range tests {
		command, err := Parse(test.query)
		if err != nil {
			t.Fatalf("Unexpected error while parsing")
			return
		}
		if command.Name() != "select" {
			t.Errorf("Expected select command but got %s", command.Name())
			continue
		}
		rawResult, err := command.Execute(ExecutionContext{Backend: fakeBackend, API: fakeApi, FetchLimit: 1000, Timeout: 0})
		if err != nil {
			t.Errorf("Unexpected error while execution: %s", err.Error())
			continue
		}
		seriesListList, ok := rawResult.([]api.SeriesList)
		if !ok || len(seriesListList) != 1 {
			t.Errorf("expected query `%s` to produce []value; got %+v :: %T", test.query, rawResult, rawResult)
			continue
		}
		list := seriesListList[0]
		if err != nil {
			t.Fatal(err)
		}
		a := assert.New(t)
		expectedSeries := test.expected.Series
		for i, series := range list.Series {
			a.EqFloatArray(series.Values, expectedSeries[i].Values, 1e-100)
			if !series.TagSet.Equals(expectedSeries[i].TagSet) {
				t.Errorf("expected tagset %+v but got %+v for series %d of query %s", expectedSeries[i].TagSet, series.TagSet, i, test.query)
			}
		}
	}
}
Beispiel #30
0
func TestCommand_Select(t *testing.T) {
	epsilon := 1e-10
	fakeApi := mocks.NewFakeApi()
	fakeApi.AddPair(api.TaggedMetric{"series_1", api.ParseTagSet("dc=west")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_2", api.ParseTagSet("dc=east")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_2", api.ParseTagSet("dc=west")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_3", api.ParseTagSet("dc=west")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_3", api.ParseTagSet("dc=east")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_3", api.ParseTagSet("dc=north")}, emptyGraphiteName)
	fakeApi.AddPair(api.TaggedMetric{"series_timeout", api.ParseTagSet("dc=west")}, emptyGraphiteName)
	var fakeBackend fakeApiBackend
	testTimerange, err := api.NewTimerange(0, 120, 30)
	if err != nil {
		t.Errorf("Invalid test timerange")
		return
	}
	earlyTimerange, err := api.NewTimerange(0, 60, 30)
	if err != nil {
		t.Errorf("Invalid test timerange")
	}
	lateTimerange, err := api.NewTimerange(60, 120, 30)
	if err != nil {
		t.Errorf("Invalid test timerange")
	}
	for _, test := range []struct {
		query       string
		expectError bool
		expected    api.SeriesList
	}{
		{"select does_not_exist from 0 to 120 resolution 30ms", true, api.SeriesList{}},
		{"select series_1 from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{1, 2, 3, 4, 5},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: testTimerange,
			Name:      "series_1",
		}},
		{"select series_timeout from 0 to 120 resolution 30ms", true, api.SeriesList{}},
		{"select series_1 + 1 from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{2, 3, 4, 5, 6},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: testTimerange,
			Name:      "",
		}},
		{"select series_1 * 2 from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{2, 4, 6, 8, 10},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: testTimerange,
			Name:      "",
		}},
		{"select aggregate.max(series_2) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{3, 2, 3, 6, 5},
				api.NewTagSet(),
			}},
			Timerange: testTimerange,
			Name:      "series_2",
		}},
		{"select (1 + series_2) | aggregate.max from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{4, 3, 4, 7, 6},
				api.NewTagSet(),
			}},
			Timerange: testTimerange,
			Name:      "series_2",
		}},
		{"select series_1 from 0 to 60 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{1, 2, 3},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: earlyTimerange,
			Name:      "series_1",
		}},
		{"select transform.timeshift(series_1,31ms) from 0 to 60 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{2, 3, 4},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: earlyTimerange,
			Name:      "series_1",
		}},
		{"select transform.timeshift(series_1,62ms) from 0 to 60 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{3, 4, 5},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: earlyTimerange,
			Name:      "series_1",
		}},
		{"select transform.timeshift(series_1,29ms) from 0 to 60 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{2, 3, 4},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: earlyTimerange,
			Name:      "series_1",
		}},
		{"select transform.timeshift(series_1,-31ms) from 60 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{2, 3, 4},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: lateTimerange,
			Name:      "series_1",
		}},
		{"select transform.timeshift(series_1,-29ms) from 60 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{{
				[]float64{2, 3, 4},
				api.ParseTagSet("dc=west"),
			}},
			Timerange: lateTimerange,
			Name:      "series_1",
		}},
		{"select series_3 from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
			},
		}},
		{"select series_3 | filter.recent_highest_max(3, 30ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
			},
		}},
		{"select series_3 | filter.recent_highest_max(2, 30ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
			},
		}},
		{"select series_3 | filter.recent_highest_max(1, 30ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
			},
		}},
		{"select series_3 | filter.recent_lowest_max(3, 30ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
			},
		}},
		{"select series_3 | filter.recent_lowest_max(4, 30ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
			},
		}},
		{"select series_3 | filter.recent_highest_max(70, 30ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
			},
		}},
		{"select series_3 | filter.recent_lowest_max(2, 30ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
			},
		}},
		{"select series_3 | filter.recent_lowest_max(1, 30ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
			},
		}},
		{"select series_3 | filter.recent_highest_max(3, 3000ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
			},
		}},
		{"select series_3 | filter.recent_highest_max(2, 3000ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
			},
		}},
		{"select series_3 | filter.recent_highest_max(1, 3000ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
			},
		}},
		{"select series_3 | filter.recent_lowest_max(3, 3000ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
				{
					[]float64{5, 5, 5, 2, 2},
					api.ParseTagSet("dc=east"),
				},
			},
		}},
		{"select series_3 | filter.recent_lowest_max(2, 3000ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
				{
					[]float64{1, 1, 1, 4, 4},
					api.ParseTagSet("dc=west"),
				},
			},
		}},
		{"select series_3 | filter.recent_lowest_max(1, 3000ms) from 0 to 120 resolution 30ms", false, api.SeriesList{
			Series: []api.Timeseries{
				{
					[]float64{3, 3, 3, 3, 3},
					api.ParseTagSet("dc=north"),
				},
			},
		}},
		{"select series_1 from -1000d to now resolution 30s", true, api.SeriesList{}},
	} {
		a := assert.New(t).Contextf("query=%s", test.query)
		expected := test.expected
		command, err := Parse(test.query)
		if err != nil {
			a.Errorf("Unexpected error while parsing")
			continue
		}
		a.EqString(command.Name(), "select")
		rawResult, err := command.Execute(ExecutionContext{
			Backend:    backend.NewSequentialMultiBackend(fakeBackend),
			API:        fakeApi,
			FetchLimit: 1000,
			Timeout:    10 * time.Millisecond,
		})
		if err != nil {
			if !test.expectError {
				a.Errorf("Unexpected error while executing: %s", err.Error())
			}
		} else {
			casted := rawResult.([]function.Value)
			actual, _ := casted[0].ToSeriesList(api.Timerange{})
			a.EqInt(len(actual.Series), len(expected.Series))
			if len(actual.Series) == len(expected.Series) {
				for i := 0; i < len(expected.Series); i++ {
					a.Eq(actual.Series[i].TagSet, expected.Series[i].TagSet)
					actualLength := len(actual.Series[i].Values)
					expectedLength := len(actual.Series[i].Values)
					a.Eq(actualLength, expectedLength)
					if actualLength == expectedLength {
						for j := 0; j < actualLength; j++ {
							a.EqFloat(actual.Series[i].Values[j], expected.Series[i].Values[j], epsilon)
						}
					}
				}
			}
		}
	}

	// Test that the limit is correct
	command, err := Parse("select series_1, series_2 from 0 to 120 resolution 30ms")
	if err != nil {
		t.Fatalf("Unexpected error while parsing")
		return
	}
	context := ExecutionContext{Backend: backend.NewSequentialMultiBackend(fakeBackend), API: fakeApi, FetchLimit: 3, Timeout: 0}
	_, err = command.Execute(context)
	if err != nil {
		t.Fatalf("expected success with limit 3 but got err = %s", err.Error())
		return
	}
	context.FetchLimit = 2
	_, err = command.Execute(context)
	if err == nil {
		t.Fatalf("expected failure with limit = 2")
		return
	}
	command, err = Parse("select series2 from 0 to 120 resolution 30ms")
	if err != nil {
		t.Fatalf("Unexpected error while parsing")
		return
	}
	_, err = command.Execute(context)
	if err != nil {
		t.Fatalf("expected success with limit = 2 but got %s", err.Error())
	}
}