初始化仓库
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/chenhg5/cc-connect/core"
|
||||
)
|
||||
|
||||
// TestMessage creates a basic test message with sensible defaults.
|
||||
func TestMessage() *core.Message {
|
||||
return &core.Message{
|
||||
SessionKey: "test:channel:user",
|
||||
Platform: "test",
|
||||
MessageID: "msg-test-001",
|
||||
UserID: "user-test",
|
||||
UserName: "Test User",
|
||||
ChatName: "Test Channel",
|
||||
Content: "Hello, world",
|
||||
ReplyCtx: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// TestMessageWithContent creates a message with specific content.
|
||||
func TestMessageWithContent(content string) *core.Message {
|
||||
msg := TestMessage()
|
||||
msg.Content = content
|
||||
return msg
|
||||
}
|
||||
|
||||
// TestMessageWithSession creates a message with a specific session key.
|
||||
func TestMessageWithSession(sessionKey string) *core.Message {
|
||||
msg := TestMessage()
|
||||
msg.SessionKey = sessionKey
|
||||
return msg
|
||||
}
|
||||
|
||||
// TestMessageWithImages creates a message with images.
|
||||
func TestMessageWithImages(images []core.ImageAttachment) *core.Message {
|
||||
msg := TestMessage()
|
||||
msg.Images = images
|
||||
return msg
|
||||
}
|
||||
|
||||
// TestMessageWithFiles creates a message with files.
|
||||
func TestMessageWithFiles(files []core.FileAttachment) *core.Message {
|
||||
msg := TestMessage()
|
||||
msg.Files = files
|
||||
return msg
|
||||
}
|
||||
|
||||
// TestMessageWithAudio creates a message with audio.
|
||||
func TestMessageWithAudio(audio *core.AudioAttachment) *core.Message {
|
||||
msg := TestMessage()
|
||||
msg.Audio = audio
|
||||
return msg
|
||||
}
|
||||
|
||||
// TestMessageFromVoice creates a message that originated from voice.
|
||||
func TestMessageFromVoice(content string) *core.Message {
|
||||
msg := TestMessageWithContent(content)
|
||||
msg.FromVoice = true
|
||||
return msg
|
||||
}
|
||||
|
||||
// TestLongMessage creates a message with a very long content for truncation testing.
|
||||
func TestLongMessage(length int) *core.Message {
|
||||
return &core.Message{
|
||||
SessionKey: "test:channel:user",
|
||||
Platform: "test",
|
||||
MessageID: "msg-test-long",
|
||||
UserID: "user-test",
|
||||
Content: strings.Repeat("x", length),
|
||||
}
|
||||
}
|
||||
|
||||
// TestSpecialCharsMessage creates a message with special characters for security testing.
|
||||
func TestSpecialCharsMessage() *core.Message {
|
||||
return &core.Message{
|
||||
SessionKey: "test:channel:user",
|
||||
Platform: "test",
|
||||
MessageID: "msg-test-special",
|
||||
UserID: "user-test",
|
||||
Content: "Hello! 🎉 <script>alert('xss')</script> & \"quotes\"",
|
||||
}
|
||||
}
|
||||
|
||||
// TestImageAttachment creates a test image attachment.
|
||||
func TestImageAttachment(mimeType, filename string, data []byte) core.ImageAttachment {
|
||||
return core.ImageAttachment{
|
||||
MimeType: mimeType,
|
||||
Data: data,
|
||||
FileName: filename,
|
||||
}
|
||||
}
|
||||
|
||||
// TestFileAttachment creates a test file attachment.
|
||||
func TestFileAttachment(mimeType, filename string, data []byte) core.FileAttachment {
|
||||
return core.FileAttachment{
|
||||
MimeType: mimeType,
|
||||
Data: data,
|
||||
FileName: filename,
|
||||
}
|
||||
}
|
||||
|
||||
// TestAudioAttachment creates a test audio attachment.
|
||||
func TestAudioAttachment(mimeType, format string, data []byte, duration int) *core.AudioAttachment {
|
||||
return &core.AudioAttachment{
|
||||
MimeType: mimeType,
|
||||
Data: data,
|
||||
Format: format,
|
||||
Duration: duration,
|
||||
}
|
||||
}
|
||||
|
||||
// TestEvent creates a test event.
|
||||
func TestEvent(eventType core.EventType, content string) core.Event {
|
||||
return core.Event{
|
||||
Type: eventType,
|
||||
Content: content,
|
||||
Done: eventType == core.EventResult || eventType == core.EventError,
|
||||
}
|
||||
}
|
||||
|
||||
// TestTextEvent creates a text event.
|
||||
func TestTextEvent(content string) core.Event {
|
||||
return TestEvent(core.EventText, content)
|
||||
}
|
||||
|
||||
// TestResultEvent creates a result event.
|
||||
func TestResultEvent(content string) core.Event {
|
||||
return TestEvent(core.EventResult, content)
|
||||
}
|
||||
|
||||
// TestErrorEvent creates an error event.
|
||||
func TestErrorEvent(err error) core.Event {
|
||||
return core.Event{
|
||||
Type: core.EventError,
|
||||
Done: true,
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
|
||||
// TestPermissionRequestEvent creates a permission request event.
|
||||
func TestPermissionRequestEvent(requestID, toolName, toolInput string) core.Event {
|
||||
return core.Event{
|
||||
Type: core.EventPermissionRequest,
|
||||
ToolName: toolName,
|
||||
ToolInput: toolInput,
|
||||
RequestID: requestID,
|
||||
}
|
||||
}
|
||||
|
||||
// TestToolUseEvent creates a tool use event.
|
||||
func TestToolUseEvent(toolName, toolInput string) core.Event {
|
||||
return core.Event{
|
||||
Type: core.EventToolUse,
|
||||
ToolName: toolName,
|
||||
ToolInput: toolInput,
|
||||
}
|
||||
}
|
||||
|
||||
// TestThinkingEvent creates a thinking event.
|
||||
func TestThinkingEvent(content string) core.Event {
|
||||
return TestEvent(core.EventThinking, content)
|
||||
}
|
||||
|
||||
// TestHistoryEntry creates a test history entry.
|
||||
func TestHistoryEntry(role, content string) core.HistoryEntry {
|
||||
return core.HistoryEntry{
|
||||
Role: role,
|
||||
Content: content,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// TestAgentSessionInfo creates a test agent session info.
|
||||
func TestAgentSessionInfo(id, summary string, messageCount int) core.AgentSessionInfo {
|
||||
return core.AgentSessionInfo{
|
||||
ID: id,
|
||||
Summary: summary,
|
||||
MessageCount: messageCount,
|
||||
ModifiedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// TestPermissionResult creates a test permission result.
|
||||
func TestPermissionResultAllow() core.PermissionResult {
|
||||
return core.PermissionResult{
|
||||
Behavior: "allow",
|
||||
}
|
||||
}
|
||||
|
||||
func TestPermissionResultDeny(message string) core.PermissionResult {
|
||||
return core.PermissionResult{
|
||||
Behavior: "deny",
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// TestProviderConfig creates a test provider config.
|
||||
func TestProviderConfig(name, apiKey, baseURL, model string) core.ProviderConfig {
|
||||
return core.ProviderConfig{
|
||||
Name: name,
|
||||
APIKey: apiKey,
|
||||
BaseURL: baseURL,
|
||||
Model: model,
|
||||
}
|
||||
}
|
||||
|
||||
// TestModelOption creates a test model option.
|
||||
func TestModelOption(name, desc, alias string) core.ModelOption {
|
||||
return core.ModelOption{
|
||||
Name: name,
|
||||
Desc: desc,
|
||||
Alias: alias,
|
||||
}
|
||||
}
|
||||
|
||||
// BatchTestMessages creates multiple test messages for batch testing.
|
||||
func BatchTestMessages(count int) []*core.Message {
|
||||
messages := make([]*core.Message, count)
|
||||
for i := 0; i < count; i++ {
|
||||
messages[i] = TestMessageWithContent(fmt.Sprintf("Test message %d", i))
|
||||
}
|
||||
return messages
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/chenhg5/cc-connect/core"
|
||||
)
|
||||
|
||||
// TestUsageReport creates a test usage report.
|
||||
func TestUsageReport(provider, accountID, email string) *core.UsageReport {
|
||||
return &core.UsageReport{
|
||||
Provider: provider,
|
||||
AccountID: accountID,
|
||||
UserID: "test-user",
|
||||
Email: email,
|
||||
Plan: "pro",
|
||||
Buckets: []core.UsageBucket{
|
||||
{
|
||||
Name: "Standard Requests",
|
||||
Allowed: true,
|
||||
LimitReached: false,
|
||||
Windows: []core.UsageWindow{
|
||||
{UsedPercent: 45, WindowSeconds: 3600},
|
||||
},
|
||||
},
|
||||
},
|
||||
Credits: &core.UsageCredits{
|
||||
HasCredits: true,
|
||||
Unlimited: false,
|
||||
Balance: "$12.50",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TestPermissionModeInfo creates a test permission mode info.
|
||||
func TestPermissionModeInfo(key, name, nameZh, desc, descZh string) core.PermissionModeInfo {
|
||||
return core.PermissionModeInfo{
|
||||
Key: key,
|
||||
Name: name,
|
||||
NameZh: nameZh,
|
||||
Desc: desc,
|
||||
DescZh: descZh,
|
||||
}
|
||||
}
|
||||
|
||||
// TestCard creates a test card using the CardBuilder.
|
||||
func TestCard() *core.Card {
|
||||
return core.NewCard().
|
||||
Title("Test Card", "blue").
|
||||
Markdown("**Test content**").
|
||||
Build()
|
||||
}
|
||||
|
||||
// TestCardWithTitle creates a card with a specific title.
|
||||
func TestCardWithTitle(title string) *core.Card {
|
||||
return core.NewCard().
|
||||
Title(title, "blue").
|
||||
Markdown("**Content**").
|
||||
Build()
|
||||
}
|
||||
|
||||
// TestCardWithButtons creates a card with buttons.
|
||||
func TestCardWithButtons(buttons ...core.CardButton) *core.Card {
|
||||
return core.NewCard().
|
||||
Title("Test Card", "blue").
|
||||
Markdown("Select an option:").
|
||||
Buttons(buttons...).
|
||||
Build()
|
||||
}
|
||||
|
||||
// TestMessageHandler is a simple message handler for testing.
|
||||
type TestMessageHandler struct {
|
||||
mu sync.Mutex
|
||||
Messages []*core.Message
|
||||
}
|
||||
|
||||
func NewTestMessageHandler() *TestMessageHandler {
|
||||
return &TestMessageHandler{
|
||||
Messages: make([]*core.Message, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *TestMessageHandler) Handle(p core.Platform, msg *core.Message) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.Messages = append(h.Messages, msg)
|
||||
}
|
||||
|
||||
func (h *TestMessageHandler) GetMessages() []*core.Message {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
cp := make([]*core.Message, len(h.Messages))
|
||||
copy(cp, h.Messages)
|
||||
return cp
|
||||
}
|
||||
|
||||
func (h *TestMessageHandler) Clear() {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
h.Messages = h.Messages[:0]
|
||||
}
|
||||
|
||||
// TestDedupeItem creates a test deduplication item.
|
||||
type TestDedupeItem struct {
|
||||
key string
|
||||
expiration time.Time
|
||||
}
|
||||
|
||||
func NewTestDedupeItem(key string, ttl time.Duration) *TestDedupeItem {
|
||||
return &TestDedupeItem{
|
||||
key: key,
|
||||
expiration: time.Now().Add(ttl),
|
||||
}
|
||||
}
|
||||
|
||||
// TestRateLimiterToken creates a test rate limiter token bucket state.
|
||||
type TestRateLimiterToken struct{}
|
||||
|
||||
// TestCronJob creates a test cron job.
|
||||
func TestCronJob(id, desc, prompt string, cronExpr string) *core.CronJob {
|
||||
enabled := true
|
||||
return &core.CronJob{
|
||||
ID: id,
|
||||
Description: desc,
|
||||
Prompt: prompt,
|
||||
CronExpr: cronExpr,
|
||||
Enabled: enabled,
|
||||
}
|
||||
}
|
||||
|
||||
// TestAgentSessionInfoList creates a list of test agent session info.
|
||||
func TestAgentSessionInfoList(count int) []core.AgentSessionInfo {
|
||||
sessions := make([]core.AgentSessionInfo, count)
|
||||
for i := 0; i < count; i++ {
|
||||
sessions[i] = core.AgentSessionInfo{
|
||||
ID: fmt.Sprintf("session-%d", i),
|
||||
Summary: fmt.Sprintf("Test session %d", i),
|
||||
MessageCount: (i + 1) * 10,
|
||||
ModifiedAt: time.Now().Add(-time.Duration(i) * time.Hour),
|
||||
}
|
||||
}
|
||||
return sessions
|
||||
}
|
||||
|
||||
// TestContext returns a context with timeout for testing.
|
||||
func TestContext(timeout time.Duration) (context.Context, context.CancelFunc) {
|
||||
return context.WithTimeout(context.Background(), timeout)
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/chenhg5/cc-connect/core"
|
||||
)
|
||||
|
||||
// FakeAgentSession is a fake implementation of AgentSession for testing.
|
||||
// It simulates agent behavior without calling real CLI tools.
|
||||
type FakeAgentSession struct {
|
||||
mu sync.RWMutex
|
||||
sessionID string
|
||||
promptQueue []string
|
||||
events []core.Event
|
||||
closed bool
|
||||
alive bool
|
||||
responseDelay time.Duration
|
||||
responses []string
|
||||
responseIdx int
|
||||
}
|
||||
|
||||
func NewFakeAgentSession(sessionID string) *FakeAgentSession {
|
||||
return &FakeAgentSession{
|
||||
sessionID: sessionID,
|
||||
alive: true,
|
||||
events: make([]core.Event, 0),
|
||||
promptQueue: make([]string, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// SetResponseDelay sets a delay before sending responses (for timeout testing).
|
||||
func (s *FakeAgentSession) SetResponseDelay(delay time.Duration) *FakeAgentSession {
|
||||
s.responseDelay = delay
|
||||
return s
|
||||
}
|
||||
|
||||
// SetResponses sets predefined responses to return.
|
||||
func (s *FakeAgentSession) SetResponses(responses ...string) *FakeAgentSession {
|
||||
s.responses = responses
|
||||
return s
|
||||
}
|
||||
|
||||
// AddTextEvent adds a text event to the event stream.
|
||||
func (s *FakeAgentSession) AddTextEvent(content string) *FakeAgentSession {
|
||||
s.events = append(s.events, TestTextEvent(content))
|
||||
return s
|
||||
}
|
||||
|
||||
// AddResultEvent adds a result event to the event stream.
|
||||
func (s *FakeAgentSession) AddResultEvent(content string) *FakeAgentSession {
|
||||
s.events = append(s.events, TestResultEvent(content))
|
||||
return s
|
||||
}
|
||||
|
||||
// AddErrorEvent adds an error event to the event stream.
|
||||
func (s *FakeAgentSession) AddErrorEvent(err error) *FakeAgentSession {
|
||||
s.events = append(s.events, TestErrorEvent(err))
|
||||
return s
|
||||
}
|
||||
|
||||
// AddThinkingEvent adds a thinking event to the event stream.
|
||||
func (s *FakeAgentSession) AddThinkingEvent(content string) *FakeAgentSession {
|
||||
s.events = append(s.events, TestThinkingEvent(content))
|
||||
return s
|
||||
}
|
||||
|
||||
// AddPermissionRequest adds a permission request event.
|
||||
func (s *FakeAgentSession) AddPermissionRequest(requestID, toolName, toolInput string) *FakeAgentSession {
|
||||
s.events = append(s.events, TestPermissionRequestEvent(requestID, toolName, toolInput))
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *FakeAgentSession) Send(prompt string, images []core.ImageAttachment, files []core.FileAttachment) error {
|
||||
s.mu.Lock()
|
||||
if s.closed {
|
||||
s.mu.Unlock()
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
|
||||
s.promptQueue = append(s.promptQueue, prompt)
|
||||
|
||||
if len(s.events) == 0 {
|
||||
if len(s.responses) > 0 && s.responseIdx < len(s.responses) {
|
||||
resp := s.responses[s.responseIdx]
|
||||
s.responseIdx++
|
||||
s.events = append(s.events, TestTextEvent(resp), TestResultEvent(resp))
|
||||
} else {
|
||||
s.events = append(s.events, TestTextEvent("Processing: "+prompt), TestResultEvent("Done"))
|
||||
}
|
||||
}
|
||||
delay := s.responseDelay
|
||||
s.mu.Unlock()
|
||||
|
||||
if delay > 0 {
|
||||
time.Sleep(delay)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FakeAgentSession) RespondPermission(requestID string, result core.PermissionResult) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.events = append(s.events, core.Event{
|
||||
Type: core.EventToolResult,
|
||||
Content: "Permission " + result.Behavior,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FakeAgentSession) Events() <-chan core.Event {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
needsDone := len(s.events) == 0 || !s.events[len(s.events)-1].Done
|
||||
bufSize := len(s.events)
|
||||
if needsDone {
|
||||
bufSize++
|
||||
}
|
||||
ch := make(chan core.Event, bufSize)
|
||||
for _, e := range s.events {
|
||||
ch <- e
|
||||
}
|
||||
if needsDone {
|
||||
ch <- core.Event{Type: core.EventResult, Done: true}
|
||||
}
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
func (s *FakeAgentSession) CurrentSessionID() string {
|
||||
return s.sessionID
|
||||
}
|
||||
|
||||
func (s *FakeAgentSession) Alive() bool {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.alive && !s.closed
|
||||
}
|
||||
|
||||
func (s *FakeAgentSession) Close() error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.alive = false
|
||||
s.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPrompts returns all prompts sent to this session (for verification).
|
||||
func (s *FakeAgentSession) GetPrompts() []string {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
return s.promptQueue
|
||||
}
|
||||
|
||||
// FakeAgent is a fake implementation of Agent for testing.
|
||||
type FakeAgent struct {
|
||||
name string
|
||||
sessionID string
|
||||
session *FakeAgentSession
|
||||
preConfiguredSession *FakeAgentSession // session from NewFakeAgentWithSession
|
||||
sessions []core.AgentSessionInfo
|
||||
stopped bool
|
||||
}
|
||||
|
||||
func NewFakeAgent(name string) *FakeAgent {
|
||||
return &FakeAgent{
|
||||
name: name,
|
||||
sessionID: "fake-session-001",
|
||||
sessions: []core.AgentSessionInfo{
|
||||
{ID: "fake-session-001", Summary: "Test session"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *FakeAgent) Name() string {
|
||||
return a.name
|
||||
}
|
||||
|
||||
func (a *FakeAgent) StartSession(ctx context.Context, sessionID string) (core.AgentSession, error) {
|
||||
a.sessionID = sessionID
|
||||
// Return pre-configured session on first call (from NewFakeAgentWithSession)
|
||||
// then create fresh sessions for subsequent calls
|
||||
if a.preConfiguredSession != nil {
|
||||
a.session = a.preConfiguredSession
|
||||
a.preConfiguredSession = nil
|
||||
return a.session, nil
|
||||
}
|
||||
a.session = NewFakeAgentSession(sessionID)
|
||||
return a.session, nil
|
||||
}
|
||||
|
||||
func (a *FakeAgent) ListSessions(ctx context.Context) ([]core.AgentSessionInfo, error) {
|
||||
return a.sessions, nil
|
||||
}
|
||||
|
||||
func (a *FakeAgent) Stop() error {
|
||||
a.stopped = true
|
||||
if a.session != nil {
|
||||
a.session.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSession returns the current fake session.
|
||||
func (a *FakeAgent) GetSession() *FakeAgentSession {
|
||||
return a.session
|
||||
}
|
||||
|
||||
// NewFakeAgentWithSession creates a fake agent with a pre-configured session.
|
||||
// The pre-configured session is returned on the first StartSession call.
|
||||
// Subsequent StartSession calls create fresh sessions (simulating real agent behavior).
|
||||
func NewFakeAgentWithSession(name, sessionID string, session *FakeAgentSession) *FakeAgent {
|
||||
return &FakeAgent{
|
||||
name: name,
|
||||
preConfiguredSession: session,
|
||||
sessionID: sessionID,
|
||||
sessions: []core.AgentSessionInfo{
|
||||
{ID: sessionID, Summary: "Test session"},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/chenhg5/cc-connect/core"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockAgent is a mock implementation of the core.Agent interface.
|
||||
type MockAgent struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *MockAgent) Name() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
func (m *MockAgent) StartSession(ctx context.Context, sessionID string) (core.AgentSession, error) {
|
||||
args := m.Called(ctx, sessionID)
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
return args.Get(0).(core.AgentSession), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *MockAgent) ListSessions(ctx context.Context) ([]core.AgentSessionInfo, error) {
|
||||
args := m.Called(ctx)
|
||||
return args.Get(0).([]core.AgentSessionInfo), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *MockAgent) Stop() error {
|
||||
args := m.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// MockAgentSession is a mock implementation of the core.AgentSession interface.
|
||||
type MockAgentSession struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *MockAgentSession) Send(prompt string, images []core.ImageAttachment, files []core.FileAttachment) error {
|
||||
args := m.Called(prompt, images, files)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentSession) RespondPermission(requestID string, result core.PermissionResult) error {
|
||||
args := m.Called(requestID, result)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentSession) Events() <-chan core.Event {
|
||||
args := m.Called()
|
||||
return args.Get(0).(<-chan core.Event)
|
||||
}
|
||||
|
||||
func (m *MockAgentSession) CurrentSessionID() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentSession) Alive() bool {
|
||||
args := m.Called()
|
||||
return args.Bool(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentSession) Close() error {
|
||||
args := m.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// MockAgentWithProviders is a mock agent that also implements ProviderSwitcher.
|
||||
type MockAgentWithProviders struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithProviders) SetProviders(providers []core.ProviderConfig) {
|
||||
m.Called(providers)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithProviders) SetActiveProvider(name string) bool {
|
||||
args := m.Called(name)
|
||||
return args.Bool(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithProviders) GetActiveProvider() *core.ProviderConfig {
|
||||
args := m.Called()
|
||||
if args.Get(0) == nil {
|
||||
return nil
|
||||
}
|
||||
return args.Get(0).(*core.ProviderConfig)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithProviders) ListProviders() []core.ProviderConfig {
|
||||
args := m.Called()
|
||||
return args.Get(0).([]core.ProviderConfig)
|
||||
}
|
||||
|
||||
// MockAgentWithModel is a mock agent that also implements ModelSwitcher.
|
||||
type MockAgentWithModel struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithModel) SetModel(model string) {
|
||||
m.Called(model)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithModel) GetModel() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithModel) AvailableModels(ctx context.Context) []core.ModelOption {
|
||||
args := m.Called(ctx)
|
||||
return args.Get(0).([]core.ModelOption)
|
||||
}
|
||||
|
||||
// MockAgentWithMode is a mock agent that also implements ModeSwitcher.
|
||||
type MockAgentWithMode struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithMode) SetMode(mode string) {
|
||||
m.Called(mode)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithMode) GetMode() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithMode) PermissionModes() []core.PermissionModeInfo {
|
||||
args := m.Called()
|
||||
return args.Get(0).([]core.PermissionModeInfo)
|
||||
}
|
||||
|
||||
// MockAgentWithToolAuth is a mock agent that also implements ToolAuthorizer.
|
||||
type MockAgentWithToolAuth struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithToolAuth) AddAllowedTools(tools ...string) error {
|
||||
args := m.Called(tools)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithToolAuth) GetAllowedTools() []string {
|
||||
args := m.Called()
|
||||
return args.Get(0).([]string)
|
||||
}
|
||||
|
||||
// MockAgentWithHistory is a mock agent that also implements HistoryProvider.
|
||||
type MockAgentWithHistory struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithHistory) GetSessionHistory(ctx context.Context, sessionID string, limit int) ([]core.HistoryEntry, error) {
|
||||
args := m.Called(ctx, sessionID, limit)
|
||||
return args.Get(0).([]core.HistoryEntry), args.Error(1)
|
||||
}
|
||||
|
||||
// MockAgentWithUsage is a mock agent that also implements UsageReporter.
|
||||
type MockAgentWithUsage struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithUsage) GetUsage(ctx context.Context) (*core.UsageReport, error) {
|
||||
args := m.Called(ctx)
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
return args.Get(0).(*core.UsageReport), args.Error(1)
|
||||
}
|
||||
|
||||
// MockAgentWithMemory is a mock agent that also implements MemoryFileProvider.
|
||||
type MockAgentWithMemory struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithMemory) ProjectMemoryFile() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithMemory) GlobalMemoryFile() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
// MockAgentWithWorkDir is a mock agent that also implements WorkDirSwitcher.
|
||||
type MockAgentWithWorkDir struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithWorkDir) SetWorkDir(dir string) {
|
||||
m.Called(dir)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithWorkDir) GetWorkDir() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
// MockAgentWithSkill is a mock agent that also implements SkillProvider.
|
||||
type MockAgentWithSkill struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithSkill) SkillDirs() []string {
|
||||
args := m.Called()
|
||||
return args.Get(0).([]string)
|
||||
}
|
||||
|
||||
// MockAgentWithCommand is a mock agent that also implements CommandProvider.
|
||||
type MockAgentWithCommand struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithCommand) CommandDirs() []string {
|
||||
args := m.Called()
|
||||
return args.Get(0).([]string)
|
||||
}
|
||||
|
||||
// MockAgentWithContextCompressor is a mock agent that also implements ContextCompressor.
|
||||
type MockAgentWithContextCompressor struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithContextCompressor) CompressCommand() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
// MockAgentWithReasoning is a mock agent that also implements ReasoningEffortSwitcher.
|
||||
type MockAgentWithReasoning struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithReasoning) SetReasoningEffort(effort string) {
|
||||
m.Called(effort)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithReasoning) GetReasoningEffort() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
func (m *MockAgentWithReasoning) AvailableReasoningEfforts() []string {
|
||||
args := m.Called()
|
||||
return args.Get(0).([]string)
|
||||
}
|
||||
|
||||
// MockAgentWithSessionDeleter is a mock agent that also implements SessionDeleter.
|
||||
type MockAgentWithSessionDeleter struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithSessionDeleter) DeleteSession(ctx context.Context, sessionID string) error {
|
||||
args := m.Called(ctx, sessionID)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// MockAgentWithSystemPrompt is a mock agent that also implements SystemPromptSupporter.
|
||||
type MockAgentWithSystemPrompt struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithSystemPrompt) HasSystemPromptSupport() bool {
|
||||
args := m.Called()
|
||||
return args.Bool(0)
|
||||
}
|
||||
|
||||
// MockAgentWithPlatformPrompt is a mock agent that also implements PlatformPromptInjector.
|
||||
type MockAgentWithPlatformPrompt struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithPlatformPrompt) SetPlatformPrompt(prompt string) {
|
||||
m.Called(prompt)
|
||||
}
|
||||
|
||||
// MockAgentWithSessionEnv is a mock agent that also implements SessionEnvInjector.
|
||||
type MockAgentWithSessionEnv struct {
|
||||
*MockAgent
|
||||
}
|
||||
|
||||
func (m *MockAgentWithSessionEnv) SetSessionEnv(env []string) {
|
||||
m.Called(env)
|
||||
}
|
||||
|
||||
// MockAgentFull implements all optional interfaces for comprehensive testing.
|
||||
type MockAgentFull struct {
|
||||
*MockAgent
|
||||
*MockAgentWithProviders
|
||||
*MockAgentWithModel
|
||||
*MockAgentWithMode
|
||||
*MockAgentWithToolAuth
|
||||
*MockAgentWithHistory
|
||||
*MockAgentWithUsage
|
||||
*MockAgentWithMemory
|
||||
*MockAgentWithWorkDir
|
||||
*MockAgentWithSkill
|
||||
*MockAgentWithCommand
|
||||
*MockAgentWithContextCompressor
|
||||
*MockAgentWithReasoning
|
||||
*MockAgentWithSessionDeleter
|
||||
*MockAgentWithSystemPrompt
|
||||
*MockAgentWithPlatformPrompt
|
||||
*MockAgentWithSessionEnv
|
||||
}
|
||||
|
||||
func NewMockAgentFull(name string) *MockAgentFull {
|
||||
m := &MockAgentFull{
|
||||
MockAgent: new(MockAgent),
|
||||
MockAgentWithProviders: new(MockAgentWithProviders),
|
||||
MockAgentWithModel: new(MockAgentWithModel),
|
||||
MockAgentWithMode: new(MockAgentWithMode),
|
||||
MockAgentWithToolAuth: new(MockAgentWithToolAuth),
|
||||
MockAgentWithHistory: new(MockAgentWithHistory),
|
||||
MockAgentWithUsage: new(MockAgentWithUsage),
|
||||
MockAgentWithMemory: new(MockAgentWithMemory),
|
||||
MockAgentWithWorkDir: new(MockAgentWithWorkDir),
|
||||
MockAgentWithSkill: new(MockAgentWithSkill),
|
||||
MockAgentWithCommand: new(MockAgentWithCommand),
|
||||
MockAgentWithContextCompressor: new(MockAgentWithContextCompressor),
|
||||
MockAgentWithReasoning: new(MockAgentWithReasoning),
|
||||
MockAgentWithSessionDeleter: new(MockAgentWithSessionDeleter),
|
||||
MockAgentWithSystemPrompt: new(MockAgentWithSystemPrompt),
|
||||
MockAgentWithPlatformPrompt: new(MockAgentWithPlatformPrompt),
|
||||
MockAgentWithSessionEnv: new(MockAgentWithSessionEnv),
|
||||
}
|
||||
m.MockAgent.On("Name").Return(name)
|
||||
return m
|
||||
}
|
||||
|
||||
// EventIterator is a helper for simulating agent events in tests.
|
||||
type EventIterator struct {
|
||||
events []core.Event
|
||||
index int
|
||||
}
|
||||
|
||||
func NewEventIterator(events []core.Event) *EventIterator {
|
||||
return &EventIterator{events: events, index: 0}
|
||||
}
|
||||
|
||||
func (e *EventIterator) Next() (core.Event, bool) {
|
||||
if e.index >= len(e.events) {
|
||||
return core.Event{}, false
|
||||
}
|
||||
event := e.events[e.index]
|
||||
e.index++
|
||||
return event, true
|
||||
}
|
||||
|
||||
func (e *EventIterator) EventChannel() <-chan core.Event {
|
||||
ch := make(chan core.Event, len(e.events))
|
||||
for _, event := range e.events {
|
||||
ch <- event
|
||||
}
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
// NewMockAgentSessionWithEvents creates a mock session that emits predefined events.
|
||||
func NewMockAgentSessionWithEvents(sessionID string, events []core.Event) *MockAgentSession {
|
||||
m := new(MockAgentSession)
|
||||
m.On("CurrentSessionID").Return(sessionID)
|
||||
m.On("Alive").Return(true)
|
||||
m.On("Events").Return(NewEventIterator(events).EventChannel())
|
||||
m.On("Close").Return(nil)
|
||||
m.On("Send", mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
return m
|
||||
}
|
||||
|
||||
// MockEventReader implements io.Reader for testing streaming scenarios.
|
||||
type MockEventReader struct {
|
||||
events []core.Event
|
||||
index int
|
||||
}
|
||||
|
||||
func NewMockEventReader(events []core.Event) *MockEventReader {
|
||||
return &MockEventReader{events: events, index: 0}
|
||||
}
|
||||
|
||||
func (r *MockEventReader) Read(p []byte) (n int, err error) {
|
||||
if r.index >= len(r.events) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
event := r.events[r.index]
|
||||
r.index++
|
||||
data := []byte(event.Content)
|
||||
copy(p, data)
|
||||
return len(data), nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Package mocks provides mock implementations for testing cc-connect components.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/chenhg5/cc-connect/core"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockPlatform is a mock implementation of the core.Platform interface.
|
||||
type MockPlatform struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *MockPlatform) Name() string {
|
||||
args := m.Called()
|
||||
return args.String(0)
|
||||
}
|
||||
|
||||
func (m *MockPlatform) Start(handler core.MessageHandler) error {
|
||||
args := m.Called(handler)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *MockPlatform) Reply(ctx context.Context, replyCtx any, content string) error {
|
||||
args := m.Called(ctx, replyCtx, content)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *MockPlatform) Send(ctx context.Context, replyCtx any, content string) error {
|
||||
args := m.Called(ctx, replyCtx, content)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *MockPlatform) Stop() error {
|
||||
args := m.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// MockPlatformWithReplyCtxReconstructor is a mock platform that also implements
|
||||
// ReplyContextReconstructor for testing cron job scenarios.
|
||||
type MockPlatformWithReplyCtxReconstructor struct {
|
||||
*MockPlatform
|
||||
}
|
||||
|
||||
func (m *MockPlatformWithReplyCtxReconstructor) ReconstructReplyCtx(sessionKey string) (any, error) {
|
||||
args := m.Called(sessionKey)
|
||||
return args.Get(0), args.Error(1)
|
||||
}
|
||||
Reference in New Issue
Block a user