service/dap: support terminateDebuggee option for attach only (#2940)
* service/dap: support terminateDebuggee option for attach only * Update dlv_test Co-authored-by: Polina Sokolova <polinasok@users.noreply.github.com>
This commit is contained in:
parent
e1e4b09a5e
commit
b5f60db954
@ -696,6 +696,7 @@ func TestDAPCmd(t *testing.T) {
|
|||||||
func newDAPRemoteClient(t *testing.T, addr string) *daptest.Client {
|
func newDAPRemoteClient(t *testing.T, addr string) *daptest.Client {
|
||||||
c := daptest.NewClient(addr)
|
c := daptest.NewClient(addr)
|
||||||
c.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
c.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
||||||
|
c.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
c.ExpectInitializedEvent(t)
|
c.ExpectInitializedEvent(t)
|
||||||
c.ExpectAttachResponse(t)
|
c.ExpectAttachResponse(t)
|
||||||
c.ConfigurationDoneRequest()
|
c.ConfigurationDoneRequest()
|
||||||
|
|||||||
@ -105,7 +105,6 @@ func (c *Client) ExpectInitializeResponseAndCapabilities(t *testing.T) *dap.Init
|
|||||||
SupportsConfigurationDoneRequest: true,
|
SupportsConfigurationDoneRequest: true,
|
||||||
SupportsConditionalBreakpoints: true,
|
SupportsConditionalBreakpoints: true,
|
||||||
SupportsDelayedStackTraceLoading: true,
|
SupportsDelayedStackTraceLoading: true,
|
||||||
SupportTerminateDebuggee: true,
|
|
||||||
SupportsExceptionInfoRequest: true,
|
SupportsExceptionInfoRequest: true,
|
||||||
SupportsSetVariable: true,
|
SupportsSetVariable: true,
|
||||||
SupportsFunctionBreakpoints: true,
|
SupportsFunctionBreakpoints: true,
|
||||||
@ -137,6 +136,15 @@ func (c *Client) ExpectUnsupportedCommandErrorResponse(t *testing.T) *dap.ErrorR
|
|||||||
return c.ExpectErrorResponseWith(t, 9999, "Unsupported command", false)
|
return c.ExpectErrorResponseWith(t, 9999, "Unsupported command", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) ExpectCapabilitiesEventSupportTerminateDebuggee(t *testing.T) *dap.CapabilitiesEvent {
|
||||||
|
t.Helper()
|
||||||
|
e := c.ExpectCapabilitiesEvent(t)
|
||||||
|
if !e.Body.Capabilities.SupportTerminateDebuggee {
|
||||||
|
t.Errorf("\ngot %#v\nwant SupportTerminateDebuggee=true", e.Body.Capabilities.SupportTerminateDebuggee)
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) ExpectOutputEventRegex(t *testing.T, want string) *dap.OutputEvent {
|
func (c *Client) ExpectOutputEventRegex(t *testing.T, want string) *dap.OutputEvent {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
e := c.ExpectOutputEvent(t)
|
e := c.ExpectOutputEvent(t)
|
||||||
|
|||||||
@ -834,7 +834,6 @@ func (s *Session) onInitializeRequest(request *dap.InitializeRequest) {
|
|||||||
response.Body.SupportsConfigurationDoneRequest = true
|
response.Body.SupportsConfigurationDoneRequest = true
|
||||||
response.Body.SupportsConditionalBreakpoints = true
|
response.Body.SupportsConditionalBreakpoints = true
|
||||||
response.Body.SupportsDelayedStackTraceLoading = true
|
response.Body.SupportsDelayedStackTraceLoading = true
|
||||||
response.Body.SupportTerminateDebuggee = true
|
|
||||||
response.Body.SupportsFunctionBreakpoints = true
|
response.Body.SupportsFunctionBreakpoints = true
|
||||||
response.Body.SupportsInstructionBreakpoints = true
|
response.Body.SupportsInstructionBreakpoints = true
|
||||||
response.Body.SupportsExceptionInfoRequest = true
|
response.Body.SupportsExceptionInfoRequest = true
|
||||||
@ -844,10 +843,12 @@ func (s *Session) onInitializeRequest(request *dap.InitializeRequest) {
|
|||||||
response.Body.SupportsSteppingGranularity = true
|
response.Body.SupportsSteppingGranularity = true
|
||||||
response.Body.SupportsLogPoints = true
|
response.Body.SupportsLogPoints = true
|
||||||
response.Body.SupportsDisassembleRequest = true
|
response.Body.SupportsDisassembleRequest = true
|
||||||
|
// To be enabled by CapabilitiesEvent based on launch configuration
|
||||||
|
response.Body.SupportsStepBack = false
|
||||||
|
response.Body.SupportTerminateDebuggee = false
|
||||||
// TODO(polina): support these requests in addition to vscode-go feature parity
|
// TODO(polina): support these requests in addition to vscode-go feature parity
|
||||||
response.Body.SupportsTerminateRequest = false
|
response.Body.SupportsTerminateRequest = false
|
||||||
response.Body.SupportsRestartRequest = false
|
response.Body.SupportsRestartRequest = false
|
||||||
response.Body.SupportsStepBack = false // To be enabled by CapabilitiesEvent based on configuration
|
|
||||||
response.Body.SupportsSetExpression = false
|
response.Body.SupportsSetExpression = false
|
||||||
response.Body.SupportsLoadedSourcesRequest = false
|
response.Body.SupportsLoadedSourcesRequest = false
|
||||||
response.Body.SupportsReadMemoryRequest = false
|
response.Body.SupportsReadMemoryRequest = false
|
||||||
@ -1749,6 +1750,8 @@ func (s *Session) onAttachRequest(request *dap.AttachRequest) {
|
|||||||
s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", err.Error())
|
s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Give the user an option to terminate debuggee when client disconnects (default is to leave it)
|
||||||
|
s.send(&dap.CapabilitiesEvent{Event: *newEvent("capabilities"), Body: dap.CapabilitiesEventBody{Capabilities: dap.Capabilities{SupportTerminateDebuggee: true}}})
|
||||||
case "remote":
|
case "remote":
|
||||||
if s.debugger == nil {
|
if s.debugger == nil {
|
||||||
s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", "no debugger found")
|
s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach", "no debugger found")
|
||||||
@ -1767,6 +1770,9 @@ func (s *Session) onAttachRequest(request *dap.AttachRequest) {
|
|||||||
if s.config.Debugger.Backend == "rr" {
|
if s.config.Debugger.Backend == "rr" {
|
||||||
s.send(&dap.CapabilitiesEvent{Event: *newEvent("capabilities"), Body: dap.CapabilitiesEventBody{Capabilities: dap.Capabilities{SupportsStepBack: true}}})
|
s.send(&dap.CapabilitiesEvent{Event: *newEvent("capabilities"), Body: dap.CapabilitiesEventBody{Capabilities: dap.Capabilities{SupportsStepBack: true}}})
|
||||||
}
|
}
|
||||||
|
// Give the user an option to terminate this server when client disconnects (default is to leave it)
|
||||||
|
s.send(&dap.CapabilitiesEvent{Event: *newEvent("capabilities"), Body: dap.CapabilitiesEventBody{Capabilities: dap.Capabilities{SupportTerminateDebuggee: true}}})
|
||||||
|
// TODO(polina); also use SupportSuspendDebuggee when available
|
||||||
default:
|
default:
|
||||||
s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach",
|
s.sendShowUserErrorResponse(request.Request, FailedToAttach, "Failed to attach",
|
||||||
fmt.Sprintf("invalid debug configuration - unsupported 'mode' attribute %q", args.Mode))
|
fmt.Sprintf("invalid debug configuration - unsupported 'mode' attribute %q", args.Mode))
|
||||||
|
|||||||
@ -506,6 +506,7 @@ func TestAttachStopOnEntry(t *testing.T) {
|
|||||||
// 2 >> attach, << initialized, << attach
|
// 2 >> attach, << initialized, << attach
|
||||||
client.AttachRequest(
|
client.AttachRequest(
|
||||||
map[string]interface{}{"mode": "local", "processId": cmd.Process.Pid, "stopOnEntry": true, "backend": "default"})
|
map[string]interface{}{"mode": "local", "processId": cmd.Process.Pid, "stopOnEntry": true, "backend": "default"})
|
||||||
|
client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
initEvent := client.ExpectInitializedEvent(t)
|
initEvent := client.ExpectInitializedEvent(t)
|
||||||
if initEvent.Seq != 0 {
|
if initEvent.Seq != 0 {
|
||||||
t.Errorf("\ngot %#v\nwant Seq=0", initEvent)
|
t.Errorf("\ngot %#v\nwant Seq=0", initEvent)
|
||||||
@ -3676,6 +3677,7 @@ func substitutePathTestHelper(t *testing.T, fixture protest.Fixture, client *dap
|
|||||||
switch request {
|
switch request {
|
||||||
case "attach":
|
case "attach":
|
||||||
client.AttachRequest(launchAttachConfig)
|
client.AttachRequest(launchAttachConfig)
|
||||||
|
client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
case "launch":
|
case "launch":
|
||||||
client.LaunchRequestWithArgs(launchAttachConfig)
|
client.LaunchRequestWithArgs(launchAttachConfig)
|
||||||
default:
|
default:
|
||||||
@ -5663,6 +5665,7 @@ func TestAttachRequest(t *testing.T) {
|
|||||||
func() {
|
func() {
|
||||||
client.AttachRequest(map[string]interface{}{
|
client.AttachRequest(map[string]interface{}{
|
||||||
/*"mode": "local" by default*/ "processId": cmd.Process.Pid, "stopOnEntry": false})
|
/*"mode": "local" by default*/ "processId": cmd.Process.Pid, "stopOnEntry": false})
|
||||||
|
client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
},
|
},
|
||||||
// Set breakpoints
|
// Set breakpoints
|
||||||
fixture.Source, []int{8},
|
fixture.Source, []int{8},
|
||||||
@ -6555,6 +6558,7 @@ func TestAttachRemoteToHaltedTargetStopOnEntry(t *testing.T) {
|
|||||||
_, dbg := launchDebuggerWithTargetHalted(t, "increment")
|
_, dbg := launchDebuggerWithTargetHalted(t, "increment")
|
||||||
runTestWithDebugger(t, dbg, func(client *daptest.Client) {
|
runTestWithDebugger(t, dbg, func(client *daptest.Client) {
|
||||||
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
||||||
|
client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
client.ExpectInitializedEvent(t)
|
client.ExpectInitializedEvent(t)
|
||||||
client.ExpectAttachResponse(t)
|
client.ExpectAttachResponse(t)
|
||||||
client.ConfigurationDoneRequest()
|
client.ConfigurationDoneRequest()
|
||||||
@ -6568,6 +6572,7 @@ func TestAttachRemoteToHaltedTargetContinueOnEntry(t *testing.T) {
|
|||||||
_, dbg := launchDebuggerWithTargetHalted(t, "http_server")
|
_, dbg := launchDebuggerWithTargetHalted(t, "http_server")
|
||||||
runTestWithDebugger(t, dbg, func(client *daptest.Client) {
|
runTestWithDebugger(t, dbg, func(client *daptest.Client) {
|
||||||
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": false})
|
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": false})
|
||||||
|
client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
client.ExpectInitializedEvent(t)
|
client.ExpectInitializedEvent(t)
|
||||||
client.ExpectAttachResponse(t)
|
client.ExpectAttachResponse(t)
|
||||||
client.ConfigurationDoneRequest()
|
client.ConfigurationDoneRequest()
|
||||||
@ -6584,6 +6589,7 @@ func TestAttachRemoteToRunningTargetStopOnEntry(t *testing.T) {
|
|||||||
fixture, dbg := launchDebuggerWithTargetRunning(t, "loopprog")
|
fixture, dbg := launchDebuggerWithTargetRunning(t, "loopprog")
|
||||||
runTestWithDebugger(t, dbg, func(client *daptest.Client) {
|
runTestWithDebugger(t, dbg, func(client *daptest.Client) {
|
||||||
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
||||||
|
client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
client.ExpectInitializedEvent(t)
|
client.ExpectInitializedEvent(t)
|
||||||
client.ExpectAttachResponse(t)
|
client.ExpectAttachResponse(t)
|
||||||
// Target is halted here
|
// Target is halted here
|
||||||
@ -6603,6 +6609,7 @@ func TestAttachRemoteToRunningTargetContinueOnEntry(t *testing.T) {
|
|||||||
fixture, dbg := launchDebuggerWithTargetRunning(t, "loopprog")
|
fixture, dbg := launchDebuggerWithTargetRunning(t, "loopprog")
|
||||||
runTestWithDebugger(t, dbg, func(client *daptest.Client) {
|
runTestWithDebugger(t, dbg, func(client *daptest.Client) {
|
||||||
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": false})
|
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": false})
|
||||||
|
client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
client.ExpectInitializedEvent(t)
|
client.ExpectInitializedEvent(t)
|
||||||
client.ExpectAttachResponse(t)
|
client.ExpectAttachResponse(t)
|
||||||
// Target is halted here
|
// Target is halted here
|
||||||
@ -6617,7 +6624,7 @@ func TestAttachRemoteToRunningTargetContinueOnEntry(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TestAttachRemoteMultiClientDisconnect tests that that remote attach doesn't take down
|
// TestAttachRemoteMultiClientDisconnect tests that that remote attach doesn't take down
|
||||||
// the server in multi-client mode unless terminateDebugee is explicitely set.
|
// the server in multi-client mode unless terminateDebuggee is explicitely set.
|
||||||
func TestAttachRemoteMultiClientDisconnect(t *testing.T) {
|
func TestAttachRemoteMultiClientDisconnect(t *testing.T) {
|
||||||
closingClientSessionOnly := fmt.Sprintf(daptest.ClosingClient, "halted")
|
closingClientSessionOnly := fmt.Sprintf(daptest.ClosingClient, "halted")
|
||||||
detachingAndTerminating := "Detaching and terminating target process"
|
detachingAndTerminating := "Detaching and terminating target process"
|
||||||
@ -6651,6 +6658,7 @@ func TestAttachRemoteMultiClientDisconnect(t *testing.T) {
|
|||||||
client.ExpectInitializeResponseAndCapabilities(t)
|
client.ExpectInitializeResponseAndCapabilities(t)
|
||||||
|
|
||||||
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
client.AttachRequest(map[string]interface{}{"mode": "remote", "stopOnEntry": true})
|
||||||
|
client.ExpectCapabilitiesEventSupportTerminateDebuggee(t)
|
||||||
client.ExpectInitializedEvent(t)
|
client.ExpectInitializedEvent(t)
|
||||||
client.ExpectAttachResponse(t)
|
client.ExpectAttachResponse(t)
|
||||||
client.ConfigurationDoneRequest()
|
client.ConfigurationDoneRequest()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user