package cmd import ( "context" "io" "regexp" "testing" "time" "golang.org/x/tools/internal/jsonrpc2" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/telemetry/log" ) type fakeServer struct { protocol.Server client protocol.Client } func (s *fakeServer) DidOpen(ctx context.Context, params *protocol.DidOpenTextDocumentParams) error { // Our instrumentation should cause this message to be logged back to the LSP // client. log.Print(ctx, "ping") return nil } type fakeClient struct { protocol.Client logs chan string } func (c *fakeClient) LogMessage(ctx context.Context, params *protocol.LogMessageParams) error { c.logs <- params.Message return nil } func TestClientLogging(t *testing.T) { server := &fakeServer{} client := &fakeClient{logs: make(chan string)} ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Bind our fake client and server. // sReader and sWriter read from and write to the server. cReader and cWriter // read from and write to the client. sReader, sWriter := io.Pipe() cReader, cWriter := io.Pipe() close := func() { failOnErr := func(err error) { if err != nil { t.Fatal(err) } } failOnErr(sReader.Close()) failOnErr(cReader.Close()) failOnErr(sWriter.Close()) failOnErr(cWriter.Close()) } defer close() serverStream := jsonrpc2.NewStream(sReader, cWriter) // The returned client dispatches to the client, but it is already stored // in the context by NewServer, so we can ignore it. serverCtx, serverConn, _ := protocol.NewServer(ctx, serverStream, server) serverConn.AddHandler(&handler{}) clientStream := jsonrpc2.NewStream(cReader, sWriter) clientCtx, clientConn, serverDispatch := protocol.NewClient(ctx, clientStream, client) go clientConn.Run(clientCtx) go serverConn.Run(serverCtx) serverDispatch.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{}) 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") } }