Pulse/internal/api/chat_service_adapter_test.go
rcourtman e86c25c771 test(api): increase coverage for discovery and chat adapter
- Add comprehensive tests for discovery_handlers.go (~75% coverage)
- Add tests for chat_service_adapter.go (previously 0% coverage)
- Fix missing API key issues in chat adapter tests by using ollama model configuration
2026-02-02 14:53:52 +00:00

120 lines
4.1 KiB
Go

package api
import (
"context"
"testing"
"github.com/rcourtman/pulse-go-rewrite/internal/ai/chat"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Mock implementation of chat.StateProvider
type mockChatStateProvider struct{}
func (m *mockChatStateProvider) GetState() interface{} { return nil } // simplified for test
func TestChatServiceAdapter_CreateSession(t *testing.T) {
// Setup real chat service with minimal config
cfg := chat.Config{
DataDir: t.TempDir(),
AIConfig: &config.AIConfig{
ChatModel: "ollama:llama3",
},
}
realSvc := chat.NewService(cfg)
require.NoError(t, realSvc.Start(context.Background()))
defer realSvc.Stop(context.Background())
// Create adapter
adapter := &chatServiceAdapter{svc: realSvc}
// Test
session, err := adapter.CreateSession(context.Background())
require.NoError(t, err)
assert.NotEmpty(t, session.ID)
}
func TestChatServiceAdapter_GetMessages(t *testing.T) {
// Setup real chat service
cfg := chat.Config{
DataDir: t.TempDir(),
AIConfig: &config.AIConfig{
ChatModel: "ollama:llama3",
},
}
realSvc := chat.NewService(cfg)
require.NoError(t, realSvc.Start(context.Background()))
defer realSvc.Stop(context.Background())
// Seed a session and message directly into the real service's store?
// Since we can't easily inject into the private store, we'll use the public API of the real service
// BUT chat.Service.ExecuteStream is hard to use without a real AI provider.
//
// However, we can use CreateSession via adapter, then maybe we can't *add* messages easily
// because `adapter` doesn't expose AddMessage.
//
// We can use the real service's internal SessionStore if we can access it...
// But it's private `sessions *SessionStore`.
//
// Wait, internal/ai/chat/service.go has CreateSession but not AddMessage exposed directly?
// It does! But we need `CreateSession` first.
// Let's rely on the fact that `ExecuteStream` adds a user message.
// But `ExecuteStream` will try to call the AI provider and fail if we don't mock it.
// `chat.NewService` doesn't allow easy mocking of the provider factory (it's unexported).
// Actually, looking at `internal/ai/chat/service.go`, `CreateSession` is exposed.
// But `AddMessage` is NOT exposed on Service.
// So `GetMessages` test is hard without a way to insert messages.
// Unless... we can modify `chat.Service` to be more testable, OR we skip `GetMessages` integration test
// and accept that `CreateSession` coverage proves the wiring is correct.
// Let's stick to CreateSession and implicit interface satisfaction tests.
adapter := &chatServiceAdapter{svc: realSvc}
// Verify interface compliance (compile-time check)
// var _ ai.ChatServiceProvider = adapter // We can't do this easily inside the test function
// but the fact that it compiles is enough.
// Just reuse the session creation test.
session, err := adapter.CreateSession(context.Background())
require.NoError(t, err)
// Try to get messages for empty session
msgs, err := adapter.GetMessages(context.Background(), session.ID)
require.NoError(t, err)
assert.Empty(t, msgs)
// Try delete
err = adapter.DeleteSession(context.Background(), session.ID)
require.NoError(t, err)
}
func TestChatServiceAdapter_ReloadConfig(t *testing.T) {
cfg := chat.Config{
DataDir: t.TempDir(),
AIConfig: &config.AIConfig{ChatModel: "ollama:llama3"},
}
realSvc := chat.NewService(cfg)
require.NoError(t, realSvc.Start(context.Background()))
adapter := &chatServiceAdapter{svc: realSvc}
newCfg := &config.AIConfig{ChatModel: "ollama:llama3"}
err := adapter.ReloadConfig(context.Background(), newCfg)
require.NoError(t, err)
}
func TestChatServiceAdapter_GetExecutor(t *testing.T) {
cfg := chat.Config{DataDir: t.TempDir(), AIConfig: &config.AIConfig{}}
realSvc := chat.NewService(cfg)
adapter := &chatServiceAdapter{svc: realSvc}
exec := adapter.GetExecutor()
// It might be nil if not fully initialized or config not set, but assert we get value or nil
// actually NewService initializes executor.
assert.NotNil(t, exec)
}