influxdb/influx/users_test.go

1128 lines
29 KiB
Go

package influx
import (
"context"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"strings"
"testing"
"github.com/influxdata/chronograf"
"github.com/influxdata/chronograf/log"
)
func TestClient_userPermissions(t *testing.T) {
t.Parallel()
type args struct {
ctx context.Context
name string
}
tests := []struct {
name string
showGrants []byte
status int
args args
want chronograf.Permissions
wantErr bool
}{
{
name: "Check all grants",
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
status: http.StatusOK,
args: args{
ctx: context.Background(),
name: "docbrown",
},
want: chronograf.Permissions{
chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
{
name: "Permission Denied",
status: http.StatusUnauthorized,
args: args{
ctx: context.Background(),
name: "docbrown",
},
wantErr: true,
},
{
name: "bad JSON",
showGrants: []byte(`{"results":[{"series":"adffdadf"}]}`),
status: http.StatusOK,
args: args{
ctx: context.Background(),
name: "docbrown",
},
wantErr: true,
},
}
for _, tt := range tests {
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
rw.WriteHeader(tt.status)
rw.Write(tt.showGrants)
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
got, err := c.userPermissions(tt.args.ctx, tt.args.name)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Client.userPermissions() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("%q. Client.userPermissions() = %v, want %v", tt.name, got, tt.want)
}
}
}
func TestClient_Add(t *testing.T) {
t.Parallel()
type args struct {
ctx context.Context
u *chronograf.User
}
tests := []struct {
name string
args args
status int
want *chronograf.User
wantQueries []string
wantErr bool
}{
{
name: "Create User",
status: http.StatusOK,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Passwd: "Dont Need Roads",
},
},
wantQueries: []string{
`CREATE USER "docbrown" WITH PASSWORD 'Dont Need Roads'`,
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
},
want: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: chronograf.AllScope,
Allowed: chronograf.Allowances{
"ALL",
},
},
},
},
},
{
name: "Create User with permissions",
status: http.StatusOK,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Passwd: "Dont Need Roads",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: chronograf.AllScope,
Allowed: chronograf.Allowances{
"ALL",
},
},
},
},
},
wantQueries: []string{
`CREATE USER "docbrown" WITH PASSWORD 'Dont Need Roads'`,
`GRANT ALL PRIVILEGES TO "docbrown"`,
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
},
want: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: chronograf.AllScope,
Allowed: chronograf.Allowances{
"ALL",
},
},
},
},
},
{
name: "Permission Denied",
status: http.StatusUnauthorized,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Passwd: "Dont Need Roads",
},
},
wantQueries: []string{`CREATE USER "docbrown" WITH PASSWORD 'Dont Need Roads'`},
wantErr: true,
},
}
for _, tt := range tests {
queries := []string{}
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
queries = append(queries, r.URL.Query().Get("q"))
rw.WriteHeader(tt.status)
rw.Write([]byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`))
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
got, err := c.Add(tt.args.ctx, tt.args.u)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Client.Add() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if len(tt.wantQueries) != len(queries) {
t.Errorf("%q. Client.Add() queries = %v, want %v", tt.name, queries, tt.wantQueries)
continue
}
for i := range tt.wantQueries {
if tt.wantQueries[i] != queries[i] {
t.Errorf("%q. Client.Add() query = %v, want %v", tt.name, queries[i], tt.wantQueries[i])
}
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("%q. Client.Add() = %v, want %v", tt.name, got, tt.want)
}
}
}
func TestClient_Delete(t *testing.T) {
type args struct {
ctx context.Context
u *chronograf.User
}
tests := []struct {
name string
status int
dropUser []byte
args args
wantErr bool
}{
{
name: "Drop User",
dropUser: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
status: http.StatusOK,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
},
},
},
{
name: "No such user",
dropUser: []byte(`{"results":[{"error":"user not found"}]}`),
status: http.StatusOK,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
},
},
wantErr: true,
},
{
name: "Bad InfluxQL",
dropUser: []byte(`{"error":"error parsing query: found doody, expected ; at line 1, char 17"}`),
status: http.StatusBadRequest,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
},
},
wantErr: true,
},
{
name: "Bad JSON",
dropUser: []byte(`{"results":[{"error":breakhere}]}`),
status: http.StatusOK,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
},
},
wantErr: true,
},
}
for _, tt := range tests {
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
rw.WriteHeader(tt.status)
rw.Write(tt.dropUser)
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
if err := c.Delete(tt.args.ctx, tt.args.u); (err != nil) != tt.wantErr {
t.Errorf("%q. Client.Delete() error = %v, wantErr %v", tt.name, err, tt.wantErr)
}
}
}
func TestClient_Get(t *testing.T) {
type args struct {
ctx context.Context
name string
}
tests := []struct {
name string
args args
statusUsers int
showUsers []byte
statusGrants int
showGrants []byte
want *chronograf.User
wantErr bool
}{
{
name: "Get User",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
args: args{
ctx: context.Background(),
name: "docbrown",
},
want: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: "all",
Allowed: []string{"ALL"},
},
chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
},
{
name: "Fail show users",
statusUsers: http.StatusBadRequest,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
args: args{
ctx: context.Background(),
name: "docbrown",
},
wantErr: true,
},
{
name: "Fail show grants",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusBadRequest,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
args: args{
ctx: context.Background(),
name: "docbrown",
},
wantErr: true,
},
{
name: "Fail no such user",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true]]}]}]}`),
args: args{
ctx: context.Background(),
name: "docbrown",
},
wantErr: true,
},
}
for _, tt := range tests {
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
query := r.URL.Query().Get("q")
if strings.Contains(query, "GRANTS") {
rw.WriteHeader(tt.statusGrants)
rw.Write(tt.showGrants)
} else if strings.Contains(query, "USERS") {
rw.WriteHeader(tt.statusUsers)
rw.Write(tt.showUsers)
}
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
got, err := c.Get(tt.args.ctx, chronograf.UserQuery{Name: &tt.args.name})
if (err != nil) != tt.wantErr {
t.Errorf("%q. Client.Get() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("%q. Client.Get() = %v, want %v", tt.name, got, tt.want)
}
}
}
func TestClient_grantPermission(t *testing.T) {
type args struct {
ctx context.Context
username string
perm chronograf.Permission
}
tests := []struct {
name string
args args
status int
results []byte
wantQuery string
wantErr bool
}{
{
name: "simple grants",
status: http.StatusOK,
results: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
username: "docbrown",
perm: chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
wantQuery: `GRANT ALL ON "mydb" TO "docbrown"`,
},
{
name: "bad grants",
status: http.StatusOK,
results: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
username: "docbrown",
perm: chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"howdy"},
},
},
wantQuery: ``,
},
{
name: "no grants",
status: http.StatusOK,
results: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
username: "docbrown",
perm: chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{},
},
},
wantQuery: ``,
},
}
for _, tt := range tests {
query := ""
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
query = r.URL.Query().Get("q")
rw.WriteHeader(tt.status)
rw.Write(tt.results)
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
if err := c.grantPermission(tt.args.ctx, tt.args.username, tt.args.perm); (err != nil) != tt.wantErr {
t.Errorf("%q. Client.grantPermission() error = %v, wantErr %v", tt.name, err, tt.wantErr)
}
if query != tt.wantQuery {
t.Errorf("%q. Client.grantPermission() = %v, want %v", tt.name, query, tt.wantQuery)
}
}
}
func TestClient_revokePermission(t *testing.T) {
type args struct {
ctx context.Context
username string
perm chronograf.Permission
}
tests := []struct {
name string
args args
status int
results []byte
wantQuery string
wantErr bool
}{
{
name: "simple revoke",
status: http.StatusOK,
results: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
username: "docbrown",
perm: chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
wantQuery: `REVOKE ALL ON "mydb" FROM "docbrown"`,
},
{
name: "bad revoke",
status: http.StatusOK,
results: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
username: "docbrown",
perm: chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"howdy"},
},
},
wantQuery: ``,
},
{
name: "no permissions",
status: http.StatusOK,
results: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
username: "docbrown",
perm: chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{},
},
},
wantQuery: `REVOKE ALL PRIVILEGES ON "mydb" FROM "docbrown"`,
},
}
for _, tt := range tests {
query := ""
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
query = r.URL.Query().Get("q")
rw.WriteHeader(tt.status)
rw.Write(tt.results)
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
if err := c.revokePermission(tt.args.ctx, tt.args.username, tt.args.perm); (err != nil) != tt.wantErr {
t.Errorf("%q. Client.revokePermission() error = %v, wantErr %v", tt.name, err, tt.wantErr)
}
if query != tt.wantQuery {
t.Errorf("%q. Client.revokePermission() = %v, want %v", tt.name, query, tt.wantQuery)
}
}
}
func TestClient_Num(t *testing.T) {
type args struct {
ctx context.Context
}
tests := []struct {
name string
args args
statusUsers int
showUsers []byte
statusGrants int
showGrants []byte
want []chronograf.User
wantErr bool
}{
{
name: "All Users",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
args: args{
ctx: context.Background(),
},
want: []chronograf.User{
{
Name: "admin",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: "all",
Allowed: []string{"ALL"},
},
chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
{
Name: "docbrown",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: "all",
Allowed: []string{"ALL"},
},
chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
{
Name: "reader",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
},
},
}
for _, tt := range tests {
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
query := r.URL.Query().Get("q")
if strings.Contains(query, "GRANTS") {
rw.WriteHeader(tt.statusGrants)
rw.Write(tt.showGrants)
} else if strings.Contains(query, "USERS") {
rw.WriteHeader(tt.statusUsers)
rw.Write(tt.showUsers)
}
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
got, err := c.Num(tt.args.ctx)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Client.Num() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if got != len(tt.want) {
t.Errorf("%q. Client.Num() = %v, want %v", tt.name, got, len(tt.want))
}
}
}
func TestClient_All(t *testing.T) {
type args struct {
ctx context.Context
}
tests := []struct {
name string
args args
statusUsers int
showUsers []byte
statusGrants int
showGrants []byte
want []chronograf.User
wantErr bool
}{
{
name: "All Users",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
args: args{
ctx: context.Background(),
},
want: []chronograf.User{
{
Name: "admin",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: "all",
Allowed: []string{"ALL"},
},
chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
{
Name: "docbrown",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: "all",
Allowed: []string{"ALL"},
},
chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
{
Name: "reader",
Permissions: chronograf.Permissions{
chronograf.Permission{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
},
},
{
name: "Unauthorized",
statusUsers: http.StatusUnauthorized,
showUsers: []byte(`{}`),
args: args{
ctx: context.Background(),
},
wantErr: true,
},
{
name: "Permission error",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusBadRequest,
showGrants: []byte(`{}`),
args: args{
ctx: context.Background(),
},
wantErr: true,
},
}
for _, tt := range tests {
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
query := r.URL.Query().Get("q")
if strings.Contains(query, "GRANTS") {
rw.WriteHeader(tt.statusGrants)
rw.Write(tt.showGrants)
} else if strings.Contains(query, "USERS") {
rw.WriteHeader(tt.statusUsers)
rw.Write(tt.showUsers)
}
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
got, err := c.All(tt.args.ctx)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Client.All() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("%q. Client.All() = %v, want %v", tt.name, got, tt.want)
}
}
}
func TestClient_Update(t *testing.T) {
type args struct {
ctx context.Context
u *chronograf.User
}
tests := []struct {
name string
statusUsers int
showUsers []byte
statusGrants int
showGrants []byte
statusRevoke int
revoke []byte
statusGrant int
grant []byte
statusPassword int
password []byte
args args
want []string
wantErr bool
}{
{
name: "Change Password",
statusPassword: http.StatusOK,
password: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Passwd: "hunter2",
},
},
want: []string{
`SET PASSWORD for "docbrown" = 'hunter2'`,
},
},
{
name: "Grant all permissions",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
statusRevoke: http.StatusOK,
revoke: []byte(`{"results":[]}`),
statusGrant: http.StatusOK,
grant: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
{
Scope: "all",
Allowed: []string{"all"},
},
{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
},
want: []string{
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
`GRANT ALL PRIVILEGES TO "docbrown"`,
`GRANT ALL ON "mydb" TO "docbrown"`,
},
},
{
name: "Revoke all permissions",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
statusRevoke: http.StatusOK,
revoke: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
},
},
want: []string{
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
`REVOKE ALL PRIVILEGES FROM "docbrown"`,
`REVOKE ALL ON "mydb" FROM "docbrown"`,
},
},
{
name: "Grant all permissions",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
statusRevoke: http.StatusOK,
revoke: []byte(`{"results":[]}`),
statusGrant: http.StatusOK,
grant: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
{
Scope: "all",
Allowed: []string{"all"},
},
{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE", "READ"},
},
},
},
},
want: []string{
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
`GRANT ALL PRIVILEGES TO "docbrown"`,
`GRANT ALL ON "mydb" TO "docbrown"`,
},
},
{
name: "Revoke some add some",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
statusRevoke: http.StatusOK,
revoke: []byte(`{"results":[]}`),
statusGrant: http.StatusOK,
grant: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
{
Scope: "all",
Allowed: []string{},
},
{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE"},
},
{
Scope: "database",
Name: "newdb",
Allowed: []string{"WRITE", "READ"},
},
},
},
},
want: []string{
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
`GRANT WRITE ON "mydb" TO "docbrown"`,
`GRANT ALL ON "newdb" TO "docbrown"`,
`REVOKE ALL PRIVILEGES FROM "docbrown"`,
},
},
{
name: "Revoke some",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",false],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[]}`),
statusRevoke: http.StatusOK,
revoke: []byte(`{"results":[]}`),
statusGrant: http.StatusOK,
grant: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
{
Scope: "all",
Allowed: []string{"ALL"},
},
},
},
},
want: []string{
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
`GRANT ALL PRIVILEGES TO "docbrown"`,
},
},
{
name: "Fail users",
statusUsers: http.StatusBadRequest,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
statusRevoke: http.StatusOK,
revoke: []byte(`{"results":[]}`),
statusGrant: http.StatusOK,
grant: []byte(`{"results":[]}`),
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
},
},
wantErr: true,
want: []string{
`SHOW USERS`,
},
},
{
name: "fail grants",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
statusRevoke: http.StatusOK,
revoke: []byte(`{"results":[]}`),
statusGrant: http.StatusBadRequest,
grant: []byte(`{"results":[]}`),
wantErr: true,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
{
Scope: "all",
Allowed: []string{},
},
{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE"},
},
{
Scope: "database",
Name: "newdb",
Allowed: []string{"WRITE", "READ"},
},
},
},
},
want: []string{
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
`GRANT WRITE ON "mydb" TO "docbrown"`,
},
},
{
name: "fail revoke",
statusUsers: http.StatusOK,
showUsers: []byte(`{"results":[{"series":[{"columns":["user","admin"],"values":[["admin",true],["docbrown",true],["reader",false]]}]}]}`),
statusGrants: http.StatusOK,
showGrants: []byte(`{"results":[{"series":[{"columns":["database","privilege"],"values":[["mydb","ALL PRIVILEGES"]]}]}]}`),
statusRevoke: http.StatusBadRequest,
revoke: []byte(`{"results":[]}`),
statusGrant: http.StatusOK,
grant: []byte(`{"results":[]}`),
wantErr: true,
args: args{
ctx: context.Background(),
u: &chronograf.User{
Name: "docbrown",
Permissions: chronograf.Permissions{
{
Scope: "all",
Allowed: []string{},
},
{
Scope: "database",
Name: "mydb",
Allowed: []string{"WRITE"},
},
{
Scope: "database",
Name: "newdb",
Allowed: []string{"WRITE", "READ"},
},
},
},
},
want: []string{
`SHOW USERS`,
`SHOW GRANTS FOR "docbrown"`,
`GRANT WRITE ON "mydb" TO "docbrown"`,
`GRANT ALL ON "newdb" TO "docbrown"`,
`REVOKE ALL PRIVILEGES FROM "docbrown"`,
},
},
}
for _, tt := range tests {
queries := []string{}
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if path := r.URL.Path; path != "/query" {
t.Error("Expected the path to contain `/query` but was", path)
}
query := r.URL.Query().Get("q")
if strings.Contains(query, "GRANTS") {
rw.WriteHeader(tt.statusGrants)
rw.Write(tt.showGrants)
} else if strings.Contains(query, "USERS") {
rw.WriteHeader(tt.statusUsers)
rw.Write(tt.showUsers)
} else if strings.Contains(query, "REVOKE") {
rw.WriteHeader(tt.statusRevoke)
rw.Write(tt.revoke)
} else if strings.Contains(query, "GRANT") {
rw.WriteHeader(tt.statusGrant)
rw.Write(tt.grant)
} else if strings.Contains(query, "PASSWORD") {
rw.WriteHeader(tt.statusPassword)
rw.Write(tt.password)
}
queries = append(queries, query)
}))
u, _ := url.Parse(ts.URL)
c := &Client{
URL: u,
Logger: log.New(log.DebugLevel),
}
defer ts.Close()
if err := c.Update(tt.args.ctx, tt.args.u); (err != nil) != tt.wantErr {
t.Errorf("%q. Client.Update() error = %v, wantErr %v", tt.name, err, tt.wantErr)
}
if !reflect.DeepEqual(queries, tt.want) {
t.Errorf("%q. Client.Update() = %v, want %v", tt.name, queries, tt.want)
}
}
}
/*
*/