mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-28 07:36:38 +08:00
9de240f034
- Add NodeMetric/TunnelMetric/ServiceMonitor models and repository methods - Implement metrics ingestion service with per-minute bucket aggregation - Add health checker for node connectivity monitoring - Wire node metrics from WebSocket SystemInfo messages - Add tunnel metrics ingestion from flow upload endpoint - Create monitoring REST API endpoints for nodes, tunnels, services - Implement service monitor CRUD and execution (TCP/ICMP checks) - Add MonitorPermission for non-admin access control - Create frontend monitor page with node/tunnel/service views - Add tunnel metrics ingestion from agent flow reports - Include schema migration for tunnel_metric unique index - Fix tunnel entry port conflict validation to use transaction Entire-Checkpoint: 030821a7c8e3
98 lines
2.3 KiB
Go
98 lines
2.3 KiB
Go
package contract_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"go-backend/internal/store/model"
|
|
)
|
|
|
|
func TestFlowUploadInsertsTunnelMetrics(t *testing.T) {
|
|
secret := "monitoring-jwt-secret"
|
|
router, repo := setupContractRouter(t, secret)
|
|
|
|
now := time.Now().UnixMilli()
|
|
|
|
node := &model.Node{
|
|
Name: "node-1",
|
|
Secret: "node-secret",
|
|
ServerIP: "127.0.0.1",
|
|
Port: "10000-10010",
|
|
TCPListenAddr: "[::]",
|
|
UDPListenAddr: "[::]",
|
|
CreatedTime: now,
|
|
Status: 1,
|
|
}
|
|
if err := repo.DB().Create(node).Error; err != nil {
|
|
t.Fatalf("seed node: %v", err)
|
|
}
|
|
|
|
tunnel := &model.Tunnel{
|
|
Name: "tunnel-1",
|
|
TrafficRatio: 1.0,
|
|
Type: 1,
|
|
Protocol: "tls",
|
|
Flow: 1,
|
|
CreatedTime: now,
|
|
UpdatedTime: now,
|
|
Status: 1,
|
|
}
|
|
if err := repo.DB().Create(tunnel).Error; err != nil {
|
|
t.Fatalf("seed tunnel: %v", err)
|
|
}
|
|
|
|
forward := &model.Forward{
|
|
UserID: 123,
|
|
UserName: "user-123",
|
|
Name: "forward-1",
|
|
TunnelID: tunnel.ID,
|
|
RemoteAddr: "1.1.1.1:80",
|
|
CreatedTime: now,
|
|
UpdatedTime: now,
|
|
Status: 1,
|
|
}
|
|
if err := repo.DB().Create(forward).Error; err != nil {
|
|
t.Fatalf("seed forward: %v", err)
|
|
}
|
|
|
|
serviceName := jsonNumber(forward.ID) + "_123_0"
|
|
body, _ := json.Marshal([]map[string]interface{}{{
|
|
"n": serviceName,
|
|
"u": 200,
|
|
"d": 100,
|
|
}})
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/flow/upload?secret="+node.Secret, bytes.NewReader(body))
|
|
res := httptest.NewRecorder()
|
|
router.ServeHTTP(res, req)
|
|
|
|
if res.Code != http.StatusOK {
|
|
t.Fatalf("expected status 200, got %d", res.Code)
|
|
}
|
|
|
|
metrics, err := repo.GetTunnelMetrics(tunnel.ID, 0, now+60_000)
|
|
if err != nil {
|
|
t.Fatalf("get tunnel metrics: %v", err)
|
|
}
|
|
if len(metrics) != 1 {
|
|
t.Fatalf("expected 1 tunnel metric row, got %d", len(metrics))
|
|
}
|
|
|
|
if metrics[0].TunnelID != tunnel.ID {
|
|
t.Fatalf("expected tunnelId %d, got %d", tunnel.ID, metrics[0].TunnelID)
|
|
}
|
|
if metrics[0].NodeID != node.ID {
|
|
t.Fatalf("expected nodeId %d, got %d", node.ID, metrics[0].NodeID)
|
|
}
|
|
if metrics[0].BytesIn != 100 {
|
|
t.Fatalf("expected bytesIn 100, got %d", metrics[0].BytesIn)
|
|
}
|
|
if metrics[0].BytesOut != 200 {
|
|
t.Fatalf("expected bytesOut 200, got %d", metrics[0].BytesOut)
|
|
}
|
|
}
|