Files
akvorado/console/sankey_test.go
Vincent Bernat 8be1bca4fd license: AGPL-3.0-only
```
git ls-files \*.js \*.go \
  | xargs sed -i '1i // SPDX-FileCopyrightText: 2022 Free Mobile\n// SPDX-License-Identifier: AGPL-3.0-only\n'
git ls-files \*.vue \
  | xargs sed -i '1i <!-- SPDX-FileCopyrightText: 2022 Free Mobile -->\n<!-- SPDX-License-Identifier: AGPL-3.0-only -->\n'
```
2022-06-29 11:42:28 +02:00

288 lines
10 KiB
Go

// SPDX-FileCopyrightText: 2022 Free Mobile
// SPDX-License-Identifier: AGPL-3.0-only
package console
import (
"strings"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/golang/mock/gomock"
"akvorado/common/helpers"
)
func TestSankeyQuerySQL(t *testing.T) {
cases := []struct {
Description string
Input sankeyHandlerInput
Expected string
}{
{
Description: "two dimensions, no filters, l3 bps",
Input: sankeyHandlerInput{
Start: time.Date(2022, 04, 10, 15, 45, 10, 0, time.UTC),
End: time.Date(2022, 04, 11, 15, 45, 10, 0, time.UTC),
Dimensions: []queryColumn{queryColumnSrcAS, queryColumnExporterName},
Limit: 5,
Filter: queryFilter{},
Units: "l3bps",
},
Expected: `
WITH
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM {table} WHERE {timefilter}) AS range,
rows AS (SELECT SrcAS, ExporterName FROM {table} WHERE {timefilter} GROUP BY SrcAS, ExporterName ORDER BY SUM(Bytes) DESC LIMIT 5)
SELECT
SUM(Bytes*SamplingRate*8/range) AS xps,
[if(SrcAS IN (SELECT SrcAS FROM rows), concat(toString(SrcAS), ': ', dictGetOrDefault('asns', 'name', SrcAS, '???')), 'Other'),
if(ExporterName IN (SELECT ExporterName FROM rows), ExporterName, 'Other')] AS dimensions
FROM {table}
WHERE {timefilter}
GROUP BY dimensions
ORDER BY xps DESC`,
}, {
Description: "two dimensions, no filters, l2 bps",
Input: sankeyHandlerInput{
Start: time.Date(2022, 04, 10, 15, 45, 10, 0, time.UTC),
End: time.Date(2022, 04, 11, 15, 45, 10, 0, time.UTC),
Dimensions: []queryColumn{queryColumnSrcAS, queryColumnExporterName},
Limit: 5,
Filter: queryFilter{},
Units: "l2bps",
},
Expected: `
WITH
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM {table} WHERE {timefilter}) AS range,
rows AS (SELECT SrcAS, ExporterName FROM {table} WHERE {timefilter} GROUP BY SrcAS, ExporterName ORDER BY SUM(Bytes) DESC LIMIT 5)
SELECT
SUM((Bytes+18*Packets)*SamplingRate*8/range) AS xps,
[if(SrcAS IN (SELECT SrcAS FROM rows), concat(toString(SrcAS), ': ', dictGetOrDefault('asns', 'name', SrcAS, '???')), 'Other'),
if(ExporterName IN (SELECT ExporterName FROM rows), ExporterName, 'Other')] AS dimensions
FROM {table}
WHERE {timefilter}
GROUP BY dimensions
ORDER BY xps DESC`,
}, {
Description: "two dimensions, no filters, pps",
Input: sankeyHandlerInput{
Start: time.Date(2022, 04, 10, 15, 45, 10, 0, time.UTC),
End: time.Date(2022, 04, 11, 15, 45, 10, 0, time.UTC),
Dimensions: []queryColumn{queryColumnSrcAS, queryColumnExporterName},
Limit: 5,
Filter: queryFilter{},
Units: "pps",
},
Expected: `
WITH
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM {table} WHERE {timefilter}) AS range,
rows AS (SELECT SrcAS, ExporterName FROM {table} WHERE {timefilter} GROUP BY SrcAS, ExporterName ORDER BY SUM(Bytes) DESC LIMIT 5)
SELECT
SUM(Packets*SamplingRate/range) AS xps,
[if(SrcAS IN (SELECT SrcAS FROM rows), concat(toString(SrcAS), ': ', dictGetOrDefault('asns', 'name', SrcAS, '???')), 'Other'),
if(ExporterName IN (SELECT ExporterName FROM rows), ExporterName, 'Other')] AS dimensions
FROM {table}
WHERE {timefilter}
GROUP BY dimensions
ORDER BY xps DESC`,
}, {
Description: "two dimensions, with filter",
Input: sankeyHandlerInput{
Start: time.Date(2022, 04, 10, 15, 45, 10, 0, time.UTC),
End: time.Date(2022, 04, 11, 15, 45, 10, 0, time.UTC),
Dimensions: []queryColumn{queryColumnSrcAS, queryColumnExporterName},
Limit: 10,
Filter: queryFilter{"DstCountry = 'FR'"},
Units: "l3bps",
},
Expected: `
WITH
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM {table} WHERE {timefilter} AND (DstCountry = 'FR')) AS range,
rows AS (SELECT SrcAS, ExporterName FROM {table} WHERE {timefilter} AND (DstCountry = 'FR') GROUP BY SrcAS, ExporterName ORDER BY SUM(Bytes) DESC LIMIT 10)
SELECT
SUM(Bytes*SamplingRate*8/range) AS xps,
[if(SrcAS IN (SELECT SrcAS FROM rows), concat(toString(SrcAS), ': ', dictGetOrDefault('asns', 'name', SrcAS, '???')), 'Other'),
if(ExporterName IN (SELECT ExporterName FROM rows), ExporterName, 'Other')] AS dimensions
FROM {table}
WHERE {timefilter} AND (DstCountry = 'FR')
GROUP BY dimensions
ORDER BY xps DESC`,
},
}
for _, tc := range cases {
t.Run(tc.Description, func(t *testing.T) {
got, _ := tc.Input.toSQL()
if diff := helpers.Diff(strings.Split(got, "\n"), strings.Split(tc.Expected, "\n")); diff != "" {
t.Errorf("toSQL (-got, +want):\n%s", diff)
}
})
}
}
func TestSankeyHandler(t *testing.T) {
_, h, mockConn, _ := NewMock(t, DefaultConfiguration())
expectedSQL := []struct {
Xps float64 `ch:"xps"`
Dimensions []string `ch:"dimensions"`
}{
// [(random.randrange(100, 10000), x)
// for x in set([(random.choice(asn),
// random.choice(providers),
// random.choice(routers)) for x in range(30)])]
{9677, []string{"AS100", "Other", "router1"}},
{9472, []string{"AS300", "provider1", "Other"}},
{7593, []string{"AS300", "provider2", "router1"}},
{7234, []string{"AS200", "provider1", "Other"}},
{6006, []string{"AS100", "provider1", "Other"}},
{5988, []string{"Other", "provider1", "Other"}},
{4675, []string{"AS200", "provider3", "Other"}},
{4348, []string{"AS200", "Other", "router2"}},
{3999, []string{"AS100", "provider3", "Other"}},
{3978, []string{"AS100", "provider3", "router2"}},
{3623, []string{"Other", "Other", "router1"}},
{3080, []string{"AS300", "provider3", "router2"}},
{2915, []string{"AS300", "Other", "router1"}},
{2623, []string{"AS100", "provider1", "router1"}},
{2482, []string{"AS200", "provider2", "router2"}},
{2234, []string{"AS100", "provider2", "Other"}},
{1360, []string{"AS200", "Other", "router1"}},
{975, []string{"AS300", "Other", "Other"}},
{717, []string{"AS200", "provider3", "router2"}},
{621, []string{"Other", "Other", "Other"}},
{159, []string{"Other", "provider1", "router1"}},
}
mockConn.EXPECT().
Select(gomock.Any(), gomock.Any(), gomock.Any()).
SetArg(1, expectedSQL).
Return(nil)
helpers.TestHTTPEndpoints(t, h.Address, helpers.HTTPEndpointCases{
{
URL: "/api/v0/console/sankey",
JSONInput: gin.H{
"start": time.Date(2022, 04, 10, 15, 45, 10, 0, time.UTC),
"end": time.Date(2022, 04, 11, 15, 45, 10, 0, time.UTC),
"dimensions": []string{"SrcAS", "InIfProvider", "ExporterName"},
"limit": 10,
"filter": "DstCountry = 'FR'",
"units": "l3bps",
},
JSONOutput: gin.H{
// Raw data
"rows": [][]string{
{"AS100", "Other", "router1"},
{"AS300", "provider1", "Other"},
{"AS300", "provider2", "router1"},
{"AS200", "provider1", "Other"},
{"AS100", "provider1", "Other"},
{"Other", "provider1", "Other"},
{"AS200", "provider3", "Other"},
{"AS200", "Other", "router2"},
{"AS100", "provider3", "Other"},
{"AS100", "provider3", "router2"},
{"Other", "Other", "router1"},
{"AS300", "provider3", "router2"},
{"AS300", "Other", "router1"},
{"AS100", "provider1", "router1"},
{"AS200", "provider2", "router2"},
{"AS100", "provider2", "Other"},
{"AS200", "Other", "router1"},
{"AS300", "Other", "Other"},
{"AS200", "provider3", "router2"},
{"Other", "Other", "Other"},
{"Other", "provider1", "router1"},
},
"xps": []int{
9677,
9472,
7593,
7234,
6006,
5988,
4675,
4348,
3999,
3978,
3623,
3080,
2915,
2623,
2482,
2234,
1360,
975,
717,
621,
159,
},
// For graph
"nodes": []string{
"SrcAS: AS100",
"InIfProvider: Other",
"ExporterName: router1",
"SrcAS: AS300",
"InIfProvider: provider1",
"ExporterName: Other",
"InIfProvider: provider2",
"SrcAS: AS200",
"SrcAS: Other",
"InIfProvider: provider3",
"ExporterName: router2",
},
"links": []gin.H{
{"source": "InIfProvider: provider1", "target": "ExporterName: Other",
"xps": 9472 + 7234 + 6006 + 5988},
{"source": "InIfProvider: Other", "target": "ExporterName: router1",
"xps": 9677 + 3623 + 2915 + 1360},
{"source": "SrcAS: AS100", "target": "InIfProvider: Other",
"xps": 9677},
{"source": "SrcAS: AS300", "target": "InIfProvider: provider1",
"xps": 9472},
{"source": "InIfProvider: provider3", "target": "ExporterName: Other",
"xps": 4675 + 3999},
{"source": "SrcAS: AS100", "target": "InIfProvider: provider1",
"xps": 6006 + 2623},
{"source": "SrcAS: AS100", "target": "InIfProvider: provider3",
"xps": 3999 + 3978},
{"source": "InIfProvider: provider3", "target": "ExporterName: router2",
"xps": 3978 + 3080 + 717},
{"source": "InIfProvider: provider2", "target": "ExporterName: router1",
"xps": 7593},
{"source": "SrcAS: AS300", "target": "InIfProvider: provider2",
"xps": 7593},
{"source": "SrcAS: AS200", "target": "InIfProvider: provider1",
"xps": 7234},
{"source": "SrcAS: Other", "target": "InIfProvider: provider1",
"xps": 5988 + 159},
{"source": "SrcAS: AS200", "target": "InIfProvider: Other",
"xps": 4348 + 1360},
{"source": "SrcAS: AS200", "target": "InIfProvider: provider3",
"xps": 4675 + 717},
{"source": "InIfProvider: Other", "target": "ExporterName: router2",
"xps": 4348},
{"source": "SrcAS: Other", "target": "InIfProvider: Other",
"xps": 3623 + 621},
{"source": "SrcAS: AS300", "target": "InIfProvider: Other",
"xps": 2915 + 975},
{"source": "SrcAS: AS300", "target": "InIfProvider: provider3",
"xps": 3080},
{"source": "InIfProvider: provider1", "target": "ExporterName: router1",
"xps": 2623 + 159},
{"source": "InIfProvider: provider2", "target": "ExporterName: router2",
"xps": 2482},
{"source": "SrcAS: AS200", "target": "InIfProvider: provider2",
"xps": 2482},
{"source": "InIfProvider: provider2", "target": "ExporterName: Other",
"xps": 2234},
{"source": "SrcAS: AS100", "target": "InIfProvider: provider2",
"xps": 2234},
{"source": "InIfProvider: Other", "target": "ExporterName: Other",
"xps": 975 + 621},
},
},
},
})
}