package queryplan import ( "context" "errors" "testing" "time" "github.com/itworx/pulse/internal/auth" "github.com/itworx/pulse/internal/metriccatalog" ) func plannerForTest(t *testing.T, limits Limits) Planner { t.Helper() registry, err := metriccatalog.DefaultRegistry() if err != nil { t.Fatal(err) } return NewPlanner(registry, limits) } func viewerContext() context.Context { return auth.WithPrincipal(context.Background(), auth.Principal{Subject: "viewer", Role: auth.RoleViewer}) } func validRequest() Request { now := time.Date(2026, 8, 1, 12, 0, 0, 0, time.FixedZone("CEST", 2*60*60)) return Request{Metric: "container.cpu.utilization", Scope: map[string]string{"containerId": "media_server"}, Range: Range{From: now.Add(-time.Hour), To: now, StepSeconds: 60}, Aggregation: "avg", GroupBy: []string{"image", "container"}} } func TestPlannerRequiresAuthorizationBeforeMetricResolution(t *testing.T) { planner := plannerForTest(t, Limits{}) request := validRequest() request.Metric = "not.approved" if _, err := planner.Plan(context.Background(), request); !errors.Is(err, ErrUnauthorized) { t.Fatalf("error=%v", err) } } func TestPlannerNormalizesEquivalentRequestsDeterministically(t *testing.T) { planner := plannerForTest(t, Limits{}) first := validRequest() second := validRequest() second.GroupBy = []string{"container", "image"} second.Range.From = second.Range.From.UTC() second.Range.To = second.Range.To.UTC() firstPlan, err := planner.Plan(viewerContext(), first) if err != nil { t.Fatal(err) } secondPlan, err := planner.Plan(viewerContext(), second) if err != nil { t.Fatal(err) } if firstPlan.CacheKey != secondPlan.CacheKey { t.Fatalf("keys differ: %s/%s", firstPlan.CacheKey, secondPlan.CacheKey) } if firstPlan.Request.Scope["container"] != "media_server" || firstPlan.Cost.Points != 60 || firstPlan.Cost.EstimatedSamples != 1200 { t.Fatalf("unexpected normalized plan: %+v", firstPlan) } } func TestPlannerRejectsInvalidScopeLabelsAndGrouping(t *testing.T) { planner := plannerForTest(t, Limits{}) request := validRequest() request.Scope = map[string]string{"diskId": "disk-1"} if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_SCOPE_INVALID" { t.Fatalf("scope error=%v", err) } request = validRequest() request.GroupBy = []string{"container", "not_allowed"} if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_LABEL_INVALID" { t.Fatalf("group error=%v", err) } request = validRequest() request.GroupBy = []string{"container", "container"} if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_LABEL_DUPLICATE" { t.Fatalf("duplicate error=%v", err) } request = validRequest() request.Scope = map[string]string{"containerId": "bad value"} if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_SCOPE_INVALID" { t.Fatalf("value error=%v", err) } } func TestPlannerEnforcesRangePointSeriesAndCostBudgets(t *testing.T) { request := validRequest() request.Range.From = request.Range.To.Add(-31 * 24 * time.Hour) planner := plannerForTest(t, Limits{}) if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_RANGE_LIMIT" { t.Fatalf("range error=%v", err) } request = validRequest() request.MaxPoints = 10 if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_POINT_LIMIT" { t.Fatalf("point error=%v", err) } request = validRequest() request.MaxSeries = 201 if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_SERIES_LIMIT" { t.Fatalf("series error=%v", err) } request = validRequest() planner = plannerForTest(t, Limits{MaxCostPoints: 100}) if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_COST_LIMIT" { t.Fatalf("cost error=%v", err) } } func TestPlannerHonorsCancellationAndStepBounds(t *testing.T) { planner := plannerForTest(t, Limits{}) canceled, cancel := context.WithCancel(viewerContext()) cancel() if _, err := planner.Plan(canceled, validRequest()); !errors.Is(err, context.Canceled) { t.Fatalf("cancel error=%v", err) } request := validRequest() request.Range.StepSeconds = 0 if _, err := planner.Plan(viewerContext(), request); err == nil || err.(Error).Code != "QUERY_STEP_INVALID" { t.Fatalf("step error=%v", err) } }