|
| 1 | +package cmd |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "io" |
| 6 | + "regexp" |
| 7 | + "testing" |
| 8 | + "time" |
| 9 | + |
| 10 | + "golang.org/x/tools/internal/jsonrpc2" |
| 11 | + "golang.org/x/tools/internal/lsp/protocol" |
| 12 | + "golang.org/x/tools/internal/telemetry/log" |
| 13 | +) |
| 14 | + |
| 15 | +type fakeServer struct { |
| 16 | + protocol.Server |
| 17 | + client protocol.Client |
| 18 | +} |
| 19 | + |
| 20 | +func (s *fakeServer) DidOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error { |
| 21 | + // Our instrumentation should cause this message to be logged back to the LSP |
| 22 | + // client. |
| 23 | + log.Print(ctx, "ping") |
| 24 | + return nil |
| 25 | +} |
| 26 | + |
| 27 | +type fakeClient struct { |
| 28 | + protocol.Client |
| 29 | + |
| 30 | + logs chan string |
| 31 | +} |
| 32 | + |
| 33 | +func (c *fakeClient) LogMessage(ctx context.Context, params *protocol.LogMessageParams) error { |
| 34 | + c.logs <- params.Message |
| 35 | + return nil |
| 36 | +} |
| 37 | + |
| 38 | +func TestClientLogging(t *testing.T) { |
| 39 | + server := &fakeServer{} |
| 40 | + client := &fakeClient{logs: make(chan string)} |
| 41 | + ctx, cancel := context.WithCancel(context.Background()) |
| 42 | + defer cancel() |
| 43 | + |
| 44 | + // Bind our fake client and server. |
| 45 | + // sReader and sWriter read from and write to the server. cReader and cWriter |
| 46 | + // read from and write to the client. |
| 47 | + sReader, sWriter := io.Pipe() |
| 48 | + cReader, cWriter := io.Pipe() |
| 49 | + close := func() { |
| 50 | + failOnErr := func(err error) { |
| 51 | + if err != nil { |
| 52 | + t.Fatal(err) |
| 53 | + } |
| 54 | + } |
| 55 | + failOnErr(sReader.Close()) |
| 56 | + failOnErr(cReader.Close()) |
| 57 | + failOnErr(sWriter.Close()) |
| 58 | + failOnErr(cWriter.Close()) |
| 59 | + } |
| 60 | + defer close() |
| 61 | + serverStream := jsonrpc2.NewStream(sReader, cWriter) |
| 62 | + // The returned client dispatches to the client, but it is already stored |
| 63 | + // in the context by NewServer, so we can ignore it. |
| 64 | + serverCtx, serverConn, _ := protocol.NewServer(ctx, serverStream, server) |
| 65 | + serverConn.AddHandler(&handler{}) |
| 66 | + clientStream := jsonrpc2.NewStream(cReader, sWriter) |
| 67 | + clientCtx, clientConn, serverDispatch := protocol.NewClient(ctx, clientStream, client) |
| 68 | + |
| 69 | + go clientConn.Run(clientCtx) |
| 70 | + go serverConn.Run(serverCtx) |
| 71 | + serverDispatch.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{}) |
| 72 | + |
| 73 | + select { |
| 74 | + case got := <-client.logs: |
| 75 | + want := "ping" |
| 76 | + matched, err := regexp.MatchString(want, got) |
| 77 | + if err != nil { |
| 78 | + t.Fatal(err) |
| 79 | + } |
| 80 | + if !matched { |
| 81 | + t.Errorf("got log %q, want a log containing %q", got, want) |
| 82 | + } |
| 83 | + case <-time.After(1 * time.Second): |
| 84 | + t.Error("timeout waiting for client log") |
| 85 | + } |
| 86 | +} |
0 commit comments