mirror of
https://github.com/golang/go
synced 2024-09-30 18:08:33 -06:00
internal/lsp/debug: move all debug state onto the Instance
For testability, and to support the exchange of debug information across Forwarder and server, it is helpful to encapsulate all debug information on the instance object. This CL moves all state in the debug package into a new 'State' type, that is added as a field on the debug.Instance. While doing so, common functionality for object collections is factored out into the objset helper type. Also add two new debug object types: Client and Server. These aren't yet used, but will be in a later CL (and frankly it was easier to leave them in this CL than to more carefully rewrite history...). Updates golang/go#34111 Change-Id: Ib809cd14cb957b41a9bcbd94a991f804531a76ea Reviewed-on: https://go-review.googlesource.com/c/tools/+/220078 Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
023911ca70
commit
e02f5847d1
@ -41,7 +41,7 @@ func testCommandLine(t *testing.T, exporter packagestest.Exporter) {
|
|||||||
}
|
}
|
||||||
data := tests.Load(t, exporter, testdata)
|
data := tests.Load(t, exporter, testdata)
|
||||||
ctx := tests.Context(t)
|
ctx := tests.Context(t)
|
||||||
cache := cache.New(commandLineOptions)
|
cache := cache.New(commandLineOptions, nil)
|
||||||
ss := lsprpc.NewStreamServer(cache, false)
|
ss := lsprpc.NewStreamServer(cache, false)
|
||||||
ts := servertest.NewTCPServer(ctx, ss)
|
ts := servertest.NewTCPServer(ctx, ss)
|
||||||
for _, data := range data {
|
for _, data := range data {
|
||||||
|
11
internal/lsp/cache/cache.go
vendored
11
internal/lsp/cache/cache.go
vendored
@ -19,15 +19,19 @@ import (
|
|||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(options func(*source.Options)) *Cache {
|
func New(options func(*source.Options), debugState *debug.State) *Cache {
|
||||||
|
if debugState == nil {
|
||||||
|
debugState = &debug.State{}
|
||||||
|
}
|
||||||
index := atomic.AddInt64(&cacheIndex, 1)
|
index := atomic.AddInt64(&cacheIndex, 1)
|
||||||
c := &Cache{
|
c := &Cache{
|
||||||
fs: &nativeFileSystem{},
|
fs: &nativeFileSystem{},
|
||||||
id: strconv.FormatInt(index, 10),
|
id: strconv.FormatInt(index, 10),
|
||||||
fset: token.NewFileSet(),
|
fset: token.NewFileSet(),
|
||||||
options: options,
|
options: options,
|
||||||
|
debug: debugState,
|
||||||
}
|
}
|
||||||
debug.AddCache(debugCache{c})
|
debugState.AddCache(debugCache{c})
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,6 +40,7 @@ type Cache struct {
|
|||||||
id string
|
id string
|
||||||
fset *token.FileSet
|
fset *token.FileSet
|
||||||
options func(*source.Options)
|
options func(*source.Options)
|
||||||
|
debug *debug.State
|
||||||
|
|
||||||
store memoize.Store
|
store memoize.Store
|
||||||
}
|
}
|
||||||
@ -82,7 +87,7 @@ func (c *Cache) NewSession() *Session {
|
|||||||
options: source.DefaultOptions(),
|
options: source.DefaultOptions(),
|
||||||
overlays: make(map[span.URI]*overlay),
|
overlays: make(map[span.URI]*overlay),
|
||||||
}
|
}
|
||||||
debug.AddSession(debugSession{s})
|
c.debug.AddSession(debugSession{s})
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
internal/lsp/cache/session.go
vendored
5
internal/lsp/cache/session.go
vendored
@ -11,7 +11,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"golang.org/x/tools/internal/lsp/debug"
|
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
"golang.org/x/tools/internal/telemetry/trace"
|
"golang.org/x/tools/internal/telemetry/trace"
|
||||||
@ -78,7 +77,7 @@ func (s *Session) Shutdown(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
s.views = nil
|
s.views = nil
|
||||||
s.viewMap = nil
|
s.viewMap = nil
|
||||||
debug.DropSession(debugSession{s})
|
s.cache.debug.DropSession(debugSession{s})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) Cache() source.Cache {
|
func (s *Session) Cache() source.Cache {
|
||||||
@ -142,7 +141,7 @@ func (s *Session) createView(ctx context.Context, name string, folder span.URI,
|
|||||||
// Initialize the view without blocking.
|
// Initialize the view without blocking.
|
||||||
go v.initialize(xcontext.Detach(ctx), v.snapshot)
|
go v.initialize(xcontext.Detach(ctx), v.snapshot)
|
||||||
|
|
||||||
debug.AddView(debugView{v})
|
v.session.cache.debug.AddView(debugView{v})
|
||||||
return v, v.snapshot, nil
|
return v, v.snapshot, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
internal/lsp/cache/view.go
vendored
3
internal/lsp/cache/view.go
vendored
@ -22,7 +22,6 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/tools/go/packages"
|
"golang.org/x/tools/go/packages"
|
||||||
"golang.org/x/tools/internal/imports"
|
"golang.org/x/tools/internal/imports"
|
||||||
"golang.org/x/tools/internal/lsp/debug"
|
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/lsp/telemetry"
|
"golang.org/x/tools/internal/lsp/telemetry"
|
||||||
"golang.org/x/tools/internal/memoize"
|
"golang.org/x/tools/internal/memoize"
|
||||||
@ -483,7 +482,7 @@ func (v *view) shutdown(context.Context) {
|
|||||||
os.Remove(v.tempMod.Filename())
|
os.Remove(v.tempMod.Filename())
|
||||||
os.Remove(tempSumFile(v.tempMod.Filename()))
|
os.Remove(tempSumFile(v.tempMod.Filename()))
|
||||||
}
|
}
|
||||||
debug.DropView(debugView{v})
|
v.session.cache.debug.DropView(debugView{v})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore checks if the given URI is a URI we ignore.
|
// Ignore checks if the given URI is a URI we ignore.
|
||||||
|
@ -39,7 +39,7 @@ func TestCapabilities(t *testing.T) {
|
|||||||
params.Capabilities.Workspace.Configuration = true
|
params.Capabilities.Workspace.Configuration = true
|
||||||
|
|
||||||
// Send an initialize request to the server.
|
// Send an initialize request to the server.
|
||||||
c.Server = lsp.NewServer(cache.New(app.options).NewSession(), c.Client)
|
c.Server = lsp.NewServer(cache.New(app.options, nil).NewSession(), c.Client)
|
||||||
result, err := c.Server.Initialize(ctx, params)
|
result, err := c.Server.Initialize(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/tools/internal/jsonrpc2"
|
"golang.org/x/tools/internal/jsonrpc2"
|
||||||
"golang.org/x/tools/internal/lsp"
|
"golang.org/x/tools/internal/lsp"
|
||||||
@ -70,7 +69,7 @@ type Application struct {
|
|||||||
// It is primarily to allow the behavior of gopls to be modified by hooks.
|
// It is primarily to allow the behavior of gopls to be modified by hooks.
|
||||||
PrepareOptions func(*source.Options)
|
PrepareOptions func(*source.Options)
|
||||||
|
|
||||||
debug debug.Instance
|
debug *debug.Instance
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new Application ready to run.
|
// New returns a new Application ready to run.
|
||||||
@ -132,12 +131,7 @@ gopls flags are:
|
|||||||
// If no arguments are passed it will invoke the server sub command, as a
|
// If no arguments are passed it will invoke the server sub command, as a
|
||||||
// temporary measure for compatibility.
|
// temporary measure for compatibility.
|
||||||
func (app *Application) Run(ctx context.Context, args ...string) error {
|
func (app *Application) Run(ctx context.Context, args ...string) error {
|
||||||
app.debug = debug.Instance{
|
app.debug = debug.NewInstance(app.wd, app.OCAgent)
|
||||||
StartTime: time.Now(),
|
|
||||||
Workdir: app.wd,
|
|
||||||
OCAgentConfig: app.OCAgent,
|
|
||||||
}
|
|
||||||
app.debug.Prepare(ctx)
|
|
||||||
app.Serve.app = app
|
app.Serve.app = app
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return tool.Run(ctx, &app.Serve, args)
|
return tool.Run(ctx, &app.Serve, args)
|
||||||
@ -197,7 +191,7 @@ func (app *Application) connect(ctx context.Context) (*connection, error) {
|
|||||||
switch {
|
switch {
|
||||||
case app.Remote == "":
|
case app.Remote == "":
|
||||||
connection := newConnection(app)
|
connection := newConnection(app)
|
||||||
connection.Server = lsp.NewServer(cache.New(app.options).NewSession(), connection.Client)
|
connection.Server = lsp.NewServer(cache.New(app.options, nil).NewSession(), connection.Client)
|
||||||
ctx = protocol.WithClient(ctx, connection.Client)
|
ctx = protocol.WithClient(ctx, connection.Client)
|
||||||
return connection, connection.initialize(ctx, app.options)
|
return connection, connection.initialize(ctx, app.options)
|
||||||
case strings.HasPrefix(app.Remote, "internal@"):
|
case strings.HasPrefix(app.Remote, "internal@"):
|
||||||
|
@ -46,7 +46,7 @@ func testCommandLine(t *testing.T, exporter packagestest.Exporter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testServer(ctx context.Context) *servertest.TCPServer {
|
func testServer(ctx context.Context) *servertest.TCPServer {
|
||||||
cache := cache.New(nil)
|
cache := cache.New(nil, nil)
|
||||||
ss := lsprpc.NewStreamServer(cache, false)
|
ss := lsprpc.NewStreamServer(cache, false)
|
||||||
return servertest.NewTCPServer(ctx, ss)
|
return servertest.NewTCPServer(ctx, ss)
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func (s *Serve) Run(ctx context.Context, args ...string) error {
|
|||||||
network, addr := parseAddr(s.app.Remote)
|
network, addr := parseAddr(s.app.Remote)
|
||||||
ss = lsprpc.NewForwarder(network, addr, true)
|
ss = lsprpc.NewForwarder(network, addr, true)
|
||||||
} else {
|
} else {
|
||||||
ss = lsprpc.NewStreamServer(cache.New(s.app.options), true)
|
ss = lsprpc.NewStreamServer(cache.New(s.app.options, s.app.debug.State), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Address != "" {
|
if s.Address != "" {
|
||||||
|
@ -35,11 +35,13 @@ import (
|
|||||||
"golang.org/x/tools/internal/telemetry/tag"
|
"golang.org/x/tools/internal/telemetry/tag"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// An Instance holds all debug information associated with a gopls instance.
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
Logfile string
|
Logfile string
|
||||||
StartTime time.Time
|
StartTime time.Time
|
||||||
ServerAddress string
|
ServerAddress string
|
||||||
DebugAddress string
|
DebugAddress string
|
||||||
|
ListenedDebugAddress string
|
||||||
Workdir string
|
Workdir string
|
||||||
OCAgentConfig string
|
OCAgentConfig string
|
||||||
|
|
||||||
@ -49,14 +51,130 @@ type Instance struct {
|
|||||||
prometheus *prometheus.Exporter
|
prometheus *prometheus.Exporter
|
||||||
rpcs *rpcs
|
rpcs *rpcs
|
||||||
traces *traces
|
traces *traces
|
||||||
|
State *State
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State holds debugging information related to the server state.
|
||||||
|
type State struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
caches objset
|
||||||
|
sessions objset
|
||||||
|
views objset
|
||||||
|
clients objset
|
||||||
|
servers objset
|
||||||
|
}
|
||||||
|
|
||||||
|
type ider interface {
|
||||||
|
ID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type objset struct {
|
||||||
|
objs []ider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *objset) add(elem ider) {
|
||||||
|
s.objs = append(s.objs, elem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *objset) drop(elem ider) {
|
||||||
|
var newobjs []ider
|
||||||
|
for _, obj := range s.objs {
|
||||||
|
if obj.ID() != elem.ID() {
|
||||||
|
newobjs = append(newobjs, obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.objs = newobjs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *objset) find(id string) ider {
|
||||||
|
for _, e := range s.objs {
|
||||||
|
if e.ID() == id {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caches returns the set of Cache objects currently being served.
|
||||||
|
func (st *State) Caches() []Cache {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
caches := make([]Cache, len(st.caches.objs))
|
||||||
|
for i, c := range st.caches.objs {
|
||||||
|
caches[i] = c.(Cache)
|
||||||
|
}
|
||||||
|
return caches
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sessions returns the set of Session objects currently being served.
|
||||||
|
func (st *State) Sessions() []Session {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
sessions := make([]Session, len(st.sessions.objs))
|
||||||
|
for i, s := range st.sessions.objs {
|
||||||
|
sessions[i] = s.(Session)
|
||||||
|
}
|
||||||
|
return sessions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Views returns the set of View objects currently being served.
|
||||||
|
func (st *State) Views() []View {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
views := make([]View, len(st.views.objs))
|
||||||
|
for i, v := range st.views.objs {
|
||||||
|
views[i] = v.(View)
|
||||||
|
}
|
||||||
|
return views
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clients returns the set of Clients currently being served.
|
||||||
|
func (st *State) Clients() []Client {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
clients := make([]Client, len(st.clients.objs))
|
||||||
|
for i, c := range st.clients.objs {
|
||||||
|
clients[i] = c.(Client)
|
||||||
|
}
|
||||||
|
return clients
|
||||||
|
}
|
||||||
|
|
||||||
|
// Servers returns the set of Servers the instance is currently connected to.
|
||||||
|
func (st *State) Servers() []Server {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
servers := make([]Server, len(st.servers.objs))
|
||||||
|
for i, s := range st.servers.objs {
|
||||||
|
servers[i] = s.(Server)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Client is an incoming connection from a remote client.
|
||||||
|
type Client interface {
|
||||||
|
ID() string
|
||||||
|
Session() Session
|
||||||
|
DebugAddr() string
|
||||||
|
Logfile() string
|
||||||
|
ServerID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Server is an outgoing connection to a remote LSP server.
|
||||||
|
type Server interface {
|
||||||
|
ID() string
|
||||||
|
DebugAddr() string
|
||||||
|
Logfile() string
|
||||||
|
ClientID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Cache is an in-memory cache.
|
||||||
type Cache interface {
|
type Cache interface {
|
||||||
ID() string
|
ID() string
|
||||||
FileSet() *token.FileSet
|
FileSet() *token.FileSet
|
||||||
MemStats() map[reflect.Type]int
|
MemStats() map[reflect.Type]int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A Session is an LSP serving session.
|
||||||
type Session interface {
|
type Session interface {
|
||||||
ID() string
|
ID() string
|
||||||
Cache() Cache
|
Cache() Cache
|
||||||
@ -64,6 +182,7 @@ type Session interface {
|
|||||||
File(hash string) *File
|
File(hash string) *File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A View is a root directory within a Session.
|
||||||
type View interface {
|
type View interface {
|
||||||
ID() string
|
ID() string
|
||||||
Name() string
|
Name() string
|
||||||
@ -71,6 +190,7 @@ type View interface {
|
|||||||
Session() Session
|
Session() Session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A File is is a file within a session.
|
||||||
type File struct {
|
type File struct {
|
||||||
Session Session
|
Session Session
|
||||||
URI span.URI
|
URI span.URI
|
||||||
@ -79,55 +199,91 @@ type File struct {
|
|||||||
Hash string
|
Hash string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
// AddCache adds a cache to the set being served.
|
||||||
mu sync.Mutex
|
func (st *State) AddCache(cache Cache) {
|
||||||
data = struct {
|
st.mu.Lock()
|
||||||
Caches []Cache
|
defer st.mu.Unlock()
|
||||||
Sessions []Session
|
st.caches.add(cache)
|
||||||
Views []View
|
|
||||||
}{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddCache adds a cache to the set being served
|
|
||||||
func AddCache(cache Cache) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
data.Caches = append(data.Caches, cache)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DropCache drops a cache from the set being served
|
// DropCache drops a cache from the set being served.
|
||||||
func DropCache(cache Cache) {
|
func (st *State) DropCache(cache Cache) {
|
||||||
mu.Lock()
|
st.mu.Lock()
|
||||||
defer mu.Unlock()
|
defer st.mu.Unlock()
|
||||||
//find and remove the cache
|
st.caches.drop(cache)
|
||||||
if i, _ := findCache(cache.ID()); i >= 0 {
|
|
||||||
copy(data.Caches[i:], data.Caches[i+1:])
|
|
||||||
data.Caches[len(data.Caches)-1] = nil
|
|
||||||
data.Caches = data.Caches[:len(data.Caches)-1]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func findCache(id string) (int, Cache) {
|
// AddSession adds a session to the set being served.
|
||||||
for i, c := range data.Caches {
|
func (st *State) AddSession(session Session) {
|
||||||
if c.ID() == id {
|
st.mu.Lock()
|
||||||
return i, c
|
defer st.mu.Unlock()
|
||||||
}
|
st.sessions.add(session)
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCache(r *http.Request) interface{} {
|
// DropSession drops a session from the set being served.
|
||||||
mu.Lock()
|
func (st *State) DropSession(session Session) {
|
||||||
defer mu.Unlock()
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
st.sessions.drop(session)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddView adds a view to the set being served.
|
||||||
|
func (st *State) AddView(view View) {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
st.views.add(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropView drops a view from the set being served.
|
||||||
|
func (st *State) DropView(view View) {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
st.views.drop(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddClient adds a client to the set being served.
|
||||||
|
func (st *State) AddClient(client Client) {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
st.clients.add(client)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropClient adds a client to the set being served.
|
||||||
|
func (st *State) DropClient(client Client) {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
st.clients.drop(client)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddServer adds a server to the set being queried. In practice, there should
|
||||||
|
// be at most one remote server.
|
||||||
|
func (st *State) AddServer(server Server) {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
st.servers.add(server)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropServer drops a server to the set being queried.
|
||||||
|
func (st *State) DropServer(server Server) {
|
||||||
|
st.mu.Lock()
|
||||||
|
defer st.mu.Unlock()
|
||||||
|
st.servers.drop(server)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Instance) getCache(r *http.Request) interface{} {
|
||||||
|
i.State.mu.Lock()
|
||||||
|
defer i.State.mu.Unlock()
|
||||||
id := path.Base(r.URL.Path)
|
id := path.Base(r.URL.Path)
|
||||||
result := struct {
|
result := struct {
|
||||||
Cache
|
Cache
|
||||||
Sessions []Session
|
Sessions []Session
|
||||||
}{}
|
}{
|
||||||
_, result.Cache = findCache(id)
|
Cache: i.State.caches.find(id).(Cache),
|
||||||
|
}
|
||||||
|
|
||||||
// now find all the views that belong to this session
|
// now find all the views that belong to this session
|
||||||
for _, v := range data.Sessions {
|
for _, vd := range i.State.sessions.objs {
|
||||||
|
v := vd.(Session)
|
||||||
if v.Cache().ID() == id {
|
if v.Cache().ID() == id {
|
||||||
result.Sessions = append(result.Sessions, v)
|
result.Sessions = append(result.Sessions, v)
|
||||||
}
|
}
|
||||||
@ -135,28 +291,19 @@ func getCache(r *http.Request) interface{} {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func findSession(id string) (int, Session) {
|
func (i *Instance) getSession(r *http.Request) interface{} {
|
||||||
for i, c := range data.Sessions {
|
i.State.mu.Lock()
|
||||||
if c.ID() == id {
|
defer i.State.mu.Unlock()
|
||||||
return i, c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSession(r *http.Request) interface{} {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
id := path.Base(r.URL.Path)
|
id := path.Base(r.URL.Path)
|
||||||
_, session := findSession(id)
|
|
||||||
result := struct {
|
result := struct {
|
||||||
Session
|
Session
|
||||||
Views []View
|
Views []View
|
||||||
}{
|
}{
|
||||||
Session: session,
|
Session: i.State.sessions.find(id).(Session),
|
||||||
}
|
}
|
||||||
// now find all the views that belong to this session
|
// now find all the views that belong to this session
|
||||||
for _, v := range data.Views {
|
for _, vd := range i.State.views.objs {
|
||||||
|
v := vd.(View)
|
||||||
if v.Session().ID() == id {
|
if v.Session().ID() == id {
|
||||||
result.Views = append(result.Views, v)
|
result.Views = append(result.Views, v)
|
||||||
}
|
}
|
||||||
@ -164,38 +311,39 @@ func getSession(r *http.Request) interface{} {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func findView(id string) (int, View) {
|
func (i Instance) getClient(r *http.Request) interface{} {
|
||||||
for i, c := range data.Views {
|
i.State.mu.Lock()
|
||||||
if c.ID() == id {
|
defer i.State.mu.Unlock()
|
||||||
return i, c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getView(r *http.Request) interface{} {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
id := path.Base(r.URL.Path)
|
id := path.Base(r.URL.Path)
|
||||||
_, v := findView(id)
|
return i.State.clients.find(id).(Client)
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFile(r *http.Request) interface{} {
|
func (i Instance) getServer(r *http.Request) interface{} {
|
||||||
mu.Lock()
|
i.State.mu.Lock()
|
||||||
defer mu.Unlock()
|
defer i.State.mu.Unlock()
|
||||||
|
id := path.Base(r.URL.Path)
|
||||||
|
return i.State.servers.find(id).(Server)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Instance) getView(r *http.Request) interface{} {
|
||||||
|
i.State.mu.Lock()
|
||||||
|
defer i.State.mu.Unlock()
|
||||||
|
id := path.Base(r.URL.Path)
|
||||||
|
return i.State.views.find(id).(View)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Instance) getFile(r *http.Request) interface{} {
|
||||||
|
i.State.mu.Lock()
|
||||||
|
defer i.State.mu.Unlock()
|
||||||
hash := path.Base(r.URL.Path)
|
hash := path.Base(r.URL.Path)
|
||||||
sid := path.Base(path.Dir(r.URL.Path))
|
sid := path.Base(path.Dir(r.URL.Path))
|
||||||
_, session := findSession(sid)
|
return i.State.sessions.find(sid).(Session).File(hash)
|
||||||
return session.File(hash)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Instance) getInfo() dataFunc {
|
func (i *Instance) getInfo(r *http.Request) interface{} {
|
||||||
return func(r *http.Request) interface{} {
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
i.PrintServerInfo(buf)
|
i.PrintServerInfo(buf)
|
||||||
return template.HTML(buf.String())
|
return template.HTML(buf.String())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMemory(r *http.Request) interface{} {
|
func getMemory(r *http.Request) interface{} {
|
||||||
@ -204,49 +352,13 @@ func getMemory(r *http.Request) interface{} {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSession adds a session to the set being served
|
// NewInstance creates debug instance ready for use using the supplied configuration.
|
||||||
func AddSession(session Session) {
|
func NewInstance(workdir, agent string) *Instance {
|
||||||
mu.Lock()
|
i := &Instance{
|
||||||
defer mu.Unlock()
|
StartTime: time.Now(),
|
||||||
data.Sessions = append(data.Sessions, session)
|
Workdir: workdir,
|
||||||
}
|
OCAgentConfig: agent,
|
||||||
|
|
||||||
// DropSession drops a session from the set being served
|
|
||||||
func DropSession(session Session) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
if i, _ := findSession(session.ID()); i >= 0 {
|
|
||||||
copy(data.Sessions[i:], data.Sessions[i+1:])
|
|
||||||
data.Sessions[len(data.Sessions)-1] = nil
|
|
||||||
data.Sessions = data.Sessions[:len(data.Sessions)-1]
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// AddView adds a view to the set being served
|
|
||||||
func AddView(view View) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
data.Views = append(data.Views, view)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DropView drops a view from the set being served
|
|
||||||
func DropView(view View) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
|
|
||||||
//find and remove the view
|
|
||||||
if i, _ := findView(view.ID()); i >= 0 {
|
|
||||||
copy(data.Views[i:], data.Views[i+1:])
|
|
||||||
data.Views[len(data.Views)-1] = nil
|
|
||||||
data.Views = data.Views[:len(data.Views)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare gets a debug instance ready for use using the supplied configuration.
|
|
||||||
func (i *Instance) Prepare(ctx context.Context) {
|
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
i.LogWriter = os.Stderr
|
i.LogWriter = os.Stderr
|
||||||
ocConfig := ocagent.Discover()
|
ocConfig := ocagent.Discover()
|
||||||
//TODO: we should not need to adjust the discovered configuration
|
//TODO: we should not need to adjust the discovered configuration
|
||||||
@ -255,9 +367,12 @@ func (i *Instance) Prepare(ctx context.Context) {
|
|||||||
i.prometheus = prometheus.New()
|
i.prometheus = prometheus.New()
|
||||||
i.rpcs = &rpcs{}
|
i.rpcs = &rpcs{}
|
||||||
i.traces = &traces{}
|
i.traces = &traces{}
|
||||||
|
i.State = &State{}
|
||||||
export.AddExporters(i.ocagent, i.prometheus, i.rpcs, i.traces)
|
export.AddExporters(i.ocagent, i.prometheus, i.rpcs, i.traces)
|
||||||
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLogFile sets the logfile for use with this instance.
|
||||||
func (i *Instance) SetLogFile(logfile string) (func(), error) {
|
func (i *Instance) SetLogFile(logfile string) (func(), error) {
|
||||||
// TODO: probably a better solution for deferring closure to the caller would
|
// TODO: probably a better solution for deferring closure to the caller would
|
||||||
// be for the debug instance to itself be closed, but this fixes the
|
// be for the debug instance to itself be closed, but this fixes the
|
||||||
@ -285,8 +400,6 @@ func (i *Instance) SetLogFile(logfile string) (func(), error) {
|
|||||||
// It also logs the port the server starts on, to allow for :0 auto assigned
|
// It also logs the port the server starts on, to allow for :0 auto assigned
|
||||||
// ports.
|
// ports.
|
||||||
func (i *Instance) Serve(ctx context.Context) error {
|
func (i *Instance) Serve(ctx context.Context) error {
|
||||||
mu.Lock()
|
|
||||||
defer mu.Unlock()
|
|
||||||
if i.DebugAddress == "" {
|
if i.DebugAddress == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -294,6 +407,7 @@ func (i *Instance) Serve(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
i.ListenedDebugAddress = listener.Addr().String()
|
||||||
|
|
||||||
port := listener.Addr().(*net.TCPAddr).Port
|
port := listener.Addr().(*net.TCPAddr).Port
|
||||||
if strings.HasSuffix(i.DebugAddress, ":0") {
|
if strings.HasSuffix(i.DebugAddress, ":0") {
|
||||||
@ -302,7 +416,7 @@ func (i *Instance) Serve(ctx context.Context) error {
|
|||||||
log.Print(ctx, "Debug serving", tag.Of("Port", port))
|
log.Print(ctx, "Debug serving", tag.Of("Port", port))
|
||||||
go func() {
|
go func() {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/", render(mainTmpl, func(*http.Request) interface{} { return data }))
|
mux.HandleFunc("/", render(mainTmpl, func(*http.Request) interface{} { return i }))
|
||||||
mux.HandleFunc("/debug/", render(debugTmpl, nil))
|
mux.HandleFunc("/debug/", render(debugTmpl, nil))
|
||||||
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||||
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||||
@ -318,11 +432,13 @@ func (i *Instance) Serve(ctx context.Context) error {
|
|||||||
if i.traces != nil {
|
if i.traces != nil {
|
||||||
mux.HandleFunc("/trace/", render(traceTmpl, i.traces.getData))
|
mux.HandleFunc("/trace/", render(traceTmpl, i.traces.getData))
|
||||||
}
|
}
|
||||||
mux.HandleFunc("/cache/", render(cacheTmpl, getCache))
|
mux.HandleFunc("/cache/", render(cacheTmpl, i.getCache))
|
||||||
mux.HandleFunc("/session/", render(sessionTmpl, getSession))
|
mux.HandleFunc("/session/", render(sessionTmpl, i.getSession))
|
||||||
mux.HandleFunc("/view/", render(viewTmpl, getView))
|
mux.HandleFunc("/view/", render(viewTmpl, i.getView))
|
||||||
mux.HandleFunc("/file/", render(fileTmpl, getFile))
|
mux.HandleFunc("/client/", render(clientTmpl, i.getClient))
|
||||||
mux.HandleFunc("/info", render(infoTmpl, i.getInfo()))
|
mux.HandleFunc("/server/", render(serverTmpl, i.getServer))
|
||||||
|
mux.HandleFunc("/file/", render(fileTmpl, i.getFile))
|
||||||
|
mux.HandleFunc("/info", render(infoTmpl, i.getInfo))
|
||||||
mux.HandleFunc("/memory", render(memoryTmpl, getMemory))
|
mux.HandleFunc("/memory", render(memoryTmpl, getMemory))
|
||||||
if err := http.Serve(listener, mux); err != nil {
|
if err := http.Serve(listener, mux); err != nil {
|
||||||
log.Error(ctx, "Debug server failed", err)
|
log.Error(ctx, "Debug server failed", err)
|
||||||
@ -333,6 +449,7 @@ func (i *Instance) Serve(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonitorMemory starts recording memory statistics each second.
|
||||||
func (i *Instance) MonitorMemory(ctx context.Context) {
|
func (i *Instance) MonitorMemory(ctx context.Context) {
|
||||||
tick := time.NewTicker(time.Second)
|
tick := time.NewTicker(time.Second)
|
||||||
nextThresholdGiB := uint64(1)
|
nextThresholdGiB := uint64(1)
|
||||||
@ -386,6 +503,7 @@ func render(tmpl *template.Template, fun dataFunc) func(http.ResponseWriter, *ht
|
|||||||
}
|
}
|
||||||
if err := tmpl.Execute(w, data); err != nil {
|
if err := tmpl.Execute(w, data); err != nil {
|
||||||
log.Error(context.Background(), "", err)
|
log.Error(context.Background(), "", err)
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -441,23 +559,30 @@ Unknown page
|
|||||||
</html>
|
</html>
|
||||||
|
|
||||||
{{define "cachelink"}}<a href="/cache/{{.}}">Cache {{.}}</a>{{end}}
|
{{define "cachelink"}}<a href="/cache/{{.}}">Cache {{.}}</a>{{end}}
|
||||||
|
{{define "clientlink"}}<a href="/client/{{.}}">Client {{.}}</a>{{end}}
|
||||||
|
{{define "serverlink"}}<a href="/server/{{.}}">Server {{.}}</a>{{end}}
|
||||||
{{define "sessionlink"}}<a href="/session/{{.}}">Session {{.}}</a>{{end}}
|
{{define "sessionlink"}}<a href="/session/{{.}}">Session {{.}}</a>{{end}}
|
||||||
{{define "viewlink"}}<a href="/view/{{.}}">View {{.}}</a>{{end}}
|
{{define "viewlink"}}<a href="/view/{{.}}">View {{.}}</a>{{end}}
|
||||||
{{define "filelink"}}<a href="/file/{{.Session.ID}}/{{.Hash}}">{{.URI}}</a>{{end}}
|
{{define "filelink"}}<a href="/file/{{.Session.ID}}/{{.Hash}}">{{.URI}}</a>{{end}}
|
||||||
`)).Funcs(template.FuncMap{
|
`)).Funcs(template.FuncMap{
|
||||||
"fuint64": fuint64,
|
"fuint64": fuint64,
|
||||||
"fuint32": fuint32,
|
"fuint32": fuint32,
|
||||||
|
"url": func(s string) template.URL { return template.URL(s) },
|
||||||
})
|
})
|
||||||
|
|
||||||
var mainTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
|
var mainTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
|
||||||
{{define "title"}}GoPls server information{{end}}
|
{{define "title"}}GoPls server information{{end}}
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<h2>Caches</h2>
|
<h2>Caches</h2>
|
||||||
<ul>{{range .Caches}}<li>{{template "cachelink" .ID}}</li>{{end}}</ul>
|
<ul>{{range .State.Caches}}<li>{{template "cachelink" .ID}}</li>{{end}}</ul>
|
||||||
<h2>Sessions</h2>
|
<h2>Sessions</h2>
|
||||||
<ul>{{range .Sessions}}<li>{{template "sessionlink" .ID}} from {{template "cachelink" .Cache.ID}}</li>{{end}}</ul>
|
<ul>{{range .State.Sessions}}<li>{{template "sessionlink" .ID}} from {{template "cachelink" .Cache.ID}}</li>{{end}}</ul>
|
||||||
<h2>Views</h2>
|
<h2>Views</h2>
|
||||||
<ul>{{range .Views}}<li>{{.Name}} is {{template "viewlink" .ID}} from {{template "sessionlink" .Session.ID}} in {{.Folder}}</li>{{end}}</ul>
|
<ul>{{range .State.Views}}<li>{{.Name}} is {{template "viewlink" .ID}} from {{template "sessionlink" .Session.ID}} in {{.Folder}}</li>{{end}}</ul>
|
||||||
|
<h2>Clients</h2>
|
||||||
|
<ul>{{range .State.Clients}}<li>{{template "clientlink" .ID}}</li>{{end}}</ul>
|
||||||
|
<h2>Servers</h2>
|
||||||
|
<ul>{{range .State.Servers}}<li>{{template "serverlink" .ID}}</li>{{end}}</ul>
|
||||||
{{end}}
|
{{end}}
|
||||||
`))
|
`))
|
||||||
|
|
||||||
@ -515,6 +640,23 @@ var cacheTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
|
|||||||
{{end}}
|
{{end}}
|
||||||
`))
|
`))
|
||||||
|
|
||||||
|
var clientTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
|
||||||
|
{{define "title"}}Client {{.ID}}{{end}}
|
||||||
|
{{define "body"}}
|
||||||
|
Using session: <b>{{template "sessionlink" .Session.ID}}</b><br>
|
||||||
|
Debug this client at: <a href="http://{{url .DebugAddr}}">{{.DebugAddr}}</a><br>
|
||||||
|
Logfile: {{.Logfile}}<br>
|
||||||
|
{{end}}
|
||||||
|
`))
|
||||||
|
|
||||||
|
var serverTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
|
||||||
|
{{define "title"}}Server {{.ID}}{{end}}
|
||||||
|
{{define "body"}}
|
||||||
|
Debug this server at: <a href="http://{{.DebugAddr}}">{{.DebugAddr}}</a><br>
|
||||||
|
Logfile: {{.Logfile}}<br>
|
||||||
|
{{end}}
|
||||||
|
`))
|
||||||
|
|
||||||
var sessionTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
|
var sessionTmpl = template.Must(template.Must(baseTemplate.Clone()).Parse(`
|
||||||
{{define "title"}}Session {{.ID}}{{end}}
|
{{define "title"}}Session {{.ID}}{{end}}
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
|
54
internal/lsp/debug/serve_test.go
Normal file
54
internal/lsp/debug/serve_test.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2020 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 debug
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
type fakeCache struct {
|
||||||
|
Cache
|
||||||
|
|
||||||
|
id string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c fakeCache) ID() string {
|
||||||
|
return c.id
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestState(t *testing.T) {
|
||||||
|
c1 := fakeCache{id: "1"}
|
||||||
|
c2 := fakeCache{id: "2"}
|
||||||
|
c3 := fakeCache{id: "3"}
|
||||||
|
|
||||||
|
var s State
|
||||||
|
s.AddCache(c1)
|
||||||
|
s.AddCache(c2)
|
||||||
|
s.AddCache(c3)
|
||||||
|
|
||||||
|
compareCaches := func(desc string, want []fakeCache) {
|
||||||
|
t.Run(desc, func(t *testing.T) {
|
||||||
|
caches := s.Caches()
|
||||||
|
if gotLen, wantLen := len(caches), len(want); gotLen != wantLen {
|
||||||
|
t.Fatalf("len(Caches) = %d, want %d", gotLen, wantLen)
|
||||||
|
}
|
||||||
|
for i, got := range caches {
|
||||||
|
if got != want[i] {
|
||||||
|
t.Errorf("Caches[%d] = %v, want %v", i, got, want[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
compareCaches("initial load", []fakeCache{c1, c2, c3})
|
||||||
|
s.DropCache(c2)
|
||||||
|
compareCaches("dropped cache 2", []fakeCache{c1, c3})
|
||||||
|
s.DropCache(c2)
|
||||||
|
compareCaches("duplicate drop", []fakeCache{c1, c3})
|
||||||
|
s.AddCache(c2)
|
||||||
|
compareCaches("re-add cache 2", []fakeCache{c1, c3, c2})
|
||||||
|
s.DropCache(c1)
|
||||||
|
s.DropCache(c2)
|
||||||
|
s.DropCache(c3)
|
||||||
|
compareCaches("drop all", []fakeCache{})
|
||||||
|
}
|
@ -49,7 +49,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
|||||||
for _, datum := range data {
|
for _, datum := range data {
|
||||||
defer datum.Exported.Cleanup()
|
defer datum.Exported.Cleanup()
|
||||||
|
|
||||||
cache := cache.New(nil)
|
cache := cache.New(nil, nil)
|
||||||
session := cache.NewSession()
|
session := cache.NewSession()
|
||||||
options := tests.DefaultOptions()
|
options := tests.DefaultOptions()
|
||||||
session.SetOptions(options)
|
session.SetOptions(options)
|
||||||
|
@ -25,9 +25,10 @@ import (
|
|||||||
// streams as a new LSP session, using a shared cache.
|
// streams as a new LSP session, using a shared cache.
|
||||||
type StreamServer struct {
|
type StreamServer struct {
|
||||||
withTelemetry bool
|
withTelemetry bool
|
||||||
|
cache *cache.Cache
|
||||||
|
|
||||||
// accept is mutable for testing.
|
// If set, serverForTest is used instead of an actual lsp.Server.
|
||||||
accept func(protocol.Client) protocol.Server
|
serverForTest protocol.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStreamServer creates a StreamServer using the shared cache. If
|
// NewStreamServer creates a StreamServer using the shared cache. If
|
||||||
@ -36,10 +37,7 @@ type StreamServer struct {
|
|||||||
func NewStreamServer(cache *cache.Cache, withTelemetry bool) *StreamServer {
|
func NewStreamServer(cache *cache.Cache, withTelemetry bool) *StreamServer {
|
||||||
s := &StreamServer{
|
s := &StreamServer{
|
||||||
withTelemetry: withTelemetry,
|
withTelemetry: withTelemetry,
|
||||||
}
|
cache: cache,
|
||||||
s.accept = func(c protocol.Client) protocol.Server {
|
|
||||||
session := cache.NewSession()
|
|
||||||
return lsp.NewServer(session, c)
|
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -49,7 +47,10 @@ func NewStreamServer(cache *cache.Cache, withTelemetry bool) *StreamServer {
|
|||||||
func (s *StreamServer) ServeStream(ctx context.Context, stream jsonrpc2.Stream) error {
|
func (s *StreamServer) ServeStream(ctx context.Context, stream jsonrpc2.Stream) error {
|
||||||
conn := jsonrpc2.NewConn(stream)
|
conn := jsonrpc2.NewConn(stream)
|
||||||
client := protocol.ClientDispatcher(conn)
|
client := protocol.ClientDispatcher(conn)
|
||||||
server := s.accept(client)
|
server := s.serverForTest
|
||||||
|
if server == nil {
|
||||||
|
server = lsp.NewServer(s.cache.NewSession(), client)
|
||||||
|
}
|
||||||
conn.AddHandler(protocol.ServerHandler(server))
|
conn.AddHandler(protocol.ServerHandler(server))
|
||||||
conn.AddHandler(protocol.Canceller{})
|
conn.AddHandler(protocol.Canceller{})
|
||||||
if s.withTelemetry {
|
if s.withTelemetry {
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/tools/internal/jsonrpc2/servertest"
|
"golang.org/x/tools/internal/jsonrpc2/servertest"
|
||||||
|
"golang.org/x/tools/internal/lsp/cache"
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
"golang.org/x/tools/internal/telemetry/log"
|
"golang.org/x/tools/internal/telemetry/log"
|
||||||
)
|
)
|
||||||
@ -41,11 +42,8 @@ func TestClientLogging(t *testing.T) {
|
|||||||
server := pingServer{}
|
server := pingServer{}
|
||||||
client := fakeClient{logs: make(chan string, 10)}
|
client := fakeClient{logs: make(chan string, 10)}
|
||||||
|
|
||||||
ss := &StreamServer{
|
ss := NewStreamServer(cache.New(nil, nil), false)
|
||||||
accept: func(c protocol.Client) protocol.Server {
|
ss.serverForTest = server
|
||||||
return server
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ts := servertest.NewPipeServer(ctx, ss)
|
ts := servertest.NewPipeServer(ctx, ss)
|
||||||
cc := ts.Connect(ctx)
|
cc := ts.Connect(ctx)
|
||||||
cc.AddHandler(protocol.ClientHandler(client))
|
cc.AddHandler(protocol.ClientHandler(client))
|
||||||
@ -94,11 +92,8 @@ func TestRequestCancellation(t *testing.T) {
|
|||||||
server := waitableServer{
|
server := waitableServer{
|
||||||
started: make(chan struct{}),
|
started: make(chan struct{}),
|
||||||
}
|
}
|
||||||
ss := &StreamServer{
|
ss := NewStreamServer(cache.New(nil, nil), false)
|
||||||
accept: func(c protocol.Client) protocol.Server {
|
ss.serverForTest = server
|
||||||
return server
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
tsDirect := servertest.NewTCPServer(ctx, ss)
|
tsDirect := servertest.NewTCPServer(ctx, ss)
|
||||||
|
|
||||||
@ -149,4 +144,18 @@ func TestRequestCancellation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const exampleProgram = `
|
||||||
|
-- go.mod --
|
||||||
|
module mod
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
-- main.go --
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("Hello World.")
|
||||||
|
}`
|
||||||
|
|
||||||
// TODO: add a test for telemetry.
|
// TODO: add a test for telemetry.
|
||||||
|
@ -23,7 +23,7 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
func TestModfileRemainsUnchanged(t *testing.T) {
|
func TestModfileRemainsUnchanged(t *testing.T) {
|
||||||
ctx := tests.Context(t)
|
ctx := tests.Context(t)
|
||||||
cache := cache.New(nil)
|
cache := cache.New(nil, nil)
|
||||||
session := cache.NewSession()
|
session := cache.NewSession()
|
||||||
options := tests.DefaultOptions()
|
options := tests.DefaultOptions()
|
||||||
options.TempModfile = true
|
options.TempModfile = true
|
||||||
|
@ -79,7 +79,7 @@ func (r *Runner) getTestServer() *servertest.TCPServer {
|
|||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
defer r.mu.Unlock()
|
defer r.mu.Unlock()
|
||||||
if r.ts == nil {
|
if r.ts == nil {
|
||||||
ss := lsprpc.NewStreamServer(cache.New(nil), false)
|
ss := lsprpc.NewStreamServer(cache.New(nil, nil), false)
|
||||||
r.ts = servertest.NewTCPServer(context.Background(), ss)
|
r.ts = servertest.NewTCPServer(context.Background(), ss)
|
||||||
}
|
}
|
||||||
return r.ts
|
return r.ts
|
||||||
@ -184,7 +184,7 @@ func (r *Runner) RunInMode(modes EnvMode, t *testing.T, filedata string, test fu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) singletonEnv(ctx context.Context, t *testing.T) (servertest.Connector, func()) {
|
func (r *Runner) singletonEnv(ctx context.Context, t *testing.T) (servertest.Connector, func()) {
|
||||||
ss := lsprpc.NewStreamServer(cache.New(nil), false)
|
ss := lsprpc.NewStreamServer(cache.New(nil, nil), false)
|
||||||
ts := servertest.NewPipeServer(ctx, ss)
|
ts := servertest.NewPipeServer(ctx, ss)
|
||||||
cleanup := func() {
|
cleanup := func() {
|
||||||
ts.Close()
|
ts.Close()
|
||||||
|
@ -47,7 +47,7 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
|
|||||||
for _, datum := range data {
|
for _, datum := range data {
|
||||||
defer datum.Exported.Cleanup()
|
defer datum.Exported.Cleanup()
|
||||||
|
|
||||||
cache := cache.New(nil)
|
cache := cache.New(nil, nil)
|
||||||
session := cache.NewSession()
|
session := cache.NewSession()
|
||||||
options := tests.DefaultOptions()
|
options := tests.DefaultOptions()
|
||||||
options.Env = datum.Config.Env
|
options.Env = datum.Config.Env
|
||||||
|
Loading…
Reference in New Issue
Block a user