Pulse/internal/config/persistence_ai_test.go
rcourtman d909f319a5 feat: improve AI config and persistence
- Enhance AI configuration options
- Improve persistence layer
- Add AI config tests
2026-01-22 22:31:42 +00:00

165 lines
4.3 KiB
Go

package config
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPersistence_AIFindings(t *testing.T) {
tempDir := t.TempDir()
p := NewConfigPersistence(tempDir)
// Default load (empty)
data, err := p.LoadAIFindings()
require.NoError(t, err)
assert.Empty(t, data.Findings)
// Save
record := &AIFindingRecord{
ID: "id1",
Description: "analysis",
DetectedAt: time.Now(),
}
data.Findings["id1"] = record
err = p.SaveAIFindings(data.Findings) // SaveAIFindings takes map[string]*AIFindingRecord
require.NoError(t, err)
// Reload
loaded, err := p.LoadAIFindings()
require.NoError(t, err)
assert.Len(t, loaded.Findings, 1)
assert.Equal(t, "analysis", loaded.Findings["id1"].Description)
// Test Corrupt file (Unmarshal error)
require.NoError(t, os.WriteFile(filepath.Join(tempDir, "ai_findings.json"), []byte("{invalid"), 0644))
loaded, err = p.LoadAIFindings()
// Should return empty structure on unmarshal error, not fail completely (as per code)
require.NoError(t, err)
assert.Empty(t, loaded.Findings)
}
func TestPersistence_AIUsageHistory(t *testing.T) {
tempDir := t.TempDir()
p := NewConfigPersistence(tempDir)
// Default load
data, err := p.LoadAIUsageHistory()
require.NoError(t, err)
assert.Empty(t, data.Events)
// Save
record := AIUsageEventRecord{
Timestamp: time.Now(),
RequestModel: "gpt-4",
InputTokens: 10,
OutputTokens: 20,
}
data.Events = append(data.Events, record)
err = p.SaveAIUsageHistory(data.Events)
require.NoError(t, err)
// Reload
loaded, err := p.LoadAIUsageHistory()
require.NoError(t, err)
assert.Len(t, loaded.Events, 1)
assert.Equal(t, 10, loaded.Events[0].InputTokens)
// Test Corrupt file
require.NoError(t, os.WriteFile(filepath.Join(tempDir, "ai_usage_history.json"), []byte("{invalid"), 0644))
loaded, err = p.LoadAIUsageHistory()
// Should return empty structure
require.NoError(t, err)
assert.Empty(t, loaded.Events)
}
func TestPersistence_AIConfig(t *testing.T) {
tempDir := t.TempDir()
p := NewConfigPersistence(tempDir)
// Load default (empty/nil config if file missing? LoadAIConfig returns NewDefaultAIConfig logic inside persistence??)
// Let's check logic: LoadAIConfig reads file, if missing returns default?
loaded, err := p.LoadAIConfig()
require.NoError(t, err)
assert.NotNil(t, loaded) // Default config
// Save
cfg := NewDefaultAIConfig()
cfg.APIKey = "testkey"
err = p.SaveAIConfig(*cfg)
require.NoError(t, err)
// Reload
loaded, err = p.LoadAIConfig()
require.NoError(t, err)
assert.Equal(t, "testkey", loaded.APIKey)
// Corrupt file
require.NoError(t, os.WriteFile(filepath.Join(tempDir, "ai.enc"), []byte("{invalid"), 0644))
// Without encryption, it's just json
// If encryption enabled (not in this test), behaviour changes.
// If crypto nil:
// Persistence.LoadAIConfig attempts decrypt if crypto != nil.
// If Unmarshal fails:
_, err = p.LoadAIConfig()
assert.Error(t, err)
}
func TestPersistence_AIConfig_MigratesSuggestControlLevel(t *testing.T) {
tempDir := t.TempDir()
p := NewConfigPersistence(tempDir)
cfg := NewDefaultAIConfig()
cfg.ControlLevel = "suggest"
require.NoError(t, p.SaveAIConfig(*cfg))
loaded, err := p.LoadAIConfig()
require.NoError(t, err)
assert.Equal(t, ControlLevelControlled, loaded.ControlLevel)
updatedRaw, err := os.ReadFile(filepath.Join(tempDir, "ai.enc"))
require.NoError(t, err)
if p.crypto != nil {
decoded, err := p.crypto.Decrypt(updatedRaw)
require.NoError(t, err)
updatedRaw = decoded
}
var saved AIConfig
require.NoError(t, json.Unmarshal(updatedRaw, &saved))
assert.Equal(t, ControlLevelControlled, saved.ControlLevel)
}
func TestPersistence_PatrolRunHistory(t *testing.T) {
tempDir := t.TempDir()
p := NewConfigPersistence(tempDir)
hist, err := p.LoadPatrolRunHistory()
require.NoError(t, err)
assert.Empty(t, hist.Runs)
hist.Runs = append(hist.Runs, PatrolRunRecord{ID: "run1"})
err = p.SavePatrolRunHistory(hist.Runs)
require.NoError(t, err)
loaded, err := p.LoadPatrolRunHistory()
require.NoError(t, err)
assert.Len(t, loaded.Runs, 1)
// Corrupt
require.NoError(t, os.WriteFile(filepath.Join(tempDir, "ai_patrol_runs.json"), []byte("{invalid"), 0644))
loaded, err = p.LoadPatrolRunHistory()
require.NoError(t, err) // Returns empty on error
assert.Empty(t, loaded.Runs)
}