Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
356 changes: 356 additions & 0 deletions chatapps/base/adapter_options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
package base

import (
"context"
"log/slog"
"net/http"
"testing"
"time"
)

// =============================================================================
// Adapter Options Tests
// =============================================================================

func TestWithSessionTimeout(t *testing.T) {
adapter := &Adapter{
sessionTimeout: 30 * time.Minute,
}

opt := WithSessionTimeout(15 * time.Minute)
opt(adapter)

if adapter.sessionTimeout != 15*time.Minute {
t.Errorf("sessionTimeout = %v, want %v", adapter.sessionTimeout, 15*time.Minute)
}
}

func TestWithSessionTimeout_ZeroValue(t *testing.T) {
adapter := &Adapter{
sessionTimeout: 30 * time.Minute,
}

opt := WithSessionTimeout(0)
opt(adapter)

// Zero value should not change the timeout
if adapter.sessionTimeout != 30*time.Minute {
t.Errorf("sessionTimeout = %v, want %v", adapter.sessionTimeout, 30*time.Minute)
}
}

func TestWithCleanupInterval(t *testing.T) {
adapter := &Adapter{
cleanupInterval: 5 * time.Minute,
}

opt := WithCleanupInterval(10 * time.Minute)
opt(adapter)

if adapter.cleanupInterval != 10*time.Minute {
t.Errorf("cleanupInterval = %v, want %v", adapter.cleanupInterval, 10*time.Minute)
}
}

func TestWithCleanupInterval_ZeroValue(t *testing.T) {
adapter := &Adapter{
cleanupInterval: 5 * time.Minute,
}

opt := WithCleanupInterval(0)
opt(adapter)

// Zero value should not change the interval
if adapter.cleanupInterval != 5*time.Minute {
t.Errorf("cleanupInterval = %v, want %v", adapter.cleanupInterval, 5*time.Minute)
}
}

func TestWithMetadataExtractor(t *testing.T) {
adapter := &Adapter{}

extractor := func(update any) map[string]any {
return map[string]any{"test": "value"}
}

opt := WithMetadataExtractor(extractor)
opt(adapter)

if adapter.metadataExtract == nil {
t.Error("metadataExtract should be set")
}
}

func TestWithMessageParser(t *testing.T) {
adapter := &Adapter{}

parser := func(body []byte, metadata map[string]any) (*ChatMessage, error) {
return &ChatMessage{Content: "test"}, nil
}

opt := WithMessageParser(parser)
opt(adapter)

if adapter.messageParser == nil {
t.Error("messageParser should be set")
}
}

func TestWithMessageSender(t *testing.T) {
adapter := &Adapter{}

sender := func(ctx context.Context, sessionID string, msg *ChatMessage) error {
return nil
}

opt := WithMessageSender(sender)
opt(adapter)

if adapter.messageSender == nil {
t.Error("messageSender should be set")
}
}

func TestWithHTTPHandler(t *testing.T) {
adapter := &Adapter{
httpHandlers: make(map[string]http.HandlerFunc),
}

handler := func(w http.ResponseWriter, r *http.Request) {}

opt := WithHTTPHandler("/webhook", handler)
opt(adapter)

if _, ok := adapter.httpHandlers["/webhook"]; !ok {
t.Error("httpHandlers should contain /webhook")
}
}

func TestWithoutServer(t *testing.T) {
adapter := &Adapter{
disableServer: false,
}

opt := WithoutServer()
opt(adapter)

if !adapter.disableServer {
t.Error("disableServer should be true")
}
}

// =============================================================================
// Adapter Basic Method Tests
// =============================================================================

func TestAdapter_NewAdapter(t *testing.T) {
logger := slog.Default()

adapter := NewAdapter("test", Config{
ServerAddr: ":8080",
SystemPrompt: "You are a test bot",
}, logger)

if adapter == nil {
t.Fatal("NewAdapter() should not return nil")
}

if adapter.platformName != "test" {
t.Errorf("platformName = %v, want 'test'", adapter.platformName)
}

if adapter.config.ServerAddr != ":8080" {
t.Errorf("ServerAddr = %v, want ':8080'", adapter.config.ServerAddr)
}
}

func TestAdapter_NewAdapter_DefaultServerAddr(t *testing.T) {
logger := slog.Default()

adapter := NewAdapter("test", Config{}, logger)

if adapter.config.ServerAddr != ":8080" {
t.Errorf("ServerAddr = %v, want ':8080' (default)", adapter.config.ServerAddr)
}
}

func TestAdapter_Platform(t *testing.T) {
adapter := &Adapter{platformName: "slack"}

if adapter.Platform() != "slack" {
t.Errorf("Platform() = %v, want 'slack'", adapter.Platform())
}
}

func TestAdapter_SystemPrompt(t *testing.T) {
adapter := &Adapter{
config: Config{SystemPrompt: "You are helpful"},
}

if adapter.SystemPrompt() != "You are helpful" {
t.Errorf("SystemPrompt() = %v, want 'You are helpful'", adapter.SystemPrompt())
}
}

func TestAdapter_SetHandler(t *testing.T) {
adapter := &Adapter{}

handler := func(ctx context.Context, msg *ChatMessage) error {
return nil
}

adapter.SetHandler(handler)

// Verify handler is set
adapter.mu.RLock()
h := adapter.handler
adapter.mu.RUnlock()

if h == nil {
t.Error("handler should be set")
}
}

func TestAdapter_Logger(t *testing.T) {
logger := slog.Default()
adapter := &Adapter{logger: logger}

if adapter.Logger() != logger {
t.Error("Logger() should return the same logger")
}
}

func TestAdapter_SetLogger(t *testing.T) {
adapter := &Adapter{}
logger := slog.Default()

adapter.SetLogger(logger)

if adapter.logger != logger {
t.Error("SetLogger() should set the logger")
}
}

func TestAdapter_WebhookPath(t *testing.T) {
adapter := &Adapter{
httpHandlers: map[string]http.HandlerFunc{
"/webhook": nil,
"/events": nil,
},
}

path := adapter.WebhookPath()
if path != "/webhook" {
t.Errorf("WebhookPath() = %v, want '/webhook'", path)
}
}

func TestAdapter_WebhookPath_Empty(t *testing.T) {
adapter := &Adapter{
httpHandlers: make(map[string]http.HandlerFunc),
}

path := adapter.WebhookPath()
if path != "" {
t.Errorf("WebhookPath() = %v, want ''", path)
}
}

func TestAdapter_WebhookHandler(t *testing.T) {
adapter := &Adapter{
httpHandlers: map[string]http.HandlerFunc{
"/webhook": func(w http.ResponseWriter, r *http.Request) {},
},
}

handler := adapter.WebhookHandler()
if handler == nil {
t.Error("WebhookHandler() should not return nil")
}
}

// =============================================================================
// Adapter SendMessage Tests
// =============================================================================

func TestAdapter_SendMessage_NoSender(t *testing.T) {
adapter := &Adapter{}

err := adapter.SendMessage(context.Background(), "session1", &ChatMessage{Content: "test"})
if err == nil {
t.Error("SendMessage() should return error when messageSender is nil")
}
}

func TestAdapter_SendMessage_WithSender(t *testing.T) {
adapter := &Adapter{
messageSender: func(ctx context.Context, sessionID string, msg *ChatMessage) error {
return nil
},
}

err := adapter.SendMessage(context.Background(), "session1", &ChatMessage{Content: "test"})
if err != nil {
t.Errorf("SendMessage() error = %v", err)
}
}

// =============================================================================
// Adapter Session Tests
// =============================================================================

func TestAdapter_GetOrCreateSession_New(t *testing.T) {
adapter := NewAdapter("test", Config{}, slog.Default())

sessionID := adapter.GetOrCreateSession("user1", "bot1", "channel1", "thread1")

if sessionID == "" {
t.Error("sessionID should not be empty")
}

// Just verify we get a session ID back - no need to check internal state
}

func TestAdapter_GetOrCreateSession_Existing(t *testing.T) {
adapter := NewAdapter("test", Config{}, slog.Default())

sessionID1 := adapter.GetOrCreateSession("user1", "bot1", "channel1", "thread1")
sessionID2 := adapter.GetOrCreateSession("user1", "bot1", "channel1", "thread1")

if sessionID1 != sessionID2 {
t.Error("Same inputs should return same session ID")
}
}

func TestAdapter_FindSessionByUserAndChannel(t *testing.T) {
adapter := NewAdapter("test", Config{}, slog.Default())

_ = adapter.GetOrCreateSession("user1", "bot1", "channel1", "thread1")

session := adapter.FindSessionByUserAndChannel("user1", "channel1")
if session == nil {
t.Error("Should find session by user and channel")
}
}

func TestAdapter_FindSessionByUserAndChannel_NotFound(t *testing.T) {
adapter := NewAdapter("test", Config{}, slog.Default())

session := adapter.FindSessionByUserAndChannel("user1", "channel1")
if session != nil {
t.Error("Should not find session that doesn't exist")
}
}

// =============================================================================
// Adapter HandleMessage Tests
// =============================================================================

func TestAdapter_HandleMessage(t *testing.T) {
adapter := &Adapter{}

err := adapter.HandleMessage(context.Background(), &ChatMessage{Content: "test"})
if err != nil {
t.Error("HandleMessage() should return nil by default")
}
}
Loading
Loading