package e2e import ( "strconv" "testing" "time" "git.veillax.com/Veillax/blacktip" "git.veillax.com/Veillax/reef/model" ) // Traffic through an edge shows up in Hammerhead's charts, with the client address named. func TestTrafficAnalyticsFlow(t *testing.T) { w := setup(t, blacktip.TraefikConfig{}) target := freeRun(t, 1) pub := freeRun(t, 1) if pub == target { pub = freeRun(t, 2) + 1 } tcpOn(t, target) var m model.Mapping if code, raw := w.admin.do("POST", "/api/orgs/"+w.org+"/mappings", map[string]any{"proto": "tcp", "edgeId": w.edge, "bindIp": "127.0.0.1", "port": pub, "targets": tgt(w.local, target), "enabled": true}, &m); code != 200 { t.Fatalf("open: %d %s", code, raw) } for i := 0; i < 3; i++ { if got := tcpAsk(t, "127.0.0.1:"+strconv.Itoa(pub), "hello"); got == "" { t.Fatal("no answer through the edge") } } type detail struct { Total struct{ Conns, BytesIn, BytesOut int64 } `json:"total"` Points []struct{ Conns int64 } `json:"points"` Sources []struct { IP string Conns int64 } `json:"sources"` } var d detail for i := 0; ; i++ { // the edge reports every 20 seconds d = detail{} if code, _ := w.admin.do("GET", "/api/orgs/"+w.org+"/traffic/"+m.ID+"?range=1h", nil, &d); code == 200 && d.Total.Conns >= 3 { break } if i >= 450 { t.Fatal("timed out waiting for the edge to report the traffic") } time.Sleep(100 * time.Millisecond) } if d.Total.BytesIn < 15 || d.Total.BytesOut == 0 || len(d.Points) != 60 { t.Errorf("totals: %+v with %d points", d.Total, len(d.Points)) } if len(d.Sources) != 1 || d.Sources[0].IP != "127.0.0.1" || d.Sources[0].Conns < 3 { t.Errorf("sources: %+v", d.Sources) } var all detail if code, raw := w.admin.do("GET", "/api/orgs/"+w.org+"/traffic/all?range=24h", nil, &all); code != 200 || all.Total.Conns < 3 || len(all.Points) != 24 { t.Errorf("organization total: %d %s", code, raw) } if code, _ := w.admin.do("GET", "/api/orgs/"+w.org+"/traffic/"+m.ID+"?range=5y", nil, nil); code != 400 { t.Errorf("bad range: %d", code) } if code, _ := w.admin.do("GET", "/api/orgs/"+w.org+"/traffic/nope", nil, nil); code != 404 { t.Errorf("unknown port: %d", code) } alerts := "/api/orgs/" + w.org + "/alerts" if code, _ := w.admin.do("PUT", alerts+"/traffic", map[string]any{"spikeFactor": 1}, nil); code != 400 { t.Errorf("a spike of 1x was accepted: %d", code) } if code, raw := w.admin.do("PUT", alerts+"/traffic", map[string]any{"spikeFactor": 5, "dailyMb": 2048}, nil); code != 200 { t.Fatalf("save traffic alerts: %d %s", code, raw) } var ov struct{ Settings map[string]int } if code, _ := w.admin.do("GET", alerts, nil, &ov); code != 200 || ov.Settings["spikeFactor"] != 5 || ov.Settings["dailyMb"] != 2048 || ov.Settings["debounceMin"] != 2 { t.Errorf("settings after save: %d %+v", code, ov.Settings) } }