Add tests to sources/users endpoints
parent
c784a6260e
commit
72dbae043f
|
@ -0,0 +1,43 @@
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/influxdata/chronograf"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ chronograf.SourcesStore = &SourcesStore{}
|
||||||
|
|
||||||
|
// SourcesStore mock allows all functions to be set for testing
|
||||||
|
type SourcesStore struct {
|
||||||
|
AllF func(context.Context) ([]chronograf.Source, error)
|
||||||
|
AddF func(context.Context, chronograf.Source) (chronograf.Source, error)
|
||||||
|
DeleteF func(context.Context, chronograf.Source) error
|
||||||
|
GetF func(ctx context.Context, ID int) (chronograf.Source, error)
|
||||||
|
UpdateF func(context.Context, chronograf.Source) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// All returns all sources in the store
|
||||||
|
func (s *SourcesStore) All(ctx context.Context) ([]chronograf.Source, error) {
|
||||||
|
return s.AllF(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add creates a new source in the SourcesStore and returns Source with ID
|
||||||
|
func (s *SourcesStore) Add(ctx context.Context, src chronograf.Source) (chronograf.Source, error) {
|
||||||
|
return s.AddF(ctx, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the Source from the store
|
||||||
|
func (s *SourcesStore) Delete(ctx context.Context, src chronograf.Source) error {
|
||||||
|
return s.DeleteF(ctx, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves Source if `ID` exists
|
||||||
|
func (s *SourcesStore) Get(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return s.GetF(ctx, ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the Source in the store.
|
||||||
|
func (s *SourcesStore) Update(ctx context.Context, src chronograf.Source) error {
|
||||||
|
return s.UpdateF(ctx, src)
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/influxdata/chronograf"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ chronograf.TimeSeries = &TimeSeries{}
|
||||||
|
|
||||||
|
// TimeSeries is a mockable chronograf time series by overriding the functions.
|
||||||
|
type TimeSeries struct {
|
||||||
|
// Query retrieves time series data from the database.
|
||||||
|
QueryF func(context.Context, chronograf.Query) (chronograf.Response, error)
|
||||||
|
// Connect will connect to the time series using the information in `Source`.
|
||||||
|
ConnectF func(context.Context, *chronograf.Source) error
|
||||||
|
// UsersStore represents the user accounts within the TimeSeries database
|
||||||
|
UsersF func(context.Context) chronograf.UsersStore
|
||||||
|
// Allowances returns all valid names permissions in this database
|
||||||
|
AllowancesF func(context.Context) chronograf.Allowances
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query retrieves time series data from the database.
|
||||||
|
func (t *TimeSeries) Query(ctx context.Context, query chronograf.Query) (chronograf.Response, error) {
|
||||||
|
return t.QueryF(ctx, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect will connect to the time series using the information in `Source`.
|
||||||
|
func (t *TimeSeries) Connect(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return t.ConnectF(ctx, src)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Users represents the user accounts within the TimeSeries database
|
||||||
|
func (t *TimeSeries) Users(ctx context.Context) chronograf.UsersStore {
|
||||||
|
return t.UsersF(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allowances returns all valid names permissions in this database
|
||||||
|
func (t *TimeSeries) Allowances(ctx context.Context) chronograf.Allowances {
|
||||||
|
return t.AllowancesF(ctx)
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"github.com/influxdata/chronograf"
|
"github.com/influxdata/chronograf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ chronograf.UsersStore = &UsersStore{}
|
||||||
|
|
||||||
// UsersStore mock allows all functions to be set for testing
|
// UsersStore mock allows all functions to be set for testing
|
||||||
type UsersStore struct {
|
type UsersStore struct {
|
||||||
AllF func(context.Context) ([]chronograf.User, error)
|
AllF func(context.Context) ([]chronograf.User, error)
|
||||||
|
|
|
@ -40,8 +40,8 @@ type sourceUser struct {
|
||||||
Links sourceUserLinks `json:"links"` // Links are URI locations related to user
|
Links sourceUserLinks `json:"links"` // Links are URI locations related to user
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSourceUser creates a new user in the InfluxDB data source
|
// newSourceUser creates a new user in the InfluxDB data source
|
||||||
func NewSourceUser(srcID int, name string, perms chronograf.Permissions) sourceUser {
|
func newSourceUser(srcID int, name string, perms chronograf.Permissions) sourceUser {
|
||||||
u := &url.URL{Path: name}
|
u := &url.URL{Path: name}
|
||||||
encodedUser := u.String()
|
encodedUser := u.String()
|
||||||
httpAPISrcs := "/chronograf/v1/sources"
|
httpAPISrcs := "/chronograf/v1/sources"
|
||||||
|
@ -88,7 +88,7 @@ func (h *Service) NewSourceUser(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
su := NewSourceUser(srcID, res.Name, req.Permissions)
|
su := newSourceUser(srcID, res.Name, req.Permissions)
|
||||||
w.Header().Add("Location", su.Links.Self)
|
w.Header().Add("Location", su.Links.Self)
|
||||||
encodeJSON(w, http.StatusCreated, su, h.Logger)
|
encodeJSON(w, http.StatusCreated, su, h.Logger)
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ func (h *Service) SourceUsers(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
su := []sourceUser{}
|
su := []sourceUser{}
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
su = append(su, NewSourceUser(srcID, u.Name, u.Permissions))
|
su = append(su, newSourceUser(srcID, u.Name, u.Permissions))
|
||||||
}
|
}
|
||||||
|
|
||||||
res := sourceUsers{
|
res := sourceUsers{
|
||||||
|
@ -140,7 +140,7 @@ func (h *Service) SourceUserID(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res := NewSourceUser(srcID, u.Name, u.Permissions)
|
res := newSourceUser(srcID, u.Name, u.Permissions)
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,9 +192,9 @@ func (h *Service) UpdateSourceUser(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
su := NewSourceUser(srcID, user.Name, user.Permissions)
|
su := newSourceUser(srcID, user.Name, user.Permissions)
|
||||||
w.Header().Add("Location", su.Links.Self)
|
w.Header().Add("Location", su.Links.Self)
|
||||||
encodeJSON(w, http.StatusCreated, su, h.Logger)
|
encodeJSON(w, http.StatusOK, su, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Service) sourceUsersStore(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, chronograf.UsersStore, error) {
|
func (h *Service) sourceUsersStore(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, chronograf.UsersStore, error) {
|
||||||
|
@ -246,11 +246,16 @@ func (h *Service) Permissions(w http.ResponseWriter, r *http.Request) {
|
||||||
Error(w, http.StatusBadRequest, err.Error(), h.Logger)
|
Error(w, http.StatusBadRequest, err.Error(), h.Logger)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
httpAPISrcs := "/chronograf/v1/sources"
|
||||||
res := struct {
|
res := struct {
|
||||||
Permissions chronograf.Allowances `json:"permissions"`
|
Permissions chronograf.Allowances `json:"permissions"`
|
||||||
|
Links map[string]string `json:"links"` // Links are URI locations related to user
|
||||||
}{
|
}{
|
||||||
Permissions: perms,
|
Permissions: perms,
|
||||||
|
Links: map[string]string{
|
||||||
|
"self": fmt.Sprintf("%s/%d/permissions", httpAPISrcs, srcID),
|
||||||
|
"source": fmt.Sprintf("%s/%d", httpAPISrcs, srcID),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
encodeJSON(w, http.StatusOK, res, h.Logger)
|
encodeJSON(w, http.StatusOK, res, h.Logger)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,797 @@
|
||||||
|
package server_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/bouk/httprouter"
|
||||||
|
|
||||||
|
"github.com/influxdata/chronograf"
|
||||||
|
"github.com/influxdata/chronograf/log"
|
||||||
|
"github.com/influxdata/chronograf/mocks"
|
||||||
|
"github.com/influxdata/chronograf/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestService_NewSourceUser(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
SourcesStore chronograf.SourcesStore
|
||||||
|
TimeSeries chronograf.TimeSeries
|
||||||
|
Logger chronograf.Logger
|
||||||
|
UseAuth bool
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
w *httptest.ResponseRecorder
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
ID string
|
||||||
|
wantStatus int
|
||||||
|
wantContentType string
|
||||||
|
wantBody string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "New user for data source",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"username": "marty", "password": "the_lake"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{
|
||||||
|
ID: 1,
|
||||||
|
Name: "muh source",
|
||||||
|
Username: "username",
|
||||||
|
Password: "hunter2",
|
||||||
|
URL: "http://localhost:8086",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeSeries: &mocks.TimeSeries{
|
||||||
|
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
UsersF: func(ctx context.Context) chronograf.UsersStore {
|
||||||
|
return &mocks.UsersStore{
|
||||||
|
AddF: func(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
|
||||||
|
return u, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
wantStatus: http.StatusCreated,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"username":"marty","links":{"self":"/chronograf/v1/sources/1/users/marty"}}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Error adding user",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"username": "marty", "password": "the_lake"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{
|
||||||
|
ID: 1,
|
||||||
|
Name: "muh source",
|
||||||
|
Username: "username",
|
||||||
|
Password: "hunter2",
|
||||||
|
URL: "http://localhost:8086",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeSeries: &mocks.TimeSeries{
|
||||||
|
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
UsersF: func(ctx context.Context) chronograf.UsersStore {
|
||||||
|
return &mocks.UsersStore{
|
||||||
|
AddF: func(ctx context.Context, u *chronograf.User) (*chronograf.User, error) {
|
||||||
|
return nil, fmt.Errorf("Weight Has Nothing to Do With It")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
wantStatus: http.StatusBadRequest,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"code":400,"message":"Weight Has Nothing to Do With It"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Failure connecting to user store",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"username": "marty", "password": "the_lake"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{
|
||||||
|
ID: 1,
|
||||||
|
Name: "muh source",
|
||||||
|
Username: "username",
|
||||||
|
Password: "hunter2",
|
||||||
|
URL: "http://localhost:8086",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeSeries: &mocks.TimeSeries{
|
||||||
|
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return fmt.Errorf("Biff just happens to be my supervisor")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
wantStatus: http.StatusBadRequest,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"code":400,"message":"Unable to connect to source 1"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Failure getting source",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"username": "marty", "password": "the_lake"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{}, fmt.Errorf("No McFly ever amounted to anything in the history of Hill Valley")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
wantStatus: http.StatusNotFound,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"code":404,"message":"ID 1 not found"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad ID",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"username": "marty", "password": "the_lake"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
},
|
||||||
|
ID: "BAD",
|
||||||
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"code":422,"message":"Error converting ID BAD"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad username",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"password": "the_lake"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
},
|
||||||
|
ID: "BAD",
|
||||||
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"code":422,"message":"Username required"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bad JSON",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{password}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
},
|
||||||
|
ID: "BAD",
|
||||||
|
wantStatus: http.StatusBadRequest,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"code":400,"message":"Unparsable JSON"}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
|
||||||
|
context.Background(),
|
||||||
|
httprouter.Params{
|
||||||
|
{
|
||||||
|
Key: "id",
|
||||||
|
Value: tt.ID,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
h := &server.Service{
|
||||||
|
SourcesStore: tt.fields.SourcesStore,
|
||||||
|
TimeSeries: tt.fields.TimeSeries,
|
||||||
|
Logger: tt.fields.Logger,
|
||||||
|
UseAuth: tt.fields.UseAuth,
|
||||||
|
}
|
||||||
|
|
||||||
|
h.NewSourceUser(tt.args.w, tt.args.r)
|
||||||
|
|
||||||
|
resp := tt.args.w.Result()
|
||||||
|
content := resp.Header.Get("Content-Type")
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != tt.wantStatus {
|
||||||
|
t.Errorf("%q. NewSourceUser() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||||||
|
}
|
||||||
|
if tt.wantContentType != "" && content != tt.wantContentType {
|
||||||
|
t.Errorf("%q. NewSourceUser() = %v, want %v", tt.name, content, tt.wantContentType)
|
||||||
|
}
|
||||||
|
if tt.wantBody != "" && string(body) != tt.wantBody {
|
||||||
|
t.Errorf("%q. NewSourceUser() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SourceUsers(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
SourcesStore chronograf.SourcesStore
|
||||||
|
TimeSeries chronograf.TimeSeries
|
||||||
|
Logger chronograf.Logger
|
||||||
|
UseAuth bool
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
w *httptest.ResponseRecorder
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
ID string
|
||||||
|
wantStatus int
|
||||||
|
wantContentType string
|
||||||
|
wantBody string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "All users for data source",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"GET",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
nil),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{
|
||||||
|
ID: 1,
|
||||||
|
Name: "muh source",
|
||||||
|
Username: "username",
|
||||||
|
Password: "hunter2",
|
||||||
|
URL: "http://localhost:8086",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeSeries: &mocks.TimeSeries{
|
||||||
|
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
UsersF: func(ctx context.Context) chronograf.UsersStore {
|
||||||
|
return &mocks.UsersStore{
|
||||||
|
AllF: func(ctx context.Context) ([]chronograf.User, error) {
|
||||||
|
return []chronograf.User{
|
||||||
|
{
|
||||||
|
Name: "strickland",
|
||||||
|
Passwd: "discipline",
|
||||||
|
Permissions: chronograf.Permissions{
|
||||||
|
{
|
||||||
|
Scope: chronograf.AllScope,
|
||||||
|
Allowed: chronograf.Allowances{"READ"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
wantStatus: http.StatusOK,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"users":[{"username":"strickland","permissions":[{"scope":"all","allowed":["READ"]}],"links":{"self":"/chronograf/v1/sources/1/users/strickland"}}]}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
|
||||||
|
context.Background(),
|
||||||
|
httprouter.Params{
|
||||||
|
{
|
||||||
|
Key: "id",
|
||||||
|
Value: tt.ID,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
h := &server.Service{
|
||||||
|
SourcesStore: tt.fields.SourcesStore,
|
||||||
|
TimeSeries: tt.fields.TimeSeries,
|
||||||
|
Logger: tt.fields.Logger,
|
||||||
|
UseAuth: tt.fields.UseAuth,
|
||||||
|
}
|
||||||
|
|
||||||
|
h.SourceUsers(tt.args.w, tt.args.r)
|
||||||
|
resp := tt.args.w.Result()
|
||||||
|
content := resp.Header.Get("Content-Type")
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != tt.wantStatus {
|
||||||
|
t.Errorf("%q. SourceUsers() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||||||
|
}
|
||||||
|
if tt.wantContentType != "" && content != tt.wantContentType {
|
||||||
|
t.Errorf("%q. SourceUsers() = %v, want %v", tt.name, content, tt.wantContentType)
|
||||||
|
}
|
||||||
|
if tt.wantBody != "" && string(body) != tt.wantBody {
|
||||||
|
t.Errorf("%q. SourceUsers() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_SourceUserID(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
SourcesStore chronograf.SourcesStore
|
||||||
|
TimeSeries chronograf.TimeSeries
|
||||||
|
Logger chronograf.Logger
|
||||||
|
UseAuth bool
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
w *httptest.ResponseRecorder
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
ID string
|
||||||
|
UID string
|
||||||
|
wantStatus int
|
||||||
|
wantContentType string
|
||||||
|
wantBody string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Single user for data source",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"GET",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
nil),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{
|
||||||
|
ID: 1,
|
||||||
|
Name: "muh source",
|
||||||
|
Username: "username",
|
||||||
|
Password: "hunter2",
|
||||||
|
URL: "http://localhost:8086",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeSeries: &mocks.TimeSeries{
|
||||||
|
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
UsersF: func(ctx context.Context) chronograf.UsersStore {
|
||||||
|
return &mocks.UsersStore{
|
||||||
|
GetF: func(ctx context.Context, uid string) (*chronograf.User, error) {
|
||||||
|
return &chronograf.User{
|
||||||
|
Name: "strickland",
|
||||||
|
Passwd: "discipline",
|
||||||
|
Permissions: chronograf.Permissions{
|
||||||
|
{
|
||||||
|
Scope: chronograf.AllScope,
|
||||||
|
Allowed: chronograf.Allowances{"READ"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
UID: "strickland",
|
||||||
|
wantStatus: http.StatusOK,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"username":"strickland","permissions":[{"scope":"all","allowed":["READ"]}],"links":{"self":"/chronograf/v1/sources/1/users/strickland"}}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
|
||||||
|
context.Background(),
|
||||||
|
httprouter.Params{
|
||||||
|
{
|
||||||
|
Key: "id",
|
||||||
|
Value: tt.ID,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
h := &server.Service{
|
||||||
|
SourcesStore: tt.fields.SourcesStore,
|
||||||
|
TimeSeries: tt.fields.TimeSeries,
|
||||||
|
Logger: tt.fields.Logger,
|
||||||
|
UseAuth: tt.fields.UseAuth,
|
||||||
|
}
|
||||||
|
|
||||||
|
h.SourceUserID(tt.args.w, tt.args.r)
|
||||||
|
resp := tt.args.w.Result()
|
||||||
|
content := resp.Header.Get("Content-Type")
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != tt.wantStatus {
|
||||||
|
t.Errorf("%q. SourceUserID() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||||||
|
}
|
||||||
|
if tt.wantContentType != "" && content != tt.wantContentType {
|
||||||
|
t.Errorf("%q. SourceUserID() = %v, want %v", tt.name, content, tt.wantContentType)
|
||||||
|
}
|
||||||
|
if tt.wantBody != "" && string(body) != tt.wantBody {
|
||||||
|
t.Errorf("%q. SourceUserID() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_RemoveSourceUser(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
SourcesStore chronograf.SourcesStore
|
||||||
|
TimeSeries chronograf.TimeSeries
|
||||||
|
Logger chronograf.Logger
|
||||||
|
UseAuth bool
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
w *httptest.ResponseRecorder
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
ID string
|
||||||
|
UID string
|
||||||
|
wantStatus int
|
||||||
|
wantContentType string
|
||||||
|
wantBody string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Delete user for data source",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"GET",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
nil),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{
|
||||||
|
ID: 1,
|
||||||
|
Name: "muh source",
|
||||||
|
Username: "username",
|
||||||
|
Password: "hunter2",
|
||||||
|
URL: "http://localhost:8086",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeSeries: &mocks.TimeSeries{
|
||||||
|
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
UsersF: func(ctx context.Context) chronograf.UsersStore {
|
||||||
|
return &mocks.UsersStore{
|
||||||
|
DeleteF: func(ctx context.Context, u *chronograf.User) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
UID: "strickland",
|
||||||
|
wantStatus: http.StatusNoContent,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
|
||||||
|
context.Background(),
|
||||||
|
httprouter.Params{
|
||||||
|
{
|
||||||
|
Key: "id",
|
||||||
|
Value: tt.ID,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
h := &server.Service{
|
||||||
|
SourcesStore: tt.fields.SourcesStore,
|
||||||
|
TimeSeries: tt.fields.TimeSeries,
|
||||||
|
Logger: tt.fields.Logger,
|
||||||
|
UseAuth: tt.fields.UseAuth,
|
||||||
|
}
|
||||||
|
h.RemoveSourceUser(tt.args.w, tt.args.r)
|
||||||
|
resp := tt.args.w.Result()
|
||||||
|
content := resp.Header.Get("Content-Type")
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != tt.wantStatus {
|
||||||
|
t.Errorf("%q. RemoveSourceUser() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||||||
|
}
|
||||||
|
if tt.wantContentType != "" && content != tt.wantContentType {
|
||||||
|
t.Errorf("%q. RemoveSourceUser() = %v, want %v", tt.name, content, tt.wantContentType)
|
||||||
|
}
|
||||||
|
if tt.wantBody != "" && string(body) != tt.wantBody {
|
||||||
|
t.Errorf("%q. RemoveSourceUser() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_UpdateSourceUser(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
SourcesStore chronograf.SourcesStore
|
||||||
|
TimeSeries chronograf.TimeSeries
|
||||||
|
Logger chronograf.Logger
|
||||||
|
UseAuth bool
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
w *httptest.ResponseRecorder
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
ID string
|
||||||
|
UID string
|
||||||
|
wantStatus int
|
||||||
|
wantContentType string
|
||||||
|
wantBody string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Update user password for data source",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"username": "marty", "password": "the_lake"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{
|
||||||
|
ID: 1,
|
||||||
|
Name: "muh source",
|
||||||
|
Username: "username",
|
||||||
|
Password: "hunter2",
|
||||||
|
URL: "http://localhost:8086",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeSeries: &mocks.TimeSeries{
|
||||||
|
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
UsersF: func(ctx context.Context) chronograf.UsersStore {
|
||||||
|
return &mocks.UsersStore{
|
||||||
|
UpdateF: func(ctx context.Context, u *chronograf.User) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
UID: "marty",
|
||||||
|
wantStatus: http.StatusOK,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"username":"marty","links":{"self":"/chronograf/v1/sources/1/users/marty"}}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid update JSON",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"username": "marty"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
UID: "marty",
|
||||||
|
wantStatus: http.StatusUnprocessableEntity,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"code":422,"message":"No fields to update"}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
|
||||||
|
context.Background(),
|
||||||
|
httprouter.Params{
|
||||||
|
{
|
||||||
|
Key: "id",
|
||||||
|
Value: tt.ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: "uid",
|
||||||
|
Value: tt.UID,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
h := &server.Service{
|
||||||
|
SourcesStore: tt.fields.SourcesStore,
|
||||||
|
TimeSeries: tt.fields.TimeSeries,
|
||||||
|
Logger: tt.fields.Logger,
|
||||||
|
UseAuth: tt.fields.UseAuth,
|
||||||
|
}
|
||||||
|
h.UpdateSourceUser(tt.args.w, tt.args.r)
|
||||||
|
resp := tt.args.w.Result()
|
||||||
|
content := resp.Header.Get("Content-Type")
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != tt.wantStatus {
|
||||||
|
t.Errorf("%q. UpdateSourceUser() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||||||
|
}
|
||||||
|
if tt.wantContentType != "" && content != tt.wantContentType {
|
||||||
|
t.Errorf("%q. UpdateSourceUser() = %v, want %v", tt.name, content, tt.wantContentType)
|
||||||
|
}
|
||||||
|
if tt.wantBody != "" && string(body) != tt.wantBody {
|
||||||
|
t.Errorf("%q. UpdateSourceUser() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestService_Permissions(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
SourcesStore chronograf.SourcesStore
|
||||||
|
TimeSeries chronograf.TimeSeries
|
||||||
|
Logger chronograf.Logger
|
||||||
|
UseAuth bool
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
w *httptest.ResponseRecorder
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
ID string
|
||||||
|
wantStatus int
|
||||||
|
wantContentType string
|
||||||
|
wantBody string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "New user for data source",
|
||||||
|
args: args{
|
||||||
|
w: httptest.NewRecorder(),
|
||||||
|
r: httptest.NewRequest(
|
||||||
|
"POST",
|
||||||
|
"http://server.local/chronograf/v1/sources/1",
|
||||||
|
ioutil.NopCloser(
|
||||||
|
bytes.NewReader([]byte(`{"username": "marty", "password": "the_lake"}`)))),
|
||||||
|
},
|
||||||
|
fields: fields{
|
||||||
|
UseAuth: true,
|
||||||
|
Logger: log.New(log.DebugLevel),
|
||||||
|
SourcesStore: &mocks.SourcesStore{
|
||||||
|
GetF: func(ctx context.Context, ID int) (chronograf.Source, error) {
|
||||||
|
return chronograf.Source{
|
||||||
|
ID: 1,
|
||||||
|
Name: "muh source",
|
||||||
|
Username: "username",
|
||||||
|
Password: "hunter2",
|
||||||
|
URL: "http://localhost:8086",
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TimeSeries: &mocks.TimeSeries{
|
||||||
|
ConnectF: func(ctx context.Context, src *chronograf.Source) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
AllowancesF: func(ctx context.Context) chronograf.Allowances {
|
||||||
|
return chronograf.Allowances{"READ", "WRITE"}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ID: "1",
|
||||||
|
wantStatus: http.StatusOK,
|
||||||
|
wantContentType: "application/json",
|
||||||
|
wantBody: `{"permissions":["READ","WRITE"],"links":{"self":"/chronograf/v1/sources/1/permissions","source":"/chronograf/v1/sources/1"}}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
|
||||||
|
context.Background(),
|
||||||
|
httprouter.Params{
|
||||||
|
{
|
||||||
|
Key: "id",
|
||||||
|
Value: tt.ID,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
h := &server.Service{
|
||||||
|
SourcesStore: tt.fields.SourcesStore,
|
||||||
|
TimeSeries: tt.fields.TimeSeries,
|
||||||
|
Logger: tt.fields.Logger,
|
||||||
|
UseAuth: tt.fields.UseAuth,
|
||||||
|
}
|
||||||
|
h.Permissions(tt.args.w, tt.args.r)
|
||||||
|
resp := tt.args.w.Result()
|
||||||
|
content := resp.Header.Get("Content-Type")
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if resp.StatusCode != tt.wantStatus {
|
||||||
|
t.Errorf("%q. Permissions() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||||||
|
}
|
||||||
|
if tt.wantContentType != "" && content != tt.wantContentType {
|
||||||
|
t.Errorf("%q. Permissions() = %v, want %v", tt.name, content, tt.wantContentType)
|
||||||
|
}
|
||||||
|
if tt.wantBody != "" && string(body) != tt.wantBody {
|
||||||
|
t.Errorf("%q. Permissions() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue