Skip to content

Commit bc09a2c

Browse files
committed
internal/lsp/regtest: output gopls logs on test failure
Wrap the regtest test servers to capture jsonrpc2 logs, so that they can be printed on test failure. There was a little bit of complication to implement this in the 'Shared' execution mode, and since we're not really using this mode I just deleted it. Updates golang/go#36897 Updates golang/go#37318 Change-Id: Ic0107c3f317850ae3beb760fc94ae474e647cb78 Reviewed-on: https://go-review.googlesource.com/c/tools/+/226957 Run-TryBot: Robert Findley <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Cottrell <[email protected]>
1 parent 97c4fbe commit bc09a2c

File tree

1 file changed

+48
-35
lines changed

1 file changed

+48
-35
lines changed

internal/lsp/regtest/env.go

+48-35
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"bytes"
1010
"context"
1111
"fmt"
12+
"io"
1213
"io/ioutil"
1314
"os"
1415
"os/exec"
@@ -34,8 +35,7 @@ type EnvMode int
3435
const (
3536
// Singleton mode uses a separate cache for each test.
3637
Singleton EnvMode = 1 << iota
37-
// Shared mode uses a Shared cache.
38-
Shared
38+
3939
// Forwarded forwards connections to an in-process gopls instance.
4040
Forwarded
4141
// SeparateProcess runs a separate gopls process, and forwards connections to
@@ -150,12 +150,11 @@ func (r *Runner) Run(t *testing.T, filedata string, test func(e *Env)) {
150150
func (r *Runner) RunInMode(modes EnvMode, t *testing.T, filedata string, test func(e *Env)) {
151151
t.Helper()
152152
tests := []struct {
153-
name string
154-
mode EnvMode
155-
getConnector func(context.Context, *testing.T) (servertest.Connector, func())
153+
name string
154+
mode EnvMode
155+
getServer func(context.Context, *testing.T) jsonrpc2.StreamServer
156156
}{
157-
{"singleton", Singleton, r.singletonEnv},
158-
{"shared", Shared, r.sharedEnv},
157+
{"singleton", Singleton, singletonEnv},
159158
{"forwarded", Forwarded, r.forwardedEnv},
160159
{"separate_process", SeparateProcess, r.separateProcessEnv},
161160
}
@@ -169,15 +168,24 @@ func (r *Runner) RunInMode(modes EnvMode, t *testing.T, filedata string, test fu
169168
t.Helper()
170169
ctx, cancel := context.WithTimeout(context.Background(), r.timeout)
171170
defer cancel()
171+
ctx = debug.WithInstance(ctx, "", "")
172+
172173
ws, err := fake.NewWorkspace("lsprpc", []byte(filedata))
173174
if err != nil {
174175
t.Fatal(err)
175176
}
176177
defer ws.Close()
177-
ts, cleanup := tc.getConnector(ctx, t)
178-
defer cleanup()
178+
ss := tc.getServer(ctx, t)
179+
ls := &loggingServer{delegate: ss}
180+
ts := servertest.NewPipeServer(ctx, ls)
181+
defer func() {
182+
ts.Close()
183+
}()
179184
env := NewEnv(ctx, t, ws, ts)
180185
defer func() {
186+
if t.Failed() {
187+
ls.printBuffers(t.Name(), os.Stderr)
188+
}
181189
if err := env.E.Shutdown(ctx); err != nil {
182190
panic(err)
183191
}
@@ -187,42 +195,47 @@ func (r *Runner) RunInMode(modes EnvMode, t *testing.T, filedata string, test fu
187195
}
188196
}
189197

190-
func (r *Runner) singletonEnv(ctx context.Context, t *testing.T) (servertest.Connector, func()) {
191-
ctx = debug.WithInstance(ctx, "", "")
192-
ss := lsprpc.NewStreamServer(cache.New(ctx, nil))
193-
ts := servertest.NewPipeServer(ctx, ss)
194-
cleanup := func() {
195-
ts.Close()
198+
type loggingServer struct {
199+
delegate jsonrpc2.StreamServer
200+
201+
mu sync.Mutex
202+
buffers []*bytes.Buffer
203+
}
204+
205+
func (s *loggingServer) ServeStream(ctx context.Context, stream jsonrpc2.Stream) error {
206+
s.mu.Lock()
207+
var buf bytes.Buffer
208+
s.buffers = append(s.buffers, &buf)
209+
s.mu.Unlock()
210+
logStream := protocol.LoggingStream(stream, &buf)
211+
return s.delegate.ServeStream(ctx, logStream)
212+
}
213+
214+
func (s *loggingServer) printBuffers(testname string, w io.Writer) {
215+
s.mu.Lock()
216+
defer s.mu.Unlock()
217+
218+
for i, buf := range s.buffers {
219+
fmt.Fprintf(os.Stderr, "#### Start Gopls Test Logs %d of %d for %q\n", i+1, len(s.buffers), testname)
220+
io.Copy(w, buf)
221+
fmt.Fprintf(os.Stderr, "#### End Gopls Test Logs %d of %d for %q\n", i+1, len(s.buffers), testname)
196222
}
197-
return ts, cleanup
198223
}
199224

200-
func (r *Runner) sharedEnv(ctx context.Context, t *testing.T) (servertest.Connector, func()) {
201-
return r.getTestServer(), func() {}
225+
func singletonEnv(ctx context.Context, t *testing.T) jsonrpc2.StreamServer {
226+
return lsprpc.NewStreamServer(cache.New(ctx, nil))
202227
}
203228

204-
func (r *Runner) forwardedEnv(ctx context.Context, t *testing.T) (servertest.Connector, func()) {
205-
ctx = debug.WithInstance(ctx, "", "")
229+
func (r *Runner) forwardedEnv(ctx context.Context, t *testing.T) jsonrpc2.StreamServer {
206230
ts := r.getTestServer()
207-
forwarder := lsprpc.NewForwarder("tcp", ts.Addr)
208-
ts2 := servertest.NewPipeServer(ctx, forwarder)
209-
cleanup := func() {
210-
ts2.Close()
211-
}
212-
return ts2, cleanup
231+
return lsprpc.NewForwarder("tcp", ts.Addr)
213232
}
214233

215-
func (r *Runner) separateProcessEnv(ctx context.Context, t *testing.T) (servertest.Connector, func()) {
216-
ctx = debug.WithInstance(ctx, "", "")
217-
socket := r.getRemoteSocket(t)
234+
func (r *Runner) separateProcessEnv(ctx context.Context, t *testing.T) jsonrpc2.StreamServer {
218235
// TODO(rfindley): can we use the autostart behavior here, instead of
219236
// pre-starting the remote?
220-
forwarder := lsprpc.NewForwarder("unix", socket)
221-
ts2 := servertest.NewPipeServer(ctx, forwarder)
222-
cleanup := func() {
223-
ts2.Close()
224-
}
225-
return ts2, cleanup
237+
socket := r.getRemoteSocket(t)
238+
return lsprpc.NewForwarder("unix", socket)
226239
}
227240

228241
// Env holds an initialized fake Editor, Workspace, and Server, which may be

0 commit comments

Comments
 (0)