2015-06-21 03:47:44 +00:00
package servicetest
2015-03-20 21:11:11 +00:00
import (
2015-06-28 15:00:56 +00:00
"fmt"
2016-02-15 14:39:29 +00:00
"math/rand"
2015-03-20 21:11:11 +00:00
"net"
2015-06-13 04:47:30 +00:00
"os"
2015-05-08 20:16:22 +00:00
"path/filepath"
2015-06-13 04:47:30 +00:00
"runtime"
2015-06-28 15:00:56 +00:00
"strconv"
2016-01-30 21:27:08 +00:00
"strings"
2015-03-20 21:11:11 +00:00
"testing"
2016-02-15 14:39:29 +00:00
"time"
2015-03-20 21:11:11 +00:00
2015-06-12 19:49:23 +00:00
protest "github.com/derekparker/delve/proc/test"
2015-06-21 03:47:44 +00:00
2016-02-25 09:48:42 +00:00
"github.com/derekparker/delve/proc"
2015-03-20 21:11:11 +00:00
"github.com/derekparker/delve/service"
"github.com/derekparker/delve/service/api"
2015-06-21 03:47:44 +00:00
"github.com/derekparker/delve/service/rpc"
2015-03-20 21:11:11 +00:00
)
2015-06-13 04:47:30 +00:00
func init ( ) {
runtime . GOMAXPROCS ( 2 )
}
2015-09-17 08:42:34 +00:00
func assertNoError ( err error , t * testing . T , s string ) {
if err != nil {
_ , file , line , _ := runtime . Caller ( 1 )
fname := filepath . Base ( file )
t . Fatalf ( "failed assertion at %s:%d: %s - %s\n" , fname , line , s , err )
}
}
2016-01-30 06:23:14 +00:00
func assertError ( err error , t * testing . T , s string ) {
if err == nil {
_ , file , line , _ := runtime . Caller ( 1 )
fname := filepath . Base ( file )
t . Fatalf ( "failed assertion at %s:%d: %s (no error)\n" , fname , line , s )
}
}
2015-04-27 15:51:02 +00:00
func TestMain ( m * testing . M ) {
2015-06-21 03:47:44 +00:00
os . Exit ( protest . RunTestsWithFixtures ( m ) )
2015-04-27 15:51:02 +00:00
}
func withTestClient ( name string , t * testing . T , fn func ( c service . Client ) ) {
2015-03-20 21:11:11 +00:00
listener , err := net . Listen ( "tcp" , "localhost:0" )
if err != nil {
t . Fatalf ( "couldn't start listener: %s\n" , err )
}
2015-06-21 03:47:44 +00:00
defer listener . Close ( )
2015-06-24 13:08:48 +00:00
server := rpc . NewServer ( & service . Config {
Listener : listener ,
ProcessArgs : [ ] string { protest . BuildFixture ( name ) . Path } ,
} , false )
2015-06-27 04:05:15 +00:00
if err := server . Run ( ) ; err != nil {
t . Fatal ( err )
}
2015-06-24 13:08:48 +00:00
client := rpc . NewClient ( listener . Addr ( ) . String ( ) )
2015-06-24 14:44:24 +00:00
defer func ( ) {
client . Detach ( true )
} ( )
2015-06-24 13:08:48 +00:00
fn ( client )
2015-03-20 21:11:11 +00:00
}
2015-06-27 04:05:15 +00:00
func TestRunWithInvalidPath ( t * testing . T ) {
listener , err := net . Listen ( "tcp" , "localhost:0" )
if err != nil {
t . Fatalf ( "couldn't start listener: %s\n" , err )
}
defer listener . Close ( )
server := rpc . NewServer ( & service . Config {
Listener : listener ,
ProcessArgs : [ ] string { "invalid_path" } ,
} , false )
if err := server . Run ( ) ; err == nil {
t . Fatal ( "Expected Run to return error for invalid program path" )
}
}
2015-07-03 20:35:22 +00:00
func TestRestart_afterExit ( t * testing . T ) {
withTestClient ( "continuetestprog" , t , func ( c service . Client ) {
origPid := c . ProcessPid ( )
state := <- c . Continue ( )
if ! state . Exited {
t . Fatal ( "expected initial process to have exited" )
}
if err := c . Restart ( ) ; err != nil {
t . Fatal ( err )
}
if c . ProcessPid ( ) == origPid {
t . Fatal ( "did not spawn new process, has same PID" )
}
state = <- c . Continue ( )
if ! state . Exited {
2015-09-26 19:36:13 +00:00
t . Fatalf ( "expected restarted process to have exited %v" , state )
2015-07-03 20:35:22 +00:00
}
} )
}
2016-01-24 08:16:45 +00:00
func TestRestart_breakpointPreservation ( t * testing . T ) {
withTestClient ( "continuetestprog" , t , func ( c service . Client ) {
_ , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.main" , Line : 1 , Name : "firstbreakpoint" , Tracepoint : true } )
assertNoError ( err , t , "CreateBreakpoint()" )
stateCh := c . Continue ( )
2016-02-22 15:08:45 +00:00
state := <- stateCh
2016-01-24 08:16:45 +00:00
if state . CurrentThread . Breakpoint . Name != "firstbreakpoint" || ! state . CurrentThread . Breakpoint . Tracepoint {
t . Fatalf ( "Wrong breakpoint: %#v\n" , state . CurrentThread . Breakpoint )
}
2016-02-22 15:08:45 +00:00
state = <- stateCh
2016-01-24 08:16:45 +00:00
if ! state . Exited {
t . Fatal ( "Did not exit after first tracepoint" )
}
2016-02-22 15:08:45 +00:00
2016-01-24 08:16:45 +00:00
t . Log ( "Restart" )
c . Restart ( )
stateCh = c . Continue ( )
2016-02-22 15:08:45 +00:00
state = <- stateCh
2016-01-24 08:16:45 +00:00
if state . CurrentThread . Breakpoint . Name != "firstbreakpoint" || ! state . CurrentThread . Breakpoint . Tracepoint {
t . Fatalf ( "Wrong breakpoint (after restart): %#v\n" , state . CurrentThread . Breakpoint )
}
2016-02-22 15:08:45 +00:00
state = <- stateCh
2016-01-24 08:16:45 +00:00
if ! state . Exited {
t . Fatal ( "Did not exit after first tracepoint (after restart)" )
}
} )
}
2015-07-03 20:35:22 +00:00
func TestRestart_duringStop ( t * testing . T ) {
withTestClient ( "continuetestprog" , t , func ( c service . Client ) {
origPid := c . ProcessPid ( )
2015-08-07 16:50:14 +00:00
_ , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.main" , Line : 1 } )
2015-07-03 20:35:22 +00:00
if err != nil {
t . Fatal ( err )
}
state := <- c . Continue ( )
2015-10-29 09:59:22 +00:00
if state . CurrentThread . Breakpoint == nil {
2015-07-03 20:35:22 +00:00
t . Fatal ( "did not hit breakpoint" )
}
if err := c . Restart ( ) ; err != nil {
t . Fatal ( err )
}
if c . ProcessPid ( ) == origPid {
t . Fatal ( "did not spawn new process, has same PID" )
}
bps , err := c . ListBreakpoints ( )
if err != nil {
t . Fatal ( err )
}
2015-08-02 05:08:48 +00:00
if len ( bps ) == 0 {
t . Fatal ( "breakpoints not preserved" )
2015-07-03 20:35:22 +00:00
}
} )
}
func TestRestart_attachPid ( t * testing . T ) {
// Assert it does not work and returns error.
// We cannot restart a process we did not spawn.
server := rpc . NewServer ( & service . Config {
Listener : nil ,
AttachPid : 999 ,
} , false )
2016-01-29 11:37:58 +00:00
if err := server . Restart ( ) ; err == nil {
2015-07-03 20:35:22 +00:00
t . Fatal ( "expected error on restart after attaching to pid but got none" )
}
}
2015-03-20 21:11:11 +00:00
func TestClientServer_exit ( t * testing . T ) {
2015-04-27 15:51:02 +00:00
withTestClient ( "continuetestprog" , t , func ( c service . Client ) {
2015-03-20 21:11:11 +00:00
state , err := c . GetState ( )
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
if e , a := false , state . Exited ; e != a {
t . Fatalf ( "Expected exited %v, got %v" , e , a )
}
2015-06-28 15:00:56 +00:00
state = <- c . Continue ( )
2015-07-03 19:18:03 +00:00
if state . Err == nil {
t . Fatalf ( "Error expected after continue" )
2015-06-21 18:08:14 +00:00
}
2015-06-28 15:00:56 +00:00
if ! state . Exited {
t . Fatalf ( "Expected exit after continue: %v" , state )
2015-06-21 18:08:14 +00:00
}
state , err = c . GetState ( )
2015-10-09 23:30:28 +00:00
if err == nil {
t . Fatal ( "Expected error on querying state from exited process" )
2015-03-20 21:11:11 +00:00
}
} )
}
func TestClientServer_step ( t * testing . T ) {
2015-04-27 15:51:02 +00:00
withTestClient ( "testprog" , t , func ( c service . Client ) {
2015-08-07 16:50:14 +00:00
_ , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.helloworld" , Line : 1 } )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
2015-07-01 03:16:52 +00:00
stateBefore := <- c . Continue ( )
2015-06-28 15:00:56 +00:00
if stateBefore . Err != nil {
t . Fatalf ( "Unexpected error: %v" , stateBefore . Err )
2015-03-20 21:11:11 +00:00
}
stateAfter , err := c . Step ( )
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
if before , after := stateBefore . CurrentThread . PC , stateAfter . CurrentThread . PC ; before >= after {
t . Errorf ( "Expected %#v to be greater than %#v" , before , after )
}
} )
}
type nextTest struct {
begin , end int
}
func testnext ( testcases [ ] nextTest , initialLocation string , t * testing . T ) {
2015-04-27 15:51:02 +00:00
withTestClient ( "testnextprog" , t , func ( c service . Client ) {
2015-08-07 16:50:14 +00:00
bp , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : initialLocation , Line : - 1 } )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
2015-06-28 15:00:56 +00:00
state := <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Unexpected error: %v" , state . Err )
2015-03-20 21:11:11 +00:00
}
2015-06-12 19:32:32 +00:00
_ , err = c . ClearBreakpoint ( bp . ID )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
for _ , tc := range testcases {
if state . CurrentThread . Line != tc . begin {
2015-04-27 15:51:02 +00:00
t . Fatalf ( "Program not stopped at correct spot expected %d was %d" , tc . begin , state . CurrentThread . Line )
2015-03-20 21:11:11 +00:00
}
t . Logf ( "Next for scenario %#v" , tc )
state , err = c . Next ( )
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
if state . CurrentThread . Line != tc . end {
2015-04-27 15:51:02 +00:00
t . Fatalf ( "Program did not continue to correct next location expected %d was %d" , tc . end , state . CurrentThread . Line )
2015-03-20 21:11:11 +00:00
}
}
} )
}
func TestNextGeneral ( t * testing . T ) {
2016-02-25 09:48:42 +00:00
var testcases [ ] nextTest
ver , _ := proc . ParseVersionString ( runtime . Version ( ) )
if ver . Major < 0 || ver . AfterOrEqual ( proc . GoVersion { 1 , 7 , 0 , 0 , 0 } ) {
testcases = [ ] nextTest {
{ 17 , 19 } ,
{ 19 , 20 } ,
{ 20 , 23 } ,
{ 23 , 24 } ,
{ 24 , 26 } ,
{ 26 , 31 } ,
{ 31 , 23 } ,
{ 23 , 24 } ,
{ 24 , 26 } ,
{ 26 , 31 } ,
{ 31 , 23 } ,
{ 23 , 24 } ,
{ 24 , 26 } ,
{ 26 , 27 } ,
{ 27 , 28 } ,
{ 28 , 34 } ,
}
} else {
testcases = [ ] nextTest {
{ 17 , 19 } ,
{ 19 , 20 } ,
{ 20 , 23 } ,
{ 23 , 24 } ,
{ 24 , 26 } ,
{ 26 , 31 } ,
{ 31 , 23 } ,
{ 23 , 24 } ,
{ 24 , 26 } ,
{ 26 , 31 } ,
{ 31 , 23 } ,
{ 23 , 24 } ,
{ 24 , 26 } ,
{ 26 , 27 } ,
{ 27 , 34 } ,
}
2015-03-20 21:11:11 +00:00
}
2016-02-25 09:48:42 +00:00
2015-03-20 21:11:11 +00:00
testnext ( testcases , "main.testnext" , t )
}
func TestNextFunctionReturn ( t * testing . T ) {
testcases := [ ] nextTest {
2016-02-11 07:18:39 +00:00
{ 13 , 14 } ,
2015-10-22 17:07:24 +00:00
{ 14 , 15 } ,
{ 15 , 35 } ,
2015-03-20 21:11:11 +00:00
}
testnext ( testcases , "main.helloworld" , t )
}
func TestClientServer_breakpointInMainThread ( t * testing . T ) {
2015-04-27 15:51:02 +00:00
withTestClient ( "testprog" , t , func ( c service . Client ) {
2015-08-07 16:50:14 +00:00
bp , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.helloworld" , Line : 1 } )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
2015-06-28 15:00:56 +00:00
state := <- c . Continue ( )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v, state: %#v" , err , state )
}
pc := state . CurrentThread . PC
if pc - 1 != bp . Addr && pc != bp . Addr {
f , l := state . CurrentThread . File , state . CurrentThread . Line
t . Fatalf ( "Break not respected:\nPC:%#v %s:%d\nFN:%#v \n" , pc , f , l , bp . Addr )
}
} )
}
func TestClientServer_breakpointInSeparateGoroutine ( t * testing . T ) {
2015-04-27 15:51:02 +00:00
withTestClient ( "testthreads" , t , func ( c service . Client ) {
2015-08-07 16:50:14 +00:00
_ , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.anotherthread" , Line : 1 } )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
2015-06-28 15:00:56 +00:00
state := <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Unexpected error: %v, state: %#v" , state . Err , state )
2015-03-20 21:11:11 +00:00
}
f , l := state . CurrentThread . File , state . CurrentThread . Line
2015-07-10 15:16:03 +00:00
if f != "testthreads.go" && l != 9 {
2015-03-20 21:11:11 +00:00
t . Fatal ( "Program did not hit breakpoint" )
}
} )
}
func TestClientServer_breakAtNonexistentPoint ( t * testing . T ) {
2015-04-27 15:51:02 +00:00
withTestClient ( "testprog" , t , func ( c service . Client ) {
2015-08-07 16:50:14 +00:00
_ , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "nowhere" , Line : 1 } )
2015-03-20 21:11:11 +00:00
if err == nil {
t . Fatal ( "Should not be able to break at non existent function" )
}
} )
}
func TestClientServer_clearBreakpoint ( t * testing . T ) {
2015-04-27 15:51:02 +00:00
withTestClient ( "testprog" , t , func ( c service . Client ) {
2015-08-07 16:50:14 +00:00
bp , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.sleepytime" , Line : 1 } )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
2015-06-12 19:32:32 +00:00
bps , err := c . ListBreakpoints ( )
2015-03-20 21:11:11 +00:00
if e , a := 1 , len ( bps ) ; e != a {
t . Fatalf ( "Expected breakpoint count %d, got %d" , e , a )
}
2015-06-12 19:32:32 +00:00
deleted , err := c . ClearBreakpoint ( bp . ID )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
if deleted . ID != bp . ID {
t . Fatalf ( "Expected deleted breakpoint ID %v, got %v" , bp . ID , deleted . ID )
}
2015-06-12 19:32:32 +00:00
bps , err = c . ListBreakpoints ( )
2015-03-20 21:11:11 +00:00
if e , a := 0 , len ( bps ) ; e != a {
t . Fatalf ( "Expected breakpoint count %d, got %d" , e , a )
}
} )
}
func TestClientServer_switchThread ( t * testing . T ) {
2015-04-27 15:51:02 +00:00
withTestClient ( "testnextprog" , t , func ( c service . Client ) {
2015-03-20 21:11:11 +00:00
// With invalid thread id
_ , err := c . SwitchThread ( - 1 )
if err == nil {
t . Fatal ( "Expected error for invalid thread id" )
}
2015-08-07 16:50:14 +00:00
_ , err = c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.main" , Line : 1 } )
2015-03-20 21:11:11 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
2015-06-28 15:00:56 +00:00
state := <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Unexpected error: %v, state: %#v" , state . Err , state )
2015-03-20 21:11:11 +00:00
}
var nt int
ct := state . CurrentThread . ID
threads , err := c . ListThreads ( )
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
for _ , th := range threads {
if th . ID != ct {
nt = th . ID
break
}
}
if nt == 0 {
t . Fatal ( "could not find thread to switch to" )
}
// With valid thread id
state , err = c . SwitchThread ( nt )
if err != nil {
t . Fatal ( err )
}
if state . CurrentThread . ID != nt {
t . Fatal ( "Did not switch threads" )
}
} )
}
2015-05-08 20:16:22 +00:00
2015-06-28 15:00:56 +00:00
func testProgPath ( t * testing . T , name string ) string {
fp , err := filepath . Abs ( fmt . Sprintf ( "_fixtures/%s.go" , name ) )
if err != nil {
t . Fatal ( err )
}
if _ , err := os . Stat ( fp ) ; err != nil {
fp , err = filepath . Abs ( fmt . Sprintf ( "../../_fixtures/%s.go" , name ) )
2015-05-08 20:16:22 +00:00
if err != nil {
t . Fatal ( err )
}
2015-06-28 15:00:56 +00:00
}
return fp
}
func TestClientServer_infoLocals ( t * testing . T ) {
withTestClient ( "testnextprog" , t , func ( c service . Client ) {
fp := testProgPath ( t , "testnextprog" )
_ , err := c . CreateBreakpoint ( & api . Breakpoint { File : fp , Line : 23 } )
2015-05-08 20:16:22 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
2015-06-28 15:00:56 +00:00
state := <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Unexpected error: %v, state: %#v" , state . Err , state )
2015-05-08 20:16:22 +00:00
}
2015-08-28 20:06:29 +00:00
locals , err := c . ListLocalVariables ( api . EvalScope { - 1 , 0 } )
2015-05-08 20:16:22 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
if len ( locals ) != 3 {
t . Fatalf ( "Expected 3 locals, got %d %#v" , len ( locals ) , locals )
}
} )
}
func TestClientServer_infoArgs ( t * testing . T ) {
withTestClient ( "testnextprog" , t , func ( c service . Client ) {
2015-06-28 15:00:56 +00:00
fp := testProgPath ( t , "testnextprog" )
_ , err := c . CreateBreakpoint ( & api . Breakpoint { File : fp , Line : 47 } )
2015-05-08 20:16:22 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
2015-06-28 15:00:56 +00:00
state := <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Unexpected error: %v, state: %#v" , state . Err , state )
2015-05-08 20:16:22 +00:00
}
2015-06-19 07:20:10 +00:00
regs , err := c . ListRegisters ( )
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
if regs == "" {
t . Fatal ( "Expected string showing registers values, got empty string" )
}
2015-08-28 20:06:29 +00:00
locals , err := c . ListFunctionArgs ( api . EvalScope { - 1 , 0 } )
2015-05-08 20:16:22 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v" , err )
}
if len ( locals ) != 2 {
t . Fatalf ( "Expected 2 function args, got %d %#v" , len ( locals ) , locals )
}
} )
}
2015-06-28 15:00:56 +00:00
func TestClientServer_traceContinue ( t * testing . T ) {
withTestClient ( "integrationprog" , t , func ( c service . Client ) {
fp := testProgPath ( t , "integrationprog" )
2015-07-01 03:16:52 +00:00
_ , err := c . CreateBreakpoint ( & api . Breakpoint { File : fp , Line : 15 , Tracepoint : true , Goroutine : true , Stacktrace : 5 , Variables : [ ] string { "i" } } )
2015-06-28 15:00:56 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v\n" , err )
}
count := 0
2015-07-01 03:16:52 +00:00
contChan := c . Continue ( )
for state := range contChan {
2015-10-29 09:59:22 +00:00
if state . CurrentThread != nil && state . CurrentThread . Breakpoint != nil {
2015-06-28 15:00:56 +00:00
count ++
t . Logf ( "%v" , state )
2015-10-29 09:59:22 +00:00
bpi := state . CurrentThread . BreakpointInfo
2015-06-28 15:00:56 +00:00
if bpi . Goroutine == nil {
t . Fatalf ( "No goroutine information" )
}
if len ( bpi . Stacktrace ) <= 0 {
t . Fatalf ( "No stacktrace\n" )
}
if len ( bpi . Variables ) != 1 {
t . Fatalf ( "Wrong number of variables returned: %d" , len ( bpi . Variables ) )
}
if bpi . Variables [ 0 ] . Name != "i" {
t . Fatalf ( "Wrong variable returned %s" , bpi . Variables [ 0 ] . Name )
}
2015-10-18 17:37:13 +00:00
t . Logf ( "Variable i is %v" , bpi . Variables [ 0 ] )
n , err := strconv . Atoi ( bpi . Variables [ 0 ] . Value )
if err != nil || n != count - 1 {
t . Fatalf ( "Wrong variable value %q (%v %d)" , bpi . Variables [ 0 ] . Value , err , count )
2015-06-28 15:00:56 +00:00
}
}
if state . Exited {
continue
}
t . Logf ( "%v" , state )
if state . Err != nil {
t . Fatalf ( "Unexpected error during continue: %v\n" , state . Err )
}
}
if count != 3 {
t . Fatalf ( "Wrong number of continues hit: %d\n" , count )
}
} )
}
2015-07-09 16:41:03 +00:00
func TestClientServer_traceContinue2 ( t * testing . T ) {
withTestClient ( "integrationprog" , t , func ( c service . Client ) {
2015-08-07 16:50:14 +00:00
bp1 , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.main" , Line : 1 , Tracepoint : true } )
2015-07-09 16:41:03 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v\n" , err )
}
2015-08-07 16:50:14 +00:00
bp2 , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.sayhi" , Line : 1 , Tracepoint : true } )
2015-07-09 16:41:03 +00:00
if err != nil {
t . Fatalf ( "Unexpected error: %v\n" , err )
}
countMain := 0
countSayhi := 0
contChan := c . Continue ( )
for state := range contChan {
2015-10-29 09:59:22 +00:00
if state . CurrentThread != nil && state . CurrentThread . Breakpoint != nil {
switch state . CurrentThread . Breakpoint . ID {
2015-07-09 16:41:03 +00:00
case bp1 . ID :
countMain ++
case bp2 . ID :
countSayhi ++
}
t . Logf ( "%v" , state )
}
if state . Exited {
continue
}
if state . Err != nil {
t . Fatalf ( "Unexpected error during continue: %v\n" , state . Err )
}
}
if countMain != 1 {
t . Fatalf ( "Wrong number of continues (main.main) hit: %d\n" , countMain )
}
if countSayhi != 3 {
t . Fatalf ( "Wrong number of continues (main.sayhi) hit: %d\n" , countSayhi )
}
} )
}
2015-08-07 16:50:14 +00:00
func findLocationHelper ( t * testing . T , c service . Client , loc string , shouldErr bool , count int , checkAddr uint64 ) [ ] uint64 {
2015-08-28 20:06:29 +00:00
locs , err := c . FindLocation ( api . EvalScope { - 1 , 0 } , loc )
2015-08-07 16:50:14 +00:00
t . Logf ( "FindLocation(\"%s\") → %v\n" , loc , locs )
if shouldErr {
if err == nil {
t . Fatalf ( "Resolving location <%s> didn't return an error: %v" , loc , locs )
}
} else {
if err != nil {
t . Fatalf ( "Error resolving location <%s>: %v" , loc , err )
}
}
if ( count >= 0 ) && ( len ( locs ) != count ) {
t . Fatalf ( "Wrong number of breakpoints returned for location <%s> (got %d, expected %d)" , loc , len ( locs ) , count )
}
if checkAddr != 0 && checkAddr != locs [ 0 ] . PC {
t . Fatalf ( "Wrong address returned for location <%s> (got %v, epected %v)" , loc , locs [ 0 ] . PC , checkAddr )
}
addrs := make ( [ ] uint64 , len ( locs ) )
for i := range locs {
addrs [ i ] = locs [ i ] . PC
}
return addrs
}
func TestClientServer_FindLocations ( t * testing . T ) {
withTestClient ( "locationsprog" , t , func ( c service . Client ) {
2016-02-11 07:18:39 +00:00
someFunctionCallAddr := findLocationHelper ( t , c , "locationsprog.go:26" , false , 1 , 0 ) [ 0 ]
someFunctionLine1 := findLocationHelper ( t , c , "locationsprog.go:27" , false , 1 , 0 ) [ 0 ]
findLocationHelper ( t , c , "anotherFunction:1" , false , 1 , someFunctionLine1 )
findLocationHelper ( t , c , "main.anotherFunction:1" , false , 1 , someFunctionLine1 )
2015-08-07 16:50:14 +00:00
findLocationHelper ( t , c , "anotherFunction" , false , 1 , someFunctionCallAddr )
findLocationHelper ( t , c , "main.anotherFunction" , false , 1 , someFunctionCallAddr )
findLocationHelper ( t , c , fmt . Sprintf ( "*0x%x" , someFunctionCallAddr ) , false , 1 , someFunctionCallAddr )
findLocationHelper ( t , c , "sprog.go:26" , true , 0 , 0 )
findLocationHelper ( t , c , "String" , true , 0 , 0 )
findLocationHelper ( t , c , "main.String" , true , 0 , 0 )
2016-02-11 07:18:39 +00:00
someTypeStringFuncAddr := findLocationHelper ( t , c , "locationsprog.go:14" , false , 1 , 0 ) [ 0 ]
otherTypeStringFuncAddr := findLocationHelper ( t , c , "locationsprog.go:18" , false , 1 , 0 ) [ 0 ]
2015-08-07 16:50:14 +00:00
findLocationHelper ( t , c , "SomeType.String" , false , 1 , someTypeStringFuncAddr )
findLocationHelper ( t , c , "(*SomeType).String" , false , 1 , someTypeStringFuncAddr )
findLocationHelper ( t , c , "main.SomeType.String" , false , 1 , someTypeStringFuncAddr )
findLocationHelper ( t , c , "main.(*SomeType).String" , false , 1 , someTypeStringFuncAddr )
2015-10-17 07:31:07 +00:00
// Issue #275
2015-12-12 14:01:35 +00:00
readfile := findLocationHelper ( t , c , "io/ioutil.ReadFile" , false , 1 , 0 ) [ 0 ]
// Issue #296
findLocationHelper ( t , c , "/io/ioutil.ReadFile" , false , 1 , readfile )
findLocationHelper ( t , c , "ioutil.ReadFile" , false , 1 , readfile )
2015-10-17 07:31:07 +00:00
2015-08-07 16:50:14 +00:00
stringAddrs := findLocationHelper ( t , c , "/^main.*Type.*String$/" , false , 2 , 0 )
if otherTypeStringFuncAddr != stringAddrs [ 0 ] && otherTypeStringFuncAddr != stringAddrs [ 1 ] {
t . Fatalf ( "Wrong locations returned for \"/.*Type.*String/\", got: %v expected: %v and %v\n" , stringAddrs , someTypeStringFuncAddr , otherTypeStringFuncAddr )
}
2015-10-17 07:31:07 +00:00
_ , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.main" , Line : 3 , Tracepoint : false } )
2015-08-07 16:50:14 +00:00
if err != nil {
t . Fatalf ( "CreateBreakpoint(): %v\n" , err )
}
<- c . Continue ( )
locationsprog34Addr := findLocationHelper ( t , c , "locationsprog.go:34" , false , 1 , 0 ) [ 0 ]
2015-09-08 20:00:38 +00:00
findLocationHelper ( t , c , fmt . Sprintf ( "%s:34" , testProgPath ( t , "locationsprog" ) ) , false , 1 , locationsprog34Addr )
2015-08-07 16:50:14 +00:00
findLocationHelper ( t , c , "+1" , false , 1 , locationsprog34Addr )
findLocationHelper ( t , c , "34" , false , 1 , locationsprog34Addr )
findLocationHelper ( t , c , "-1" , false , 1 , findLocationHelper ( t , c , "locationsprog.go:32" , false , 1 , 0 ) [ 0 ] )
} )
withTestClient ( "testnextdefer" , t , func ( c service . Client ) {
2016-02-11 07:18:39 +00:00
firstMainLine := findLocationHelper ( t , c , "testnextdefer.go:5" , false , 1 , 0 ) [ 0 ]
2015-08-07 16:50:14 +00:00
findLocationHelper ( t , c , "main.main" , false , 1 , firstMainLine )
} )
withTestClient ( "stacktraceprog" , t , func ( c service . Client ) {
stacktracemeAddr := findLocationHelper ( t , c , "stacktraceprog.go:4" , false , 1 , 0 ) [ 0 ]
findLocationHelper ( t , c , "main.stacktraceme" , false , 1 , stacktracemeAddr )
} )
2016-01-30 21:27:08 +00:00
withTestClient ( "locationsUpperCase" , t , func ( c service . Client ) {
// Upper case
findLocationHelper ( t , c , "locationsUpperCase.go:6" , false , 1 , 0 )
// Fully qualified path
path := protest . Fixtures [ "locationsUpperCase" ] . Source
findLocationHelper ( t , c , path + ":6" , false , 1 , 0 )
bp , err := c . CreateBreakpoint ( & api . Breakpoint { File : path , Line : 6 } )
if err != nil {
t . Fatalf ( "Could not set breakpoint in %s: %v\n" , path , err )
}
c . ClearBreakpoint ( bp . ID )
// Allow `/` or `\` on Windows
if runtime . GOOS == "windows" {
findLocationHelper ( t , c , filepath . FromSlash ( path ) + ":6" , false , 1 , 0 )
bp , err = c . CreateBreakpoint ( & api . Breakpoint { File : filepath . FromSlash ( path ) , Line : 6 } )
if err != nil {
t . Fatalf ( "Could not set breakpoint in %s: %v\n" , filepath . FromSlash ( path ) , err )
}
c . ClearBreakpoint ( bp . ID )
}
// Case-insensitive on Windows, case-sensitive otherwise
shouldWrongCaseBeError := true
numExpectedMatches := 0
if runtime . GOOS == "windows" {
shouldWrongCaseBeError = false
numExpectedMatches = 1
}
findLocationHelper ( t , c , strings . ToLower ( path ) + ":6" , shouldWrongCaseBeError , numExpectedMatches , 0 )
bp , err = c . CreateBreakpoint ( & api . Breakpoint { File : strings . ToLower ( path ) , Line : 6 } )
if ( err == nil ) == shouldWrongCaseBeError {
t . Fatalf ( "Could not set breakpoint in %s: %v\n" , strings . ToLower ( path ) , err )
}
c . ClearBreakpoint ( bp . ID )
} )
2015-08-07 16:50:14 +00:00
}
2015-08-07 07:30:01 +00:00
2016-01-10 13:08:16 +00:00
func TestClientServer_FindLocationsAddr ( t * testing . T ) {
withTestClient ( "locationsprog2" , t , func ( c service . Client ) {
<- c . Continue ( )
afunction := findLocationHelper ( t , c , "main.afunction" , false , 1 , 0 ) [ 0 ]
2016-02-11 07:18:39 +00:00
anonfunc := findLocationHelper ( t , c , "main.main.func1" , false , 1 , 0 ) [ 0 ]
2016-01-10 13:08:16 +00:00
findLocationHelper ( t , c , "*fn1" , false , 1 , afunction )
findLocationHelper ( t , c , "*fn3" , false , 1 , anonfunc )
} )
}
2015-08-28 20:06:29 +00:00
func TestClientServer_EvalVariable ( t * testing . T ) {
2015-08-07 07:30:01 +00:00
withTestClient ( "testvariables" , t , func ( c service . Client ) {
state := <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Continue(): %v\n" , state . Err )
}
2015-08-28 20:06:29 +00:00
var1 , err := c . EvalVariable ( api . EvalScope { - 1 , 0 } , "a1" )
2015-09-17 08:42:34 +00:00
assertNoError ( err , t , "EvalVariable" )
2015-08-07 07:30:01 +00:00
2015-10-18 17:37:13 +00:00
t . Logf ( "var1: %s" , var1 . SinglelineString ( ) )
2015-08-07 07:30:01 +00:00
if var1 . Value != "foofoofoofoofoofoo" {
2015-10-18 17:37:13 +00:00
t . Fatalf ( "Wrong variable value: %s" , var1 . Value )
2015-09-28 10:01:18 +00:00
}
} )
}
func TestClientServer_SetVariable ( t * testing . T ) {
withTestClient ( "testvariables" , t , func ( c service . Client ) {
state := <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Continue(): %v\n" , state . Err )
}
2015-10-04 17:58:32 +00:00
assertNoError ( c . SetVariable ( api . EvalScope { - 1 , 0 } , "a2" , "8" ) , t , "SetVariable()" )
2015-09-28 10:01:18 +00:00
2015-10-04 17:58:32 +00:00
a2 , err := c . EvalVariable ( api . EvalScope { - 1 , 0 } , "a2" )
2015-09-28 10:01:18 +00:00
2015-10-18 17:37:13 +00:00
t . Logf ( "a2: %v" , a2 )
2015-09-28 10:01:18 +00:00
2015-10-18 17:37:13 +00:00
n , err := strconv . Atoi ( a2 . Value )
if err != nil && n != 8 {
t . Fatalf ( "Wrong variable value: %v" , a2 )
2015-08-07 07:30:01 +00:00
}
} )
}
2015-09-17 08:42:34 +00:00
func TestClientServer_FullStacktrace ( t * testing . T ) {
withTestClient ( "goroutinestackprog" , t , func ( c service . Client ) {
_ , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.stacktraceme" , Line : - 1 } )
assertNoError ( err , t , "CreateBreakpoint()" )
state := <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Continue(): %v\n" , state . Err )
}
gs , err := c . ListGoroutines ( )
assertNoError ( err , t , "GoroutinesInfo()" )
found := make ( [ ] bool , 10 )
for _ , g := range gs {
frames , err := c . Stacktrace ( g . ID , 10 , true )
assertNoError ( err , t , fmt . Sprintf ( "Stacktrace(%d)" , g . ID ) )
for i , frame := range frames {
if frame . Function == nil {
continue
}
if frame . Function . Name != "main.agoroutine" {
continue
}
t . Logf ( "frame %d: %v" , i , frame )
for _ , arg := range frame . Arguments {
if arg . Name != "i" {
continue
}
2015-10-18 17:37:13 +00:00
t . Logf ( "frame %d, variable i is %v\n" , arg )
argn , err := strconv . Atoi ( arg . Value )
if err == nil {
found [ argn ] = true
}
2015-09-17 08:42:34 +00:00
}
}
}
for i := range found {
if ! found [ i ] {
t . Fatalf ( "Goroutine %d not found" , i )
}
}
state = <- c . Continue ( )
if state . Err != nil {
t . Fatalf ( "Continue(): %v\n" , state . Err )
}
frames , err := c . Stacktrace ( - 1 , 10 , true )
assertNoError ( err , t , "Stacktrace" )
cur := 3
for i , frame := range frames {
if i == 0 {
continue
}
t . Logf ( "frame %d: %v" , i , frame )
v := frame . Var ( "n" )
if v == nil {
t . Fatalf ( "Could not find value of variable n in frame %d" , i )
}
2015-10-18 17:37:13 +00:00
vn , err := strconv . Atoi ( v . Value )
if err != nil || vn != cur {
t . Fatalf ( "Expected value %d got %d (error: %v)" , cur , vn , err )
2015-09-17 08:42:34 +00:00
}
cur --
if cur < 0 {
break
}
}
} )
}
2016-01-30 06:23:14 +00:00
func TestIssue355 ( t * testing . T ) {
// After the target process has terminated should return an error but not crash
withTestClient ( "continuetestprog" , t , func ( c service . Client ) {
bp , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.sayhi" , Line : - 1 } )
assertNoError ( err , t , "CreateBreakpoint()" )
ch := c . Continue ( )
state := <- ch
tid := state . CurrentThread . ID
gid := state . SelectedGoroutine . ID
assertNoError ( state . Err , t , "First Continue()" )
ch = c . Continue ( )
state = <- ch
if ! state . Exited {
t . Fatalf ( "Target did not terminate after second continue" )
}
ch = c . Continue ( )
state = <- ch
assertError ( state . Err , t , "Continue()" )
_ , err = c . Next ( )
assertError ( err , t , "Next()" )
_ , err = c . Step ( )
assertError ( err , t , "Step()" )
_ , err = c . StepInstruction ( )
assertError ( err , t , "StepInstruction()" )
_ , err = c . SwitchThread ( tid )
assertError ( err , t , "SwitchThread()" )
_ , err = c . SwitchGoroutine ( gid )
assertError ( err , t , "SwitchGoroutine()" )
_ , err = c . Halt ( )
assertError ( err , t , "Halt()" )
_ , err = c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.main" , Line : - 1 } )
assertError ( err , t , "CreateBreakpoint()" )
_ , err = c . ClearBreakpoint ( bp . ID )
assertError ( err , t , "ClearBreakpoint()" )
_ , err = c . ListThreads ( )
assertError ( err , t , "ListThreads()" )
_ , err = c . GetThread ( tid )
assertError ( err , t , "GetThread()" )
assertError ( c . SetVariable ( api . EvalScope { gid , 0 } , "a" , "10" ) , t , "SetVariable()" )
_ , err = c . ListLocalVariables ( api . EvalScope { gid , 0 } )
assertError ( err , t , "ListLocalVariables()" )
_ , err = c . ListFunctionArgs ( api . EvalScope { gid , 0 } )
assertError ( err , t , "ListFunctionArgs()" )
_ , err = c . ListRegisters ( )
assertError ( err , t , "ListRegisters()" )
_ , err = c . ListGoroutines ( )
assertError ( err , t , "ListGoroutines()" )
_ , err = c . Stacktrace ( gid , 10 , false )
assertError ( err , t , "Stacktrace()" )
_ , err = c . FindLocation ( api . EvalScope { gid , 0 } , "+1" )
assertError ( err , t , "FindLocation()" )
2016-02-06 06:00:48 +00:00
_ , err = c . DisassemblePC ( api . EvalScope { - 1 , 0 } , 0x40100 , api . IntelFlavour )
assertError ( err , t , "DisassemblePC()" )
} )
}
func getCurinstr ( d3 api . AsmInstructions ) * api . AsmInstruction {
for i := range d3 {
if d3 [ i ] . AtPC {
return & d3 [ i ]
}
}
return nil
}
func TestDisasm ( t * testing . T ) {
// Tests that disassembling by PC, range, and current PC all yeld similar results
// Tests that disassembly by current PC will return a disassembly containing the instruction at PC
// Tests that stepping on a calculated CALL instruction will yield a disassembly that contains the
// effective destination of the CALL instruction
withTestClient ( "locationsprog2" , t , func ( c service . Client ) {
ch := c . Continue ( )
state := <- ch
assertNoError ( state . Err , t , "Continue()" )
locs , err := c . FindLocation ( api . EvalScope { - 1 , 0 } , "main.main" )
assertNoError ( err , t , "FindLocation()" )
if len ( locs ) != 1 {
t . Fatalf ( "wrong number of locations for main.main: %d" , len ( locs ) )
}
d1 , err := c . DisassemblePC ( api . EvalScope { - 1 , 0 } , locs [ 0 ] . PC , api . IntelFlavour )
assertNoError ( err , t , "DisassemblePC()" )
if len ( d1 ) < 2 {
t . Fatalf ( "wrong size of disassembly: %d" , len ( d1 ) )
}
pcstart := d1 [ 0 ] . Loc . PC
pcend := d1 [ len ( d1 ) - 1 ] . Loc . PC + uint64 ( len ( d1 [ len ( d1 ) - 1 ] . Bytes ) )
d2 , err := c . DisassembleRange ( api . EvalScope { - 1 , 0 } , pcstart , pcend , api . IntelFlavour )
assertNoError ( err , t , "DisassembleRange()" )
if len ( d1 ) != len ( d2 ) {
t . Logf ( "d1: %v" , d1 )
t . Logf ( "d2: %v" , d2 )
t . Fatal ( "mismatched length between disassemble pc and disassemble range" )
}
d3 , err := c . DisassemblePC ( api . EvalScope { - 1 , 0 } , state . CurrentThread . PC , api . IntelFlavour )
assertNoError ( err , t , "DisassemblePC() - second call" )
if len ( d1 ) != len ( d3 ) {
t . Logf ( "d1: %v" , d1 )
t . Logf ( "d3: %v" , d3 )
t . Fatal ( "mismatched length between the two calls of disassemble pc" )
}
// look for static call to afunction() on line 29
found := false
for i := range d3 {
if d3 [ i ] . Loc . Line == 29 && strings . HasPrefix ( d3 [ i ] . Text , "call" ) && d3 [ i ] . DestLoc != nil && d3 [ i ] . DestLoc . Function != nil && d3 [ i ] . DestLoc . Function . Name == "main.afunction" {
found = true
break
}
}
if ! found {
t . Fatal ( "Could not find call to main.afunction on line 29" )
}
haspc := false
for i := range d3 {
if d3 [ i ] . AtPC {
haspc = true
break
}
}
if ! haspc {
t . Logf ( "d3: %v" , d3 )
t . Fatal ( "PC instruction not found" )
}
startinstr := getCurinstr ( d3 )
count := 0
for {
if count > 20 {
t . Fatal ( "too many step instructions executed without finding a call instruction" )
}
state , err := c . StepInstruction ( )
assertNoError ( err , t , fmt . Sprintf ( "StepInstruction() %d" , count ) )
d3 , err = c . DisassemblePC ( api . EvalScope { - 1 , 0 } , state . CurrentThread . PC , api . IntelFlavour )
assertNoError ( err , t , fmt . Sprintf ( "StepInstruction() %d" , count ) )
curinstr := getCurinstr ( d3 )
if curinstr == nil {
t . Fatalf ( "Could not find current instruction %d" , count )
}
if curinstr . Loc . Line != startinstr . Loc . Line {
t . Fatal ( "Calling StepInstruction() repeatedly did not find the call instruction" )
}
if strings . HasPrefix ( curinstr . Text , "call" ) {
t . Logf ( "call: %v" , curinstr )
if curinstr . DestLoc == nil || curinstr . DestLoc . Function == nil {
t . Fatalf ( "Call instruction does not have destination: %v" , curinstr )
}
if curinstr . DestLoc . Function . Name != "main.afunction" {
t . Fatalf ( "Call instruction destination not main.afunction: %v" , curinstr )
}
break
}
count ++
}
2016-01-30 06:23:14 +00:00
} )
}
2016-02-02 11:26:29 +00:00
func TestNegativeStackDepthBug ( t * testing . T ) {
// After the target process has terminated should return an error but not crash
withTestClient ( "continuetestprog" , t , func ( c service . Client ) {
_ , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.sayhi" , Line : - 1 } )
assertNoError ( err , t , "CreateBreakpoint()" )
ch := c . Continue ( )
state := <- ch
assertNoError ( state . Err , t , "Continue()" )
_ , err = c . Stacktrace ( - 1 , - 2 , true )
assertError ( err , t , "Stacktrace()" )
} )
}
2016-01-24 08:16:45 +00:00
func TestClientServer_CondBreakpoint ( t * testing . T ) {
withTestClient ( "parallel_next" , t , func ( c service . Client ) {
bp , err := c . CreateBreakpoint ( & api . Breakpoint { FunctionName : "main.sayhi" , Line : 1 } )
assertNoError ( err , t , "CreateBreakpoint()" )
bp . Cond = "n == 7"
assertNoError ( c . AmendBreakpoint ( bp ) , t , "AmendBreakpoint() 1" )
bp , err = c . GetBreakpoint ( bp . ID )
assertNoError ( err , t , "GetBreakpoint() 1" )
bp . Variables = append ( bp . Variables , "n" )
assertNoError ( c . AmendBreakpoint ( bp ) , t , "AmendBreakpoint() 2" )
bp , err = c . GetBreakpoint ( bp . ID )
assertNoError ( err , t , "GetBreakpoint() 2" )
if bp . Cond == "" {
t . Fatalf ( "No condition set on breakpoint %#v" , bp )
}
if len ( bp . Variables ) != 1 {
t . Fatalf ( "Wrong number of expressions to evaluate on breakpoint %#v" , bp )
}
state := <- c . Continue ( )
assertNoError ( state . Err , t , "Continue()" )
nvar , err := c . EvalVariable ( api . EvalScope { - 1 , 0 } , "n" )
assertNoError ( err , t , "EvalVariable()" )
if nvar . SinglelineString ( ) != "7" {
t . Fatalf ( "Stopped on wrong goroutine %s\n" , nvar . Value )
}
} )
}
2016-02-11 07:18:39 +00:00
func TestSkipPrologue ( t * testing . T ) {
withTestClient ( "locationsprog2" , t , func ( c service . Client ) {
<- c . Continue ( )
afunction := findLocationHelper ( t , c , "main.afunction" , false , 1 , 0 ) [ 0 ]
findLocationHelper ( t , c , "*fn1" , false , 1 , afunction )
findLocationHelper ( t , c , "locationsprog2.go:8" , false , 1 , afunction )
afunction0 := findLocationHelper ( t , c , "main.afunction:0" , false , 1 , 0 ) [ 0 ]
if afunction == afunction0 {
t . Fatal ( "Skip prologue failed" )
}
} )
}
func TestSkipPrologue2 ( t * testing . T ) {
withTestClient ( "callme" , t , func ( c service . Client ) {
callme := findLocationHelper ( t , c , "main.callme" , false , 1 , 0 ) [ 0 ]
callmeZ := findLocationHelper ( t , c , "main.callme:0" , false , 1 , 0 ) [ 0 ]
findLocationHelper ( t , c , "callme.go:5" , false , 1 , callme )
if callme == callmeZ {
t . Fatal ( "Skip prologue failed" )
}
callme2 := findLocationHelper ( t , c , "main.callme2" , false , 1 , 0 ) [ 0 ]
callme2Z := findLocationHelper ( t , c , "main.callme2:0" , false , 1 , 0 ) [ 0 ]
findLocationHelper ( t , c , "callme.go:12" , false , 1 , callme2 )
if callme2 == callme2Z {
t . Fatal ( "Skip prologue failed" )
}
callme3 := findLocationHelper ( t , c , "main.callme3" , false , 1 , 0 ) [ 0 ]
callme3Z := findLocationHelper ( t , c , "main.callme3:0" , false , 1 , 0 ) [ 0 ]
// callme3 does not have local variables therefore the first line of the function is immediately after the prologue
findLocationHelper ( t , c , "callme.go:18" , false , 1 , callme3Z )
if callme3 == callme3Z {
t . Fatal ( "Skip prologue failed" )
}
} )
}
2016-02-15 14:39:29 +00:00
func TestIssue419 ( t * testing . T ) {
// Calling service/rpc.(*Client).Halt could cause a crash because both Halt and Continue simultaneously
// try to read 'runtime.g' and debug/dwarf.Data.Type is not thread safe
withTestClient ( "issue419" , t , func ( c service . Client ) {
go func ( ) {
rand . Seed ( time . Now ( ) . Unix ( ) )
d := time . Duration ( rand . Intn ( 4 ) + 1 )
time . Sleep ( d * time . Second )
_ , err := c . Halt ( )
assertNoError ( err , t , "RequestManualStop()" )
} ( )
statech := c . Continue ( )
state := <- statech
assertNoError ( state . Err , t , "Continue()" )
} )
}
2016-02-22 15:08:45 +00:00
func TestTypesCommand ( t * testing . T ) {
withTestClient ( "testvariables2" , t , func ( c service . Client ) {
state := <- c . Continue ( )
assertNoError ( state . Err , t , "Continue()" )
types , err := c . ListTypes ( "" )
assertNoError ( err , t , "ListTypes()" )
found := false
for i := range types {
if types [ i ] == "main.astruct" {
found = true
break
}
}
if ! found {
t . Fatal ( "Type astruct not found in ListTypes output" )
}
2016-02-27 23:50:37 +00:00
types , err = c . ListTypes ( "^main.astruct$" )
2016-02-22 15:08:45 +00:00
assertNoError ( err , t , "ListTypes(\"main.astruct\")" )
2016-02-27 23:50:37 +00:00
if len ( types ) != 1 {
t . Fatalf ( "ListTypes(\"^main.astruct$\") did not filter properly, expected 1 got %d: %v" , len ( types ) , types )
2016-02-22 15:08:45 +00:00
}
} )
}