feat: enhance completion service with session management and language support
- Introduced session management using Redis for tracking active sessions. - Added session claiming and releasing functionality in the completion manager. - Enhanced HTTP and WebSocket completion endpoints to support multiple languages. - Implemented request timeout and maximum body size configurations for API routes. - Updated client-side code to handle session IDs and language parameters in completion requests. - Improved error handling for unsupported languages and session conflicts. - Added tests for the completion manager to ensure proper session handling and cleanup.
This commit is contained in:
125
backend/internal/completion/manager_test.go
Normal file
125
backend/internal/completion/manager_test.go
Normal file
@@ -0,0 +1,125 @@
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user