golang.org/x/tools/gopls@v0.15.3/internal/lsprpc/goenv_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package lsprpc_test 6 7 import ( 8 "context" 9 "encoding/json" 10 "fmt" 11 "os" 12 "testing" 13 14 "golang.org/x/tools/gopls/internal/protocol" 15 "golang.org/x/tools/internal/event" 16 jsonrpc2_v2 "golang.org/x/tools/internal/jsonrpc2_v2" 17 "golang.org/x/tools/internal/testenv" 18 19 . "golang.org/x/tools/gopls/internal/lsprpc" 20 ) 21 22 func GoEnvMiddleware() (Middleware, error) { 23 return BindHandler(func(delegate jsonrpc2_v2.Handler) jsonrpc2_v2.Handler { 24 return jsonrpc2_v2.HandlerFunc(func(ctx context.Context, req *jsonrpc2_v2.Request) (interface{}, error) { 25 if req.Method == "initialize" { 26 if err := addGoEnvToInitializeRequestV2(ctx, req); err != nil { 27 event.Error(ctx, "adding go env to initialize", err) 28 } 29 } 30 return delegate.Handle(ctx, req) 31 }) 32 }), nil 33 } 34 35 // This function is almost identical to addGoEnvToInitializeRequest in lsprpc.go. 36 // Make changes in parallel. 37 func addGoEnvToInitializeRequestV2(ctx context.Context, req *jsonrpc2_v2.Request) error { 38 var params protocol.ParamInitialize 39 if err := json.Unmarshal(req.Params, ¶ms); err != nil { 40 return err 41 } 42 var opts map[string]interface{} 43 switch v := params.InitializationOptions.(type) { 44 case nil: 45 opts = make(map[string]interface{}) 46 case map[string]interface{}: 47 opts = v 48 default: 49 return fmt.Errorf("unexpected type for InitializationOptions: %T", v) 50 } 51 envOpt, ok := opts["env"] 52 if !ok { 53 envOpt = make(map[string]interface{}) 54 } 55 env, ok := envOpt.(map[string]interface{}) 56 if !ok { 57 return fmt.Errorf("env option is %T, expected a map", envOpt) 58 } 59 goenv, err := GetGoEnv(ctx, env) 60 if err != nil { 61 return err 62 } 63 // We don't want to propagate GOWORK unless explicitly set since that could mess with 64 // path inference during cmd/go invocations, see golang/go#51825. 65 _, goworkSet := os.LookupEnv("GOWORK") 66 for govar, value := range goenv { 67 if govar == "GOWORK" && !goworkSet { 68 continue 69 } 70 env[govar] = value 71 } 72 opts["env"] = env 73 params.InitializationOptions = opts 74 raw, err := json.Marshal(params) 75 if err != nil { 76 return fmt.Errorf("marshaling updated options: %v", err) 77 } 78 req.Params = json.RawMessage(raw) 79 return nil 80 } 81 82 type initServer struct { 83 protocol.Server 84 85 params *protocol.ParamInitialize 86 } 87 88 func (s *initServer) Initialize(ctx context.Context, params *protocol.ParamInitialize) (*protocol.InitializeResult, error) { 89 s.params = params 90 return &protocol.InitializeResult{}, nil 91 } 92 93 func TestGoEnvMiddleware(t *testing.T) { 94 testenv.NeedsTool(t, "go") 95 96 ctx := context.Background() 97 98 server := &initServer{} 99 env := new(TestEnv) 100 defer env.Shutdown(t) 101 l, _ := env.serve(ctx, t, staticServerBinder(server)) 102 mw, err := GoEnvMiddleware() 103 if err != nil { 104 t.Fatal(err) 105 } 106 binder := mw(NewForwardBinder(l.Dialer())) 107 l, _ = env.serve(ctx, t, binder) 108 conn := env.dial(ctx, t, l.Dialer(), noopBinder, true) 109 dispatch := protocol.ServerDispatcherV2(conn) 110 initParams := &protocol.ParamInitialize{} 111 initParams.InitializationOptions = map[string]interface{}{ 112 "env": map[string]interface{}{ 113 "GONOPROXY": "example.com", 114 }, 115 } 116 if _, err := dispatch.Initialize(ctx, initParams); err != nil { 117 t.Fatal(err) 118 } 119 120 if server.params == nil { 121 t.Fatalf("initialize params are unset") 122 } 123 envOpts := server.params.InitializationOptions.(map[string]interface{})["env"].(map[string]interface{}) 124 125 // Check for an arbitrary Go variable. It should be set. 126 if _, ok := envOpts["GOPRIVATE"]; !ok { 127 t.Errorf("Go environment variable GOPRIVATE unset in initialization options") 128 } 129 // Check that the variable present in our user config was not overwritten. 130 if got, want := envOpts["GONOPROXY"], "example.com"; got != want { 131 t.Errorf("GONOPROXY=%q, want %q", got, want) 132 } 133 }