2019-05-22 21:16:55 +00:00
|
|
|
package graphite
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2024-07-17 10:37:07 +00:00
|
|
|
func TestUnmarshalMetricAndTags_Failure(t *testing.T) {
|
2020-11-15 22:42:27 +00:00
|
|
|
f := func(s string) {
|
|
|
|
t.Helper()
|
|
|
|
var r Row
|
|
|
|
_, err := r.UnmarshalMetricAndTags(s, nil)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("expecting non-nil error for UnmarshalMetricAndTags(%q)", s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f("")
|
|
|
|
f(";foo=bar")
|
|
|
|
}
|
|
|
|
|
2024-07-17 10:37:07 +00:00
|
|
|
func TestUnmarshalMetricAndTags_Success(t *testing.T) {
|
2020-11-15 22:42:27 +00:00
|
|
|
f := func(s string, rExpected *Row) {
|
|
|
|
t.Helper()
|
|
|
|
var r Row
|
|
|
|
_, err := r.UnmarshalMetricAndTags(s, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error in UnmarshalMetricAndTags(%q): %s", s, err)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(&r, rExpected) {
|
|
|
|
t.Fatalf("unexpected row;\ngot\n%+v\nwant\n%+v", &r, rExpected)
|
|
|
|
}
|
|
|
|
}
|
2022-09-26 12:17:22 +00:00
|
|
|
f(" ", &Row{
|
2024-07-17 10:37:07 +00:00
|
|
|
Metric: " ",
|
2022-09-26 12:17:22 +00:00
|
|
|
})
|
|
|
|
f("foo ;bar=baz", &Row{
|
2024-07-17 10:37:07 +00:00
|
|
|
Metric: "foo ",
|
2022-09-26 12:17:22 +00:00
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "bar",
|
|
|
|
Value: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
f("f oo;bar=baz", &Row{
|
2024-07-17 10:37:07 +00:00
|
|
|
Metric: "f oo",
|
2022-09-26 12:17:22 +00:00
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "bar",
|
|
|
|
Value: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
f("foo;bar=baz ", &Row{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "bar",
|
2024-07-17 10:37:07 +00:00
|
|
|
Value: "baz ",
|
2022-09-26 12:17:22 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
f("foo;bar= baz", &Row{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "bar",
|
2024-07-17 10:37:07 +00:00
|
|
|
Value: " baz",
|
2022-09-26 12:17:22 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
f("foo;bar=b az", &Row{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "bar",
|
2024-07-17 10:37:07 +00:00
|
|
|
Value: "b az",
|
2022-09-26 12:17:22 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
f("foo;b ar=baz", &Row{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
2024-07-17 10:37:07 +00:00
|
|
|
Key: "b ar",
|
2022-09-26 12:17:22 +00:00
|
|
|
Value: "baz",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
2020-11-15 22:42:27 +00:00
|
|
|
f("foo", &Row{
|
|
|
|
Metric: "foo",
|
|
|
|
})
|
2022-09-26 12:17:22 +00:00
|
|
|
f("foo;bar=123;baz=aa=bb", &Row{
|
2020-11-15 22:42:27 +00:00
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "bar",
|
|
|
|
Value: "123",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "baz",
|
2022-09-26 12:17:22 +00:00
|
|
|
Value: "aa=bb",
|
2020-11-15 22:42:27 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-07-17 10:37:07 +00:00
|
|
|
func TestRowsUnmarshal_Failure(t *testing.T) {
|
2019-05-22 21:16:55 +00:00
|
|
|
f := func(s string) {
|
|
|
|
t.Helper()
|
|
|
|
var rows Rows
|
2019-08-24 09:42:59 +00:00
|
|
|
rows.Unmarshal(s)
|
|
|
|
if len(rows.Rows) != 0 {
|
|
|
|
t.Fatalf("unexpected number of rows parsed; got %d; want 0", len(rows.Rows))
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Try again
|
2019-08-24 09:42:59 +00:00
|
|
|
rows.Unmarshal(s)
|
|
|
|
if len(rows.Rows) != 0 {
|
|
|
|
t.Fatalf("unexpected number of rows parsed; got %d; want 0", len(rows.Rows))
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Missing value
|
|
|
|
f("aaa")
|
|
|
|
|
2020-09-15 22:33:32 +00:00
|
|
|
// invalid value
|
|
|
|
f("aa bb")
|
|
|
|
|
|
|
|
// invalid timestamp
|
|
|
|
f("aa 123 bar")
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
2024-07-17 10:37:07 +00:00
|
|
|
func TestRowsUnmarshal_SanitizeMetricNamesSuccess(t *testing.T) {
|
|
|
|
f := func(s string, rowsExpected *Rows) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
sanitizeMetricNameOrig := *sanitizeMetricName
|
|
|
|
*sanitizeMetricName = true
|
|
|
|
defer func() {
|
|
|
|
*sanitizeMetricName = sanitizeMetricNameOrig
|
|
|
|
}()
|
|
|
|
|
|
|
|
var rows Rows
|
|
|
|
rows.Unmarshal(s)
|
|
|
|
if !reflect.DeepEqual(rows.Rows, rowsExpected.Rows) {
|
|
|
|
t.Fatalf("unexpected rows;\ngot\n%+v;\nwant\n%+v", rows.Rows, rowsExpected.Rows)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only metric name.
|
|
|
|
f(`foo...b..a.r\a--baz 123`, &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: `foo.b.a.r_a__baz`,
|
|
|
|
Value: 123,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
|
|
|
|
// Metric name with tags.
|
|
|
|
// Tag values shouldn't be sanitized.
|
|
|
|
f(`s a;ta g..1=a-b..c;tag2 123 456`, &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: `s_a`,
|
|
|
|
Value: 123,
|
|
|
|
Timestamp: 456,
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "ta_g.1",
|
|
|
|
Value: "a-b..c",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRowsUnmarshal_Success(t *testing.T) {
|
2019-05-22 21:16:55 +00:00
|
|
|
f := func(s string, rowsExpected *Rows) {
|
|
|
|
t.Helper()
|
|
|
|
var rows Rows
|
2019-08-24 09:42:59 +00:00
|
|
|
rows.Unmarshal(s)
|
2019-05-22 21:16:55 +00:00
|
|
|
if !reflect.DeepEqual(rows.Rows, rowsExpected.Rows) {
|
|
|
|
t.Fatalf("unexpected rows;\ngot\n%+v;\nwant\n%+v", rows.Rows, rowsExpected.Rows)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try unmarshaling again
|
2019-08-24 09:42:59 +00:00
|
|
|
rows.Unmarshal(s)
|
2019-05-22 21:16:55 +00:00
|
|
|
if !reflect.DeepEqual(rows.Rows, rowsExpected.Rows) {
|
2022-09-26 12:17:22 +00:00
|
|
|
t.Fatalf("unexpected rows on second unmarshal;\ngot\n%+v;\nwant\n%+v", rows.Rows, rowsExpected.Rows)
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rows.Reset()
|
|
|
|
if len(rows.Rows) != 0 {
|
|
|
|
t.Fatalf("non-empty rows after reset: %+v", rows.Rows)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Empty line
|
|
|
|
f("", &Rows{})
|
2019-08-24 09:42:59 +00:00
|
|
|
f("\r", &Rows{})
|
2019-05-22 21:16:55 +00:00
|
|
|
f("\n\n", &Rows{})
|
2019-08-24 09:42:59 +00:00
|
|
|
f("\n\r\n", &Rows{})
|
2019-05-22 21:16:55 +00:00
|
|
|
|
|
|
|
// Single line
|
2022-09-26 12:17:22 +00:00
|
|
|
f(" 123 455", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "123",
|
|
|
|
Value: 455,
|
|
|
|
}},
|
|
|
|
})
|
2019-05-22 21:16:55 +00:00
|
|
|
f("foobar -123.456 789", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foobar",
|
|
|
|
Value: -123.456,
|
|
|
|
Timestamp: 789,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
f("foo.bar 123.456 789\n", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo.bar",
|
|
|
|
Value: 123.456,
|
|
|
|
Timestamp: 789,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
|
2022-09-26 12:17:22 +00:00
|
|
|
// Whitespace in metric name, tag name and tag value
|
|
|
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3102
|
|
|
|
f("s a;ta g1=aaa1;tag2=bb b2;tag3 1 23", &Rows{
|
|
|
|
Rows: []Row{{
|
2024-07-17 10:37:07 +00:00
|
|
|
Metric: "s a",
|
2022-09-26 12:17:22 +00:00
|
|
|
Value: 1,
|
|
|
|
Timestamp: 23,
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
2024-07-17 10:37:07 +00:00
|
|
|
Key: "ta g1",
|
2022-09-26 12:17:22 +00:00
|
|
|
Value: "aaa1",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "tag2",
|
2024-07-17 10:37:07 +00:00
|
|
|
Value: "bb b2",
|
2022-09-26 12:17:22 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
|
2019-06-18 16:04:02 +00:00
|
|
|
// Missing timestamp
|
|
|
|
f("aaa 1123", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "aaa",
|
|
|
|
Value: 1123,
|
|
|
|
}},
|
|
|
|
})
|
2020-07-08 11:10:31 +00:00
|
|
|
f("aaa 1123 -1", &Rows{
|
|
|
|
Rows: []Row{{
|
2020-07-08 11:12:10 +00:00
|
|
|
Metric: "aaa",
|
|
|
|
Value: 1123,
|
2020-07-08 11:10:31 +00:00
|
|
|
Timestamp: -1,
|
|
|
|
}},
|
|
|
|
})
|
2019-06-18 16:04:02 +00:00
|
|
|
|
2019-10-17 15:22:56 +00:00
|
|
|
// Timestamp bigger than 1<<31
|
|
|
|
f("aaa 1123 429496729600", &Rows{
|
|
|
|
Rows: []Row{{
|
2019-10-17 17:04:26 +00:00
|
|
|
Metric: "aaa",
|
|
|
|
Value: 1123,
|
2019-10-17 15:22:56 +00:00
|
|
|
Timestamp: 429496729600,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
|
2020-10-06 08:37:50 +00:00
|
|
|
// Floating-point timestamp
|
|
|
|
// See https://github.com/graphite-project/carbon/blob/b0ba62a62d40a37950fed47a8f6ae6d0f02e6af5/lib/carbon/protocols.py#L197
|
|
|
|
f("aaa 1123 4294.943", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "aaa",
|
|
|
|
Value: 1123,
|
|
|
|
Timestamp: 4294,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
|
2019-05-22 21:16:55 +00:00
|
|
|
// Tags
|
|
|
|
f("foo;bar=baz 1 2", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{{
|
|
|
|
Key: "bar",
|
|
|
|
Value: "baz",
|
|
|
|
}},
|
|
|
|
Value: 1,
|
|
|
|
Timestamp: 2,
|
|
|
|
}},
|
|
|
|
})
|
2019-08-24 10:35:29 +00:00
|
|
|
// Empty tags
|
2021-03-01 15:15:52 +00:00
|
|
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1100
|
|
|
|
f("foo; 1", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{},
|
|
|
|
Value: 1,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
f("foo; 1 2", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{},
|
|
|
|
Value: 1,
|
|
|
|
Timestamp: 2,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
// Empty tag name or value
|
|
|
|
f("foo;bar 1 2", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{},
|
|
|
|
Value: 1,
|
|
|
|
Timestamp: 2,
|
|
|
|
}},
|
|
|
|
})
|
2019-08-24 10:35:29 +00:00
|
|
|
f("foo;bar=baz;aa=;x=y;=z 1 2", &Rows{
|
2019-05-22 21:16:55 +00:00
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "bar",
|
|
|
|
Value: "baz",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "x",
|
|
|
|
Value: "y",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Value: 1,
|
|
|
|
Timestamp: 2,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
|
|
|
|
// Multi lines
|
2019-06-18 16:04:02 +00:00
|
|
|
f("foo 0.3 2\naaa 3\nbar.baz 0.34 43\n", &Rows{
|
2019-05-22 21:16:55 +00:00
|
|
|
Rows: []Row{
|
|
|
|
{
|
|
|
|
Metric: "foo",
|
|
|
|
Value: 0.3,
|
|
|
|
Timestamp: 2,
|
|
|
|
},
|
2019-06-18 16:04:02 +00:00
|
|
|
{
|
|
|
|
Metric: "aaa",
|
|
|
|
Value: 3,
|
|
|
|
},
|
2019-05-22 21:16:55 +00:00
|
|
|
{
|
|
|
|
Metric: "bar.baz",
|
|
|
|
Value: 0.34,
|
|
|
|
Timestamp: 43,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
2019-08-24 09:42:59 +00:00
|
|
|
|
|
|
|
// Multi lines with invalid line
|
|
|
|
f("foo 0.3 2\naaa\nbar.baz 0.34 43\n", &Rows{
|
|
|
|
Rows: []Row{
|
|
|
|
{
|
|
|
|
Metric: "foo",
|
|
|
|
Value: 0.3,
|
|
|
|
Timestamp: 2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Metric: "bar.baz",
|
|
|
|
Value: 0.34,
|
|
|
|
Timestamp: 43,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
2021-10-22 09:23:45 +00:00
|
|
|
|
|
|
|
// With tab as separator
|
|
|
|
// See https://github.com/grobian/carbon-c-relay/commit/f3ffe6cc2b52b07d14acbda649ad3fd6babdd528
|
|
|
|
f("foo.baz\t125.456\t1789\n", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo.baz",
|
|
|
|
Value: 125.456,
|
|
|
|
Timestamp: 1789,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
// With tab as separator and tags
|
|
|
|
f("foo;baz=bar;bb=;y=x;=z\t1\t2", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{
|
|
|
|
{
|
|
|
|
Key: "baz",
|
|
|
|
Value: "bar",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Key: "y",
|
|
|
|
Value: "x",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Value: 1,
|
|
|
|
Timestamp: 2,
|
|
|
|
}},
|
|
|
|
})
|
|
|
|
|
2021-12-02 11:32:25 +00:00
|
|
|
// Whitespace after the timestamp
|
|
|
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1865
|
|
|
|
f("foo.baz 125 1789 \na 1.34 567\t ", &Rows{
|
|
|
|
Rows: []Row{
|
|
|
|
{
|
|
|
|
Metric: "foo.baz",
|
|
|
|
Value: 125,
|
|
|
|
Timestamp: 1789,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Metric: "a",
|
|
|
|
Value: 1.34,
|
|
|
|
Timestamp: 567,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2021-12-02 11:43:49 +00:00
|
|
|
// Multiple whitespaces as separators
|
|
|
|
f("foo.baz \t125 1789 \t\n", &Rows{
|
|
|
|
Rows: []Row{{
|
|
|
|
Metric: "foo.baz",
|
|
|
|
Value: 125,
|
|
|
|
Timestamp: 1789,
|
|
|
|
}},
|
|
|
|
})
|
2019-05-22 21:16:55 +00:00
|
|
|
}
|