Files
MonocoEditor-With-Lsp-Backend/backend/internal/completion/manager_test.go
meowrain 3284ce07c7 feat: enhance API and session management with Nacos and Redis integration
- Add Nacos registry for service registration and deregistration.
- Implement Redis registry for session management with heartbeat and session claiming.
- Improve completion service with session handling and request validation.
- Enhance WebSocket handling for completion requests with JSON-RPC support.
- Add tests for new registry implementations and completion manager functionalities.
- Refactor existing code for better readability and maintainability.
2026-02-15 17:46:34 +08:00

129 lines
3.2 KiB
Go

package completion
import (
"context"
"errors"
"fmt"
"testing"
"time"
)
type fakeRuntimeClient struct {
closed bool
}
func (f *fakeRuntimeClient) DidOpen(_ context.Context, _ string, _ string, _ int) error {
return nil
}
func (f *fakeRuntimeClient) DidChange(_ context.Context, _ string, _ string, _ int) error {
return nil
}
func (f *fakeRuntimeClient) Completion(_ context.Context, _ string, _ int, _ int) (Response, error) {
return Response{
Items: []Item{{Label: "ok"}},
}, nil
}
func (f *fakeRuntimeClient) Close() error {
f.closed = true
return nil
}
// 同 language+session 的请求应复用同一个底层 client。
func TestManagerCompleteSelectsLanguageAndSession(t *testing.T) {
createCount := 0
factory := func(_ context.Context, spec LanguageServerSpec, _ string) (RuntimeClient, error) {
createCount++
if spec.Language != "go" {
return nil, fmt.Errorf("unexpected language: %s", spec.Language)
}
return &fakeRuntimeClient{}, nil
}
m := NewManager(ManagerConfig{WorkspaceDir: "."}, []LanguageServerSpec{
{Language: "go", LanguageID: "go", Command: "gopls"},
}, factory)
defer m.Close()
for i := 0; i < 2; i++ {
resp, err := m.Complete(context.Background(), Request{
Language: "go",
SessionID: "s1",
URI: "file:///main.go",
Text: "package main",
Line: 0,
Character: 0,
})
if err != nil {
t.Fatalf("Complete() error = %v", err)
}
if len(resp.Items) != 1 || resp.Items[0].Label != "ok" {
t.Fatalf("unexpected response: %+v", resp)
}
}
if createCount != 1 {
t.Fatalf("expected one client creation, got %d", createCount)
}
}
// 未配置的语言应返回 ErrUnsupportedLanguage。
func TestManagerCompleteUnsupportedLanguage(t *testing.T) {
m := NewManager(ManagerConfig{}, []LanguageServerSpec{
{Language: "go", LanguageID: "go", Command: "gopls"},
}, func(_ context.Context, _ LanguageServerSpec, _ string) (RuntimeClient, error) {
return &fakeRuntimeClient{}, nil
})
defer m.Close()
_, err := m.Complete(context.Background(), Request{
Language: "python",
URI: "file:///main.py",
Text: "print('hi')",
Line: 0,
Character: 0,
})
if !errors.Is(err, ErrUnsupportedLanguage) {
t.Fatalf("expected ErrUnsupportedLanguage, got %v", err)
}
}
// 超过空闲 TTL 的会话应被后台清理并关闭 client。
func TestManagerCleanupIdleSession(t *testing.T) {
client := &fakeRuntimeClient{}
m := NewManager(ManagerConfig{
WorkspaceDir: ".",
SessionTTL: 30 * time.Millisecond,
CleanupInterval: 10 * time.Millisecond,
}, []LanguageServerSpec{
{Language: "go", LanguageID: "go", Command: "gopls"},
}, func(_ context.Context, _ LanguageServerSpec, _ string) (RuntimeClient, error) {
return client, nil
})
defer m.Close()
_, err := m.Complete(context.Background(), Request{
Language: "go",
SessionID: "s2",
URI: "file:///main.go",
Text: "package main",
Line: 0,
Character: 0,
})
if err != nil {
t.Fatalf("Complete() error = %v", err)
}
time.Sleep(90 * time.Millisecond)
sessions := m.ActiveSessions()
if sessions["go"] != 0 {
t.Fatalf("expected session cleanup, got %+v", sessions)
}
if !client.closed {
t.Fatal("expected client to be closed by cleanup")
}
}