package influxdb_test import ( "bytes" "io/ioutil" "net/http" "net/http/httptest" "strings" "testing" "time" //"fmt" "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") db := srvr.Database("foo") rp := influxdb.NewRetentionPolicy("bar") db.CreateRetentionPolicy(rp) db.CreateShardsIfNotExists(rp, 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) } 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) } 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) } 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) } 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) } 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) } 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) } 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) } 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) } if body != "" { t.Fatalf("unexpected body: %s", body) } 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) } 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") 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 != "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) } 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) } 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) } 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) } 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) } 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) } 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_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) } 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) } 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) } 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) } 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) } 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) } 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) } if body != `user 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"}}) } */