aboutsummaryrefslogtreecommitdiff
path: root/gopls/internal/regtest/misc/leak_test.go
blob: 28a5843ec2e998f1d824242e6255e1d7994ebc23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 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, 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)
	e, err := fake.NewEditor(s, fake.EditorConfig{}).Connect(ctx, ts, a.Hooks())

	return &Env{
		T:       t,
		Ctx:     ctx,
		Editor:  e,
		Sandbox: s,
		Awaiter: a,
	}
}