Wire up POST /db/:db/users/:user

pull/1239/head
David Norton 2014-11-26 17:10:56 -05:00
parent 661ef86c51
commit c80b5a698b
3 changed files with 337 additions and 74 deletions

View File

@ -232,7 +232,7 @@ func (h *Handler) serveCreateDatabase(w http.ResponseWriter, r *http.Request) {
func (h *Handler) serveDeleteDatabase(w http.ResponseWriter, r *http.Request) { func (h *Handler) serveDeleteDatabase(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get(":name") name := r.URL.Query().Get(":name")
if err := h.server.DeleteDatabase(name); err == ErrDatabaseNotFound { if err := h.server.DeleteDatabase(name); err == ErrDatabaseNotFound {
h.error(w, ErrDatabaseNotFound.Error(), http.StatusNotFound) h.error(w, err.Error(), http.StatusNotFound)
return return
} else if err != nil { } else if err != nil {
h.error(w, err.Error(), http.StatusInternalServerError) h.error(w, err.Error(), http.StatusInternalServerError)
@ -291,13 +291,13 @@ func (h *Handler) serveCreateDBUser(w http.ResponseWriter, r *http.Request) {
return return
} }
nu := &userJSON{} u := &userJSON{}
if err := json.NewDecoder(r.Body).Decode(nu); err != nil { if err := json.NewDecoder(r.Body).Decode(u); err != nil {
h.error(w, err.Error(), http.StatusBadRequest) h.error(w, err.Error(), http.StatusBadRequest)
return return
} }
if err := db.CreateUser(nu.Name, nu.Password, nu.ReadFrom, nu.WriteTo); err != nil { if err := db.CreateUser(u.Name, u.Password, u.ReadFrom, u.WriteTo); err != nil {
h.error(w, err.Error(), http.StatusInternalServerError) h.error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@ -334,7 +334,84 @@ func (h *Handler) serveDBUser(w http.ResponseWriter, r *http.Request) {
} }
// serveUpdateDBUser updates an existing database user. // serveUpdateDBUser updates an existing database user.
func (h *Handler) serveUpdateDBUser(w http.ResponseWriter, r *http.Request) {} func (h *Handler) serveUpdateDBUser(w http.ResponseWriter, r *http.Request) {
// TODO: Authentication
urlQry := r.URL.Query()
db := h.server.Database(urlQry.Get(":db"))
if db == nil {
h.error(w, ErrDatabaseNotFound.Error(), http.StatusNotFound)
return
}
dbUser := db.User(urlQry.Get(":user"))
if dbUser == nil {
h.error(w, ErrUserNotFound.Error(), http.StatusNotFound)
return
}
uu := make(map[string]interface{})
if err := json.NewDecoder(r.Body).Decode(&uu); err != nil {
h.error(w, err.Error(), http.StatusBadRequest)
return
}
if pwd, ok := uu["password"]; ok {
newPwd, ok := pwd.(string);
if !ok {
h.error(w, "password must be a string", http.StatusBadRequest)
return
}
if err := db.ChangePassword(dbUser.Name, newPwd); err != nil {
h.error(w, err.Error(), http.StatusInternalServerError)
return
}
}
if rd, ok := uu["readFrom"]; ok {
rdstr, ok := rd.(string)
if !ok {
h.error(w, "readFrom must be a string", http.StatusBadRequest)
return
}
var matchers []*Matcher
if err := json.NewDecoder(strings.NewReader(rdstr)).Decode(&matchers); err != nil {
h.error(w, err.Error(), http.StatusBadRequest)
return
}
dbUser.ReadFrom = matchers
}
if wr, ok := uu["writeTo"]; ok {
wrstr, ok := wr.(string)
if !ok {
h.error(w, "writeTo must be a string", http.StatusBadRequest)
return
}
var matchers []*Matcher
if err := json.NewDecoder(strings.NewReader(wrstr)).Decode(&matchers); err != nil {
h.error(w, err.Error(), http.StatusBadRequest)
return
}
dbUser.WriteTo = matchers
}
if admin, ok := uu["isAdmin"]; ok {
isAdmin, ok := admin.(bool)
if !ok {
h.error(w, "isAdmin must be a bool", http.StatusBadRequest)
return
}
dbUser.IsAdmin = isAdmin
}
}
// serveDeleteDBUser removes an existing database user. // serveDeleteDBUser removes an existing database user.
func (h *Handler) serveDeleteDBUser(w http.ResponseWriter, r *http.Request) {} func (h *Handler) serveDeleteDBUser(w http.ResponseWriter, r *http.Request) {}
@ -469,8 +546,6 @@ func (h *Handler) serveUpdateRetentionPolicy(w http.ResponseWriter, r *http.Requ
// Update the policy // Update the policy
*policy = *newPolicy *policy = *newPolicy
w.WriteHeader(http.StatusOK)
} }
// serveDeleteRetentionPolicy removes an existing retention policy. // serveDeleteRetentionPolicy removes an existing retention policy.

View File

@ -2,6 +2,7 @@ package influxdb_test
import ( import (
"bytes" "bytes"
"errors"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -12,6 +13,10 @@ import (
"github.com/influxdb/influxdb" "github.com/influxdb/influxdb"
) )
func init() {
influxdb.BcryptCost = 4
}
func TestHandler_Databases(t *testing.T) { func TestHandler_Databases(t *testing.T) {
srvr := OpenServer(NewMessagingClient()) srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo") srvr.CreateDatabase("foo")
@ -21,8 +26,7 @@ func TestHandler_Databases(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db`, "") status, body := MustHTTP("GET", s.URL+`/db`, "")
if status != http.StatusOK { if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `[{"name":"bar"},{"name":"foo"}]` {
if body != `[{"name":"bar"},{"name":"foo"}]` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -34,8 +38,7 @@ func TestHandler_CreateDatabase(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db`, `{"name": "foo"}`) status, body := MustHTTP("POST", s.URL+`/db`, `{"name": "foo"}`)
if status != http.StatusCreated { if status != http.StatusCreated {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `` {
if body != `` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -47,8 +50,7 @@ func TestHandler_CreateDatabase_BadRequest_NoName(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db`, `{"BadRequest": 1}`) status, body := MustHTTP("POST", s.URL+`/db`, `{"BadRequest": 1}`)
if status != http.StatusBadRequest { if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `database name required` {
if body != `database name required` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -60,8 +62,7 @@ func TestHandler_CreateDatabase_BadRequest_InvalidJSON(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db`, `"BadRequest": 1`) status, body := MustHTTP("POST", s.URL+`/db`, `"BadRequest": 1`)
if status != http.StatusBadRequest { if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `json: cannot unmarshal string into Go value of type struct { Name string "json:\"name\"" }` {
if body != `json: cannot unmarshal string into Go value of type struct { Name string "json:\"name\"" }` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -74,8 +75,7 @@ func TestHandler_CreateDatabase_Conflict(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db`, `{"name": "foo"}`) status, body := MustHTTP("POST", s.URL+`/db`, `{"name": "foo"}`)
if status != http.StatusConflict { if status != http.StatusConflict {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `database exists` {
if body != `database exists` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -88,8 +88,7 @@ func TestHandler_DeleteDatabase(t *testing.T) {
status, body := MustHTTP("DELETE", s.URL+`/db/foo`, "") status, body := MustHTTP("DELETE", s.URL+`/db/foo`, "")
if status != http.StatusNoContent { if status != http.StatusNoContent {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "" {
if body != "" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -101,8 +100,7 @@ func TestHandler_DeleteDatabase_NotFound(t *testing.T) {
status, body := MustHTTP("DELETE", s.URL+`/db/foo`, "") status, body := MustHTTP("DELETE", s.URL+`/db/foo`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `database not found` {
if body != `database not found` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -118,8 +116,7 @@ func TestHandler_Shards(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/shards`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/shards`, "")
if status != http.StatusOK { if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `[{"id":3,"startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z"}]` {
if body != `[{"id":3,"startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z"}]` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -131,8 +128,7 @@ func TestHandler_Shards_DatabaseNotFound(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/shards`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/shards`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `database not found` {
if body != `database not found` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -147,8 +143,7 @@ func TestHandler_RetentionPolicies(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies`, "")
if status != http.StatusOK { if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `[{"name":"bar","replicaN":1,"splitN":1}]` {
if body != `[{"name":"bar","replicaN":1,"splitN":1}]` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -160,8 +155,7 @@ func TestHandler_RetentionPolicies_DatabaseNotFound(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `database not found` {
if body != `database not found` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -175,8 +169,7 @@ func TestHandler_CreateRetentionPolicy(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy) status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy)
if status != http.StatusCreated { if status != http.StatusCreated {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "" {
if body != "" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -189,8 +182,7 @@ func TestHandler_CreateRetentionPolicy_DatabaseNotFound(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy) status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy)
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "database not found" {
if body != "database not found" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -205,8 +197,7 @@ func TestHandler_CreateRetentionPolicy_Conflict(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy) status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy)
if status != http.StatusConflict { if status != http.StatusConflict {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "retention policy exists" {
if body != "retention policy exists" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -220,8 +211,7 @@ func TestHandler_CreateRetentionPolicy_BadRequest(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy) status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy)
if status != http.StatusBadRequest { if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "json: cannot unmarshal string into Go value of type time.Duration" {
if body != "json: cannot unmarshal string into Go value of type time.Duration" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -240,11 +230,9 @@ func TestHandler_UpdateRetentionPolicy(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy) status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy)
if status != http.StatusOK { if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "" {
if body != "" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} } else if policy.Name != "newName" {
if policy.Name != "newName" {
t.Fatalf("unexpected policy name: %s", policy.Name) t.Fatalf("unexpected policy name: %s", policy.Name)
} }
} }
@ -263,8 +251,7 @@ func TestHandler_UpdateRetentionPolicy_BadRequest(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy) status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy)
if status != http.StatusBadRequest { if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "json: cannot unmarshal string into Go value of type time.Duration" {
if body != "json: cannot unmarshal string into Go value of type time.Duration" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -278,8 +265,7 @@ func TestHandler_UpdateRetentionPolicy_DatabaseNotFound(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy) status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy)
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "database not found" {
if body != "database not found" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -294,8 +280,7 @@ func TestHandler_UpdateRetentionPolicy_NotFound(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy) status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy)
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "retention policy not found" {
if body != "retention policy not found" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -310,8 +295,7 @@ func TestHandler_DeleteRetentionPolicy(t *testing.T) {
status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "") status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "")
if status != http.StatusNoContent { if status != http.StatusNoContent {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "" {
if body != "" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -323,8 +307,7 @@ func TestHandler_DeleteRetentionPolicy_DatabaseNotFound(t *testing.T) {
status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "") status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "database not found" {
if body != "database not found" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -337,8 +320,7 @@ func TestHandler_DeleteRetentionPolicy_NotFound(t *testing.T) {
status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "") status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "retention policy not found" {
if body != "retention policy not found" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -355,8 +337,7 @@ func TestHandler_ShardsByRetentionPolicy(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "")
if status != http.StatusOK { if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `[{"id":42,"startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z"}]` {
if body != `[{"id":42,"startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z"}]` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -368,8 +349,7 @@ func TestHandler_ShardsByRetentionPolicy_DatabaseNotFound(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "database not found" {
if body != "database not found" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -382,8 +362,7 @@ func TestHandler_ShardsByRetentionPolicy_PolicyNotFound(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "retention policy not found" {
if body != "retention policy not found" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -408,8 +387,7 @@ func TestHandler_CreateDBUser(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser) status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser)
if status != http.StatusOK { if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "" {
if body != "" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -423,8 +401,7 @@ func TestHandler_CreateDBUser_DatabaseNotFound(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser) status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser)
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != "database not found" {
if body != "database not found" {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -439,8 +416,7 @@ func TestHandler_CreateDBUser_BadRequest(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser) status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser)
if status != http.StatusBadRequest { if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `invalid character 'x' after object key:value pair` {
if body != `invalid character 'x' after object key:value pair` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -455,8 +431,7 @@ func TestHandler_CreateDBUser_InternalServerError(t *testing.T) {
status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser) status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser)
if status != http.StatusInternalServerError { if status != http.StatusInternalServerError {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `username required` {
if body != `username required` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -473,8 +448,7 @@ func TestHandler_DBUser(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/users/jdoe`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/users/jdoe`, "")
if status != http.StatusOK { if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `{"name":"jdoe","password":"","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}` {
if body != `{"name":"jdoe","password":"","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -486,8 +460,7 @@ func TestHandler_DBUser_DatabaseNotFound(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/users/jdoe`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/users/jdoe`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} } else if body != `database not found` {
if body != `database not found` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }
@ -504,8 +477,222 @@ func TestHandler_DBUser_UserNotFound(t *testing.T) {
status, body := MustHTTP("GET", s.URL+`/db/foo/users/jane`, "") status, body := MustHTTP("GET", s.URL+`/db/foo/users/jane`, "")
if status != http.StatusNotFound { if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status) t.Fatalf("unexpected status: %d", status)
} else if body != `user not found` {
t.Fatalf("unexpected body: %s", body)
} }
if body != `user not found` { }
func TestHandler_UpdateDBUser_DatabaseNotFound(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
s := NewHTTPServer(srvr)
defer s.Close()
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, "")
if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status)
} else if body != `database not found` {
t.Fatalf("unexpected body: %s", body)
}
}
func TestHandler_UpdateDBUser_UserNotFound(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
s := NewHTTPServer(srvr)
defer s.Close()
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, "")
if status != http.StatusNotFound {
t.Fatalf("unexpected status: %d", status)
} else if body != `user not found` {
t.Fatalf("unexpected body: %s", body)
}
}
func TestHandler_UpdateDBUser_BadRequest(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
badRequest := `{10: "7331"}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, badRequest)
if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status)
} else if body != `invalid character '1' looking for beginning of object key string` {
t.Fatalf("unexpected body: %s", body)
}
}
func TestHandler_UpdateDBUser_Password(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
origHash := db.User("jdoe").Hash
s := NewHTTPServer(srvr)
defer s.Close()
updatedUser := `{"password": "7331"}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, updatedUser)
newHash := db.User("jdoe").Hash
if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status)
} else if body != `` {
t.Fatalf("unexpected body: %s", body)
} else if (newHash == origHash) {
t.Fatalf("expected password hash to change")
}
}
func TestHandler_UpdateDBUser_PasswordBadRequest(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
updatedUser := `{"password": 10}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, updatedUser)
if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status)
} else if body != `password must be a string` {
t.Fatalf("unexpected body: %s", body)
}
}
func TestHandler_UpdateDBUser_Password_InternalServerError(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
updatedUser := `{"password": ""}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, updatedUser)
if status != http.StatusInternalServerError {
t.Fatalf("unexpected status: %d", status)
} else if body != `Password must be more than 4 and less than 56 characters` {
t.Fatalf("unexpected body: %s", body)
}
}
func TestHandler_UpdateDBUser_ReadFrom(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
updatedUser := `{"readFrom":"[{\"IsRegex\":true,\"Name\":\"changed\"}]"}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, updatedUser)
newReadFrom := db.User("jdoe").ReadFrom[0].Name
if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status)
} else if body != `` {
t.Fatalf("unexpected body: %s", body)
} else if newReadFrom != "changed" {
t.Fatalf("unexpected readFrom: %s", newReadFrom)
}
}
func TestHandler_UpdateDBUser_ReadFrom_BadRequest_Type(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
badRequest := `{"readFrom":10}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, badRequest)
if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status)
} else if body != `readFrom must be a string` {
t.Fatalf("unexpected body: %s", body)
}
}
func TestHandler_UpdateDBUser_ReadFrom_BadRequest_Data(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
badRequest := `{"readFrom":"[{\"IsRegex\":true,\"Name\":10}]"}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, badRequest)
if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status)
} else if body != `json: cannot unmarshal number into Go value of type string` {
t.Fatalf("unexpected body: %s", body)
}
}
func TestHandler_UpdateDBUser_WriteTo(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
updatedUser := `{"writeTo":"[{\"IsRegex\":true,\"Name\":\"changed\"}]"}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, updatedUser)
newWriteTo := db.User("jdoe").WriteTo[0].Name
if status != http.StatusOK {
t.Fatalf("unexpected status: %d", status)
} else if body != `` {
t.Fatalf("unexpected body: %s", body)
} else if newWriteTo != "changed" {
t.Fatalf("unexpected writeTo: %s", newWriteTo)
}
}
func TestHandler_UpdateDBUser_WriteTo_BadRequest_Type(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
badRequest := `{"writeTo":10}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, badRequest)
if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status)
} else if body != `writeTo must be a string` {
t.Fatalf("unexpected body: %s", body)
}
}
func TestHandler_UpdateDBUser_WriteTo_BadRequest_Data(t *testing.T) {
srvr := OpenServer(NewMessagingClient())
srvr.CreateDatabase("foo")
db := srvr.Database("foo")
readFrom := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
writeTo := []*influxdb.Matcher{{IsRegex: true, Name: ".*"}}
db.CreateUser("jdoe", "1337", readFrom, writeTo)
s := NewHTTPServer(srvr)
defer s.Close()
badRequest := `{"writeTo":"[{\"IsRegex\":true,\"Name\":10}]"}`
status, body := MustHTTP("POST", s.URL+`/db/foo/users/jdoe`, badRequest)
if status != http.StatusBadRequest {
t.Fatalf("unexpected status: %d", status)
} else if body != `json: cannot unmarshal number into Go value of type string` {
t.Fatalf("unexpected body: %s", body) t.Fatalf("unexpected body: %s", body)
} }
} }

View File

@ -10,6 +10,7 @@ import (
) )
var userCache = cache.New(0, 0) var userCache = cache.New(0, 0)
var BcryptCost = 10
type Matcher struct { type Matcher struct {
IsRegex bool IsRegex bool
@ -139,14 +140,14 @@ func (p dbUsers) Len() int { return len(p) }
func (p dbUsers) Less(i, j int) bool { return p[i].Name < p[j].Name } func (p dbUsers) Less(i, j int) bool { return p[i].Name < p[j].Name }
func (p dbUsers) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p dbUsers) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func HashPassword(password string) ([]byte, error) { var HashPassword = func(password string) ([]byte, error) {
if length := len(password); length < 4 || length > 56 { if length := len(password); length < 4 || length > 56 {
return nil, fmt.Errorf("Password must be more than 4 and less than 56 characters") return nil, fmt.Errorf("Password must be more than 4 and less than 56 characters")
} }
// The second arg is the cost of the hashing, higher is slower but makes it harder // The second arg is the cost of the hashing, higher is slower but makes it harder
// to brute force, since it will be really slow and impractical // to brute force, since it will be really slow and impractical
return bcrypt.GenerateFromPassword([]byte(password), 10) return bcrypt.GenerateFromPassword([]byte(password), BcryptCost)
} }
// isValidName returns true if the name contains no invalid characters. // isValidName returns true if the name contains no invalid characters.