| // Copyright 2022 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package misc |
| |
| import ( |
| "context" |
| "testing" |
| |
| "github.com/google/go-cmp/cmp" |
| "golang.org/x/tools/gopls/internal/hooks" |
| "golang.org/x/tools/gopls/internal/lsp/cache" |
| "golang.org/x/tools/gopls/internal/lsp/debug" |
| "golang.org/x/tools/gopls/internal/lsp/fake" |
| "golang.org/x/tools/gopls/internal/lsp/lsprpc" |
| . "golang.org/x/tools/gopls/internal/lsp/regtest" |
| "golang.org/x/tools/internal/jsonrpc2" |
| "golang.org/x/tools/internal/jsonrpc2/servertest" |
| ) |
| |
| // Test for golang/go#57222. |
| func TestCacheLeak(t *testing.T) { |
| // TODO(rfindley): either fix this test with additional instrumentation, or |
| // delete it. |
| t.Skip("This test races with cache eviction.") |
| const files = `-- a.go -- |
| package a |
| |
| func _() { |
| println("1") |
| } |
| ` |
| c := cache.New(nil) |
| env := setupEnv(t, files, c) |
| env.Await(InitialWorkspaceLoad) |
| env.OpenFile("a.go") |
| |
| // Make a couple edits to stabilize cache state. |
| // |
| // For some reason, after only one edit we're left with two parsed files |
| // (perhaps because something had to ParseHeader). If this test proves flaky, |
| // we'll need to investigate exactly what is causing various parse modes to |
| // be present (or rewrite the test to be more tolerant, for example make ~100 |
| // modifications and assert that we're within a few of where we're started). |
| env.RegexpReplace("a.go", "1", "2") |
| env.RegexpReplace("a.go", "2", "3") |
| env.AfterChange() |
| |
| // Capture cache state, make an arbitrary change, and wait for gopls to do |
| // its work. Afterward, we should have the exact same number of parsed |
| before := c.MemStats() |
| env.RegexpReplace("a.go", "3", "4") |
| env.AfterChange() |
| after := c.MemStats() |
| |
| if diff := cmp.Diff(before, after); diff != "" { |
| t.Errorf("store objects differ after change (-before +after)\n%s", diff) |
| } |
| } |
| |
| // setupEnv creates a new sandbox environment for editing the txtar encoded |
| // content of files. It uses a new gopls instance backed by the Cache c. |
| func setupEnv(t *testing.T, files string, c *cache.Cache) *Env { |
| ctx := debug.WithInstance(context.Background(), "", "off") |
| server := lsprpc.NewStreamServer(c, false, hooks.Options) |
| ts := servertest.NewPipeServer(server, jsonrpc2.NewRawStream) |
| s, err := fake.NewSandbox(&fake.SandboxConfig{ |
| Files: fake.UnpackTxt(files), |
| }) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| a := NewAwaiter(s.Workdir) |
| const skipApplyEdits = false |
| editor, err := fake.NewEditor(s, fake.EditorConfig{}).Connect(ctx, ts, a.Hooks(), skipApplyEdits) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| return &Env{ |
| T: t, |
| Ctx: ctx, |
| Editor: editor, |
| Sandbox: s, |
| Awaiter: a, |
| } |
| } |