internal/lsp: allow command line tests to connect through a pipe

With this change (finally, after a lot of detours) if you run the lsp tests with `-race -pipe` then you
can reliably reproduce the race in golang/go#30091

Change-Id: Ibd9fda5e07409a15d1bc8d14cb46fde41155aa6e
Reviewed-on: https://go-review.googlesource.com/c/tools/+/169999
Run-TryBot: Ian Cottrell <iancottrell@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cmd/check_test.go b/internal/lsp/cmd/check_test.go
index 7dc292e..9f77e82 100644
--- a/internal/lsp/cmd/check_test.go
+++ b/internal/lsp/cmd/check_test.go
@@ -40,7 +40,11 @@
 		if len(want) == 1 && want[0].Message == "" {
 			continue
 		}
-		args := []string{"check", fname}
+		args := []string{}
+		if *internalPipe {
+			args = append(args, "-remote=internal")
+		}
+		args = append(args, "check", fname)
 		app := &cmd.Application{}
 		app.Config = *e.Config
 		out := captureStdOut(t, func() {
diff --git a/internal/lsp/cmd/cmd.go b/internal/lsp/cmd/cmd.go
index afdc781..e664cd1 100644
--- a/internal/lsp/cmd/cmd.go
+++ b/internal/lsp/cmd/cmd.go
@@ -119,7 +119,15 @@
 
 func (app *Application) connect(ctx context.Context, client protocol.Client) (protocol.Server, error) {
 	var server protocol.Server
-	if app.Remote != "" {
+	switch app.Remote {
+	case "":
+		server = lsp.NewServer(client)
+	case "internal":
+		cr, sw, _ := os.Pipe()
+		sr, cw, _ := os.Pipe()
+		_, server = protocol.RunClient(ctx, jsonrpc2.NewHeaderStream(cr, cw), client)
+		go lsp.RunServer(ctx, jsonrpc2.NewHeaderStream(sr, sw))
+	default:
 		conn, err := net.Dial("tcp", app.Remote)
 		if err != nil {
 			return nil, err
@@ -129,8 +137,6 @@
 		if err != nil {
 			return nil, err
 		}
-	} else {
-		server = lsp.NewServer(client)
 	}
 	params := &protocol.InitializeParams{}
 	params.RootURI = string(span.FileURI(app.Config.Dir))
diff --git a/internal/lsp/cmd/cmd_test.go b/internal/lsp/cmd/cmd_test.go
index 8a56587..b67866e 100644
--- a/internal/lsp/cmd/cmd_test.go
+++ b/internal/lsp/cmd/cmd_test.go
@@ -5,6 +5,7 @@
 package cmd_test
 
 import (
+	"flag"
 	"io/ioutil"
 	"os"
 	"strings"
@@ -23,6 +24,8 @@
 	expectedFormatCount      = 4
 )
 
+var internalPipe = flag.Bool("pipe", false, "connect the command line client to a server through a pipe")
+
 func TestCommandLine(t *testing.T) {
 	packagestest.TestAll(t, testCommandLine)
 }