package server import ( "context" "encoding/json" "io/ioutil" "net/http" "net/http/httptest" "testing" "github.com/influxdata/httprouter" "github.com/influxdata/influxdb/v2/chronograf" "github.com/influxdata/influxdb/v2/chronograf/mocks" ) func TestService_GetDatabases(t *testing.T) { type fields struct { SourcesStore chronograf.SourcesStore ServersStore chronograf.ServersStore LayoutsStore chronograf.LayoutsStore UsersStore chronograf.UsersStore DashboardsStore chronograf.DashboardsStore TimeSeriesClient TimeSeriesClient Logger chronograf.Logger UseAuth bool Databases chronograf.Databases } type args struct { w http.ResponseWriter r *http.Request } tests := []struct { name string fields fields args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &Service{ Store: &Store{ SourcesStore: tt.fields.SourcesStore, ServersStore: tt.fields.ServersStore, LayoutsStore: tt.fields.LayoutsStore, UsersStore: tt.fields.UsersStore, DashboardsStore: tt.fields.DashboardsStore, }, TimeSeriesClient: tt.fields.TimeSeriesClient, Logger: tt.fields.Logger, UseAuth: tt.fields.UseAuth, Databases: tt.fields.Databases, } h.GetDatabases(tt.args.w, tt.args.r) }) } } func TestService_NewDatabase(t *testing.T) { type fields struct { SourcesStore chronograf.SourcesStore ServersStore chronograf.ServersStore LayoutsStore chronograf.LayoutsStore UsersStore chronograf.UsersStore DashboardsStore chronograf.DashboardsStore TimeSeriesClient TimeSeriesClient Logger chronograf.Logger UseAuth bool Databases chronograf.Databases } type args struct { w http.ResponseWriter r *http.Request } tests := []struct { name string fields fields args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &Service{ Store: &Store{ SourcesStore: tt.fields.SourcesStore, ServersStore: tt.fields.ServersStore, LayoutsStore: tt.fields.LayoutsStore, UsersStore: tt.fields.UsersStore, DashboardsStore: tt.fields.DashboardsStore, }, TimeSeriesClient: tt.fields.TimeSeriesClient, Logger: tt.fields.Logger, UseAuth: tt.fields.UseAuth, Databases: tt.fields.Databases, } h.NewDatabase(tt.args.w, tt.args.r) }) } } func TestService_DropDatabase(t *testing.T) { type fields struct { SourcesStore chronograf.SourcesStore ServersStore chronograf.ServersStore LayoutsStore chronograf.LayoutsStore UsersStore chronograf.UsersStore DashboardsStore chronograf.DashboardsStore TimeSeriesClient TimeSeriesClient Logger chronograf.Logger UseAuth bool Databases chronograf.Databases } type args struct { w http.ResponseWriter r *http.Request } tests := []struct { name string fields fields args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &Service{ Store: &Store{ SourcesStore: tt.fields.SourcesStore, ServersStore: tt.fields.ServersStore, LayoutsStore: tt.fields.LayoutsStore, UsersStore: tt.fields.UsersStore, DashboardsStore: tt.fields.DashboardsStore, }, TimeSeriesClient: tt.fields.TimeSeriesClient, Logger: tt.fields.Logger, UseAuth: tt.fields.UseAuth, Databases: tt.fields.Databases, } h.DropDatabase(tt.args.w, tt.args.r) }) } } func TestService_RetentionPolicies(t *testing.T) { type fields struct { SourcesStore chronograf.SourcesStore ServersStore chronograf.ServersStore LayoutsStore chronograf.LayoutsStore UsersStore chronograf.UsersStore DashboardsStore chronograf.DashboardsStore TimeSeriesClient TimeSeriesClient Logger chronograf.Logger UseAuth bool Databases chronograf.Databases } type args struct { w http.ResponseWriter r *http.Request } tests := []struct { name string fields fields args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &Service{ Store: &Store{ SourcesStore: tt.fields.SourcesStore, ServersStore: tt.fields.ServersStore, LayoutsStore: tt.fields.LayoutsStore, UsersStore: tt.fields.UsersStore, DashboardsStore: tt.fields.DashboardsStore, }, TimeSeriesClient: tt.fields.TimeSeriesClient, Logger: tt.fields.Logger, UseAuth: tt.fields.UseAuth, Databases: tt.fields.Databases, } h.RetentionPolicies(tt.args.w, tt.args.r) }) } } func TestService_NewRetentionPolicy(t *testing.T) { type fields struct { SourcesStore chronograf.SourcesStore ServersStore chronograf.ServersStore LayoutsStore chronograf.LayoutsStore UsersStore chronograf.UsersStore DashboardsStore chronograf.DashboardsStore TimeSeriesClient TimeSeriesClient Logger chronograf.Logger UseAuth bool Databases chronograf.Databases } type args struct { w http.ResponseWriter r *http.Request } tests := []struct { name string fields fields args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &Service{ Store: &Store{ SourcesStore: tt.fields.SourcesStore, ServersStore: tt.fields.ServersStore, LayoutsStore: tt.fields.LayoutsStore, UsersStore: tt.fields.UsersStore, DashboardsStore: tt.fields.DashboardsStore, }, TimeSeriesClient: tt.fields.TimeSeriesClient, Logger: tt.fields.Logger, UseAuth: tt.fields.UseAuth, Databases: tt.fields.Databases, } h.NewRetentionPolicy(tt.args.w, tt.args.r) }) } } func TestService_UpdateRetentionPolicy(t *testing.T) { type fields struct { SourcesStore chronograf.SourcesStore ServersStore chronograf.ServersStore LayoutsStore chronograf.LayoutsStore UsersStore chronograf.UsersStore DashboardsStore chronograf.DashboardsStore TimeSeriesClient TimeSeriesClient Logger chronograf.Logger UseAuth bool Databases chronograf.Databases } type args struct { w http.ResponseWriter r *http.Request } tests := []struct { name string fields fields args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &Service{ Store: &Store{ SourcesStore: tt.fields.SourcesStore, ServersStore: tt.fields.ServersStore, LayoutsStore: tt.fields.LayoutsStore, UsersStore: tt.fields.UsersStore, DashboardsStore: tt.fields.DashboardsStore, }, TimeSeriesClient: tt.fields.TimeSeriesClient, Logger: tt.fields.Logger, UseAuth: tt.fields.UseAuth, Databases: tt.fields.Databases, } h.UpdateRetentionPolicy(tt.args.w, tt.args.r) }) } } func TestService_DropRetentionPolicy(t *testing.T) { type fields struct { SourcesStore chronograf.SourcesStore ServersStore chronograf.ServersStore LayoutsStore chronograf.LayoutsStore UsersStore chronograf.UsersStore DashboardsStore chronograf.DashboardsStore TimeSeriesClient TimeSeriesClient Logger chronograf.Logger UseAuth bool Databases chronograf.Databases } type args struct { w http.ResponseWriter r *http.Request } tests := []struct { name string fields fields args args }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { h := &Service{ Store: &Store{ SourcesStore: tt.fields.SourcesStore, ServersStore: tt.fields.ServersStore, LayoutsStore: tt.fields.LayoutsStore, UsersStore: tt.fields.UsersStore, DashboardsStore: tt.fields.DashboardsStore, }, TimeSeriesClient: tt.fields.TimeSeriesClient, Logger: tt.fields.Logger, UseAuth: tt.fields.UseAuth, Databases: tt.fields.Databases, } h.DropRetentionPolicy(tt.args.w, tt.args.r) }) } } func TestService_Measurements(t *testing.T) { type fields struct { SourcesStore chronograf.SourcesStore Logger chronograf.Logger Databases chronograf.Databases } type args struct { queryParams map[string]string } type wants struct { statusCode int body string } tests := []struct { name string fields fields args args wants wants }{ { name: "Gets 100 measurements when no limit or offset provided", fields: fields{ SourcesStore: &mocks.SourcesStore{ GetF: func(ctx context.Context, srcID int) (chronograf.Source, error) { return chronograf.Source{ ID: 0, }, nil }, }, Databases: &mocks.Databases{ ConnectF: func(context.Context, *chronograf.Source) error { return nil }, GetMeasurementsF: func(ctx context.Context, db string, limit, offset int) ([]chronograf.Measurement, error) { return []chronograf.Measurement{ { Name: "pineapple", }, { Name: "cubeapple", }, { Name: "pinecube", }, }, nil }, }, }, args: args{ queryParams: map[string]string{}, }, wants: wants{ statusCode: 200, body: `{"measurements":[{"name":"pineapple"},{"name":"cubeapple"},{"name":"pinecube"}],"links":{"self":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=0","first":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=0","next":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=100"}} `, }, }, { name: "Fails when invalid limit value provided", fields: fields{ SourcesStore: &mocks.SourcesStore{ GetF: func(ctx context.Context, srcID int) (chronograf.Source, error) { return chronograf.Source{ ID: 0, }, nil }, }, }, args: args{ queryParams: map[string]string{ "limit": "joe", }, }, wants: wants{ statusCode: 422, body: `{"code":422,"message":"strconv.Atoi: parsing \"joe\": invalid syntax"}`, }, }, { name: "Fails when invalid offset value provided", fields: fields{ SourcesStore: &mocks.SourcesStore{ GetF: func(ctx context.Context, srcID int) (chronograf.Source, error) { return chronograf.Source{ ID: 0, }, nil }, }, }, args: args{ queryParams: map[string]string{ "offset": "bob", }, }, wants: wants{ statusCode: 422, body: `{"code":422,"message":"strconv.Atoi: parsing \"bob\": invalid syntax"}`, }, }, { name: "Overrides limit less than or equal to 0 with limit 100", fields: fields{ SourcesStore: &mocks.SourcesStore{ GetF: func(ctx context.Context, srcID int) (chronograf.Source, error) { return chronograf.Source{ ID: 0, }, nil }, }, Databases: &mocks.Databases{ ConnectF: func(context.Context, *chronograf.Source) error { return nil }, GetMeasurementsF: func(ctx context.Context, db string, limit, offset int) ([]chronograf.Measurement, error) { return []chronograf.Measurement{ { Name: "pineapple", }, { Name: "cubeapple", }, { Name: "pinecube", }, }, nil }, }, }, args: args{ queryParams: map[string]string{ "limit": "0", }, }, wants: wants{ statusCode: 200, body: `{"measurements":[{"name":"pineapple"},{"name":"cubeapple"},{"name":"pinecube"}],"links":{"self":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=0","first":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=0","next":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=100"}} `, }, }, { name: "Overrides offset less than 0 with offset 0", fields: fields{ SourcesStore: &mocks.SourcesStore{ GetF: func(ctx context.Context, srcID int) (chronograf.Source, error) { return chronograf.Source{ ID: 0, }, nil }, }, Databases: &mocks.Databases{ ConnectF: func(context.Context, *chronograf.Source) error { return nil }, GetMeasurementsF: func(ctx context.Context, db string, limit, offset int) ([]chronograf.Measurement, error) { return []chronograf.Measurement{ { Name: "pineapple", }, { Name: "cubeapple", }, { Name: "pinecube", }, }, nil }, }, }, args: args{ queryParams: map[string]string{ "offset": "-1337", }, }, wants: wants{ statusCode: 200, body: `{"measurements":[{"name":"pineapple"},{"name":"cubeapple"},{"name":"pinecube"}],"links":{"self":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=0","first":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=0","next":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=100\u0026offset=100"}} `, }, }, { name: "Provides a prev link when offset exceeds limit", fields: fields{ SourcesStore: &mocks.SourcesStore{ GetF: func(ctx context.Context, srcID int) (chronograf.Source, error) { return chronograf.Source{ ID: 0, }, nil }, }, Databases: &mocks.Databases{ ConnectF: func(context.Context, *chronograf.Source) error { return nil }, GetMeasurementsF: func(ctx context.Context, db string, limit, offset int) ([]chronograf.Measurement, error) { return []chronograf.Measurement{ { Name: "pineapple", }, { Name: "cubeapple", }, { Name: "pinecube", }, { Name: "billietta", }, { Name: "bobbetta", }, { Name: "bobcube", }, }, nil }, }, }, args: args{ queryParams: map[string]string{ "limit": "2", "offset": "4", }, }, wants: wants{ statusCode: 200, body: `{"measurements":[{"name":"pineapple"},{"name":"cubeapple"},{"name":"pinecube"},{"name":"billietta"},{"name":"bobbetta"},{"name":"bobcube"}],"links":{"self":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=2\u0026offset=4","first":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=2\u0026offset=0","next":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=2\u0026offset=6","prev":"/chronograf/v1/sources/0/dbs/pineapples/measurements?limit=2\u0026offset=2"}} `, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { logger := &chronograf.NoopLogger{} h := &Service{ Store: &mocks.Store{ SourcesStore: tt.fields.SourcesStore, }, Logger: logger, Databases: tt.fields.Databases, } w := httptest.NewRecorder() r := httptest.NewRequest( "GET", "http://any.url", nil, ) r = r.WithContext(context.WithValue( context.TODO(), httprouter.ParamsKey, httprouter.Params{ { Key: "id", Value: "0", }, { Key: "db", Value: "pineapples", }, })) q := r.URL.Query() for key, value := range tt.args.queryParams { q.Add(key, value) } r.URL.RawQuery = q.Encode() h.Measurements(w, r) resp := w.Result() body, err := ioutil.ReadAll(resp.Body) defer resp.Body.Close() if err != nil { t.Error("TestService_Measurements not able to retrieve body") } var msmts measurementsResponse if err := json.Unmarshal(body, &msmts); err != nil { t.Error("TestService_Measurements not able to unmarshal JSON response") } if tt.wants.statusCode != resp.StatusCode { t.Errorf("%q. StatusCode:\nwant\n%v\ngot\n%v", tt.name, tt.wants.statusCode, resp.StatusCode) } if tt.wants.body != string(body) { t.Errorf("%q. Body:\nwant\n*%s*\ngot\n*%s*", tt.name, tt.wants.body, string(body)) } }) } } func TestValidDatabaseRequest(t *testing.T) { type args struct { d *chronograf.Database } tests := []struct { name string args args wantErr bool }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if err := ValidDatabaseRequest(tt.args.d); (err != nil) != tt.wantErr { t.Errorf("ValidDatabaseRequest() error = %v, wantErr %v", err, tt.wantErr) } }) } } func TestValidRetentionPolicyRequest(t *testing.T) { type args struct { rp *chronograf.RetentionPolicy } tests := []struct { name string args args wantErr bool }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if err := ValidRetentionPolicyRequest(tt.args.rp); (err != nil) != tt.wantErr { t.Errorf("ValidRetentionPolicyRequest() error = %v, wantErr %v", err, tt.wantErr) } }) } }