Files
vps-control/control-plane/backend/observability_test.go
DizelBadCoder c4dc19cd41
Some checks failed
CI / containers (push) Has been cancelled
CI / agent (push) Has been cancelled
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
git init
2026-09-19 19:31:36 +03:00

102 lines
3.8 KiB
Go

package main
import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestParseMetricQuery(t *testing.T) {
query, err := parseMetricQuery(`vps_control_cpu_usage_percent{server_id="srv-1",server_name="edge"}`)
if err != nil || query.Name != "vps_control_cpu_usage_percent" || query.ServerID != "srv-1" || query.ServerName != "edge" {
t.Fatalf("unexpected metric query: %#v, %v", query, err)
}
for _, invalid := range []string{
`process_cpu_seconds_total`,
`vps_control_cpu_usage_percent{job=~".*"}`,
`vps_control_cpu_usage_percent or vector(1)`,
} {
if _, err = parseMetricQuery(invalid); err == nil {
t.Fatalf("accepted unsupported PromQL %q", invalid)
}
}
}
func TestParseLogQueryIsAllowListedAndAnchored(t *testing.T) {
matchers, err := parseLogQuery(`{server_name="edge",unit=~"(nginx|ssh)\.service"}`)
if err != nil || len(matchers) != 2 {
t.Fatalf("unexpected log selector: %#v, %v", matchers, err)
}
if logMatches(map[string]string{"server_name": "edge", "unit": "prefix-nginx.service"}, matchers) {
t.Fatal("regex matcher was not anchored")
}
if !logMatches(map[string]string{"server_name": "edge", "unit": "nginx.service"}, matchers) {
t.Fatal("valid labels did not match")
}
for _, invalid := range []string{`{}`, `{message="secret"}`, `{unit!="ssh.service"}`, `{unit="x"} |= "error"`} {
if _, err = parseLogQuery(invalid); err == nil {
t.Fatalf("accepted unsupported LogQL %q", invalid)
}
}
}
func TestBuildLokiStreamsIsBounded(t *testing.T) {
now := time.Now()
entries := []IntegrationLog{
{ServerID: "1", ServerName: "edge", Unit: "nginx.service", Priority: 6, Timestamp: now, Message: "new"},
{ServerID: "1", ServerName: "edge", Unit: "nginx.service", Priority: 6, Timestamp: now.Add(-time.Second), Message: "old"},
}
streams := buildLokiStreams(entries, []logMatcher{{Label: "server_id", Exact: "1"}}, 1, "backward")
if len(streams) != 1 || len(streams[0].Values) != 1 || streams[0].Values[0][1] != "new" {
t.Fatalf("unexpected bounded streams: %#v", streams)
}
}
func TestReadIntegrationTokenPermissionsAndLength(t *testing.T) {
path := filepath.Join(t.TempDir(), "token")
if err := os.WriteFile(path, []byte("0123456789abcdef0123456789abcdef\n"), 0o600); err != nil {
t.Fatal(err)
}
if _, err := readIntegrationToken(path); err != nil {
t.Fatalf("valid token rejected: %v", err)
}
if err := os.Chmod(path, 0o622); err != nil {
t.Fatal(err)
}
if _, err := readIntegrationToken(path); err == nil {
t.Fatal("group-writable token accepted")
}
}
func TestTimestampBounds(t *testing.T) {
if _, err := parseTimestamp("NaN", time.Now()); err == nil {
t.Fatal("NaN timestamp accepted")
}
if _, err := parseLokiTimestamp("4102444800000000000", time.Now()); err == nil {
t.Fatal("2100 timestamp accepted")
}
}
func TestGrafanaDatasourceHealthExpressions(t *testing.T) {
app := &App{}
prometheusRequest := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("query=1%2B1&time=4"))
prometheusRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
prometheusResponse := httptest.NewRecorder()
app.prometheusQuery(prometheusResponse, prometheusRequest, false)
if prometheusResponse.Code != http.StatusOK || !strings.Contains(prometheusResponse.Body.String(), `"resultType":"scalar"`) {
t.Fatalf("unexpected Prometheus health response: %d %s", prometheusResponse.Code, prometheusResponse.Body.String())
}
lokiRequest := httptest.NewRequest(http.MethodGet,
"/integrations/loki/loki/api/v1/query?query=vector%281%29%2Bvector%281%29&time=4000000000", nil)
lokiResponse := httptest.NewRecorder()
app.lokiAPI(lokiResponse, lokiRequest)
if lokiResponse.Code != http.StatusOK || !strings.Contains(lokiResponse.Body.String(), `"resultType":"vector"`) {
t.Fatalf("unexpected Loki health response: %d %s", lokiResponse.Code, lokiResponse.Body.String())
}
}