blob: 586ffcc41e9566c8b114c0b491332807bd829bd5 [file] [log] [blame]
// 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,
}
}