package influx

import (
	"context"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"strings"
	"testing"

	"github.com/influxdata/influxdb/v2/chronograf"
)

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: &chronograf.NoopLogger{},
		}
		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: &chronograf.NoopLogger{},
		}
		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: &chronograf.NoopLogger{},
		}
		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: &chronograf.NoopLogger{},
		}
		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: &chronograf.NoopLogger{},
		}
		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: &chronograf.NoopLogger{},
		}
		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: &chronograf.NoopLogger{},
		}
		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: &chronograf.NoopLogger{},
		}
		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: &chronograf.NoopLogger{},
		}
		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)
		}
	}
}

/*



 */
