1817 lines
60 KiB
Go
1817 lines
60 KiB
Go
package influxdb_test
|
|
|
|
import (
|
|
"bytes"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
//"fmt"
|
|
"github.com/influxdb/influxdb"
|
|
)
|
|
|
|
func init() {
|
|
influxdb.BcryptCost = 4
|
|
}
|
|
|
|
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)
|
|
} else 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)
|
|
} else 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)
|
|
} else 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)
|
|
} else 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)
|
|
} else 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)
|
|
} else 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)
|
|
} else if body != `database not found` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_Shards(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
db := srvr.Database("foo")
|
|
db.CreateRetentionPolicy(influxdb.NewRetentionPolicy("bar"))
|
|
db.CreateShardsIfNotExists("bar", time.Time{})
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/shards`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `[{"id":3,"startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z"}]` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
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)
|
|
} else if body != `database not found` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_RetentionPolicies(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
db := srvr.Database("foo")
|
|
db.CreateRetentionPolicy(influxdb.NewRetentionPolicy("bar"))
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `[{"name":"bar","replicaN":1,"splitN":1}]` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
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)
|
|
} else if body != `database not found` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateRetentionPolicy(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
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.StatusCreated {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
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)
|
|
} else if body != "database not found" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateRetentionPolicy_Conflict(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
policy := `{"name": "newName", "duration": 1000000, "replicaN": 1, "splitN": 2}`
|
|
MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy)
|
|
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy)
|
|
if status != http.StatusConflict {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "retention policy exists" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateRetentionPolicy_BadRequest(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
policy := `{"name": "bar", "duration": "**BAD**", "replicaN": 1, "splitN": 2}`
|
|
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies`, policy)
|
|
if status != http.StatusBadRequest {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "json: cannot unmarshal string into Go value of type time.Duration" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_UpdateRetentionPolicy(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": 1000000, "replicaN": 1, "splitN": 2}`
|
|
status, body := MustHTTP("POST", s.URL+`/db/foo/retention_policies/bar`, newPolicy)
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
} else if policy.Name != "newName" {
|
|
t.Fatalf("unexpected policy name: %s", policy.Name)
|
|
}
|
|
}
|
|
|
|
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)
|
|
} else 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)
|
|
} else if body != "database not found" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_UpdateRetentionPolicy_NotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
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)
|
|
} else if body != "retention policy not found" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_DeleteRetentionPolicy(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
db := srvr.Database("foo")
|
|
db.CreateRetentionPolicy(influxdb.NewRetentionPolicy("bar"))
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("DELETE", s.URL+`/db/foo/retention_policies/bar`, "")
|
|
if status != http.StatusNoContent {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
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)
|
|
} else if body != "database not found" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_DeleteRetentionPolicy_NotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
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)
|
|
} else if body != "retention policy not found" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_ShardsByRetentionPolicy(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
db := srvr.Database("foo")
|
|
db.CreateRetentionPolicy(influxdb.NewRetentionPolicy("bar"))
|
|
policy := db.RetentionPolicy("bar")
|
|
policy.Shards = append(policy.Shards, &influxdb.Shard{ID: 42})
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `[{"id":42,"startTime":"0001-01-01T00:00:00Z","endTime":"0001-01-01T00:00:00Z"}]` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_ShardsByRetentionPolicy_DatabaseNotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "")
|
|
if status != http.StatusNotFound {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "database not found" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_ShardsByRetentionPolicy_PolicyNotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/retention_policies/bar/shards`, "")
|
|
if status != http.StatusNotFound {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "retention policy not found" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_Ping(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, _ := MustHTTP("GET", s.URL+`/ping`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
}
|
|
}
|
|
|
|
func TestHandler_Users_NoUsers(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/users`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "[]" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_Users_OneUser(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()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/users`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `[{"name":"jdoe","password":"","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}]` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_Users_MultipleUsers(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)
|
|
db.CreateUser("mclark", "1337", readFrom, writeTo)
|
|
db.CreateUser("csmith", "1337", readFrom, writeTo)
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/users`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `[{"name":"csmith","password":"","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]},{"name":"jdoe","password":"","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]},{"name":"mclark","password":"","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}]` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateDBUser(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
|
|
newUser := `{"name":"jdoe","password":"1337","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}`
|
|
status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser)
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateDBUser_DatabaseNotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
|
|
newUser := `{"name":"jdoe","password":"1337","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}`
|
|
status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser)
|
|
if status != http.StatusNotFound {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != "database not found" {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateDBUser_BadRequest(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
|
|
newUser := `{"name":0xBAD,"password":"1337","isAdmin":true,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}`
|
|
status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser)
|
|
if status != http.StatusBadRequest {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `invalid character 'x' after object key:value pair` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateDBUser_InternalServerError(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
|
|
newUser := `{"name":"","password":"1337","isAdmin":true,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}`
|
|
status, body := MustHTTP("POST", s.URL+`/db/foo/users`, newUser)
|
|
if status != http.StatusInternalServerError {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `username required` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_DBUser(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()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/users/jdoe`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `{"name":"jdoe","password":"","isAdmin":false,"readFrom":[{"IsRegex":true,"Name":".*"}],"writeTo":[{"IsRegex":true,"Name":".*"}]}` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_DBUser_DatabaseNotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", 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_DBUser_UserNotFound(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()
|
|
status, body := MustHTTP("GET", s.URL+`/db/foo/users/jane`, "")
|
|
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_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)
|
|
}
|
|
}
|
|
|
|
func TestHandler_DeleteDBUser(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()
|
|
status, body := MustHTTP("DELETE", s.URL+`/db/foo/users/jdoe`, "")
|
|
if status != http.StatusNoContent {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_DeleteDBUser_DatabaseNotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("DELETE", 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_DeleteDBUser_UserNotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateDatabase("foo")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("DELETE", 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_ClusterAdmins(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateClusterAdmin("jdoe", "1337")
|
|
srvr.CreateClusterAdmin("mclark", "7331")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("GET", s.URL+`/cluster_admins`, "")
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `[{"common":{"name":"jdoe","hash":"","is_deleted":false,"cache_key":""}},{"common":{"name":"mclark","hash":"","is_deleted":false,"cache_key":""}}]` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateClusterAdmin(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
newAdmin := `{"name":"jdoe","password":"1337"}`
|
|
status, body := MustHTTP("POST", s.URL+`/cluster_admins`, newAdmin)
|
|
if status != http.StatusOK {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateClusterAdmin_BadRequest(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
newAdmin := `{BadRequest:"jdoe","password":"1337"}`
|
|
status, body := MustHTTP("POST", s.URL+`/cluster_admins`, newAdmin)
|
|
if status != http.StatusBadRequest {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `invalid character 'B' looking for beginning of object key string` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateClusterAdmin_Conflict(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateClusterAdmin("jdoe", "1337")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
newAdmin := `{"name":"jdoe","password":"1337"}`
|
|
status, body := MustHTTP("POST", s.URL+`/cluster_admins`, newAdmin)
|
|
if status != http.StatusConflict {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `cluster admin exists` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_CreateClusterAdmin_InternalServerError(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
newAdmin := `{"name":"jdoe","password":""}`
|
|
status, body := MustHTTP("POST", s.URL+`/cluster_admins`, newAdmin)
|
|
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_DeleteClusterAdmin(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
srvr.CreateClusterAdmin("jdoe", "1337")
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("DELETE", s.URL+`/cluster_admins/jdoe`, ``)
|
|
if status != http.StatusNoContent {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func TestHandler_DeleteClusterAdmin_NotFound(t *testing.T) {
|
|
srvr := OpenServer(NewMessagingClient())
|
|
s := NewHTTPServer(srvr)
|
|
defer s.Close()
|
|
status, body := MustHTTP("DELETE", s.URL+`/cluster_admins/jdoe`, ``)
|
|
if status != http.StatusNotFound {
|
|
t.Fatalf("unexpected status: %d", status)
|
|
} else if body != `cluster admin not found` {
|
|
t.Fatalf("unexpected body: %s", body)
|
|
}
|
|
}
|
|
|
|
func MustHTTP(verb, url, body string) (int, string) {
|
|
req, err := http.NewRequest(verb, url, bytes.NewBuffer([]byte(body)))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
req.Header.Set("Content-Type", "applicaton/json")
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
status := resp.StatusCode
|
|
respBody, err := ioutil.ReadAll(resp.Body)
|
|
return status, strings.TrimRight(string(respBody), "\n")
|
|
}
|
|
|
|
// Server is a test HTTP server that wraps a handler
|
|
type HTTPServer struct {
|
|
*httptest.Server
|
|
Handler *influxdb.Handler
|
|
}
|
|
|
|
func NewHTTPServer(s *Server) *HTTPServer {
|
|
h := influxdb.NewHandler(s.Server)
|
|
return &HTTPServer{httptest.NewServer(h), h}
|
|
}
|
|
|
|
func (s *HTTPServer) Close() {
|
|
s.Server.Close()
|
|
}
|
|
|
|
/*
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net"
|
|
libhttp "net/http"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/influxdb/influxdb/cluster"
|
|
. "github.com/influxdb/influxdb/common"
|
|
"github.com/influxdb/influxdb/configuration"
|
|
"github.com/influxdb/influxdb/coordinator"
|
|
"github.com/influxdb/influxdb/engine"
|
|
"github.com/influxdb/influxdb/parser"
|
|
"github.com/influxdb/influxdb/protocol"
|
|
. "launchpad.net/gocheck"
|
|
)
|
|
|
|
// Hook up gocheck into the gotest runner.
|
|
func Test(t *testing.T) {
|
|
TestingT(t)
|
|
}
|
|
|
|
type ApiSuite struct {
|
|
listener net.Listener
|
|
server *HttpServer
|
|
coordinator *MockCoordinator
|
|
manager *MockUserManager
|
|
}
|
|
|
|
var _ = Suite(&ApiSuite{})
|
|
|
|
func (self *MockCoordinator) RunQuery(_ User, _ string, query string, yield engine.Processor) error {
|
|
if self.returnedError != nil {
|
|
return self.returnedError
|
|
}
|
|
|
|
series, err := StringToSeriesArray(`
|
|
[
|
|
{
|
|
"points": [
|
|
{
|
|
"values": [
|
|
{ "string_value": "some_value"},{"is_null": true}
|
|
],
|
|
"timestamp": 1381346631000000,
|
|
"sequence_number": 1
|
|
},
|
|
{
|
|
"values": [
|
|
{"string_value": "some_value"},{"int64_value": 2}
|
|
],
|
|
"timestamp": 1381346632000000,
|
|
"sequence_number": 2
|
|
}
|
|
],
|
|
"name": "foo",
|
|
"fields": ["column_one", "column_two"]
|
|
},
|
|
{
|
|
"points": [
|
|
{
|
|
"values": [
|
|
{ "string_value": "some_value"},{"int64_value": 3}
|
|
],
|
|
"timestamp": 1381346633000000,
|
|
"sequence_number": 1
|
|
},
|
|
{
|
|
"values": [
|
|
{"string_value": "some_value"},{"int64_value": 4}
|
|
],
|
|
"timestamp": 1381346634000000,
|
|
"sequence_number": 2
|
|
}
|
|
],
|
|
"name": "foo",
|
|
"fields": ["column_one", "column_two"]
|
|
}
|
|
]
|
|
`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := yield.Yield(series[0]); err != nil {
|
|
return err
|
|
}
|
|
_, err = yield.Yield(series[1])
|
|
return err
|
|
}
|
|
|
|
type MockCoordinator struct {
|
|
coordinator.Coordinator
|
|
series []*protocol.Series
|
|
continuousQueries map[string][]*cluster.ContinuousQuery
|
|
deleteQueries []*parser.DeleteQuery
|
|
db string
|
|
droppedDb string
|
|
returnedError error
|
|
}
|
|
|
|
func (self *MockCoordinator) WriteSeriesData(_ User, db string, series []*protocol.Series) error {
|
|
self.series = append(self.series, series...)
|
|
return nil
|
|
}
|
|
|
|
func (self *MockCoordinator) DeleteSeriesData(_ User, db string, query *parser.DeleteQuery, localOnly bool) error {
|
|
self.deleteQueries = append(self.deleteQueries, query)
|
|
return nil
|
|
}
|
|
|
|
func (self *MockCoordinator) CreateDatabase(_ User, db string) error {
|
|
self.db = db
|
|
return nil
|
|
}
|
|
|
|
func (self *MockCoordinator) ListDatabases(_ User) ([]*cluster.Database, error) {
|
|
return []*cluster.Database{{"db1"}, {"db2"}}, nil
|
|
}
|
|
|
|
func (self *MockCoordinator) DropDatabase(_ User, db string) error {
|
|
self.droppedDb = db
|
|
return nil
|
|
}
|
|
|
|
func (self *MockCoordinator) ListContinuousQueries(_ User, db string) ([]*protocol.Series, error) {
|
|
points := []*protocol.Point{}
|
|
|
|
for _, query := range self.continuousQueries[db] {
|
|
queryId := int64(query.Id)
|
|
queryString := query.Query
|
|
points = append(points, &protocol.Point{
|
|
Values: []*protocol.FieldValue{
|
|
{Int64Value: &queryId},
|
|
{StringValue: &queryString},
|
|
},
|
|
Timestamp: nil,
|
|
SequenceNumber: nil,
|
|
})
|
|
}
|
|
|
|
seriesName := "continuous queries"
|
|
series := []*protocol.Series{{
|
|
Name: &seriesName,
|
|
Fields: []string{"id", "query"},
|
|
Points: points,
|
|
}}
|
|
return series, nil
|
|
}
|
|
|
|
func (self *MockCoordinator) CreateContinuousQuery(_ User, db string, query string) error {
|
|
self.continuousQueries[db] = append(self.continuousQueries[db], &cluster.ContinuousQuery{2, query})
|
|
return nil
|
|
}
|
|
|
|
func (self *MockCoordinator) DeleteContinuousQuery(_ User, db string, id uint32) error {
|
|
length := len(self.continuousQueries[db])
|
|
_, self.continuousQueries[db] = self.continuousQueries[db][length-1], self.continuousQueries[db][:length-1]
|
|
return nil
|
|
}
|
|
|
|
func (self *ApiSuite) formatUrl(path string, args ...interface{}) string {
|
|
path = fmt.Sprintf(path, args...)
|
|
port := self.listener.Addr().(*net.TCPAddr).Port
|
|
return fmt.Sprintf("http://localhost:%d%s", port, path)
|
|
}
|
|
|
|
func (self *ApiSuite) SetUpSuite(c *C) {
|
|
self.coordinator = &MockCoordinator{
|
|
continuousQueries: map[string][]*cluster.ContinuousQuery{
|
|
"db1": {
|
|
{1, "select * from foo into bar;"},
|
|
},
|
|
},
|
|
}
|
|
|
|
self.manager = &MockUserManager{
|
|
clusterAdmins: []string{"root"},
|
|
dbUsers: map[string]map[string]MockDbUser{"db1": {"db_user1": {Name: "db_user1", IsAdmin: false}}},
|
|
}
|
|
config := &configuration.Configuration{
|
|
ApiReadTimeout: 10 * time.Second,
|
|
}
|
|
self.server = NewHttpServer(
|
|
config,
|
|
self.coordinator,
|
|
self.manager,
|
|
cluster.NewClusterConfiguration(config, nil, nil, nil, nil),
|
|
nil)
|
|
var err error
|
|
self.listener, err = net.Listen("tcp4", ":8081")
|
|
c.Assert(err, IsNil)
|
|
go func() {
|
|
self.server.Serve(self.listener)
|
|
}()
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
|
|
func (self *ApiSuite) TearDownSuite(c *C) {
|
|
self.server.Close()
|
|
}
|
|
|
|
func (self *ApiSuite) SetUpTest(c *C) {
|
|
self.coordinator.series = nil
|
|
self.coordinator.returnedError = nil
|
|
self.manager.ops = nil
|
|
}
|
|
|
|
func (self *ApiSuite) TestHealthCheck(c *C) {
|
|
url := self.formatUrl("/ping")
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
resp.Body.Close()
|
|
}
|
|
|
|
func (self *ApiSuite) TestClusterAdminAuthentication(c *C) {
|
|
url := self.formatUrl("/cluster_admins/authenticate?u=root&p=root")
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
resp.Body.Close()
|
|
|
|
url = self.formatUrl("/cluster_admins/authenticate?u=fail_auth&p=anypass")
|
|
resp, err = libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusUnauthorized)
|
|
c.Assert(resp.Header.Get("WWW-Authenticate"), Equals, "Basic realm=\"influxdb\"")
|
|
resp.Body.Close()
|
|
}
|
|
|
|
func (self *ApiSuite) TestDbUserAuthentication(c *C) {
|
|
url := self.formatUrl("/db/foo/authenticate?u=dbuser&p=password")
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
resp.Body.Close()
|
|
|
|
url = self.formatUrl("/db/foo/authenticate?u=fail_auth&p=anypass")
|
|
resp, err = libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusUnauthorized)
|
|
c.Assert(resp.Header.Get("WWW-Authenticate"), Equals, "Basic realm=\"influxdb\"")
|
|
resp.Body.Close()
|
|
}
|
|
|
|
func (self *ApiSuite) TestDbUserBasicAuthentication(c *C) {
|
|
url := self.formatUrl("/db/foo/authenticate")
|
|
req, err := libhttp.NewRequest("GET", url, nil)
|
|
auth := base64.StdEncoding.EncodeToString([]byte("dbuser:password"))
|
|
req.Header.Add("Authorization", "Basic "+auth)
|
|
c.Assert(err, IsNil)
|
|
resp, err := libhttp.DefaultClient.Do(req)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
resp.Body.Close()
|
|
}
|
|
|
|
func (self *ApiSuite) TestQueryAsClusterAdmin(c *C) {
|
|
query := "select * from foo;"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&u=root&p=root", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
}
|
|
|
|
func (self *ApiSuite) TestQueryWithNullColumns(c *C) {
|
|
query := "select * from foo;"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&time_precision=s&u=dbuser&p=password", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
series := []SerializedSeries{}
|
|
err = json.Unmarshal(data, &series)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(series, HasLen, 1)
|
|
c.Assert(series[0].Name, Equals, "foo")
|
|
// time, seq, column_one, column_two
|
|
c.Assert(series[0].Columns, HasLen, 4)
|
|
c.Assert(series[0].Points, HasLen, 4)
|
|
c.Assert(int(series[0].Points[0][0].(float64)), Equals, 1381346631)
|
|
c.Assert(series[0].Points[0][3], Equals, nil)
|
|
}
|
|
|
|
func (self *ApiSuite) TestQueryErrorPropagatesProperly(c *C) {
|
|
self.coordinator.returnedError = fmt.Errorf("some error")
|
|
query := "select * from does_not_exist;"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&time_precision=s&u=dbuser&p=password", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusBadRequest)
|
|
}
|
|
|
|
func (self *ApiSuite) TestUnauthorizedErrorWithCompression(c *C) {
|
|
addr := self.formatUrl("/cluster_admins/authenticate?u=fail_auth&p=invalidpassword")
|
|
req, err := libhttp.NewRequest("GET", addr, nil)
|
|
c.Assert(err, IsNil)
|
|
req.Header.Set("Accept-Encoding", "gzip")
|
|
resp, err := libhttp.DefaultClient.Do(req)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusUnauthorized)
|
|
c.Assert(resp.Header.Get("Content-Type"), Equals, "text/plain")
|
|
c.Assert(resp.Header.Get("Content-Encoding"), Equals, "gzip")
|
|
}
|
|
|
|
func (self *ApiSuite) TestQueryWithSecondsPrecision(c *C) {
|
|
query := "select * from foo where column_one == 'some_value';"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&time_precision=s&u=dbuser&p=password", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
series := []SerializedSeries{}
|
|
err = json.Unmarshal(data, &series)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(series, HasLen, 1)
|
|
c.Assert(series[0].Name, Equals, "foo")
|
|
// time, seq, column_one, column_two
|
|
c.Assert(series[0].Columns, HasLen, 4)
|
|
c.Assert(series[0].Points, HasLen, 4)
|
|
c.Assert(int(series[0].Points[0][0].(float64)), Equals, 1381346631)
|
|
}
|
|
|
|
func (self *ApiSuite) TestQueryWithInvalidPrecision(c *C) {
|
|
query := "select * from foo where column_one == 'some_value';"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&time_precision=foo&u=dbuser&p=password", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusBadRequest)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "text/plain")
|
|
}
|
|
|
|
func (self *ApiSuite) TestNotChunkedQuery(c *C) {
|
|
query := "select * from foo where column_one == 'some_value';"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&u=dbuser&p=password", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
series := []SerializedSeries{}
|
|
err = json.Unmarshal(data, &series)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(series, HasLen, 1)
|
|
c.Assert(series[0].Name, Equals, "foo")
|
|
// time, seq, column_one, column_two
|
|
c.Assert(series[0].Columns, HasLen, 4)
|
|
c.Assert(series[0].Points, HasLen, 4)
|
|
// timestamp precision is milliseconds by default
|
|
c.Assert(int64(series[0].Points[0][0].(float64)), Equals, int64(1381346631000))
|
|
}
|
|
|
|
func (self *ApiSuite) TestNotChunkedPrettyQuery(c *C) {
|
|
query := "select * from foo where column_one == 'some_value';"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&u=dbuser&p=password&pretty=true", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
series := []SerializedSeries{}
|
|
err = json.Unmarshal(data, &series)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(series, HasLen, 1)
|
|
c.Assert(series[0].Name, Equals, "foo")
|
|
// time, seq, column_one, column_two
|
|
c.Assert(series[0].Columns, HasLen, 4)
|
|
c.Assert(series[0].Points, HasLen, 4)
|
|
// timestamp precision is milliseconds by default
|
|
c.Assert(int64(series[0].Points[0][0].(float64)), Equals, int64(1381346631000))
|
|
}
|
|
|
|
func (self *ApiSuite) TestNotChunkedNotPrettyQuery(c *C) {
|
|
query := "select * from foo where column_one == 'some_value';"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&u=dbuser&p=password&pretty=false", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
series := []SerializedSeries{}
|
|
err = json.Unmarshal(data, &series)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(series, HasLen, 1)
|
|
c.Assert(series[0].Name, Equals, "foo")
|
|
// time, seq, column_one, column_two
|
|
c.Assert(series[0].Columns, HasLen, 4)
|
|
c.Assert(series[0].Points, HasLen, 4)
|
|
// timestamp precision is milliseconds by default
|
|
c.Assert(int64(series[0].Points[0][0].(float64)), Equals, int64(1381346631000))
|
|
}
|
|
|
|
func (self *ApiSuite) TestChunkedQuery(c *C) {
|
|
query := "select * from foo where column_one == 'some_value';"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&chunked=true&u=dbuser&p=password", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
|
|
for i := 0; i < 2; i++ {
|
|
chunk := make([]byte, 2048, 2048)
|
|
n, err := resp.Body.Read(chunk)
|
|
|
|
series := SerializedSeries{}
|
|
err = json.Unmarshal(chunk[0:n], &series)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(series.Name, Equals, "foo")
|
|
// time, seq, column_one, column_two
|
|
c.Assert(series.Columns, HasLen, 4)
|
|
// each chunk should have 2 points
|
|
c.Assert(series.Points, HasLen, 2)
|
|
}
|
|
}
|
|
|
|
func (self *ApiSuite) TestPrettyChunkedQuery(c *C) {
|
|
query := "select * from foo where column_one == 'some_value';"
|
|
query = url.QueryEscape(query)
|
|
addr := self.formatUrl("/db/foo/series?q=%s&chunked=true&u=dbuser&p=password&pretty=true", query)
|
|
resp, err := libhttp.Get(addr)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
|
|
for i := 0; i < 2; i++ {
|
|
chunk := make([]byte, 2048, 2048)
|
|
n, err := resp.Body.Read(chunk)
|
|
|
|
series := SerializedSeries{}
|
|
err = json.Unmarshal(chunk[0:n], &series)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(series.Name, Equals, "foo")
|
|
// time, seq, column_one, column_two
|
|
c.Assert(series.Columns, HasLen, 4)
|
|
// each chunk should have 2 points
|
|
c.Assert(series.Points, HasLen, 2)
|
|
}
|
|
}
|
|
|
|
func (self *ApiSuite) TestWriteDataWithTimeInSeconds(c *C) {
|
|
data := `
|
|
[
|
|
{
|
|
"points": [
|
|
[1382131686, "1"]
|
|
],
|
|
"name": "foo",
|
|
"columns": ["time", "column_one"]
|
|
}
|
|
]
|
|
`
|
|
|
|
addr := self.formatUrl("/db/foo/series?time_precision=s&u=dbuser&p=password")
|
|
resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.coordinator.series, HasLen, 1)
|
|
series := self.coordinator.series[0]
|
|
|
|
// check the types
|
|
c.Assert(series.Fields, HasLen, 1)
|
|
c.Assert(series.Fields[0], Equals, "column_one")
|
|
|
|
// check the values
|
|
c.Assert(series.Points, HasLen, 1)
|
|
c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
|
|
c.Assert(*series.Points[0].GetTimestampInMicroseconds(), Equals, int64(1382131686000000))
|
|
}
|
|
|
|
func (self *ApiSuite) TestWriteDataWithTime(c *C) {
|
|
data := `
|
|
[
|
|
{
|
|
"points": [
|
|
[1382131686000, "1"]
|
|
],
|
|
"name": "foo",
|
|
"columns": ["time", "column_one"]
|
|
}
|
|
]
|
|
`
|
|
|
|
addr := self.formatUrl("/db/foo/series?u=dbuser&p=password")
|
|
resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.coordinator.series, HasLen, 1)
|
|
series := self.coordinator.series[0]
|
|
|
|
// check the types
|
|
c.Assert(series.Fields, HasLen, 1)
|
|
c.Assert(series.Fields[0], Equals, "column_one")
|
|
|
|
// check the values
|
|
c.Assert(series.Points, HasLen, 1)
|
|
c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
|
|
c.Assert(*series.Points[0].GetTimestampInMicroseconds(), Equals, int64(1382131686000000))
|
|
}
|
|
|
|
func (self *ApiSuite) TestWriteDataWithInvalidTime(c *C) {
|
|
data := `
|
|
[
|
|
{
|
|
"points": [
|
|
["foo", "1"]
|
|
],
|
|
"name": "foo",
|
|
"columns": ["time", "column_one"]
|
|
}
|
|
]
|
|
`
|
|
|
|
addr := self.formatUrl("/db/foo/series?u=dbuser&p=password")
|
|
resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusBadRequest)
|
|
}
|
|
|
|
func (self *ApiSuite) TestWriteDataWithNull(c *C) {
|
|
data := `
|
|
[
|
|
{
|
|
"points": [
|
|
["1", 1, 1.0, true],
|
|
["2", 2, 2.0, false],
|
|
["3", 3, 3.0, null]
|
|
],
|
|
"name": "foo",
|
|
"columns": ["column_one", "column_two", "column_three", "column_four"]
|
|
}
|
|
]
|
|
`
|
|
|
|
addr := self.formatUrl("/db/foo/series?u=dbuser&p=password")
|
|
resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.coordinator.series, HasLen, 1)
|
|
series := self.coordinator.series[0]
|
|
c.Assert(series.Fields, HasLen, 4)
|
|
|
|
// check the types
|
|
c.Assert(series.Fields[0], Equals, "column_one")
|
|
c.Assert(series.Fields[1], Equals, "column_two")
|
|
c.Assert(series.Fields[2], Equals, "column_three")
|
|
c.Assert(series.Fields[3], Equals, "column_four")
|
|
|
|
// check the values
|
|
c.Assert(series.Points, HasLen, 3)
|
|
c.Assert(*series.Points[2].Values[0].StringValue, Equals, "3")
|
|
c.Assert(*series.Points[2].Values[1].Int64Value, Equals, int64(3))
|
|
c.Assert(*series.Points[2].Values[2].DoubleValue, Equals, 3.0)
|
|
c.Assert(series.Points[2].Values[3].GetIsNull(), Equals, true)
|
|
}
|
|
|
|
func (self *ApiSuite) TestWriteData(c *C) {
|
|
data := `
|
|
[
|
|
{
|
|
"points": [
|
|
["1", 1, 1.0, true],
|
|
["2", 2, 2.0, false],
|
|
["3", 3, 3.0, true]
|
|
],
|
|
"name": "foo",
|
|
"columns": ["column_one", "column_two", "column_three", "column_four"]
|
|
}
|
|
]
|
|
`
|
|
|
|
addr := self.formatUrl("/db/foo/series?u=dbuser&p=password")
|
|
resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.coordinator.series, HasLen, 1)
|
|
series := self.coordinator.series[0]
|
|
c.Assert(series.Fields, HasLen, 4)
|
|
|
|
// check the types
|
|
c.Assert(series.Fields[0], Equals, "column_one")
|
|
c.Assert(series.Fields[1], Equals, "column_two")
|
|
c.Assert(series.Fields[2], Equals, "column_three")
|
|
c.Assert(series.Fields[3], Equals, "column_four")
|
|
|
|
// check the values
|
|
c.Assert(series.Points, HasLen, 3)
|
|
c.Assert(*series.Points[0].Values[0].StringValue, Equals, "1")
|
|
c.Assert(*series.Points[0].Values[1].Int64Value, Equals, int64(1))
|
|
c.Assert(*series.Points[0].Values[2].DoubleValue, Equals, 1.0)
|
|
c.Assert(*series.Points[0].Values[3].BoolValue, Equals, true)
|
|
}
|
|
|
|
func (self *ApiSuite) TestWriteDataAsClusterAdmin(c *C) {
|
|
data := `
|
|
[
|
|
{
|
|
"points": [
|
|
["1", true]
|
|
],
|
|
"name": "foo",
|
|
"columns": ["column_one", "column_two"]
|
|
}
|
|
]
|
|
`
|
|
|
|
addr := self.formatUrl("/db/foo/series?u=root&p=root")
|
|
resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
}
|
|
|
|
func (self *ApiSuite) TestCreateDatabase(c *C) {
|
|
data := `{"name": "foo", "apiKey": "bar"}`
|
|
addr := self.formatUrl("/db?api_key=asdf&u=root&p=root")
|
|
resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(data))
|
|
c.Assert(err, IsNil)
|
|
_, err = ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusCreated)
|
|
c.Assert(self.coordinator.db, Equals, "foo")
|
|
}
|
|
|
|
func (self *ApiSuite) TestCreateDatabaseNameFailures(c *C) {
|
|
data := map[string]string{
|
|
`{"name": ""}`: "Unable to create database without name",
|
|
`{}`: "Unable to create database without name",
|
|
`{"not_name": "bar"}`: "Unable to create database without name",
|
|
`{"name": " "}`: "Unable to create database without name"}
|
|
for k, v := range data {
|
|
addr := self.formatUrl("/db?u=root&p=root")
|
|
resp, err := libhttp.Post(addr, "application/json", bytes.NewBufferString(k))
|
|
c.Assert(err, IsNil)
|
|
m, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(v, Equals, string(m))
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusBadRequest)
|
|
}
|
|
}
|
|
|
|
func (self *ApiSuite) TestDropDatabase(c *C) {
|
|
addr := self.formatUrl("/db/foo?u=root&p=root")
|
|
req, err := libhttp.NewRequest("DELETE", addr, nil)
|
|
c.Assert(err, IsNil)
|
|
resp, err := libhttp.DefaultClient.Do(req)
|
|
c.Assert(err, IsNil)
|
|
_, err = ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusNoContent)
|
|
c.Assert(self.coordinator.droppedDb, Equals, "foo")
|
|
}
|
|
|
|
func (self *ApiSuite) TestClusterAdminOperations(c *C) {
|
|
url := self.formatUrl("/cluster_admins?u=root&p=root")
|
|
resp, err := libhttp.Post(url, "", bytes.NewBufferString(`{"name":"", "password": "new_pass"}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusBadRequest)
|
|
|
|
url = self.formatUrl("/cluster_admins?u=root&p=root")
|
|
resp, err = libhttp.Post(url, "", bytes.NewBufferString(`{"name":"new_user", "password": "new_pass"}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "cluster_admin_add")
|
|
c.Assert(self.manager.ops[0].username, Equals, "new_user")
|
|
c.Assert(self.manager.ops[0].password, Equals, "new_pass")
|
|
self.manager.ops = nil
|
|
|
|
url = self.formatUrl("/cluster_admins/new_user?u=root&p=root")
|
|
resp, err = libhttp.Post(url, "", bytes.NewBufferString(`{"password":"new_password"}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "cluster_admin_passwd")
|
|
c.Assert(self.manager.ops[0].username, Equals, "new_user")
|
|
c.Assert(self.manager.ops[0].password, Equals, "new_password")
|
|
self.manager.ops = nil
|
|
|
|
req, _ := libhttp.NewRequest("DELETE", url, nil)
|
|
resp, err = libhttp.DefaultClient.Do(req)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "cluster_admin_del")
|
|
c.Assert(self.manager.ops[0].username, Equals, "new_user")
|
|
}
|
|
|
|
func (self *ApiSuite) TestDbUserOperations(c *C) {
|
|
// create user using the `name` field
|
|
url := self.formatUrl("/db/db1/users?u=root&p=root")
|
|
resp, err := libhttp.Post(url, "", bytes.NewBufferString(`{"name":"dbuser", "password": "password"}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "db_user_add")
|
|
c.Assert(self.manager.ops[0].username, Equals, "dbuser")
|
|
c.Assert(self.manager.ops[0].password, Equals, "password")
|
|
self.manager.ops = nil
|
|
|
|
url = self.formatUrl("/db/db1/users/dbuser?u=root&p=root")
|
|
resp, err = libhttp.Post(url, "", bytes.NewBufferString(`{"password":"new_password"}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "db_user_passwd")
|
|
c.Assert(self.manager.ops[0].username, Equals, "dbuser")
|
|
c.Assert(self.manager.ops[0].password, Equals, "new_password")
|
|
self.manager.ops = nil
|
|
|
|
// empty usernames aren't valid
|
|
url = self.formatUrl("/db/db1/users?u=root&p=root")
|
|
resp, err = libhttp.Post(url, "", bytes.NewBufferString(`{"name":"", "password": "password"}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusBadRequest)
|
|
|
|
// Fix #477 - Username should support @ character - https://github.com/influxdb/influxdb/issues/447
|
|
url = self.formatUrl("/db/db1/users?u=root&p=root")
|
|
resp, err = libhttp.Post(url, "", bytes.NewBufferString(`{"name":"paul@influxdb.com", "password": "password"}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "db_user_add")
|
|
c.Assert(self.manager.ops[0].username, Equals, "paul@influxdb.com")
|
|
c.Assert(self.manager.ops[0].password, Equals, "password")
|
|
self.manager.ops = nil
|
|
|
|
// set and unset the db admin flag
|
|
url = self.formatUrl("/db/db1/users/dbuser?u=root&p=root")
|
|
resp, err = libhttp.Post(url, "", bytes.NewBufferString(`{"admin": true}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "db_user_admin")
|
|
c.Assert(self.manager.ops[0].username, Equals, "dbuser")
|
|
c.Assert(self.manager.ops[0].isAdmin, Equals, true)
|
|
self.manager.ops = nil
|
|
url = self.formatUrl("/db/db1/users/dbuser?u=root&p=root")
|
|
resp, err = libhttp.Post(url, "", bytes.NewBufferString(`{"admin": false}`))
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "db_user_admin")
|
|
c.Assert(self.manager.ops[0].username, Equals, "dbuser")
|
|
c.Assert(self.manager.ops[0].isAdmin, Equals, false)
|
|
self.manager.ops = nil
|
|
|
|
url = self.formatUrl("/db/db1/users/dbuser?u=root&p=root")
|
|
req, _ := libhttp.NewRequest("DELETE", url, nil)
|
|
resp, err = libhttp.DefaultClient.Do(req)
|
|
c.Assert(err, IsNil)
|
|
defer resp.Body.Close()
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
c.Assert(self.manager.ops, HasLen, 1)
|
|
c.Assert(self.manager.ops[0].operation, Equals, "db_user_del")
|
|
c.Assert(self.manager.ops[0].username, Equals, "dbuser")
|
|
}
|
|
|
|
func (self *ApiSuite) TestClusterAdminsIndex(c *C) {
|
|
url := self.formatUrl("/cluster_admins?u=root&p=root")
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
users := []*ApiUser{}
|
|
err = json.Unmarshal(body, &users)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(users, DeepEquals, []*ApiUser{{"root"}})
|
|
}
|
|
|
|
func (self *ApiSuite) TestPrettyClusterAdminsIndex(c *C) {
|
|
url := self.formatUrl("/cluster_admins?u=root&p=root&pretty=true")
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
users := []*ApiUser{}
|
|
err = json.Unmarshal(body, &users)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(users, DeepEquals, []*ApiUser{{"root"}})
|
|
}
|
|
|
|
func (self *ApiSuite) TestDbUsersIndex(c *C) {
|
|
url := self.formatUrl("/db/db1/users?u=root&p=root")
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
users := []*UserDetail{}
|
|
err = json.Unmarshal(body, &users)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(users, HasLen, 1)
|
|
c.Assert(users[0], DeepEquals, &UserDetail{"db_user1", false, ".*", ".*"})
|
|
}
|
|
|
|
func (self *ApiSuite) TestPrettyDbUsersIndex(c *C) {
|
|
url := self.formatUrl("/db/db1/users?u=root&p=root&pretty=true")
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
users := []*UserDetail{}
|
|
err = json.Unmarshal(body, &users)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(users, HasLen, 1)
|
|
c.Assert(users[0], DeepEquals, &UserDetail{"db_user1", false, ".*", ".*"})
|
|
}
|
|
|
|
func (self *ApiSuite) TestDbUserShow(c *C) {
|
|
url := self.formatUrl("/db/db1/users/db_user1?u=root&p=root")
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
userDetail := &UserDetail{}
|
|
err = json.Unmarshal(body, &userDetail)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(userDetail, DeepEquals, &UserDetail{"db_user1", false, ".*", ".*"})
|
|
}
|
|
|
|
func (self *ApiSuite) TestDatabasesIndex(c *C) {
|
|
for _, path := range []string{"/db?u=root&p=root", "/db?u=root&p=root"} {
|
|
url := self.formatUrl(path)
|
|
resp, err := libhttp.Get(url)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.Header.Get("content-type"), Equals, "application/json")
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
databases := []*cluster.Database{}
|
|
err = json.Unmarshal(body, &databases)
|
|
c.Assert(err, IsNil)
|
|
err = json.Unmarshal(body, &databases)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(databases, DeepEquals, []*cluster.Database{{"db1"}, {"db2"}})
|
|
}
|
|
}
|
|
|
|
func (self *ApiSuite) TestBasicAuthentication(c *C) {
|
|
url := self.formatUrl("/db")
|
|
req, err := libhttp.NewRequest("GET", url, nil)
|
|
c.Assert(err, IsNil)
|
|
auth := base64.StdEncoding.EncodeToString([]byte("root:root"))
|
|
req.Header.Add("Authorization", "Basic "+auth)
|
|
resp, err := libhttp.DefaultClient.Do(req)
|
|
defer resp.Body.Close()
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(resp.StatusCode, Equals, libhttp.StatusOK)
|
|
databases := []*cluster.Database{}
|
|
c.Assert(err, IsNil)
|
|
err = json.Unmarshal(body, &databases)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(databases, DeepEquals, []*cluster.Database{{"db1"}, {"db2"}})
|
|
}
|
|
*/
|