Skip to content

Commit e4cdcd3

Browse files
committed
gopls/cache: add test for imports of non-ambiguous non-default modules
This is a separate CL because of its size. Creating a fake and pre-populated registry, and threading it through the test framework. Signed-off-by: Matthew Sackman <[email protected]> Change-Id: Ic43e21001ef08d7a6ef731b7b12b75875ad26a92 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1218701 Reviewed-by: Roger Peppe <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 9033834 commit e4cdcd3

File tree

6 files changed

+141
-18
lines changed

6 files changed

+141
-18
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package workspace
2+
3+
import (
4+
"io/fs"
5+
"testing"
6+
7+
"cuelang.org/go/internal/golangorgx/gopls/cache"
8+
"cuelang.org/go/internal/golangorgx/gopls/protocol"
9+
. "cuelang.org/go/internal/golangorgx/gopls/test/integration"
10+
"cuelang.org/go/mod/modcache"
11+
"cuelang.org/go/mod/modconfig"
12+
"cuelang.org/go/mod/modregistrytest"
13+
14+
"github.com/go-quicktest/qt"
15+
"golang.org/x/tools/txtar"
16+
)
17+
18+
func TestImports(t *testing.T) {
19+
registryFS, err := txtar.FS(txtar.Parse([]byte(`
20+
-- _registry/example.com_foo_v0.0.1/cue.mod/module.cue --
21+
module: "example.com/foo@v0"
22+
language: version: "v0.11.0"
23+
-- _registry/example.com_foo_v0.0.1/x/y.cue --
24+
package x
25+
`)))
26+
27+
qt.Assert(t, qt.IsNil(err))
28+
reg := newRegistry(t, registryFS)
29+
30+
const files = `
31+
-- cue.mod/module.cue --
32+
module: "example.com/bar"
33+
language: version: "v0.11.0"
34+
deps: {
35+
"example.com/foo@v0": {
36+
v: "v0.0.1"
37+
}
38+
}
39+
-- a/a.cue --
40+
package a
41+
42+
import "example.com/foo/x"
43+
`
44+
45+
t.Run("open", func(t *testing.T) {
46+
WithOptions(
47+
RootURIAsDefaultFolder(), Registry(reg), Modes(DefaultModes()&^Forwarded),
48+
).Run(t, files, func(t *testing.T, env *Env) {
49+
rootURI := env.Sandbox.Workdir.RootURI()
50+
env.Await(
51+
LogExactf(protocol.Debug, 1, false, "Workspace folder added: %v", rootURI),
52+
)
53+
env.OpenFile("a/a.cue")
54+
env.Await(
55+
env.DoneWithOpen(),
56+
LogExactf(protocol.Debug, 1, false, "Module dir=%v module=unknown Created", rootURI),
57+
LogExactf(protocol.Debug, 1, false, "Module dir=%v module=example.com/bar@v0 Reloaded", rootURI),
58+
LogExactf(protocol.Debug, 1, false, "Module dir=%v module=example.com/bar@v0 For file %v/a/a.cue found [Package dir=%v/a importPath=example.com/bar/a@v0]", rootURI, rootURI, rootURI),
59+
LogExactf(protocol.Debug, 1, false, "Module dir=%v module=example.com/bar@v0 Loading packages [example.com/bar/a@v0]", rootURI),
60+
LogExactf(protocol.Debug, 1, false, "Module dir=%v module=example.com/bar@v0 Loaded Package dir=%v/a importPath=example.com/bar/a@v0", rootURI, rootURI),
61+
)
62+
})
63+
})
64+
}
65+
66+
func newRegistry(t *testing.T, fsys fs.FS) cache.Registry {
67+
t.Helper()
68+
fsys, err := fs.Sub(fsys, "_registry")
69+
qt.Assert(t, qt.IsNil(err))
70+
regSrv, err := modregistrytest.New(fsys, "")
71+
qt.Assert(t, qt.IsNil(err))
72+
cacheDir := t.TempDir()
73+
// t.TempDir calls Cleanup internally. Cleanups are invoked in
74+
// "last added, first called". We need to stop the server before we
75+
// attempt to delete the temp dir. The modcache code is very
76+
// thorough at setting permissions on files so we need a special
77+
// cleanup so that t.TempDir's cleanup doesn't error!
78+
t.Cleanup(func() { modcache.RemoveAll(cacheDir) })
79+
t.Cleanup(regSrv.Close)
80+
modcfg := &modconfig.Config{
81+
Env: []string{
82+
"CUE_REGISTRY=" + regSrv.Host(),
83+
// Set an empty cache dir so that a developer's ~/.cache/cue doesn't influence the tests!
84+
"CUE_CACHE_DIR=" + cacheDir,
85+
},
86+
}
87+
reg, err := modconfig.NewRegistry(modcfg)
88+
qt.Assert(t, qt.IsNil(err))
89+
return reg
90+
}

internal/golangorgx/gopls/cache/cache.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,32 @@ func New() (*Cache, error) {
1616
modcfg := &modconfig.Config{
1717
ClientType: "cuelsp",
1818
}
19-
var err error
20-
registry, err := modconfig.NewRegistry(modcfg)
19+
reg, err := modconfig.NewRegistry(modcfg)
2120
if err != nil {
2221
return nil, err
2322
}
23+
return NewWithRegistry(reg), nil
24+
}
2425

26+
// NewWithRegistry creates a new cache, using the specified registry.
27+
func NewWithRegistry(reg Registry) *Cache {
28+
if reg == nil {
29+
panic("nil registry")
30+
}
2531
return &Cache{
2632
fs: fscache.NewCUECachedFS(),
27-
registry: registry,
28-
}, nil
33+
registry: reg,
34+
}
2935
}
3036

3137
// A Cache holds content that is shared across multiple cuelsp
3238
// client/editor connections.
3339
type Cache struct {
3440
fs *fscache.CUECacheFS
35-
registry modregistry
41+
registry Registry
3642
}
3743

38-
type modregistry interface {
44+
type Registry interface {
3945
modrequirements.Registry
4046
modpkgload.Registry
4147
}

internal/golangorgx/gopls/cache/module.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import (
3535
type Module struct {
3636
// immutable fields: all set at construction only
3737

38-
registry modregistry
38+
registry Registry
3939
fs *fscache.OverlayFS
4040

4141
debugLog func(string)
@@ -76,7 +76,7 @@ type Module struct {
7676
// NewModule creates a new Module. The CUE module itself (that is, the
7777
// cue.mod/module.cue file) is not loaded until [Module.ReloadModule]
7878
// is called.
79-
func NewModule(modFileUri protocol.DocumentURI, registry modregistry, overlayFS *fscache.OverlayFS, debugLog func(string)) *Module {
79+
func NewModule(modFileUri protocol.DocumentURI, registry Registry, overlayFS *fscache.OverlayFS, debugLog func(string)) *Module {
8080
return &Module{
8181
rootURI: modFileUri.Dir().Dir(),
8282
modFileURI: modFileUri,

internal/golangorgx/gopls/cache/workspace.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
// configures one workspace. A workspace may have several workspace
2929
// folders [WorkspaceFolder].
3030
type Workspace struct {
31-
registry modregistry // shared with other Workspaces
31+
registry Registry // shared with other Workspaces
3232
fs *fscache.CUECacheFS
3333
overlayFS *fscache.OverlayFS
3434

internal/golangorgx/gopls/test/integration/options.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package integration
66

77
import (
8+
"cuelang.org/go/internal/golangorgx/gopls/cache"
89
"cuelang.org/go/internal/golangorgx/gopls/protocol"
910
"cuelang.org/go/internal/golangorgx/gopls/test/integration/fake"
1011
)
@@ -20,6 +21,7 @@ type runConfig struct {
2021
//
2122
// TODO(myitcv): is there a better place for this?
2223
initializeErrorMatches string
24+
reg cache.Registry
2325
}
2426

2527
func defaultConfig() runConfig {
@@ -181,3 +183,11 @@ func MessageResponder(f func(*protocol.ShowMessageRequestParams) (*protocol.Mess
181183
opts.editor.MessageResponder = f
182184
})
183185
}
186+
187+
// Registry configures the server to use the provided [cache.Registry]
188+
// instead of the default registry.
189+
func Registry(reg cache.Registry) RunOption {
190+
return optionSetter(func(opts *runConfig) {
191+
opts.reg = reg
192+
})
193+
}

internal/golangorgx/gopls/test/integration/runner.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func (r *Runner) Run(t *testing.T, files string, test TestFunc, opts ...RunOptio
140140
tests := []struct {
141141
name string
142142
mode Mode
143-
getServer func(func(*settings.Options)) jsonrpc2.StreamServer
143+
getServer func(runConfig, func(*settings.Options)) jsonrpc2.StreamServer
144144
}{
145145
{"default", Default, r.defaultServer},
146146
{"forwarded", Forwarded, r.forwardedServer},
@@ -205,7 +205,7 @@ func (r *Runner) Run(t *testing.T, files string, test TestFunc, opts ...RunOptio
205205
}
206206
}()
207207

208-
ss := tc.getServer(r.OptionsHook)
208+
ss := tc.getServer(config, r.OptionsHook)
209209

210210
framer := jsonrpc2.NewRawStream
211211
ls := &loggingFramer{}
@@ -308,17 +308,17 @@ func (s *loggingFramer) printBuffers(testname string, w io.Writer) {
308308
}
309309

310310
// defaultServer handles the Default execution mode.
311-
func (r *Runner) defaultServer(optsHook func(*settings.Options)) jsonrpc2.StreamServer {
312-
c, err := cache.New()
311+
func (r *Runner) defaultServer(config runConfig, optsHook func(*settings.Options)) jsonrpc2.StreamServer {
312+
c, err := newCache(config)
313313
if err != nil {
314314
panic(err)
315315
}
316316
return lsprpc.NewStreamServer(c, false, optsHook)
317317
}
318318

319319
// experimentalServer handles the Experimental execution mode.
320-
func (r *Runner) experimentalServer(optsHook func(*settings.Options)) jsonrpc2.StreamServer {
321-
c, err := cache.New()
320+
func (r *Runner) experimentalServer(config runConfig, optsHook func(*settings.Options)) jsonrpc2.StreamServer {
321+
c, err := newCache(config)
322322
if err != nil {
323323
panic(err)
324324
}
@@ -330,9 +330,15 @@ func (r *Runner) experimentalServer(optsHook func(*settings.Options)) jsonrpc2.S
330330
}
331331

332332
// forwardedServer handles the Forwarded execution mode.
333-
func (r *Runner) forwardedServer(optsHook func(*settings.Options)) jsonrpc2.StreamServer {
333+
func (r *Runner) forwardedServer(config runConfig, optsHook func(*settings.Options)) jsonrpc2.StreamServer {
334+
if config.reg != nil {
335+
// This is because the server may be long-lived and used for
336+
// several tests, possibly even in parallel. So we cannot allow
337+
// tests to attempt to reconfigure the server.
338+
panic("explicit registry cannot be set for separate process execution mode")
339+
}
334340
r.tsOnce.Do(func() {
335-
c, err := cache.New()
341+
c, err := newCache(config)
336342
if err != nil {
337343
panic(err)
338344
}
@@ -343,16 +349,27 @@ func (r *Runner) forwardedServer(optsHook func(*settings.Options)) jsonrpc2.Stre
343349
return newForwarder("tcp", r.ts.Addr)
344350
}
345351

352+
func newCache(config runConfig) (*cache.Cache, error) {
353+
if config.reg == nil {
354+
return cache.New()
355+
} else {
356+
return cache.NewWithRegistry(config.reg), nil
357+
}
358+
}
359+
346360
// runTestAsGoplsEnvvar triggers TestMain to run gopls instead of running
347361
// tests. It's a trick to allow tests to find a binary to use to start a gopls
348362
// subprocess.
349363
const runTestAsGoplsEnvvar = "_GOPLS_TEST_BINARY_RUN_AS_GOPLS"
350364

351365
// separateProcessServer handles the SeparateProcess execution mode.
352-
func (r *Runner) separateProcessServer(optsHook func(*settings.Options)) jsonrpc2.StreamServer {
366+
func (r *Runner) separateProcessServer(config runConfig, optsHook func(*settings.Options)) jsonrpc2.StreamServer {
353367
if runtime.GOOS != "linux" {
354368
panic("separate process execution mode is only supported on linux")
355369
}
370+
if config.reg != nil {
371+
panic("explicit registry cannot be set for separate process execution mode")
372+
}
356373

357374
r.startRemoteOnce.Do(func() {
358375
socketDir, err := os.MkdirTemp(r.tempDir, "cue-lsp-test-socket")

0 commit comments

Comments
 (0)