chronograf/server/influx_test.go

219 lines
5.1 KiB
Go

package server
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/bouk/httprouter"
"github.com/influxdata/chronograf/log"
"github.com/influxdata/chronograf/mocks"
"github.com/influxdata/chronograf"
)
func TestService_Influx(t *testing.T) {
type fields struct {
SourcesStore chronograf.SourcesStore
TimeSeries TimeSeriesClient
}
type args struct {
w *httptest.ResponseRecorder
r *http.Request
}
type want struct {
StatusCode int
ContentType string
Body string
}
tests := []struct {
name string
fields fields
args args
ID string
want want
}{
{
name: "Proxies request to Influxdb",
fields: fields{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1337,
URL: "http://any.url",
}, nil
},
},
TimeSeries: &mocks.TimeSeries{
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
return nil
},
QueryF: func(ctx context.Context, query chronograf.Query) (chronograf.Response, error) {
return mocks.NewResponse(
`{"results":[{"statement_id":0,"series":[{"name":"cpu","columns":["key","value"],"values":[["cpu","cpu-total"],["cpu","cpu0"],["cpu","cpu1"],["cpu","cpu2"],["cpu","cpu3"],["host","pineapples-MBP"],["host","pineapples-MacBook-Pro.local"]]}]}]}`,
nil,
),
nil
},
},
},
args: args{
w: httptest.NewRecorder(),
r: httptest.NewRequest(
"POST",
"http://any.url",
ioutil.NopCloser(
bytes.NewReader([]byte(
`{"db":"bob", "rp":"joe", "uuid": "bob", "query":"SELECT mean(\"usage_user\") FROM cpu WHERE \"cpu\" = 'cpu-total' AND time > now() - 10m GROUP BY host;"}`,
)),
),
),
},
ID: "1",
want: want{
StatusCode: http.StatusOK,
ContentType: "application/json",
Body: `{"results":{"results":[{"statement_id":0,"series":[{"name":"cpu","columns":["key","value"],"values":[["cpu","cpu-total"],["cpu","cpu0"],["cpu","cpu1"],["cpu","cpu2"],["cpu","cpu3"],["host","pineapples-MBP"],["host","pineapples-MacBook-Pro.local"]]}]}]},"uuid":"bob"}
`,
},
},
}
for _, tt := range tests {
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
context.Background(),
httprouter.Params{
{
Key: "id",
Value: tt.ID,
},
},
))
h := &Service{
Store: &mocks.Store{
SourcesStore: tt.fields.SourcesStore,
},
TimeSeriesClient: tt.fields.TimeSeries,
}
h.Influx(tt.args.w, tt.args.r)
resp := tt.args.w.Result()
contentType := resp.Header.Get("Content-Type")
body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode != tt.want.StatusCode {
t.Errorf("%q. Influx() = got %v, want %v", tt.name, resp.StatusCode, tt.want.StatusCode)
}
if contentType != tt.want.ContentType {
t.Errorf("%q. Influx() = got %v, want %v", tt.name, contentType, tt.want.ContentType)
}
if string(body) != tt.want.Body {
t.Errorf("%q. Influx() =\ngot ***%v***\nwant ***%v***\n", tt.name, string(body), tt.want.Body)
}
}
}
// TestService_Influx_UseCommand test preprocessing of use command
func TestService_Influx_UseCommand(t *testing.T) {
tests := []struct {
name string
db string
rp string
}{
{
name: "/* no command */",
},
{
name: "USE mydb",
db: "mydb",
},
{
name: "USE mydb.myrp",
db: "mydb",
rp: "myrp",
},
{
name: `use "mydb"`,
db: "mydb",
},
{
name: `use "mydb.myrp"`,
db: "mydb.myrp",
},
{
name: `USE "mydb"."myrp"`,
db: "mydb",
rp: "myrp",
},
}
h := &Service{
Store: &mocks.Store{
SourcesStore: &mocks.SourcesStore{
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
return chronograf.Source{
ID: 1337,
URL: "http://any.url",
}, nil
},
},
},
TimeSeriesClient: &mocks.TimeSeries{
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
return nil
},
QueryF: func(ctx context.Context, query chronograf.Query) (chronograf.Response, error) {
return mocks.NewResponse(
fmt.Sprintf(`{"db":"%s","rp":"%s"}`, query.DB, query.RP),
nil,
),
nil
},
},
Logger: log.New(log.ErrorLevel),
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
prefixCommand := strings.ReplaceAll(tt.name, "\"", "\\\"")
w := httptest.NewRecorder()
r := httptest.NewRequest(
"POST",
"http://any.url",
ioutil.NopCloser(
bytes.NewReader([]byte(
`{"uuid": "tst", "query":"`+prefixCommand+` ; DROP MEASUREMENT test"}`,
)),
),
)
r = r.WithContext(httprouter.WithParams(
context.Background(),
httprouter.Params{
{
Key: "id",
Value: "1",
},
},
))
h.Influx(w, r)
resp := w.Result()
body, _ := ioutil.ReadAll(resp.Body)
want := fmt.Sprintf(`{"results":{"db":"%s","rp":"%s"},"uuid":"tst"}`, tt.db, tt.rp)
got := strings.TrimSpace(string(body))
if got != want {
t.Errorf("%q. Influx() =\ngot ***%v***\nwant ***%v***\n", tt.name, got, want)
}
})
}
}