diff --git a/baskets_bolt_test.go b/baskets_bolt_test.go index 0ec6e47..75c13f7 100644 --- a/baskets_bolt_test.go +++ b/baskets_bolt_test.go @@ -444,6 +444,54 @@ func TestBoltBasket_SetResponse_Update(t *testing.T) { } } +func TestBoltDatabase_GetStats(t *testing.T) { + name := "test130" + db := NewBoltDatabase(name + ".db") + defer db.Release() + defer os.Remove(name + ".db") + + config := BasketConfig{Capacity: 5} + for i := 0; i < 10; i++ { + bname := fmt.Sprintf("%s_%v", name, i) + db.Create(bname, config) + + // fill basket + basket := db.Get(bname) + for j := 0; j < 9-i; j++ { + basket.Add(createTestPOSTRequest( + fmt.Sprintf("http://localhost/%v?id=%v", bname, j), fmt.Sprintf("req%v", j), "text/plain")) + } + time.Sleep(20 * time.Millisecond) + } + + // get stats + stats := db.GetStats(3) + if assert.NotNil(t, stats, "database statistics is expected") { + assert.Equal(t, 10, stats.BasketsCount, "wrong BasketsCount stats") + assert.Equal(t, 1, stats.EmptyBasketsCount, "wrong EmptyBasketsCount stats") + assert.Equal(t, 9, stats.MaxBasketSize, "wrong MaxBasketSize stats") + assert.Equal(t, 35, stats.RequestsCount, "wrong RequestsCount stats") + assert.Equal(t, 45, stats.RequestsTotalCount, "wrong RequestsTotalCount stats") + assert.Equal(t, 5, stats.AvgBasketSize, "wrong AvgBasketSize stats") + + // top 3 by date + if assert.NotNil(t, stats.TopBasketsByDate, "top baskets by date are expected") { + assert.Equal(t, 3, len(stats.TopBasketsByDate), "unexpected number of top baskets") + assert.Equal(t, fmt.Sprintf("%s_%v", name, 8), stats.TopBasketsByDate[0].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 7), stats.TopBasketsByDate[1].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 6), stats.TopBasketsByDate[2].Name) + } + + // top 3 by size + if assert.NotNil(t, stats.TopBasketsBySize, "top baskets by size are expected") { + assert.Equal(t, 3, len(stats.TopBasketsBySize), "unexpected number of top baskets") + assert.Equal(t, fmt.Sprintf("%s_%v", name, 0), stats.TopBasketsBySize[0].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 1), stats.TopBasketsBySize[1].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 2), stats.TopBasketsBySize[2].Name) + } + } +} + func TestBoltBasket_InvalidBasket(t *testing.T) { name := "test199" db, _ := bolt.Open(name+".db", 0600, &bolt.Options{Timeout: 5 * time.Second}) diff --git a/baskets_mem_test.go b/baskets_mem_test.go index c0399be..c532176 100644 --- a/baskets_mem_test.go +++ b/baskets_mem_test.go @@ -7,6 +7,7 @@ import ( "net/url" "strings" "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -400,3 +401,50 @@ func TestMemoryBasket_SetResponse_Update(t *testing.T) { } } } + +func TestMemoryDatabase_GetStats(t *testing.T) { + name := "test130" + db := NewMemoryDatabase() + defer db.Release() + + config := BasketConfig{Capacity: 5} + for i := 0; i < 10; i++ { + bname := fmt.Sprintf("%s_%v", name, i) + db.Create(bname, config) + + // fill basket + basket := db.Get(bname) + for j := 0; j < 9-i; j++ { + basket.Add(createTestPOSTRequest( + fmt.Sprintf("http://localhost/%v?id=%v", bname, j), fmt.Sprintf("req%v", j), "text/plain")) + } + time.Sleep(20 * time.Millisecond) + } + + // get stats + stats := db.GetStats(3) + if assert.NotNil(t, stats, "database statistics is expected") { + assert.Equal(t, 10, stats.BasketsCount, "wrong BasketsCount stats") + assert.Equal(t, 1, stats.EmptyBasketsCount, "wrong EmptyBasketsCount stats") + assert.Equal(t, 9, stats.MaxBasketSize, "wrong MaxBasketSize stats") + assert.Equal(t, 35, stats.RequestsCount, "wrong RequestsCount stats") + assert.Equal(t, 45, stats.RequestsTotalCount, "wrong RequestsTotalCount stats") + assert.Equal(t, 5, stats.AvgBasketSize, "wrong AvgBasketSize stats") + + // top 3 by date + if assert.NotNil(t, stats.TopBasketsByDate, "top baskets by date are expected") { + assert.Equal(t, 3, len(stats.TopBasketsByDate), "unexpected number of top baskets") + assert.Equal(t, fmt.Sprintf("%s_%v", name, 8), stats.TopBasketsByDate[0].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 7), stats.TopBasketsByDate[1].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 6), stats.TopBasketsByDate[2].Name) + } + + // top 3 by size + if assert.NotNil(t, stats.TopBasketsBySize, "top baskets by size are expected") { + assert.Equal(t, 3, len(stats.TopBasketsBySize), "unexpected number of top baskets") + assert.Equal(t, fmt.Sprintf("%s_%v", name, 0), stats.TopBasketsBySize[0].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 1), stats.TopBasketsBySize[1].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 2), stats.TopBasketsBySize[2].Name) + } + } +} diff --git a/baskets_sql_mysql_test.go b/baskets_sql_mysql_test.go index 4c12198..a4f1c95 100644 --- a/baskets_sql_mysql_test.go +++ b/baskets_sql_mysql_test.go @@ -465,3 +465,51 @@ func TestMySQLBasket_SetResponse_Error(t *testing.T) { assert.Nil(t, basket.GetResponse(method), "Response for very long method name is not expected") } } + +func TestMySQLDatabase_GetStats(t *testing.T) { + name := "test130" + db := NewSQLDatabase(mysqlTestConnection) + defer db.Release() + + config := BasketConfig{Capacity: 5} + for i := 0; i < 10; i++ { + bname := fmt.Sprintf("%s_%v", name, i) + db.Create(bname, config) + defer db.Delete(bname) + + // fill basket + basket := db.Get(bname) + for j := 0; j < 9-i; j++ { + basket.Add(createTestPOSTRequest( + fmt.Sprintf("http://localhost/%v?id=%v", bname, j), fmt.Sprintf("req%v", j), "text/plain")) + } + time.Sleep(20 * time.Millisecond) + } + + // get stats + stats := db.GetStats(3) + if assert.NotNil(t, stats, "database statistics is expected") { + assert.Equal(t, 10, stats.BasketsCount, "wrong BasketsCount stats") + assert.Equal(t, 1, stats.EmptyBasketsCount, "wrong EmptyBasketsCount stats") + assert.Equal(t, 9, stats.MaxBasketSize, "wrong MaxBasketSize stats") + assert.Equal(t, 35, stats.RequestsCount, "wrong RequestsCount stats") + assert.Equal(t, 45, stats.RequestsTotalCount, "wrong RequestsTotalCount stats") + assert.Equal(t, 5, stats.AvgBasketSize, "wrong AvgBasketSize stats") + + // top 3 by date + if assert.NotNil(t, stats.TopBasketsByDate, "top baskets by date are expected") { + assert.Equal(t, 3, len(stats.TopBasketsByDate), "unexpected number of top baskets") + assert.Equal(t, fmt.Sprintf("%s_%v", name, 8), stats.TopBasketsByDate[0].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 7), stats.TopBasketsByDate[1].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 6), stats.TopBasketsByDate[2].Name) + } + + // top 3 by size + if assert.NotNil(t, stats.TopBasketsBySize, "top baskets by size are expected") { + assert.Equal(t, 3, len(stats.TopBasketsBySize), "unexpected number of top baskets") + assert.Equal(t, fmt.Sprintf("%s_%v", name, 0), stats.TopBasketsBySize[0].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 1), stats.TopBasketsBySize[1].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 2), stats.TopBasketsBySize[2].Name) + } + } +} diff --git a/baskets_sql_pg_test.go b/baskets_sql_pg_test.go index 548042a..b1177fa 100644 --- a/baskets_sql_pg_test.go +++ b/baskets_sql_pg_test.go @@ -465,3 +465,51 @@ func TestPgSQLBasket_SetResponse_Error(t *testing.T) { assert.Nil(t, basket.GetResponse(method), "Response for very long method name is not expected") } } + +func TestPgSQLDatabase_GetStats(t *testing.T) { + name := "test130" + db := NewSQLDatabase(pgTestConnection) + defer db.Release() + + config := BasketConfig{Capacity: 5} + for i := 0; i < 10; i++ { + bname := fmt.Sprintf("%s_%v", name, i) + db.Create(bname, config) + defer db.Delete(bname) + + // fill basket + basket := db.Get(bname) + for j := 0; j < 9-i; j++ { + basket.Add(createTestPOSTRequest( + fmt.Sprintf("http://localhost/%v?id=%v", bname, j), fmt.Sprintf("req%v", j), "text/plain")) + } + time.Sleep(20 * time.Millisecond) + } + + // get stats + stats := db.GetStats(3) + if assert.NotNil(t, stats, "database statistics is expected") { + assert.Equal(t, 10, stats.BasketsCount, "wrong BasketsCount stats") + assert.Equal(t, 1, stats.EmptyBasketsCount, "wrong EmptyBasketsCount stats") + assert.Equal(t, 9, stats.MaxBasketSize, "wrong MaxBasketSize stats") + assert.Equal(t, 35, stats.RequestsCount, "wrong RequestsCount stats") + assert.Equal(t, 45, stats.RequestsTotalCount, "wrong RequestsTotalCount stats") + assert.Equal(t, 5, stats.AvgBasketSize, "wrong AvgBasketSize stats") + + // top 3 by date + if assert.NotNil(t, stats.TopBasketsByDate, "top baskets by date are expected") { + assert.Equal(t, 3, len(stats.TopBasketsByDate), "unexpected number of top baskets") + assert.Equal(t, fmt.Sprintf("%s_%v", name, 8), stats.TopBasketsByDate[0].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 7), stats.TopBasketsByDate[1].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 6), stats.TopBasketsByDate[2].Name) + } + + // top 3 by size + if assert.NotNil(t, stats.TopBasketsBySize, "top baskets by size are expected") { + assert.Equal(t, 3, len(stats.TopBasketsBySize), "unexpected number of top baskets") + assert.Equal(t, fmt.Sprintf("%s_%v", name, 0), stats.TopBasketsBySize[0].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 1), stats.TopBasketsBySize[1].Name) + assert.Equal(t, fmt.Sprintf("%s_%v", name, 2), stats.TopBasketsBySize[2].Name) + } + } +} diff --git a/handlers_test.go b/handlers_test.go index f6be45f..e8383f5 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -704,6 +704,56 @@ func TestGetBaskets_Unauthorized(t *testing.T) { } } +func TestGetStats(t *testing.T) { + // create 3 baskets + for i := 0; i < 3; i++ { + basket := fmt.Sprintf("forstats0%v", i) + r, err := http.NewRequest("POST", "http://localhost:55555/baskets/"+basket, strings.NewReader("")) + if assert.NoError(t, err) { + w := httptest.NewRecorder() + ps := append(make(httprouter.Params, 0), httprouter.Param{Key: "basket", Value: basket}) + CreateBasket(w, r, ps) + assert.Equal(t, 201, w.Code, "wrong HTTP result code") + } + } + + // get stats + r, err := http.NewRequest("GET", "http://localhost:55555/stats", strings.NewReader("")) + if assert.NoError(t, err) { + r.Header.Add("Authorization", serverConfig.MasterToken) + w := httptest.NewRecorder() + GetStats(w, r, make(httprouter.Params, 0)) + // HTTP 200 - OK + assert.Equal(t, 200, w.Code, "wrong HTTP result code") + + stats := new(DatabaseStats) + err = json.Unmarshal(w.Body.Bytes(), stats) + if assert.NoError(t, err) { + // validate response + assert.NotEmpty(t, stats.TopBasketsByDate, "top baskets are expected") + assert.NotEmpty(t, stats.TopBasketsBySize, "top baskets are expected") + assert.True(t, stats.BasketsCount > 0, "baskets count should be greater than 0") + assert.True(t, stats.EmptyBasketsCount > 0, "empty baskets count should be greater than 0") + } + } +} + +func TestGetStats_Unauthorized(t *testing.T) { + r, err := http.NewRequest("GET", "http://localhost:55555/stats", strings.NewReader("")) + if assert.NoError(t, err) { + // no authorization at all: 401 - unauthorized + w := httptest.NewRecorder() + GetStats(w, r, make(httprouter.Params, 0)) + assert.Equal(t, 401, w.Code, "wrong HTTP result code") + + // invalid master token: 401 - unauthorized + r.Header.Add("Authorization", "123-wrong-token") + w = httptest.NewRecorder() + GetStats(w, r, make(httprouter.Params, 0)) + assert.Equal(t, 401, w.Code, "wrong HTTP result code") + } +} + func TestGetBaskets_Query(t *testing.T) { // create 10 baskets for i := 0; i < 10; i++ {