mirror of https://github.com/golang/go.git
155 lines
3.9 KiB
Go
155 lines
3.9 KiB
Go
// Copyright 2021 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package lsprpc_test
|
|
|
|
import (
|
|
"context"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2"
|
|
"golang.org/x/tools/internal/lsp/protocol"
|
|
|
|
. "golang.org/x/tools/internal/lsp/lsprpc"
|
|
)
|
|
|
|
type TestEnv struct {
|
|
Listeners []jsonrpc2_v2.Listener
|
|
Conns []*jsonrpc2_v2.Connection
|
|
Servers []*jsonrpc2_v2.Server
|
|
}
|
|
|
|
func (e *TestEnv) Shutdown(t *testing.T) {
|
|
for _, l := range e.Listeners {
|
|
if err := l.Close(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
for _, c := range e.Conns {
|
|
if err := c.Close(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
for _, s := range e.Servers {
|
|
if err := s.Wait(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (e *TestEnv) serve(ctx context.Context, t *testing.T, server jsonrpc2_v2.Binder) (jsonrpc2_v2.Listener, *jsonrpc2_v2.Server) {
|
|
l, err := jsonrpc2_v2.NetPipeListener(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
e.Listeners = append(e.Listeners, l)
|
|
s, err := jsonrpc2_v2.Serve(ctx, l, server)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
e.Servers = append(e.Servers, s)
|
|
return l, s
|
|
}
|
|
|
|
func (e *TestEnv) dial(ctx context.Context, t *testing.T, dialer jsonrpc2_v2.Dialer, client jsonrpc2_v2.Binder, forwarded bool) *jsonrpc2_v2.Connection {
|
|
if forwarded {
|
|
l, _ := e.serve(ctx, t, NewForwardBinder(dialer))
|
|
dialer = l.Dialer()
|
|
}
|
|
conn, err := jsonrpc2_v2.Dial(ctx, dialer, client)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
e.Conns = append(e.Conns, conn)
|
|
return conn
|
|
}
|
|
|
|
func staticClientBinder(client protocol.Client) jsonrpc2_v2.Binder {
|
|
f := func(context.Context, protocol.Server) protocol.Client { return client }
|
|
return NewClientBinder(f)
|
|
}
|
|
|
|
func staticServerBinder(server protocol.Server) jsonrpc2_v2.Binder {
|
|
f := func(ctx context.Context, client protocol.ClientCloser) protocol.Server {
|
|
return server
|
|
}
|
|
return NewServerBinder(f)
|
|
}
|
|
|
|
func TestClientLoggingV2(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
for name, forwarded := range map[string]bool{
|
|
"forwarded": true,
|
|
"standalone": false,
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
client := FakeClient{Logs: make(chan string, 10)}
|
|
env := new(TestEnv)
|
|
defer env.Shutdown(t)
|
|
l, _ := env.serve(ctx, t, staticServerBinder(PingServer{}))
|
|
conn := env.dial(ctx, t, l.Dialer(), staticClientBinder(client), forwarded)
|
|
|
|
if err := protocol.ServerDispatcherV2(conn).DidOpen(ctx, &protocol.DidOpenTextDocumentParams{}); err != nil {
|
|
t.Errorf("DidOpen: %v", err)
|
|
}
|
|
select {
|
|
case got := <-client.Logs:
|
|
want := "ping"
|
|
matched, err := regexp.MatchString(want, got)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !matched {
|
|
t.Errorf("got log %q, want a log containing %q", got, want)
|
|
}
|
|
case <-time.After(1 * time.Second):
|
|
t.Error("timeout waiting for client log")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRequestCancellationV2(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
for name, forwarded := range map[string]bool{
|
|
"forwarded": true,
|
|
"standalone": false,
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
server := WaitableServer{
|
|
Started: make(chan struct{}),
|
|
Completed: make(chan error),
|
|
}
|
|
env := new(TestEnv)
|
|
defer env.Shutdown(t)
|
|
l, _ := env.serve(ctx, t, staticServerBinder(server))
|
|
client := FakeClient{Logs: make(chan string, 10)}
|
|
conn := env.dial(ctx, t, l.Dialer(), staticClientBinder(client), forwarded)
|
|
|
|
sd := protocol.ServerDispatcherV2(conn)
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
result := make(chan error)
|
|
go func() {
|
|
_, err := sd.Hover(ctx, &protocol.HoverParams{})
|
|
result <- err
|
|
}()
|
|
// Wait for the Hover request to start.
|
|
<-server.Started
|
|
cancel()
|
|
if err := <-result; err == nil {
|
|
t.Error("nil error for cancelled Hover(), want non-nil")
|
|
}
|
|
if err := <-server.Completed; err == nil || !strings.Contains(err.Error(), "cancelled hover") {
|
|
t.Errorf("Hover(): unexpected server-side error %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|