mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
console: API validation for /graph/table-interval
Also add simple HTTP tests.
This commit is contained in:
@@ -13,15 +13,9 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"akvorado/common/helpers"
|
|
||||||
"akvorado/console/query"
|
"akvorado/console/query"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultPointsNumber = 200
|
|
||||||
|
|
||||||
// flowsTable describe a consolidated or unconsolidated flows table.
|
// flowsTable describe a consolidated or unconsolidated flows table.
|
||||||
type flowsTable struct {
|
type flowsTable struct {
|
||||||
Name string
|
Name string
|
||||||
@@ -123,11 +117,6 @@ type context struct {
|
|||||||
ToStartOfInterval func(string) string
|
ToStartOfInterval func(string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
type tableIntervalResult struct {
|
|
||||||
Table string `json:"table"`
|
|
||||||
Interval uint64 `json:"interval"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// templateEscape escapes `{{` and `}}` from a string. In fact, only
|
// templateEscape escapes `{{` and `}}` from a string. In fact, only
|
||||||
// the opening tag needs to be escaped.
|
// the opening tag needs to be escaped.
|
||||||
func templateEscape(input string) string {
|
func templateEscape(input string) string {
|
||||||
@@ -151,17 +140,6 @@ func templateContext(context inputContext) string {
|
|||||||
return fmt.Sprintf("context `%s`", string(encoded))
|
return fmt.Sprintf("context `%s`", string(encoded))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Component) getTableAndIntervalHandlerFunc(gc *gin.Context) {
|
|
||||||
input := inputContext{Points: defaultPointsNumber}
|
|
||||||
if err := gc.ShouldBindJSON(&input); err != nil {
|
|
||||||
gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
table, interval, _ := c.computeTableAndInterval(input)
|
|
||||||
|
|
||||||
gc.JSON(http.StatusOK, tableIntervalResult{Table: table, Interval: uint64(interval.Seconds())})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Component) contextFunc(inputStr string) context {
|
func (c *Component) contextFunc(inputStr string) context {
|
||||||
var input inputContext
|
var input inputContext
|
||||||
if err := json.Unmarshal([]byte(inputStr), &input); err != nil {
|
if err := json.Unmarshal([]byte(inputStr), &input); err != nil {
|
||||||
|
|||||||
@@ -301,12 +301,12 @@ func TestFinalizeQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTableInterval(t *testing.T) {
|
func TestComputeBestTableAndInterval(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Description string
|
Description string
|
||||||
Tables []flowsTable
|
Tables []flowsTable
|
||||||
Context inputContext
|
Context inputContext
|
||||||
Expected tableIntervalResult
|
Expected tableIntervalOutput
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Description: "simple query without additional tables",
|
Description: "simple query without additional tables",
|
||||||
@@ -315,7 +315,7 @@ func TestGetTableInterval(t *testing.T) {
|
|||||||
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
Points: 86400,
|
Points: 86400,
|
||||||
},
|
},
|
||||||
Expected: tableIntervalResult{Table: "flows", Interval: 1},
|
Expected: tableIntervalOutput{Table: "flows", Interval: 1},
|
||||||
}, {
|
}, {
|
||||||
Description: "query with main table",
|
Description: "query with main table",
|
||||||
Context: inputContext{
|
Context: inputContext{
|
||||||
@@ -324,7 +324,7 @@ func TestGetTableInterval(t *testing.T) {
|
|||||||
MainTableRequired: true,
|
MainTableRequired: true,
|
||||||
Points: 86400,
|
Points: 86400,
|
||||||
},
|
},
|
||||||
Expected: tableIntervalResult{Table: "flows", Interval: 1},
|
Expected: tableIntervalOutput{Table: "flows", Interval: 1},
|
||||||
}, {
|
}, {
|
||||||
Description: "only flows table available",
|
Description: "only flows table available",
|
||||||
Tables: []flowsTable{{"flows", 0, time.Date(2022, 3, 10, 15, 45, 10, 0, time.UTC)}},
|
Tables: []flowsTable{{"flows", 0, time.Date(2022, 3, 10, 15, 45, 10, 0, time.UTC)}},
|
||||||
@@ -333,7 +333,7 @@ func TestGetTableInterval(t *testing.T) {
|
|||||||
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
Points: 86400,
|
Points: 86400,
|
||||||
},
|
},
|
||||||
Expected: tableIntervalResult{Table: "flows", Interval: 1},
|
Expected: tableIntervalOutput{Table: "flows", Interval: 1},
|
||||||
}, {
|
}, {
|
||||||
Description: "select flows table out of range",
|
Description: "select flows table out of range",
|
||||||
Tables: []flowsTable{
|
Tables: []flowsTable{
|
||||||
@@ -345,7 +345,7 @@ func TestGetTableInterval(t *testing.T) {
|
|||||||
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
Points: 720, // 2-minute resolution,
|
Points: 720, // 2-minute resolution,
|
||||||
},
|
},
|
||||||
Expected: tableIntervalResult{Table: "flows", Interval: 1},
|
Expected: tableIntervalOutput{Table: "flows", Interval: 1},
|
||||||
}, {
|
}, {
|
||||||
Description: "select consolidated table with better resolution",
|
Description: "select consolidated table with better resolution",
|
||||||
Tables: []flowsTable{
|
Tables: []flowsTable{
|
||||||
@@ -358,7 +358,7 @@ func TestGetTableInterval(t *testing.T) {
|
|||||||
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
Points: 720, // 2-minute resolution,
|
Points: 720, // 2-minute resolution,
|
||||||
},
|
},
|
||||||
Expected: tableIntervalResult{Table: "flows_1m0s", Interval: 60},
|
Expected: tableIntervalOutput{Table: "flows_1m0s", Interval: 60},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +368,7 @@ func TestGetTableInterval(t *testing.T) {
|
|||||||
c.flowsTables = tc.Tables
|
c.flowsTables = tc.Tables
|
||||||
table, interval, _ := c.computeTableAndInterval(
|
table, interval, _ := c.computeTableAndInterval(
|
||||||
tc.Context)
|
tc.Context)
|
||||||
got := tableIntervalResult{
|
got := tableIntervalOutput{
|
||||||
Table: table,
|
Table: table,
|
||||||
Interval: uint64(interval.Seconds()),
|
Interval: uint64(interval.Seconds()),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -422,3 +422,29 @@ func (c *Component) graphLineHandlerFunc(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
gc.JSON(http.StatusOK, output)
|
gc.JSON(http.StatusOK, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tableIntervalInput struct {
|
||||||
|
Start time.Time `json:"start" binding:"required"`
|
||||||
|
End time.Time `json:"end" binding:"required,gtfield=Start"`
|
||||||
|
Points uint `json:"points" binding:"required,min=5,max=2000"` // minimum number of points
|
||||||
|
}
|
||||||
|
|
||||||
|
type tableIntervalOutput struct {
|
||||||
|
Table string `json:"table"`
|
||||||
|
Interval uint64 `json:"interval"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Component) getTableAndIntervalHandlerFunc(gc *gin.Context) {
|
||||||
|
var input tableIntervalInput
|
||||||
|
if err := gc.ShouldBindJSON(&input); err != nil {
|
||||||
|
gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
table, interval, _ := c.computeTableAndInterval(inputContext{
|
||||||
|
Points: input.Points,
|
||||||
|
Start: input.Start,
|
||||||
|
End: input.End,
|
||||||
|
})
|
||||||
|
|
||||||
|
gc.JSON(http.StatusOK, tableIntervalOutput{Table: table, Interval: uint64(interval.Seconds())})
|
||||||
|
}
|
||||||
|
|||||||
@@ -979,3 +979,35 @@ func TestGraphLineHandler(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetTableInterval(t *testing.T) {
|
||||||
|
_, h, _, mockClock := NewMock(t, DefaultConfiguration())
|
||||||
|
mockClock.Set(time.Date(2022, 4, 12, 15, 45, 10, 0, time.UTC))
|
||||||
|
helpers.TestHTTPEndpoints(t, h.LocalAddr(), helpers.HTTPEndpointCases{
|
||||||
|
{
|
||||||
|
Description: "simple query",
|
||||||
|
URL: "/api/v0/console/graph/table-interval",
|
||||||
|
JSONInput: gin.H{
|
||||||
|
"start": time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
"end": time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
"points": 300,
|
||||||
|
},
|
||||||
|
JSONOutput: gin.H{
|
||||||
|
"table": "flows",
|
||||||
|
"interval": 1,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Description: "too many points",
|
||||||
|
URL: "/api/v0/console/graph/table-interval",
|
||||||
|
JSONInput: gin.H{
|
||||||
|
"start": time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
"end": time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
"points": 86400,
|
||||||
|
},
|
||||||
|
StatusCode: 400,
|
||||||
|
JSONOutput: gin.H{
|
||||||
|
"message": `Key: 'tableIntervalInput.Points' Error:Field validation for 'Points' failed on the 'max' tag`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user