1772 lines
45 KiB
Go
1772 lines
45 KiB
Go
package server
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io/ioutil"
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"testing"
|
||
|
||
"github.com/bouk/httprouter"
|
||
"github.com/influxdata/influxdb/v2/chronograf"
|
||
"github.com/influxdata/influxdb/v2/chronograf/mocks"
|
||
"github.com/influxdata/influxdb/v2/chronograf/roles"
|
||
)
|
||
|
||
func TestService_UserID(t *testing.T) {
|
||
type fields struct {
|
||
UsersStore chronograf.UsersStore
|
||
Logger chronograf.Logger
|
||
}
|
||
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: "Get Single Chronograf User",
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"GET",
|
||
"http://any.url", // can be any valid URL as we are bypassing mux
|
||
nil,
|
||
),
|
||
},
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
UsersStore: &mocks.UsersStore{
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1337:
|
||
return &chronograf.User{
|
||
ID: 1337,
|
||
Name: "billysteve",
|
||
Provider: "google",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
roles.ViewerRole,
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
id: "1337",
|
||
wantStatus: http.StatusOK,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1337","superAdmin":false,"name":"billysteve","provider":"google","scheme":"oauth2","links":{"self":"/chronograf/v1/users/1337"},"roles":[{"name":"viewer"}]}`,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
s := &Service{
|
||
Store: &mocks.Store{
|
||
UsersStore: tt.fields.UsersStore,
|
||
},
|
||
Logger: tt.fields.Logger,
|
||
}
|
||
|
||
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
|
||
context.Background(),
|
||
httprouter.Params{
|
||
{
|
||
Key: "id",
|
||
Value: tt.id,
|
||
},
|
||
}))
|
||
|
||
s.UserID(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. UserID() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||
}
|
||
if tt.wantContentType != "" && content != tt.wantContentType {
|
||
t.Errorf("%q. UserID() = %v, want %v", tt.name, content, tt.wantContentType)
|
||
}
|
||
if eq, _ := jsonEqual(string(body), tt.wantBody); tt.wantBody != "" && !eq {
|
||
t.Errorf("%q. UserID() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestService_NewUser(t *testing.T) {
|
||
type fields struct {
|
||
UsersStore chronograf.UsersStore
|
||
OrganizationsStore chronograf.OrganizationsStore
|
||
ConfigStore chronograf.ConfigStore
|
||
Logger chronograf.Logger
|
||
}
|
||
type args struct {
|
||
w *httptest.ResponseRecorder
|
||
r *http.Request
|
||
user *userRequest
|
||
userKeyUser *chronograf.User
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
fields fields
|
||
args args
|
||
wantStatus int
|
||
wantContentType string
|
||
wantBody string
|
||
}{
|
||
{
|
||
name: "Create a new Chronograf User",
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"POST",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
},
|
||
},
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
ConfigStore: &mocks.ConfigStore{
|
||
Config: &chronograf.Config{
|
||
Auth: chronograf.AuthConfig{
|
||
SuperAdminNewUsers: false,
|
||
},
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
AddF: func(ctx context.Context, user *chronograf.User) (*chronograf.User, error) {
|
||
return &chronograf.User{
|
||
ID: 1338,
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{},
|
||
}, nil
|
||
},
|
||
},
|
||
},
|
||
wantStatus: http.StatusCreated,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1338","superAdmin":false,"name":"bob","provider":"github","scheme":"oauth2","roles":[],"links":{"self":"/chronograf/v1/users/1338"}}`,
|
||
},
|
||
{
|
||
name: "Create a new Chronograf User with multiple roles",
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"POST",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
{
|
||
Name: roles.ViewerRoleName,
|
||
Organization: "2",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
ConfigStore: &mocks.ConfigStore{
|
||
Config: &chronograf.Config{
|
||
Auth: chronograf.AuthConfig{
|
||
SuperAdminNewUsers: false,
|
||
},
|
||
},
|
||
},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
case "2":
|
||
return &chronograf.Organization{
|
||
ID: "2",
|
||
Name: "another",
|
||
DefaultRole: roles.MemberRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
AddF: func(ctx context.Context, user *chronograf.User) (*chronograf.User, error) {
|
||
return &chronograf.User{
|
||
ID: 1338,
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
{
|
||
Name: roles.ViewerRoleName,
|
||
Organization: "2",
|
||
},
|
||
},
|
||
}, nil
|
||
},
|
||
},
|
||
},
|
||
wantStatus: http.StatusCreated,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1338","superAdmin":false,"name":"bob","provider":"github","scheme":"oauth2","roles":[{"name":"admin","organization":"1"},{"name":"viewer","organization":"2"}],"links":{"self":"/chronograf/v1/users/1338"}}`,
|
||
},
|
||
{
|
||
name: "Create a new Chronograf User with multiple roles same org",
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"POST",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
{
|
||
Name: roles.ViewerRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
ConfigStore: &mocks.ConfigStore{
|
||
Config: &chronograf.Config{
|
||
Auth: chronograf.AuthConfig{
|
||
SuperAdminNewUsers: false,
|
||
},
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
AddF: func(ctx context.Context, user *chronograf.User) (*chronograf.User, error) {
|
||
return &chronograf.User{
|
||
ID: 1338,
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
{
|
||
Name: roles.ViewerRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
}, nil
|
||
},
|
||
},
|
||
},
|
||
wantStatus: http.StatusUnprocessableEntity,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"code":422,"message":"duplicate organization \"1\" in roles"}`,
|
||
},
|
||
{
|
||
name: "Create a new SuperAdmin User - Not as superadmin",
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"POST",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
},
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: false,
|
||
},
|
||
},
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
ConfigStore: &mocks.ConfigStore{
|
||
Config: &chronograf.Config{
|
||
Auth: chronograf.AuthConfig{
|
||
SuperAdminNewUsers: false,
|
||
},
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
AddF: func(ctx context.Context, user *chronograf.User) (*chronograf.User, error) {
|
||
return &chronograf.User{
|
||
ID: 1338,
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{},
|
||
}, nil
|
||
},
|
||
},
|
||
},
|
||
wantStatus: http.StatusUnauthorized,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"code":401,"message":"user does not have authorization required to set SuperAdmin status. See https://github.com/influxdata/influxdb/chronograf/issues/2601 for more information"}`,
|
||
},
|
||
{
|
||
name: "Create a new SuperAdmin User - as superadmin",
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"POST",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
},
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
},
|
||
},
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
ConfigStore: &mocks.ConfigStore{
|
||
Config: &chronograf.Config{
|
||
Auth: chronograf.AuthConfig{
|
||
SuperAdminNewUsers: false,
|
||
},
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
AddF: func(ctx context.Context, user *chronograf.User) (*chronograf.User, error) {
|
||
return &chronograf.User{
|
||
ID: 1338,
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{},
|
||
SuperAdmin: true,
|
||
}, nil
|
||
},
|
||
},
|
||
},
|
||
wantStatus: http.StatusCreated,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1338","superAdmin":true,"name":"bob","provider":"github","scheme":"oauth2","roles":[],"links":{"self":"/chronograf/v1/users/1338"}}`,
|
||
},
|
||
{
|
||
name: "Create a new User with SuperAdminNewUsers: true in ConfigStore",
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"POST",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
},
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
},
|
||
},
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
ConfigStore: &mocks.ConfigStore{
|
||
Config: &chronograf.Config{
|
||
Auth: chronograf.AuthConfig{
|
||
SuperAdminNewUsers: true,
|
||
},
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
AddF: func(ctx context.Context, user *chronograf.User) (*chronograf.User, error) {
|
||
user.ID = 1338
|
||
return user, nil
|
||
},
|
||
},
|
||
},
|
||
wantStatus: http.StatusCreated,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1338","superAdmin":true,"name":"bob","provider":"github","scheme":"oauth2","roles":[],"links":{"self":"/chronograf/v1/users/1338"}}`,
|
||
},
|
||
{
|
||
name: "Create a new Chronograf User with multiple roles with wildcard default role",
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"POST",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
{
|
||
Name: roles.WildcardRoleName,
|
||
Organization: "2",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
ConfigStore: &mocks.ConfigStore{
|
||
Config: &chronograf.Config{
|
||
Auth: chronograf.AuthConfig{
|
||
SuperAdminNewUsers: false,
|
||
},
|
||
},
|
||
},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
case "2":
|
||
return &chronograf.Organization{
|
||
ID: "2",
|
||
Name: "another",
|
||
DefaultRole: roles.MemberRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
AddF: func(ctx context.Context, user *chronograf.User) (*chronograf.User, error) {
|
||
return &chronograf.User{
|
||
ID: 1338,
|
||
Name: "bob",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
{
|
||
Name: roles.MemberRoleName,
|
||
Organization: "2",
|
||
},
|
||
},
|
||
}, nil
|
||
},
|
||
},
|
||
},
|
||
wantStatus: http.StatusCreated,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1338","superAdmin":false,"name":"bob","provider":"github","scheme":"oauth2","roles":[{"name":"admin","organization":"1"},{"name":"member","organization":"2"}],"links":{"self":"/chronograf/v1/users/1338"}}`,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
s := &Service{
|
||
Store: &mocks.Store{
|
||
UsersStore: tt.fields.UsersStore,
|
||
ConfigStore: tt.fields.ConfigStore,
|
||
OrganizationsStore: tt.fields.OrganizationsStore,
|
||
},
|
||
Logger: tt.fields.Logger,
|
||
}
|
||
|
||
buf, _ := json.Marshal(tt.args.user)
|
||
tt.args.r.Body = ioutil.NopCloser(bytes.NewReader(buf))
|
||
|
||
ctx := tt.args.r.Context()
|
||
if tt.args.userKeyUser != nil {
|
||
ctx = context.WithValue(ctx, UserContextKey, tt.args.userKeyUser)
|
||
}
|
||
|
||
tt.args.r = tt.args.r.WithContext(ctx)
|
||
|
||
s.NewUser(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. UserID() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||
}
|
||
if tt.wantContentType != "" && content != tt.wantContentType {
|
||
t.Errorf("%q. UserID() = %v, want %v", tt.name, content, tt.wantContentType)
|
||
}
|
||
if eq, _ := jsonEqual(string(body), tt.wantBody); tt.wantBody != "" && !eq {
|
||
t.Errorf("%q. UserID() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestService_RemoveUser(t *testing.T) {
|
||
type fields struct {
|
||
UsersStore chronograf.UsersStore
|
||
Logger chronograf.Logger
|
||
}
|
||
type args struct {
|
||
w *httptest.ResponseRecorder
|
||
r *http.Request
|
||
user *chronograf.User
|
||
id string
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
fields fields
|
||
args args
|
||
wantStatus int
|
||
wantBody string
|
||
}{
|
||
{
|
||
name: "Delete a Chronograf User",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
UsersStore: &mocks.UsersStore{
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1339:
|
||
return &chronograf.User{
|
||
ID: 1339,
|
||
Name: "helena",
|
||
Provider: "heroku",
|
||
Scheme: "oauth2",
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
DeleteF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"DELETE",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &chronograf.User{
|
||
ID: 1338,
|
||
Name: "helena",
|
||
Provider: "heroku",
|
||
Scheme: "oauth2",
|
||
},
|
||
id: "1339",
|
||
},
|
||
wantStatus: http.StatusNoContent,
|
||
},
|
||
{
|
||
name: "Deleting yourself",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
UsersStore: &mocks.UsersStore{
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1339:
|
||
return &chronograf.User{
|
||
ID: 1339,
|
||
Name: "helena",
|
||
Provider: "heroku",
|
||
Scheme: "oauth2",
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
DeleteF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"DELETE",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &chronograf.User{
|
||
ID: 1339,
|
||
Name: "helena",
|
||
Provider: "heroku",
|
||
Scheme: "oauth2",
|
||
},
|
||
id: "1339",
|
||
},
|
||
wantStatus: http.StatusNoContent,
|
||
wantBody: ``,
|
||
},
|
||
}
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
s := &Service{
|
||
Store: &mocks.Store{
|
||
UsersStore: tt.fields.UsersStore,
|
||
},
|
||
Logger: tt.fields.Logger,
|
||
}
|
||
|
||
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(
|
||
context.Background(),
|
||
httprouter.Params{
|
||
{
|
||
Key: "id",
|
||
Value: tt.args.id,
|
||
},
|
||
},
|
||
))
|
||
|
||
if tt.args.user != nil {
|
||
ctx := tt.args.r.Context()
|
||
ctx = context.WithValue(ctx, UserContextKey, tt.args.user)
|
||
tt.args.r = tt.args.r.WithContext(ctx)
|
||
}
|
||
|
||
s.RemoveUser(tt.args.w, tt.args.r)
|
||
|
||
resp := tt.args.w.Result()
|
||
body, _ := ioutil.ReadAll(resp.Body)
|
||
|
||
if resp.StatusCode != tt.wantStatus {
|
||
t.Errorf("%q. RemoveUser() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||
}
|
||
if tt.wantStatus == http.StatusNoContent {
|
||
return
|
||
}
|
||
if eq, _ := jsonEqual(string(body), tt.wantBody); !eq {
|
||
t.Errorf("%q. RemoveUser() = %v, want %v", tt.name, string(body), tt.wantBody)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestService_UpdateUser(t *testing.T) {
|
||
type fields struct {
|
||
UsersStore chronograf.UsersStore
|
||
OrganizationsStore chronograf.OrganizationsStore
|
||
Logger chronograf.Logger
|
||
}
|
||
type args struct {
|
||
w *httptest.ResponseRecorder
|
||
r *http.Request
|
||
user *userRequest
|
||
userKeyUser *chronograf.User
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
fields fields
|
||
args args
|
||
id string
|
||
wantStatus int
|
||
wantContentType string
|
||
wantBody string
|
||
}{
|
||
{
|
||
name: "Update a Chronograf user - no roles",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: false,
|
||
},
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
Roles: []chronograf.Role{},
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusOK,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1336","superAdmin":false,"name":"bobbetta","provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/1336"},"roles":[]}`,
|
||
},
|
||
{
|
||
name: "Update a Chronograf user",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: false,
|
||
},
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusOK,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1336","superAdmin":false,"name":"bobbetta","provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/1336"},"roles":[{"name":"admin","organization":"1"}]}`,
|
||
},
|
||
{
|
||
name: "Update a Chronograf user roles different orgs",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
case "2":
|
||
return &chronograf.Organization{
|
||
ID: "2",
|
||
Name: "another",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
roles.EditorRole,
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: false,
|
||
},
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
{
|
||
Name: roles.ViewerRoleName,
|
||
Organization: "2",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusOK,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1336","superAdmin":false,"name":"bobbetta","provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/1336"},"roles":[{"name":"admin","organization":"1"},{"name":"viewer","organization":"2"}]}`,
|
||
},
|
||
{
|
||
name: "Update a Chronograf user roles same org",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
roles.EditorRole,
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
{
|
||
Name: roles.ViewerRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusUnprocessableEntity,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"code":422,"message":"duplicate organization \"1\" in roles"}`,
|
||
},
|
||
{
|
||
name: "SuperAdmin modifying their own SuperAdmin Status - user missing from context",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
SuperAdmin: false,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusInternalServerError,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"code":500,"message":"failed to retrieve user from context"}`,
|
||
},
|
||
{
|
||
name: "SuperAdmin modifying their own SuperAdmin Status",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
SuperAdmin: false,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
userKeyUser: &chronograf.User{
|
||
ID: 1336,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusUnauthorized,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"code":401,"message":"user cannot modify their own SuperAdmin status"}`,
|
||
},
|
||
{
|
||
name: "Update a SuperAdmin's Roles - without super admin context",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
SuperAdmin: true,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: false,
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusOK,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"links":{"self":"/chronograf/v1/users/1336"},"id":"1336","name":"bobbetta","provider":"github","scheme":"oauth2","superAdmin":true,"roles":[{"name":"admin","organization":"1"}]}`,
|
||
},
|
||
{
|
||
name: "Update a Chronograf user to super admin - without super admin context",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
roles.EditorRole,
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
SuperAdmin: true,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: false,
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusUnauthorized,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"code":401,"message":"user does not have authorization required to set SuperAdmin status. See https://github.com/influxdata/influxdb/chronograf/issues/2601 for more information"}`,
|
||
},
|
||
{
|
||
name: "Update a Chronograf user to super admin - with super admin context",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
OrganizationsStore: &mocks.OrganizationsStore{
|
||
GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
|
||
switch *q.ID {
|
||
case "1":
|
||
return &chronograf.Organization{
|
||
ID: "1",
|
||
Name: "org",
|
||
DefaultRole: roles.ViewerRoleName,
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("org not found")
|
||
},
|
||
},
|
||
UsersStore: &mocks.UsersStore{
|
||
UpdateF: func(ctx context.Context, user *chronograf.User) error {
|
||
return nil
|
||
},
|
||
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
|
||
switch *q.ID {
|
||
case 1336:
|
||
return &chronograf.User{
|
||
ID: 1336,
|
||
Name: "bobbetta",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
roles.EditorRole,
|
||
},
|
||
}, nil
|
||
default:
|
||
return nil, fmt.Errorf("user with ID %d not found", *q.ID)
|
||
}
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"PATCH",
|
||
"http://any.url",
|
||
nil,
|
||
),
|
||
user: &userRequest{
|
||
ID: 1336,
|
||
SuperAdmin: true,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
userKeyUser: &chronograf.User{
|
||
ID: 0,
|
||
Name: "coolUser",
|
||
Provider: "github",
|
||
Scheme: "oauth2",
|
||
SuperAdmin: true,
|
||
},
|
||
},
|
||
id: "1336",
|
||
wantStatus: http.StatusOK,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"id":"1336","superAdmin":true,"name":"bobbetta","provider":"github","scheme":"oauth2","links":{"self":"/chronograf/v1/users/1336"},"roles":[{"name":"admin","organization":"1"}]}`,
|
||
},
|
||
}
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
s := &Service{
|
||
Store: &mocks.Store{
|
||
UsersStore: tt.fields.UsersStore,
|
||
OrganizationsStore: tt.fields.OrganizationsStore,
|
||
},
|
||
Logger: tt.fields.Logger,
|
||
}
|
||
|
||
tt.args.r = tt.args.r.WithContext(httprouter.WithParams(context.Background(),
|
||
httprouter.Params{
|
||
{
|
||
Key: "id",
|
||
Value: tt.id,
|
||
},
|
||
}))
|
||
buf, _ := json.Marshal(tt.args.user)
|
||
tt.args.r.Body = ioutil.NopCloser(bytes.NewReader(buf))
|
||
|
||
ctx := tt.args.r.Context()
|
||
if tt.args.userKeyUser != nil {
|
||
ctx = context.WithValue(ctx, UserContextKey, tt.args.userKeyUser)
|
||
}
|
||
|
||
tt.args.r = tt.args.r.WithContext(ctx)
|
||
|
||
s.UpdateUser(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. UpdateUser() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||
}
|
||
if tt.wantContentType != "" && content != tt.wantContentType {
|
||
t.Errorf("%q. UpdateUser() = %v, want %v", tt.name, content, tt.wantContentType)
|
||
}
|
||
if eq, _ := jsonEqual(string(body), tt.wantBody); tt.wantBody != "" && !eq {
|
||
t.Errorf("%q. UpdateUser()\ngot:%v\n,\nwant:%v", tt.name, string(body), tt.wantBody)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestService_Users(t *testing.T) {
|
||
type fields struct {
|
||
UsersStore chronograf.UsersStore
|
||
Logger chronograf.Logger
|
||
}
|
||
type args struct {
|
||
w *httptest.ResponseRecorder
|
||
r *http.Request
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
fields fields
|
||
args args
|
||
wantStatus int
|
||
wantContentType string
|
||
wantBody string
|
||
}{
|
||
{
|
||
name: "Get all Chronograf users",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
UsersStore: &mocks.UsersStore{
|
||
AllF: func(ctx context.Context) ([]chronograf.User, error) {
|
||
return []chronograf.User{
|
||
{
|
||
ID: 1337,
|
||
Name: "billysteve",
|
||
Provider: "google",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
roles.EditorRole,
|
||
},
|
||
},
|
||
{
|
||
ID: 1338,
|
||
Name: "bobbettastuhvetta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
},
|
||
}, nil
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"GET",
|
||
"http://any.url", // can be any valid URL as we are bypassing mux
|
||
nil,
|
||
),
|
||
},
|
||
wantStatus: http.StatusOK,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"users":[{"id":"1337","superAdmin":false,"name":"billysteve","provider":"google","scheme":"oauth2","roles":[{"name":"editor"}],"links":{"self":"/chronograf/v1/users/1337"}},{"id":"1338","superAdmin":false,"name":"bobbettastuhvetta","provider":"auth0","scheme":"oauth2","roles":[],"links":{"self":"/chronograf/v1/users/1338"}}],"links":{"self":"/chronograf/v1/users"}}`,
|
||
},
|
||
{
|
||
name: "Get all Chronograf users, ensuring order of users in response",
|
||
fields: fields{
|
||
Logger: &chronograf.NoopLogger{},
|
||
UsersStore: &mocks.UsersStore{
|
||
AllF: func(ctx context.Context) ([]chronograf.User, error) {
|
||
return []chronograf.User{
|
||
{
|
||
ID: 1338,
|
||
Name: "bobbettastuhvetta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
},
|
||
{
|
||
ID: 1337,
|
||
Name: "billysteve",
|
||
Provider: "google",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
roles.EditorRole,
|
||
},
|
||
},
|
||
}, nil
|
||
},
|
||
},
|
||
},
|
||
args: args{
|
||
w: httptest.NewRecorder(),
|
||
r: httptest.NewRequest(
|
||
"GET",
|
||
"http://any.url", // can be any valid URL as we are bypassing mux
|
||
nil,
|
||
),
|
||
},
|
||
wantStatus: http.StatusOK,
|
||
wantContentType: "application/json",
|
||
wantBody: `{"users":[{"id":"1337","superAdmin":false,"name":"billysteve","provider":"google","scheme":"oauth2","roles":[{"name":"editor"}],"links":{"self":"/chronograf/v1/users/1337"}},{"id":"1338","superAdmin":false,"name":"bobbettastuhvetta","provider":"auth0","scheme":"oauth2","roles":[],"links":{"self":"/chronograf/v1/users/1338"}}],"links":{"self":"/chronograf/v1/users"}}`,
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
s := &Service{
|
||
Store: &mocks.Store{
|
||
UsersStore: tt.fields.UsersStore,
|
||
},
|
||
Logger: tt.fields.Logger,
|
||
}
|
||
|
||
s.Users(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. Users() = %v, want %v", tt.name, resp.StatusCode, tt.wantStatus)
|
||
}
|
||
if tt.wantContentType != "" && content != tt.wantContentType {
|
||
t.Errorf("%q. Users() = %v, want %v", tt.name, content, tt.wantContentType)
|
||
}
|
||
if eq, _ := jsonEqual(string(body), tt.wantBody); tt.wantBody != "" && !eq {
|
||
t.Errorf("%q. Users() = \n***%v***\n,\nwant\n***%v***", tt.name, string(body), tt.wantBody)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestUserRequest_ValidCreate(t *testing.T) {
|
||
type args struct {
|
||
u *userRequest
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
args args
|
||
wantErr bool
|
||
err error
|
||
}{
|
||
{
|
||
name: "Valid",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: false,
|
||
err: nil,
|
||
},
|
||
{
|
||
name: "Invalid – Name missing",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("name required on Chronograf User request body"),
|
||
},
|
||
{
|
||
name: "Invalid – Provider missing",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("provider required on Chronograf User request body"),
|
||
},
|
||
{
|
||
name: "Invalid – Scheme missing",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Provider: "auth0",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("scheme required on Chronograf User request body"),
|
||
},
|
||
{
|
||
name: "Invalid roles - bad role name",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: "BilliettaSpecialRole",
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("unknown role BilliettaSpecialRole. Valid roles are 'member', 'viewer', 'editor', 'admin', and '*'"),
|
||
},
|
||
{
|
||
name: "Invalid roles - missing organization",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("no organization was provided"),
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
err := tt.args.u.ValidCreate()
|
||
|
||
if tt.wantErr {
|
||
if err == nil || err.Error() != tt.err.Error() {
|
||
t.Errorf("%q. ValidCreate(): wantErr %v,\nwant %v,\ngot %v", tt.name, tt.wantErr, tt.err, err)
|
||
}
|
||
} else {
|
||
if err != nil {
|
||
t.Errorf("%q. ValidCreate(): wantErr %v,\nwant %v,\ngot %v", tt.name, tt.wantErr, tt.err, err)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestUserRequest_ValidUpdate(t *testing.T) {
|
||
type args struct {
|
||
u *userRequest
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
args args
|
||
wantErr bool
|
||
err error
|
||
}{
|
||
{
|
||
name: "Valid",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.EditorRoleName,
|
||
Organization: "1",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: false,
|
||
err: nil,
|
||
},
|
||
{
|
||
name: "Invalid – roles missing",
|
||
args: args{
|
||
u: &userRequest{},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("no Roles to update"),
|
||
},
|
||
{
|
||
name: "Invalid - bad role name",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: "BillietaSpecialOrg",
|
||
Organization: "0",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("unknown role BillietaSpecialOrg. Valid roles are 'member', 'viewer', 'editor', 'admin', and '*'"),
|
||
},
|
||
{
|
||
name: "Valid – roles empty",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{},
|
||
},
|
||
},
|
||
wantErr: false,
|
||
},
|
||
{
|
||
name: "Invalid - bad role name",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: "BillietaSpecialOrg",
|
||
Organization: "0",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("unknown role BillietaSpecialOrg. Valid roles are 'member', 'viewer', 'editor', 'admin', and '*'"),
|
||
},
|
||
{
|
||
name: "Invalid - duplicate organization",
|
||
args: args{
|
||
u: &userRequest{
|
||
ID: 1337,
|
||
Name: "billietta",
|
||
Provider: "auth0",
|
||
Scheme: "oauth2",
|
||
Roles: []chronograf.Role{
|
||
{
|
||
Name: roles.AdminRoleName,
|
||
Organization: "0",
|
||
},
|
||
{
|
||
Name: roles.ViewerRoleName,
|
||
Organization: "0",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
wantErr: true,
|
||
err: fmt.Errorf("duplicate organization \"0\" in roles"),
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
err := tt.args.u.ValidUpdate()
|
||
|
||
if tt.wantErr {
|
||
if err == nil || err.Error() != tt.err.Error() {
|
||
t.Errorf("%q. ValidUpdate(): wantErr %v,\nwant %v,\ngot %v", tt.name, tt.wantErr, tt.err, err)
|
||
}
|
||
} else {
|
||
if err != nil {
|
||
t.Errorf("%q. ValidUpdate(): wantErr %v,\nwant %v,\ngot %v", tt.name, tt.wantErr, tt.err, err)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|