Pulse/pkg/reporting/reporting_test.go
rcourtman e32d4ede44 Expose engine narrative entry points for non-rendering callers
The reporting engine's synthesis layer was reachable only through
Generate/GenerateMulti, which always rendered PDF or CSV. Pulse
Assistant needs the same retrospective synthesis (per-resource
summary, fleet outliers, period comparison) in a form it can present
in chat, not as a downloaded artifact.

Add two non-rendering entry points to the Engine interface:

  NarrativeFor(req MetricReportRequest) (*Narrative, error)
  FleetNarrativeFor(req MultiReportRequest) (*FleetNarrative, error)

Both run the same query path and the same narrator resolution as their
rendering counterparts (heuristic by default, AI when the request
supplies a narrator, fail-closed-to-heuristic on any narrator error)
and return the structured narrative without invoking the fpdf/csv
output stage. Test stubs in pkg/reporting and internal/api are
updated to implement the extended interface.

These are the seams the upcoming pulse_summarize Assistant tools wrap
to answer questions like "what's hot on pve1 this week" or "where
should I look across my fleet" without round-tripping through report
generation. Same synthesis layer, no PDF involved.

Also fixes a pre-existing flake in TestEngineGenerate_UsesSuppliedNarrator
(metrics writes are async; the first Generate sometimes ran before
the raw tier flushed). Wrapped in the same eventually-pattern used by
the prior-period and findings-provider tests.
2026-05-10 22:23:09 +01:00

40 lines
938 B
Go

package reporting
import "testing"
type fakeEngine struct {
called bool
}
func (f *fakeEngine) Generate(req MetricReportRequest) ([]byte, string, error) {
f.called = true
return []byte("ok"), "text/plain", nil
}
func (f *fakeEngine) GenerateMulti(req MultiReportRequest) ([]byte, string, error) {
f.called = true
return []byte("ok"), "text/plain", nil
}
func (f *fakeEngine) NarrativeFor(req MetricReportRequest) (*Narrative, error) {
f.called = true
return &Narrative{Source: NarrativeSourceHeuristic}, nil
}
func (f *fakeEngine) FleetNarrativeFor(req MultiReportRequest) (*FleetNarrative, error) {
f.called = true
return &FleetNarrative{Source: NarrativeSourceHeuristic}, nil
}
func TestSetGetEngine(t *testing.T) {
engine := &fakeEngine{}
SetEngine(engine)
if GetEngine() != engine {
t.Fatal("expected engine to be set")
}
SetEngine(nil)
if GetEngine() != nil {
t.Fatal("expected engine to be cleared")
}
}