internal/aggergate: make HLL state path configurable

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I8ff8ef25ad945aae918bea97ee39d7ea6a6a6964
This commit is contained in:
raf 2026-03-01 19:23:19 +03:00
commit 2ef2dabf93
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
5 changed files with 167 additions and 63 deletions

View file

@ -223,7 +223,7 @@ func (m *MetricsAggregator) Shutdown(ctx context.Context) error {
m.Stop()
// Persist HLL state if configured
if m.cfg.Site.SaltRotation != "" {
return m.estimator.Save("/tmp/watchdog-hll.state")
return m.estimator.Save(m.cfg.Server.StatePath)
}
return nil
}

View file

@ -1,6 +1,8 @@
package aggregate
import (
"context"
"os"
"strings"
"testing"
@ -190,3 +192,89 @@ func TestMetricsAggregator_MustRegister(t *testing.T) {
t.Errorf("expected at least 2 metric families, got %d", len(metrics))
}
}
func TestMetricsAggregator_Shutdown_ConfigurableStatePath(t *testing.T) {
registry := NewPathRegistry(100)
// Create temp directory for test
tmpDir := t.TempDir()
statePath := tmpDir + "/custom-hll.state"
cfg := config.Config{
Site: config.SiteConfig{
SaltRotation: "daily",
Collect: config.CollectConfig{
Pageviews: true,
},
},
Server: config.ServerConfig{
StatePath: statePath,
},
}
agg := NewMetricsAggregator(registry, NewCustomEventRegistry(100), &cfg)
// Add some unique visitors so there's state to save
agg.AddUnique("192.168.1.1", "Mozilla/5.0")
// Shutdown should save to configured path
ctx := context.Background()
if err := agg.Shutdown(ctx); err != nil {
t.Fatalf("Shutdown failed: %v", err)
}
// Verify file was created at configured path
if _, err := os.Stat(statePath); os.IsNotExist(err) {
t.Errorf("state file was not created at configured path: %s", statePath)
}
}
func TestMetricsAggregator_Shutdown_DefaultStatePath(t *testing.T) {
registry := NewPathRegistry(100)
cfg := config.Config{
Site: config.SiteConfig{
Domains: []string{"example.com"}, // Required for validation
SaltRotation: "daily",
Collect: config.CollectConfig{
Pageviews: true,
},
},
Limits: config.LimitsConfig{
MaxPaths: 1000,
MaxSources: 500,
},
Server: config.ServerConfig{
// StatePath not set - validation should set default
StatePath: "",
},
}
// Validate to apply defaults
if err := cfg.Validate(); err != nil {
t.Fatalf("config validation failed: %v", err)
}
// Verify default was applied
expectedDefault := "/var/lib/watchdog/hll.state"
if cfg.Server.StatePath != expectedDefault {
t.Errorf(
"expected default StatePath %q, got %q",
expectedDefault,
cfg.Server.StatePath,
)
}
agg := NewMetricsAggregator(registry, NewCustomEventRegistry(100), &cfg)
// Add some unique visitors
agg.AddUnique("192.168.1.1", "Mozilla/5.0")
// Shutdown should save to default path
ctx := context.Background()
if err := agg.Shutdown(ctx); err != nil {
// Might fail due to permissions on /var/lib, which is OK for this test
// We're just verifying the code path works
t.Logf("Shutdown returned error (might be expected): %v", err)
}
}