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 }