diff --git a/handler.go b/handler.go index 5e7502de8c..da2c835772 100644 --- a/handler.go +++ b/handler.go @@ -205,13 +205,16 @@ func (h *Handler) serveCreateDatabase(w http.ResponseWriter, r *http.Request) { var req struct { Name string `json:"name"` } - // TODO: Authentication // Decode the request from the body. - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { h.error(w, err.Error(), http.StatusBadRequest) return + } else if req.Name == "" { + h.error(w, ErrDatabaseNameRequired.Error(), http.StatusBadRequest) + return } // Create the database. @@ -228,8 +231,8 @@ func (h *Handler) serveCreateDatabase(w http.ResponseWriter, r *http.Request) { // serveDeleteDatabase deletes an existing database on the server. func (h *Handler) serveDeleteDatabase(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get(":name") - if err := h.server.DeleteDatabase(name); err != ErrDatabaseNotFound { - h.error(w, err.Error(), http.StatusNotFound) + if err := h.server.DeleteDatabase(name); err == ErrDatabaseNotFound { + h.error(w, ErrDatabaseNotFound.Error(), http.StatusNotFound) return } else if err != nil { h.error(w, err.Error(), http.StatusInternalServerError) @@ -421,6 +424,8 @@ func (h *Handler) serveDeleteRetentionPolicy(w http.ResponseWriter, r *http.Requ h.error(w, err.Error(), http.StatusInternalServerError) return } + + w.WriteHeader(http.StatusNoContent) } // serveServers returns a list of servers in the cluster. diff --git a/handler_test.go b/handler_test.go index 82bba087e0..59eb75073a 100644 --- a/handler_test.go +++ b/handler_test.go @@ -12,6 +12,101 @@ import ( "github.com/influxdb/influxdb" ) +func TestHandler_Databases(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + srvr.CreateDatabase("foo") + srvr.CreateDatabase("bar") + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("GET", s.URL+`/db`, "") + if status != http.StatusOK { + t.Fatalf("unexpected status: %d", status) + } + if body != `[{"name":"bar"},{"name":"foo"}]` { + t.Fatalf("unexpected body: %s", body) + } +} + +func TestHandler_CreateDatabase(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("POST", s.URL+`/db`, `{"name": "foo"}`) + if status != http.StatusCreated { + t.Fatalf("unexpected status: %d", status) + } + if body != `` { + t.Fatalf("unexpected body: %s", body) + } +} + +func TestHandler_CreateDatabase_BadRequest_NoName(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("POST", s.URL+`/db`, `{"BadRequest": 1}`) + if status != http.StatusBadRequest { + t.Fatalf("unexpected status: %d", status) + } + if body != `database name required` { + t.Fatalf("unexpected body: %s", body) + } +} + +func TestHandler_CreateDatabase_BadRequest_InvalidJSON(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("POST", s.URL+`/db`, `"BadRequest": 1`) + if status != http.StatusBadRequest { + t.Fatalf("unexpected status: %d", status) + } + if body != `json: cannot unmarshal string into Go value of type struct { Name string "json:\"name\"" }` { + t.Fatalf("unexpected body: %s", body) + } +} + +func TestHandler_CreateDatabase_Conflict(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + srvr.CreateDatabase("foo") + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("POST", s.URL+`/db`, `{"name": "foo"}`) + if status != http.StatusConflict { + t.Fatalf("unexpected status: %d", status) + } + if body != `database exists` { + t.Fatalf("unexpected body: %s", body) + } +} + +func TestHandler_DeleteDatabase(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + srvr.CreateDatabase("foo") + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("DELETE", s.URL+`/db/foo`, "") + if status != http.StatusNoContent { + t.Fatalf("unexpected status: %d", status) + } + if body != "" { + t.Fatalf("unexpected body: %s", body) + } +} + +func TestHandler_DeleteDatabase_NotFound(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("DELETE", s.URL+`/db/foo`, "") + if status != http.StatusNotFound { + t.Fatalf("unexpected status: %d", status) + } + if body != `database not found` { + t.Fatalf("unexpected body: %s", body) + } +} + func TestHandler_Shards(t *testing.T) { srvr := OpenServer(NewMessagingClient()) srvr.CreateDatabase("foo") @@ -29,6 +124,19 @@ func TestHandler_Shards(t *testing.T) { } } +func TestHandler_Shards_DatabaseNotFound(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("GET", s.URL+`/db/foo/shards`, "") + if status != http.StatusNotFound { + t.Fatalf("unexpected status: %d", status) + } + if body != `database not found` { + t.Fatalf("unexpected body: %s", body) + } +} + func TestHandler_RetentionPolicies(t *testing.T) { srvr := OpenServer(NewMessagingClient()) srvr.CreateDatabase("foo") @@ -45,6 +153,19 @@ func TestHandler_RetentionPolicies(t *testing.T) { } } +func TestHandler_RetentionPolicies_DatabaseNotFound(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies`, "") + if status != http.StatusNotFound { + t.Fatalf("unexpected status: %d", status) + } + if body != `database not found` { + t.Fatalf("unexpected body: %s", body) + } +} + func TestHandler_CreateRetentionPolicy(t *testing.T) { srvr := OpenServer(NewMessagingClient()) srvr.CreateDatabase("foo") @@ -60,6 +181,20 @@ func TestHandler_CreateRetentionPolicy(t *testing.T) { } } +func TestHandler_CreateRetentionPolicy_DatabaseNotFound(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + policy := `{"name": "bar", "duration": 1000000, "replicaN": 1, "splitN": 2}` + status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy) + if status != http.StatusNotFound { + t.Fatalf("unexpected status: %d", status) + } + if body != "database not found" { + t.Fatalf("unexpected body: %s", body) + } +} + func TestHandler_CreateRetentionPolicy_Conflict(t *testing.T) { srvr := OpenServer(NewMessagingClient()) srvr.CreateDatabase("foo") @@ -114,6 +249,41 @@ func TestHandler_UpdateRetentionPolicy(t *testing.T) { } } +func TestHandler_UpdateRetentionPolicy_BadRequest(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + srvr.CreateDatabase("foo") + db := srvr.Database("foo") + policy := influxdb.NewRetentionPolicy("bar") + db.CreateRetentionPolicy(policy) + policy = db.RetentionPolicy("bar") + s := NewHTTPServer(srvr) + defer s.Close() + + newPolicy := `{"name": "newName", "duration": "BadRequest", "replicaN": 1, "splitN": 2}` + status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy) + if status != http.StatusBadRequest { + t.Fatalf("unexpected status: %d", status) + } + if body != "json: cannot unmarshal string into Go value of type time.Duration" { + t.Fatalf("unexpected body: %s", body) + } +} + +func TestHandler_UpdateRetentionPolicy_DatabaseNotFound(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + + newPolicy := `{"name": "newName", "duration": 1000000, "replicaN": 1, "splitN": 2}` + status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy) + if status != http.StatusNotFound { + t.Fatalf("unexpected status: %d", status) + } + if body != "database not found" { + t.Fatalf("unexpected body: %s", body) + } +} + func TestHandler_UpdateRetentionPolicy_NotFound(t *testing.T) { srvr := OpenServer(NewMessagingClient()) srvr.CreateDatabase("foo") @@ -138,7 +308,7 @@ func TestHandler_DeleteRetentionPolicy(t *testing.T) { s := NewHTTPServer(srvr) defer s.Close() status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "") - if status != http.StatusOK { + if status != http.StatusNoContent { t.Fatalf("unexpected status: %d", status) } if body != "" { @@ -146,6 +316,19 @@ func TestHandler_DeleteRetentionPolicy(t *testing.T) { } } +func TestHandler_DeleteRetentionPolicy_DatabaseNotFound(t *testing.T) { + srvr := OpenServer(NewMessagingClient()) + s := NewHTTPServer(srvr) + defer s.Close() + status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "") + if status != http.StatusNotFound { + t.Fatalf("unexpected status: %d", status) + } + if body != "database not found" { + t.Fatalf("unexpected body: %s", body) + } +} + func TestHandler_DeleteRetentionPolicy_NotFound(t *testing.T) { srvr := OpenServer(NewMessagingClient()) srvr.CreateDatabase("foo") diff --git a/influxdb.go b/influxdb.go index c7a77849a9..6a7cea6f56 100644 --- a/influxdb.go +++ b/influxdb.go @@ -14,6 +14,9 @@ var ( // ErrPathRequired is returned when opening a server without a path. ErrPathRequired = errors.New("path required") + // ErrDatabaseNameRequired is returned when creating a database without a name. + ErrDatabaseNameRequired = errors.New("database name required") + // ErrDatabaseExists is returned when creating a duplicate database. ErrDatabaseExists = errors.New("database exists")