Files
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

149 lines
4.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package completion
import (
"context"
"errors"
"testing"
)
type fakeLSPClient struct {
openCalls []openCall
changeCalls []changeCall
completionCalls []completionCall
completionResp Response
openErr error
changeErr error
completionErr error
}
type openCall struct {
uri string
text string
version int
}
type changeCall struct {
uri string
text string
version int
}
type completionCall struct {
uri string
line int
character int
}
func (f *fakeLSPClient) DidOpen(_ context.Context, uri, text string, version int) error {
f.openCalls = append(f.openCalls, openCall{uri: uri, text: text, version: version})
return f.openErr
}
func (f *fakeLSPClient) DidChange(_ context.Context, uri, text string, version int) error {
f.changeCalls = append(f.changeCalls, changeCall{uri: uri, text: text, version: version})
return f.changeErr
}
func (f *fakeLSPClient) Completion(_ context.Context, uri string, line, character int) (Response, error) {
f.completionCalls = append(f.completionCalls, completionCall{uri: uri, line: line, character: character})
if f.completionErr != nil {
return Response{}, f.completionErr
}
return f.completionResp, nil
}
// 首次请求应发送 didOpen并继续请求 completion。
func TestServiceCompleteFirstRequestSendsDidOpen(t *testing.T) {
fake := &fakeLSPClient{
completionResp: Response{Items: []Item{{Label: "Println"}}, IsIncomplete: true},
}
svc := NewService(fake)
resp, err := svc.Complete(context.Background(), Request{
URI: "file:///main.go",
Text: "package main\nfunc main() { fmt.Pr }",
Line: 1,
Character: 23,
})
if err != nil {
t.Fatalf("Complete() error = %v", err)
}
if len(fake.openCalls) != 1 {
t.Fatalf("expected 1 didOpen call, got %d", len(fake.openCalls))
}
if fake.openCalls[0].version != 1 {
t.Fatalf("expected didOpen version=1, got %d", fake.openCalls[0].version)
}
if len(fake.changeCalls) != 0 {
t.Fatalf("expected 0 didChange calls, got %d", len(fake.changeCalls))
}
if len(fake.completionCalls) != 1 {
t.Fatalf("expected 1 completion call, got %d", len(fake.completionCalls))
}
if !resp.IsIncomplete || len(resp.Items) != 1 || resp.Items[0].Label != "Println" {
t.Fatalf("unexpected response: %+v", resp)
}
}
// 同一文档第二次请求应发送 didChange且版本号递增。
func TestServiceCompleteSecondRequestUsesDidChange(t *testing.T) {
fake := &fakeLSPClient{}
svc := NewService(fake)
_, err := svc.Complete(context.Background(), Request{
URI: "file:///main.go",
Text: "package main\nfunc main() {}",
Line: 1,
Character: 12,
})
if err != nil {
t.Fatalf("first Complete() error = %v", err)
}
_, err = svc.Complete(context.Background(), Request{
URI: "file:///main.go",
Text: "package main\nfunc main() { fmt.Pr }",
Line: 1,
Character: 23,
})
if err != nil {
t.Fatalf("second Complete() error = %v", err)
}
if len(fake.openCalls) != 1 {
t.Fatalf("expected 1 didOpen call, got %d", len(fake.openCalls))
}
if len(fake.changeCalls) != 1 {
t.Fatalf("expected 1 didChange call, got %d", len(fake.changeCalls))
}
if fake.changeCalls[0].version != 2 {
t.Fatalf("expected didChange version=2, got %d", fake.changeCalls[0].version)
}
}
// 参数不合法时应直接返回 ErrInvalidRequest。
func TestServiceCompleteValidatesRequest(t *testing.T) {
svc := NewService(&fakeLSPClient{})
_, err := svc.Complete(context.Background(), Request{URI: "", Text: "", Line: -1, Character: 0})
if !errors.Is(err, ErrInvalidRequest) {
t.Fatalf("expected ErrInvalidRequest, got %v", err)
}
}
// 底层 client 出错应向上透传错误。
func TestServiceCompleteReturnsClientError(t *testing.T) {
fake := &fakeLSPClient{openErr: errors.New("open failed")}
svc := NewService(fake)
_, err := svc.Complete(context.Background(), Request{
URI: "file:///main.go",
Text: "package main",
Line: 0,
Character: 0,
})
if err == nil {
t.Fatal("expected error, got nil")
}
}