package opentsdb import ( "fmt" "net" "net/http" "net/http/httptest" "net/url" "reflect" "strconv" "testing" "github.com/stretchr/testify/require" "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/testutil" ) func TestCleanTags(t *testing.T) { var tagtests = []struct { ptIn map[string]string outTags map[string]string }{ { map[string]string{"one": "two", "three": "four"}, map[string]string{"one": "two", "three": "four"}, }, { map[string]string{"aaa": "bbb"}, map[string]string{"aaa": "bbb"}, }, { map[string]string{"Sp%ci@l Chars[": "g$t repl#ce)d"}, map[string]string{"Sp-ci-l_Chars_": "g-t_repl-ce_d"}, }, { map[string]string{"μnicodε_letters": "okαy"}, map[string]string{"μnicodε_letters": "okαy"}, }, { map[string]string{"n☺": "emojies☠"}, map[string]string{"n_": "emojies_"}, }, { map[string]string{}, map[string]string{}, }, } for _, tt := range tagtests { tags := cleanTags(tt.ptIn) if !reflect.DeepEqual(tags, tt.outTags) { t.Errorf("\nexpected %+v\ngot %+v\n", tt.outTags, tags) } } } func TestBuildTagsTelnet(t *testing.T) { var tagtests = []struct { ptIn map[string]string outTags string }{ { map[string]string{"one": "two", "three": "four"}, "one=two three=four", }, { map[string]string{"aaa": "bbb"}, "aaa=bbb", }, { map[string]string{"one": "two", "aaa": "bbb"}, "aaa=bbb one=two", }, { map[string]string{}, "", }, } for _, tt := range tagtests { tags := ToLineFormat(tt.ptIn) if !reflect.DeepEqual(tags, tt.outTags) { t.Errorf("\nexpected %+v\ngot %+v\n", tt.outTags, tags) } } } func TestSanitize(t *testing.T) { tests := []struct { name string value string expected string }{ { name: "Ascii letters and numbers allowed", value: "ascii 123", expected: "ascii_123", }, { name: "Allowed punct", value: "-_./", expected: "-_./", }, { name: "Special conversions to hyphen", value: "@*%#$!", expected: "-----_", }, { name: "Unicode Letters allowed", value: "μnicodε_letters", expected: "μnicodε_letters", }, { name: "Other Unicode not allowed", value: "“☢”", expected: "___", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { actual := sanitize(tt.value) require.Equal(t, tt.expected, actual) }) } } func BenchmarkHttpSend(b *testing.B) { const batchSize = 50 const metricsCount = 4 * batchSize metrics := make([]telegraf.Metric, 0, metricsCount) for i := 0; i < metricsCount; i++ { metrics = append(metrics, testutil.TestMetric(1.0)) } ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json") fmt.Fprintln(w, "{}") })) defer ts.Close() u, err := url.Parse(ts.URL) if err != nil { panic(err) } _, p, err := net.SplitHostPort(u.Host) require.NoError(b, err) port, err := strconv.Atoi(p) if err != nil { panic(err) } o := &OpenTSDB{ Host: ts.URL, Port: port, Prefix: "", HTTPBatchSize: batchSize, HTTPPath: "/api/put", } b.ResetTimer() for i := 0; i < b.N; i++ { //nolint:errcheck // skip error check for benchmarking o.Write(metrics) } } func TestWriteIntegration(t *testing.T) { if testing.Short() { t.Skip("Skipping integration test in short mode") } t.Skip("Skip as OpenTSDB not running") o := &OpenTSDB{ Host: testutil.GetLocalHost(), Port: 4242, Prefix: "prefix.test.", } // Verify that we can connect to the OpenTSDB instance err := o.Connect() require.NoError(t, err) // Verify that we can successfully write data to OpenTSDB err = o.Write(testutil.MockMetrics()) require.NoError(t, err) // Verify positive and negative test cases of writing data metrics := testutil.MockMetrics() metrics = append(metrics, testutil.TestMetric(float64(1.0), "justametric.float"), testutil.TestMetric(int64(123456789), "justametric.int"), testutil.TestMetric(uint64(123456789012345), "justametric.uint"), testutil.TestMetric("Lorem Ipsum", "justametric.string"), testutil.TestMetric(float64(42.0), "justametric.anotherfloat"), testutil.TestMetric(float64(42.0), "metric w/ specialchars"), ) err = o.Write(metrics) require.NoError(t, err) }