github.com/ks888/tgo@v0.0.0-20190130135156-80bf89407292/tracer/controller_test.go (about)

     1  package tracer
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"runtime"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/ks888/tgo/testutils"
    13  )
    14  
    15  var helloworldAttrs = Attributes{
    16  	ProgramPath:         testutils.ProgramHelloworld,
    17  	FirstModuleDataAddr: testutils.HelloworldAddrFirstModuleData,
    18  	CompiledGoVersion:   runtime.Version(),
    19  }
    20  
    21  func TestLaunchProcess(t *testing.T) {
    22  	controller := NewController()
    23  	err := controller.LaunchTracee(testutils.ProgramHelloworld, nil, helloworldAttrs)
    24  	if err != nil {
    25  		t.Fatalf("failed to launch process: %v", err)
    26  	}
    27  }
    28  
    29  var infloopAttrs = Attributes{
    30  	ProgramPath:         testutils.ProgramInfloop,
    31  	FirstModuleDataAddr: testutils.InfloopAddrFirstModuleData,
    32  	CompiledGoVersion:   runtime.Version(),
    33  }
    34  
    35  func TestAttachProcess(t *testing.T) {
    36  	cmd := exec.Command(testutils.ProgramInfloop)
    37  	_ = cmd.Start()
    38  
    39  	controller := NewController()
    40  	err := controller.AttachTracee(cmd.Process.Pid, infloopAttrs)
    41  	if err != nil {
    42  		t.Fatalf("failed to attch to the process: %v", err)
    43  	}
    44  
    45  	controller.process.Detach() // must detach before kill. Otherwise, the program becomes zombie.
    46  	cmd.Process.Kill()
    47  	cmd.Process.Wait()
    48  }
    49  
    50  var startStopAttrs = Attributes{
    51  	ProgramPath:         testutils.ProgramStartStop,
    52  	FirstModuleDataAddr: testutils.StartStopAddrFirstModuleData,
    53  	CompiledGoVersion:   runtime.Version(),
    54  }
    55  
    56  func TestAddStartTracePoint(t *testing.T) {
    57  	controller := NewController()
    58  	err := controller.LaunchTracee(testutils.ProgramStartStop, nil, startStopAttrs)
    59  	if err != nil {
    60  		t.Fatalf("failed to launch process: %v", err)
    61  	}
    62  
    63  	if err := controller.AddStartTracePoint(testutils.StartStopAddrTracedFunc); err != nil {
    64  		t.Errorf("failed to set tracing point: %v", err)
    65  	}
    66  	if err := controller.setPendingTracePoints(); err != nil {
    67  		t.Errorf("failed to set pending trace points: %v", err)
    68  	}
    69  	if !controller.breakpoints.Exist(testutils.StartStopAddrTracedFunc) {
    70  		t.Errorf("breakpoint is not set at main.tracedFunc")
    71  	}
    72  
    73  	if err := controller.AddStartTracePoint(testutils.StartStopAddrTracedFunc); err != nil {
    74  		t.Errorf("failed to set tracing point: %v", err)
    75  	}
    76  }
    77  
    78  func TestAddEndTracePoint(t *testing.T) {
    79  	controller := NewController()
    80  	err := controller.LaunchTracee(testutils.ProgramStartStop, nil, startStopAttrs)
    81  	if err != nil {
    82  		t.Fatalf("failed to launch process: %v", err)
    83  	}
    84  
    85  	if err := controller.AddEndTracePoint(testutils.StartStopAddrTracedFunc); err != nil {
    86  		t.Errorf("failed to set tracing point: %v", err)
    87  	}
    88  	if err := controller.setPendingTracePoints(); err != nil {
    89  		t.Errorf("failed to set pending trace points: %v", err)
    90  	}
    91  	if !controller.breakpoints.Exist(testutils.StartStopAddrTracedFunc) {
    92  		t.Errorf("breakpoint is not set at main.tracedFunc")
    93  	}
    94  
    95  	if err := controller.AddEndTracePoint(testutils.StartStopAddrTracedFunc); err != nil {
    96  		t.Errorf("failed to set tracing point: %v", err)
    97  	}
    98  }
    99  
   100  func TestMainLoop_MainMain(t *testing.T) {
   101  	controller := NewController()
   102  	buff := &bytes.Buffer{}
   103  	controller.outputWriter = buff
   104  	controller.SetTraceLevel(1)
   105  	if err := controller.LaunchTracee(testutils.ProgramHelloworld, nil, helloworldAttrs); err != nil {
   106  		t.Fatalf("failed to launch process: %v", err)
   107  	}
   108  	if err := controller.AddStartTracePoint(testutils.HelloworldAddrMain); err != nil {
   109  		t.Fatalf("failed to set tracing point: %v", err)
   110  	}
   111  
   112  	if err := controller.MainLoop(); err != nil {
   113  		t.Errorf("failed to run main loop: %v", err)
   114  	}
   115  
   116  	output := buff.String()
   117  	if strings.Count(output, "main.main") != 0 {
   118  		t.Errorf("unexpected output: %s", output)
   119  	}
   120  	if strings.Count(output, "main.noParameter") != 2 {
   121  		t.Errorf("unexpected output: %s", output)
   122  	}
   123  }
   124  
   125  func TestMainLoop_NoDWARFBinary(t *testing.T) {
   126  	controller := NewController()
   127  	buff := &bytes.Buffer{}
   128  	controller.outputWriter = buff
   129  	controller.SetTraceLevel(1)
   130  	if err := controller.LaunchTracee(testutils.ProgramHelloworldNoDwarf, nil, helloworldAttrs); err != nil {
   131  		t.Fatalf("failed to launch process: %v", err)
   132  	}
   133  	if err := controller.AddStartTracePoint(testutils.HelloworldAddrMain); err != nil {
   134  		t.Fatalf("failed to set tracing point: %v", err)
   135  	}
   136  
   137  	if err := controller.MainLoop(); err != nil {
   138  		t.Errorf("failed to run main loop: %v", err)
   139  	}
   140  
   141  	output := buff.String()
   142  	if strings.Count(output, "main.main") != 0 {
   143  		t.Errorf("unexpected output: %s", output)
   144  	}
   145  }
   146  
   147  func TestMainLoop_MainNoParameter(t *testing.T) {
   148  	controller := NewController()
   149  	buff := &bytes.Buffer{}
   150  	controller.outputWriter = buff
   151  	controller.SetTraceLevel(1)
   152  	if err := controller.LaunchTracee(testutils.ProgramHelloworld, nil, helloworldAttrs); err != nil {
   153  		t.Fatalf("failed to launch process: %v", err)
   154  	}
   155  	if err := controller.AddStartTracePoint(testutils.HelloworldAddrNoParameter); err != nil {
   156  		t.Fatalf("failed to set tracing point: %v", err)
   157  	}
   158  	if err := controller.AddEndTracePoint(testutils.HelloworldAddrOneParameter); err != nil {
   159  		t.Fatalf("failed to set tracing point: %v", err)
   160  	}
   161  
   162  	if err := controller.MainLoop(); err != nil {
   163  		t.Errorf("failed to run main loop: %v", err)
   164  	}
   165  
   166  	output := buff.String()
   167  	if strings.Count(output, "fmt.Println") != 2 && strings.Count(output, "fmt.Fprintln") != 2 {
   168  		t.Errorf("unexpected output: %s", output)
   169  	}
   170  	if strings.Count(output, "main.noParameter") != 0 {
   171  		t.Errorf("unexpected output: %s", output)
   172  	}
   173  	if strings.Count(output, "main.oneParameter") != 0 {
   174  		t.Errorf("unexpected output: %s", output)
   175  	}
   176  }
   177  
   178  var goRoutinesAttrs = Attributes{
   179  	ProgramPath:         testutils.ProgramGoRoutines,
   180  	FirstModuleDataAddr: testutils.GoRoutinesAddrFirstModuleData,
   181  	CompiledGoVersion:   runtime.Version(),
   182  }
   183  
   184  func TestMainLoop_GoRoutines(t *testing.T) {
   185  	// Because this test case have many threads run the same function, one thread may pass through the breakpoint
   186  	// while another thread is single-stepping.
   187  	os.Setenv("GOMAXPROCS", "1")
   188  	defer os.Unsetenv("GOMAXPROCS")
   189  
   190  	controller := NewController()
   191  	buff := &bytes.Buffer{}
   192  	controller.outputWriter = buff
   193  	controller.SetTraceLevel(1)
   194  	if err := controller.LaunchTracee(testutils.ProgramGoRoutines, nil, goRoutinesAttrs); err != nil {
   195  		t.Fatalf("failed to launch process: %v", err)
   196  	}
   197  	if err := controller.AddStartTracePoint(testutils.GoRoutinesAddrInc); err != nil {
   198  		t.Fatalf("failed to set tracing point: %v", err)
   199  	}
   200  
   201  	if err := controller.MainLoop(); err != nil {
   202  		t.Errorf("failed to run main loop: %v", err)
   203  	}
   204  
   205  	output := buff.String()
   206  	if strings.Count(output, "main.send") != 40 {
   207  		t.Errorf("unexpected output: %d\n%s", strings.Count(output, "main.send"), output)
   208  	}
   209  	if strings.Count(output, "main.receive") != 40 {
   210  		t.Errorf("unexpected output: %d\n%s", strings.Count(output, "main.receive"), output)
   211  	}
   212  }
   213  
   214  var recursiveAttrs = Attributes{
   215  	ProgramPath:         testutils.ProgramRecursive,
   216  	FirstModuleDataAddr: testutils.RecursiveAddrFirstModuleData,
   217  	CompiledGoVersion:   runtime.Version(),
   218  }
   219  
   220  func TestMainLoop_Recursive(t *testing.T) {
   221  	controller := NewController()
   222  	buff := &bytes.Buffer{}
   223  	controller.outputWriter = buff
   224  	if err := controller.LaunchTracee(testutils.ProgramRecursive, nil, recursiveAttrs); err != nil {
   225  		t.Fatalf("failed to launch process: %v", err)
   226  	}
   227  	if err := controller.AddStartTracePoint(testutils.RecursiveAddrMain); err != nil {
   228  		t.Fatalf("failed to set tracing point: %v", err)
   229  	}
   230  	controller.SetTraceLevel(3)
   231  
   232  	if err := controller.MainLoop(); err != nil {
   233  		t.Errorf("failed to run main loop: %v", err)
   234  	}
   235  
   236  	output := buff.String()
   237  	if strings.Count(output, "main.dec") != 6 {
   238  		t.Errorf("wrong number of main.dec: %d", strings.Count(output, "main.dec"))
   239  	}
   240  }
   241  
   242  var panicAttrs = Attributes{
   243  	ProgramPath:         testutils.ProgramPanic,
   244  	FirstModuleDataAddr: testutils.PanicAddrFirstModuleData,
   245  	CompiledGoVersion:   runtime.Version(),
   246  }
   247  
   248  func TestMainLoop_Panic(t *testing.T) {
   249  	controller := NewController()
   250  	buff := &bytes.Buffer{}
   251  	controller.outputWriter = buff
   252  	if err := controller.LaunchTracee(testutils.ProgramPanic, nil, panicAttrs); err != nil {
   253  		t.Fatalf("failed to launch process: %v", err)
   254  	}
   255  	if err := controller.AddStartTracePoint(testutils.PanicAddrMain); err != nil {
   256  		t.Fatalf("failed to set tracing point: %v", err)
   257  	}
   258  	controller.SetTraceLevel(2)
   259  
   260  	if err := controller.MainLoop(); err != nil {
   261  		t.Errorf("failed to run main loop: %v", err)
   262  	}
   263  
   264  	output := buff.String()
   265  	if strings.Count(output, "main.catch") != 2 {
   266  		t.Errorf("wrong number of main.catch: %d\n%s", strings.Count(output, "main.catch"), output)
   267  	}
   268  }
   269  
   270  var specialFuncsAttrs = Attributes{
   271  	ProgramPath:         testutils.ProgramSpecialFuncs,
   272  	FirstModuleDataAddr: testutils.SpecialFuncsAddrFirstModuleData,
   273  	CompiledGoVersion:   runtime.Version(),
   274  }
   275  
   276  func TestMainLoop_SpecialFuncs(t *testing.T) {
   277  	controller := NewController()
   278  	buff := &bytes.Buffer{}
   279  	controller.outputWriter = buff
   280  	if err := controller.LaunchTracee(testutils.ProgramSpecialFuncs, nil, specialFuncsAttrs); err != nil {
   281  		t.Fatalf("failed to launch process: %v", err)
   282  	}
   283  	if err := controller.AddStartTracePoint(testutils.SpecialFuncsAddrMain); err != nil {
   284  		t.Fatalf("failed to set tracing point: %v", err)
   285  	}
   286  	controller.SetTraceLevel(3)
   287  
   288  	if err := controller.MainLoop(); err != nil {
   289  		t.Errorf("failed to run main loop: %v", err)
   290  	}
   291  
   292  	output := buff.String()
   293  	if strings.Count(output, "reflect.DeepEqual") != 2 {
   294  		t.Errorf("wrong number of reflect.DeepEqual: %d\n%s", strings.Count(output, "reflect.DeepEqual"), output)
   295  	}
   296  }
   297  
   298  func TestInterrupt(t *testing.T) {
   299  	controller := NewController()
   300  	controller.outputWriter = ioutil.Discard
   301  	err := controller.LaunchTracee(testutils.ProgramInfloop, nil, infloopAttrs)
   302  	if err != nil {
   303  		t.Fatalf("failed to launch process: %v", err)
   304  	}
   305  	if err := controller.AddStartTracePoint(testutils.InfloopAddrMain); err != nil {
   306  		t.Fatalf("failed to set tracing point: %v", err)
   307  	}
   308  
   309  	done := make(chan error)
   310  	go func(ch chan error) {
   311  		ch <- controller.MainLoop()
   312  	}(done)
   313  
   314  	controller.Interrupt()
   315  	if err := <-done; err != ErrInterrupted {
   316  		t.Errorf("not interrupted: %v", err)
   317  	}
   318  }