Skip to content
Snippets Groups Projects
Commit c68dda7d authored by Sergey Yakubov's avatar Sergey Yakubov
Browse files

start adding statistics for broker

parent c52eaccc
No related branches found
No related tags found
No related merge requests found
...@@ -12,7 +12,10 @@ func TestMockDataBase(t *testing.T) { ...@@ -12,7 +12,10 @@ func TestMockDataBase(t *testing.T) {
db.On("Close").Return() db.On("Close").Return()
db.On("Copy").Return(nil) db.On("Copy").Return(nil)
db.On("GetNextRecord", "").Return([]byte(""), nil) db.On("GetNextRecord", "").Return([]byte(""), nil)
db.Connect("") db.Connect("")
db.GetNextRecord("") db.GetNextRecord("")
db.Close()
db.Copy()
var err DBError
err.Error()
} }
...@@ -19,7 +19,7 @@ func (db *MockedDatabase) Close() { ...@@ -19,7 +19,7 @@ func (db *MockedDatabase) Close() {
db.Called() db.Called()
} }
func (db *MockedDatabase) Copy() Agent{ func (db *MockedDatabase) Copy() Agent {
db.Called() db.Called()
return db return db
} }
......
...@@ -15,8 +15,8 @@ func extractRequestParameters(r *http.Request) (string, bool) { ...@@ -15,8 +15,8 @@ func extractRequestParameters(r *http.Request) (string, bool) {
func routeGetNext(w http.ResponseWriter, r *http.Request) { func routeGetNext(w http.ResponseWriter, r *http.Request) {
r.Header.Set("Content-type", "application/json") r.Header.Set("Content-type", "application/json")
// w.Write([]byte("Hello")) // w.Write([]byte("Hello"))
// return // return
db_name, ok := extractRequestParameters(r) db_name, ok := extractRequestParameters(r)
if !ok { if !ok {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
...@@ -31,6 +31,7 @@ func routeGetNext(w http.ResponseWriter, r *http.Request) { ...@@ -31,6 +31,7 @@ func routeGetNext(w http.ResponseWriter, r *http.Request) {
func getNextRecord(db_name string) (answer []byte, code int) { func getNextRecord(db_name string) (answer []byte, code int) {
db_new := db.Copy() db_new := db.Copy()
defer db_new.Close() defer db_new.Close()
statistics.IncreaseCounter()
answer, err := db_new.GetNextRecord(db_name) answer, err := db_new.GetNextRecord(db_name)
if err != nil { if err != nil {
err_db, ok := err.(*database.DBError) err_db, ok := err.(*database.DBError)
......
...@@ -3,6 +3,7 @@ package server ...@@ -3,6 +3,7 @@ package server
import ( import (
"errors" "errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"hidra2_broker/database" "hidra2_broker/database"
"hidra2_broker/utils" "hidra2_broker/utils"
"net/http" "net/http"
...@@ -30,45 +31,57 @@ func TestGetNextWithoutDatabaseName(t *testing.T) { ...@@ -30,45 +31,57 @@ func TestGetNextWithoutDatabaseName(t *testing.T) {
assert.Equal(t, http.StatusNotFound, w.Code, "no database name") assert.Equal(t, http.StatusNotFound, w.Code, "no database name")
} }
func ExpectCopyClose(mock_db *database.MockedDatabase){ func ExpectCopyClose(mock_db *database.MockedDatabase) {
mock_db.On("Copy").Return(mock_db) mock_db.On("Copy").Return(mock_db)
mock_db.On("Close").Return() mock_db.On("Close").Return()
} }
func TestGetNextWithWrongDatabaseName(t *testing.T) { type GetNextTestSuite struct {
mock_db := new(database.MockedDatabase) suite.Suite
db = mock_db mock_db *database.MockedDatabase
defer func() { db = nil }() }
ExpectCopyClose(mock_db)
mock_db.On("GetNextRecord", "foo").Return([]byte(""), func (suite *GetNextTestSuite) SetupTest() {
statistics.Reset()
suite.mock_db = new(database.MockedDatabase)
db = suite.mock_db
ExpectCopyClose(suite.mock_db)
}
func (suite *GetNextTestSuite) TearDownTest() {
assertExpectations(suite.T(), suite.mock_db)
db = nil
}
func TestGetNextTestSuite(t *testing.T) {
suite.Run(t, new(GetNextTestSuite))
}
func (suite *GetNextTestSuite) TestGetNextWithWrongDatabaseName() {
suite.mock_db.On("GetNextRecord", "foo").Return([]byte(""),
&database.DBError{utils.StatusWrongInput, ""}) &database.DBError{utils.StatusWrongInput, ""})
w := doRequest("/database/foo/next") w := doRequest("/database/foo/next")
assert.Equal(t, http.StatusBadRequest, w.Code, "wrong database name") suite.Equal(http.StatusBadRequest, w.Code, "wrong database name")
assertExpectations(t, mock_db)
} }
func TestGetNextWithInternalDBError(t *testing.T) { func (suite *GetNextTestSuite) TestGetNextWithInternalDBError() {
mock_db := new(database.MockedDatabase) suite.mock_db.On("GetNextRecord", "foo").Return([]byte(""), errors.New(""))
db = mock_db
defer func() { db = nil }()
ExpectCopyClose(mock_db)
mock_db.On("GetNextRecord", "foo").Return([]byte(""), errors.New(""))
w := doRequest("/database/foo/next") w := doRequest("/database/foo/next")
assert.Equal(t, http.StatusInternalServerError, w.Code, "internal error") suite.Equal(http.StatusInternalServerError, w.Code, "internal error")
assertExpectations(t, mock_db)
} }
func TestGetNextWithGoodDatabaseName(t *testing.T) { func (suite *GetNextTestSuite) TestGetNextWithGoodDatabaseName() {
mock_db := new(database.MockedDatabase) suite.mock_db.On("GetNextRecord", "dbname").Return([]byte("Hello"), nil)
db = mock_db
defer func() { db = nil }()
ExpectCopyClose(mock_db)
mock_db.On("GetNextRecord", "dbname").Return([]byte("Hello"), nil)
w := doRequest("/database/dbname/next") w := doRequest("/database/dbname/next")
assert.Equal(t, http.StatusOK, w.Code, "GetNext OK") suite.Equal(http.StatusOK, w.Code, "GetNext OK")
assert.Equal(t, "Hello", string(w.Body.Bytes()), "GetNext sends data") suite.Equal("Hello", string(w.Body.Bytes()), "GetNext sends data")
assertExpectations(t, mock_db) }
func (suite *GetNextTestSuite) TestGetNextAddsCounter() {
suite.mock_db.On("GetNextRecord", "dbname").Return([]byte("Hello"), nil)
doRequest("/database/dbname/next")
suite.Equal(1, statistics.GetCounter(), "GetNext increases counter")
} }
...@@ -12,6 +12,7 @@ type serverSettings struct { ...@@ -12,6 +12,7 @@ type serverSettings struct {
} }
var settings serverSettings var settings serverSettings
var statistics serverStatistics
func InitDB(dbAgent database.Agent) error { func InitDB(dbAgent database.Agent) error {
db = dbAgent db = dbAgent
......
...@@ -9,7 +9,14 @@ import ( ...@@ -9,7 +9,14 @@ import (
"strconv" "strconv"
) )
func StartStatistics() {
statistics.Writer = new(StatisticInfluxDbWriter)
statistics.Reset()
go statistics.Monitor()
}
func Start() { func Start() {
StartStatistics()
mux := utils.NewRouter(listRoutes) mux := utils.NewRouter(listRoutes)
log.Fatal(http.ListenAndServe("localhost:"+strconv.Itoa(settings.Port), http.HandlerFunc(mux.ServeHTTP))) log.Fatal(http.ListenAndServe("localhost:"+strconv.Itoa(settings.Port), http.HandlerFunc(mux.ServeHTTP)))
} }
......
package server
import (
"fmt"
"log"
"time"
)
type statisticsWriter interface {
Write(*serverStatistics) error
}
type serverStatistics struct {
counter int
Writer statisticsWriter
}
func (st *serverStatistics) IncreaseCounter() {
st.counter++
}
func (st *serverStatistics) GetCounter() int {
return st.counter
}
func (st *serverStatistics) Reset() {
st.counter = 0
}
func (st *serverStatistics) WriteStatistic() (err error) {
defer func() {
if p := recover(); p != nil {
err = fmt.Errorf("WriteStatistic error: %v", p)
}
}()
return st.Writer.Write(st)
}
func (st *serverStatistics) Monitor() {
for {
time.Sleep(1000 * time.Millisecond)
if err := st.WriteStatistic(); err != nil {
log.Println(err.Error())
}
st.Reset()
}
}
package server
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"testing"
)
type mockWriter struct {
mock.Mock
}
func (writer *mockWriter) Write(statistics *serverStatistics) error {
args := writer.Called(statistics)
return args.Error(0)
}
func assertMockWriterExpectations(t *testing.T, mock_writer *mockWriter) {
mock_writer.AssertExpectations(t)
mock_writer.ExpectedCalls = nil
}
func TestMonitorOK(t *testing.T) {
mock_writer := new(mockWriter)
statistics.Writer = mock_writer
statistics.Reset()
statistics.IncreaseCounter()
mock_writer.On("Write", &statistics).Return(nil)
err := statistics.WriteStatistic()
assert.Nil(t, err, "Statistics written")
assertMockWriterExpectations(t, mock_writer)
}
func TestMonitorCatchesError(t *testing.T) {
statistics.Writer = nil
err := statistics.WriteStatistic()
assert.NotNil(t, err, "Error with nil pointer")
}
//+build !test
package server
import (
"github.com/influxdata/influxdb/client/v2"
"log"
"time"
)
type StatisticLogWriter struct {
}
func (writer *StatisticLogWriter) Write(statistics *serverStatistics) error {
log.Println(statistics.GetCounter())
return nil
}
type StatisticInfluxDbWriter struct {
}
func (writer *StatisticInfluxDbWriter) Write(statistics *serverStatistics) error {
c, err := client.NewHTTPClient(client.HTTPConfig{
Addr: "http://localhost:8086",
})
if err != nil {
return err
}
defer c.Close()
bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
Database: "db",
Precision: "s",
})
// tags := map[string]string{"rate": "rate-total"}
fields := map[string]interface{}{
"rate": statistics.GetCounter(),
}
pt, err := client.NewPoint("RequestsRate", nil, fields, time.Now())
if err != nil {
return err
}
bp.AddPoint(pt)
return c.Write(bp)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment