github.com/tencent/goom@v1.0.1/internal/proxy/func_test.go (about) 1 // Package proxy_test 对 proxy 包的测试 2 package proxy_test 3 4 import ( 5 "fmt" 6 "log" 7 "math/rand" 8 "runtime" 9 "strings" 10 "testing" 11 12 "github.com/tencent/goom/internal/logger" 13 "github.com/tencent/goom/internal/proxy" 14 ) 15 16 // 测试用例数据 17 var basePath = CurrentPackage() 18 19 var testCases = []*TestCase{ 20 { 21 funcName: "Caller", 22 funcDef: Caller, 23 eval: func() { 24 _ = Caller(1000) 25 }, 26 evalMakeFunc: func(makeFunc interface{}) { 27 makeFunc.(func(i int) int)(5) 28 }, 29 trampoline: func() interface{} { 30 var result = func(i int) int { 31 fmt.Println("trampoline") 32 fmt.Println("trampoline1") 33 return i + 10 34 } 35 return &result 36 }, 37 proxy: func(origin interface{}) interface{} { 38 return func(i int) int { 39 logger.Debug("proxy Caller called, args", i) 40 originFunc, _ := origin.(*func(i int) int) 41 return (*originFunc)(i) 42 } 43 }, 44 }, 45 { 46 funcName: "Caller1", 47 funcDef: Caller1, 48 eval: func() { 49 _ = Caller1(5) 50 }, 51 evalMakeFunc: func(makeFunc interface{}) { 52 makeFunc.(func(i int) int)(5) 53 }, 54 trampoline: func() interface{} { 55 var result = func(i int) int { 56 fmt.Println("trampoline") 57 fmt.Println("trampoline1") 58 return i + 20 59 } 60 return &result 61 }, 62 proxy: func(origin interface{}) interface{} { 63 var origin1 = origin 64 return func(i int) int { 65 logger.Trace("proxy Caller1 called, args", i) 66 originFunc, _ := origin1.(*func(i int) int) 67 return (*originFunc)(i) 68 } 69 }, 70 }, 71 { 72 funcName: "Caller2", 73 funcDef: Caller2, 74 eval: func() { 75 _ = Caller2(5) 76 }, 77 evalMakeFunc: func(makeFunc interface{}) { 78 makeFunc.(func(i int) int)(5) 79 }, 80 trampoline: func() interface{} { 81 var result = func(i int) int { 82 fmt.Println("trampoline") 83 fmt.Println("trampoline1") 84 return i + 30 85 } 86 return &result 87 }, 88 proxy: func(origin interface{}) interface{} { 89 var origin1 = origin 90 return func(i int) int { 91 logger.Trace("proxy Caller2 called, args", i) 92 originFunc, _ := origin1.(*func(i int) int) 93 return (*originFunc)(i) 94 } 95 }, 96 }, 97 { 98 funcName: "Caller3", 99 funcDef: Caller3, 100 eval: func() { 101 //var arg = make(map[string]int, 0) 102 Caller3(Arg{ 103 field1: field1, 104 field2: nil, 105 }) 106 }, 107 evalMakeFunc: func(makeFunc interface{}) { 108 makeFunc.(func(arg Arg) int)(Arg{ 109 field1: field1, 110 field2: nil, 111 }) 112 }, 113 trampoline: func() interface{} { 114 var result = func(arg Arg) int { 115 fmt.Println("trampoline") 116 fmt.Println("trampoline1") 117 return 40 118 } 119 return &result 120 }, 121 proxy: func(origin interface{}) interface{} { 122 var origin1 = origin 123 return func(arg Arg) int { 124 logger.Trace("proxy Caller3 called, args", arg) 125 originFunc, _ := origin1.(*func(arg Arg) int) 126 return (*originFunc)(arg) 127 } 128 }, 129 }, 130 { 131 funcName: "Caller4", 132 funcDef: Caller4, 133 eval: Caller4Eval, 134 evalMakeFunc: func(makeFunc interface{}) { 135 makeFunc.(func(arg *Arg) int)(&Arg{ 136 field1: field1, 137 field2: nil, 138 }) 139 }, 140 trampoline: func() interface{} { 141 var result = func(arg *Arg) int { 142 fmt.Println("trampoline") 143 fmt.Println("trampoline1") 144 return 50 145 } 146 return &result 147 }, 148 proxy: func(origin interface{}) interface{} { 149 var origin1 = origin 150 return func(arg *Arg) int { 151 logger.Trace("proxy Caller4 called, args", arg) 152 originFunc, _ := origin1.(*func(arg *Arg) int) 153 return (*originFunc)(arg) 154 } 155 }, 156 }, 157 { 158 funcName: "Caller5", 159 funcDef: Caller5, 160 eval: func() { 161 Caller5() 162 }, 163 evalMakeFunc: func(makeFunc interface{}) { 164 makeFunc.(func() int)() 165 }, 166 trampoline: func() interface{} { 167 var result = func() int { 168 fmt.Println("trampoline1") 169 return 60 + rand.Int() 170 } 171 return &result 172 }, 173 proxy: func(origin interface{}) interface{} { 174 var origin1 = origin 175 return func() int { 176 logger.Trace("proxy Caller5 called, no args") 177 originFunc, _ := origin1.(*func() int) 178 return (*originFunc)() 179 } 180 }, 181 }, 182 { 183 funcName: "Caller6", 184 funcDef: Caller6, 185 eval: func() { 186 Caller6(3)() 187 }, 188 evalMakeFunc: func(makeFunc interface{}) { 189 makeFunc.(func(a int) func() int)(3)() 190 }, 191 trampoline: func() interface{} { 192 var result = func(a int) func() int { 193 return func() int { 194 fmt.Println("trampoline1") 195 return a + 70 196 } 197 } 198 return &result 199 }, 200 proxy: func(origin interface{}) interface{} { 201 var origin1 = origin 202 return func(a int) func() int { 203 logger.Trace("proxy Caller6 called, args", a) 204 originFunc, _ := origin1.(*func(a int) func() int) 205 return (*originFunc)(a) 206 } 207 }, 208 }, 209 { 210 funcName: "Caller7", 211 funcDef: Caller7, 212 eval: func() { 213 Caller7(2) 214 }, 215 evalMakeFunc: func(makeFunc interface{}) { 216 makeFunc.(func(a int))(2) 217 }, 218 trampoline: func() interface{} { 219 var result = func(i int) { 220 fmt.Println("trampoline") 221 fmt.Println("trampoline1") 222 } 223 return &result 224 }, 225 proxy: func(origin interface{}) interface{} { 226 var origin1 = origin 227 return func(i int) { 228 logger.Trace("proxy Caller7 called, args", i) 229 originFunc, _ := origin1.(*func(i int)) 230 (*originFunc)(i) 231 } 232 }, 233 }, 234 { 235 funcName: "Caller8", 236 funcDef: Caller8, 237 eval: func() { 238 j := Caller8(5).inner.j 239 if j < 0 { 240 fmt.Println(j) 241 } 242 }, 243 evalMakeFunc: func(makeFunc interface{}) { 244 makeFunc.(func(i int) *Result)(5) 245 }, 246 trampoline: func() interface{} { 247 var result = func(i int) *Result { 248 fmt.Println("trampoline") 249 fmt.Println("trampoline1") 250 return &Result{ 251 i: i * 100, 252 inner: &InnerResult{ 253 j: i * 2 * 100, 254 }, 255 m: make(map[string]int, 2), 256 } 257 } 258 return &result 259 }, 260 proxy: func(origin interface{}) interface{} { 261 var origin1 = origin 262 return func(i int) *Result { 263 logger.Trace("proxy Caller8 called, args", i) 264 originFunc, _ := origin1.(*func(i int) *Result) 265 return (*originFunc)(i) 266 } 267 }, 268 }, 269 { 270 funcName: "Caller9", 271 funcDef: Caller9, 272 eval: func() { 273 j := Caller9(5).m 274 if len(j) > 0 { 275 fmt.Println(j) 276 } 277 }, 278 evalMakeFunc: func(makeFunc interface{}) { 279 makeFunc.(func(i int) Result)(5) 280 }, 281 trampoline: func() interface{} { 282 var result = func(i int) Result { 283 fmt.Println("trampoline") 284 fmt.Println("trampoline1") 285 return Result{ 286 i: i * 100, 287 inner: &InnerResult{ 288 j: i * 2 * 100, 289 }, 290 m: make(map[string]int, 2), 291 } 292 } 293 return &result 294 }, 295 proxy: func(origin interface{}) interface{} { 296 var origin1 = origin 297 return func(i int) Result { 298 logger.Trace("proxy Caller9 called, args", i) 299 originFunc, _ := origin1.(*func(i int) Result) 300 return (*originFunc)(i) 301 } 302 }, 303 }, 304 } 305 306 // TestTestStaticProxy 测试静态代理 307 func TestTestStaticProxy(t *testing.T) { 308 logger.LogLevel = logger.DebugLevel 309 logger.SetLog2Console(true) 310 311 for _, tc := range testCases { 312 trampoline := tc.trampoline() 313 314 // 静态代理函数 315 patch, err := proxy.FuncName(basePath+"."+tc.funcName, tc.proxy(trampoline), trampoline) 316 if err != nil { 317 log.Println("mock print err:", err) 318 continue 319 } 320 321 tc.eval() 322 patch.Unpatch() 323 } 324 325 fmt.Println("ok") 326 } 327 328 // TestTestStaticProxy 测试静态代理 329 func BenchmarkStaticProxy(b *testing.B) { 330 logger.LogLevel = logger.TraceLevel 331 logger.SetLog2Console(true) 332 333 for i := 0; i < b.N; i++ { 334 for _, tc := range testCases { 335 trampoline := tc.trampoline() 336 337 fun := tc.proxy(trampoline) 338 339 // 静态代理函数 340 patch, err := proxy.FuncName(basePath+"."+tc.funcName, fun, trampoline) 341 if err != nil { 342 b.Errorf("mock %s print err:%s", tc.funcName, err) 343 } 344 345 tc.eval() 346 patch.Unpatch() 347 } 348 } 349 } 350 351 // TestStaticProxyConcurrent 测试并发支持 352 func TestStaticProxyConcurrent(t *testing.T) { 353 logger.LogLevel = logger.WarningLevel 354 logger.SetLog2Console(true) 355 356 wait := make(chan int) 357 358 for c := 0; c < 10; c++ { 359 go func(c1 int) { 360 for i := 0; i < 100; i++ { 361 for _, tc := range testCases { 362 trampoline := tc.trampoline() 363 364 // 静态代理函数 365 patch, err := proxy.FuncName(basePath+"."+tc.funcName, tc.proxy(trampoline), trampoline) 366 if err != nil { 367 t.Error("mock print err:", err) 368 } 369 370 tc.eval() 371 patch.Unpatch() 372 373 wait <- i * c1 374 } 375 } 376 }(c) 377 } 378 379 for i := 0; i < 10*100*len(testCases); i++ { 380 <-wait 381 } 382 } 383 384 // TestConcurrent 测试运行中 patch 并发支持 385 func TestStaticProxyConcurrent1(t *testing.T) { 386 logger.LogLevel = logger.WarningLevel 387 logger.SetLog2Console(true) 388 389 for c := 0; c < 50; c++ { 390 go func() { 391 for i := 0; i < 10000; i++ { 392 for _, t := range testCases { 393 t.eval() 394 } 395 } 396 }() 397 } 398 399 for c := 0; c < 1000; c++ { 400 go func() { 401 for _, tc := range testCases { 402 trampoline := tc.trampoline() 403 404 // 静态代理函数 405 patch, err := proxy.FuncName(basePath+"."+tc.funcName, tc.proxy(trampoline), trampoline) 406 if err != nil { 407 t.Error("mock print err:", err) 408 } 409 410 tc.eval() 411 patch.Unpatch() 412 } 413 }() 414 } 415 416 wait := make(chan int) 417 418 for c := 0; c < 50; c++ { 419 go func(c1 int) { 420 for i := 0; i < 10000; i++ { 421 for _, t := range testCases { 422 t.eval() 423 wait <- i * c1 424 } 425 } 426 }(c) 427 } 428 429 for i := 0; i < 50*10000*len(testCases); i++ { 430 <-wait 431 } 432 } 433 434 // TestConcurrent 测试运行中 patch 并发支持 435 // TODO fix nil pointer 436 func TestStaticProxyConcurrentOnce(t *testing.T) { 437 logger.LogLevel = logger.InfoLevel 438 logger.SetLog2Console(true) 439 440 for c := 0; c < 50; c++ { 441 go func() { 442 for i := 0; i < 10000; i++ { 443 for _, t := range testCases { 444 t.eval() 445 } 446 } 447 }() 448 } 449 450 go func() { 451 for _, tc := range testCases { 452 trampoline := tc.trampoline() 453 454 // 静态代理函数 455 patch, err := proxy.FuncName(basePath+"."+tc.funcName, tc.proxy(trampoline), trampoline) 456 if err != nil { 457 t.Error("mock print err:", err) 458 } 459 460 tc.eval() 461 patch.UnpatchWithLock() 462 } 463 }() 464 465 wait := make(chan int) 466 467 for c := 0; c < 50; c++ { 468 go func(c1 int) { 469 for i := 0; i < 100; i++ { 470 for _, t := range testCases { 471 t.eval() 472 wait <- i * c1 473 } 474 } 475 }(c) 476 } 477 478 for i := 0; i < 50*100*len(testCases); i++ { 479 <-wait 480 } 481 } 482 483 // CurrentPackage 获取当前调用的包路径 484 func CurrentPackage() string { 485 return currentPackage(2) 486 } 487 488 // currentPackage 获取调用者的包路径 489 func currentPackage(skip int) string { 490 pc, _, _, _ := runtime.Caller(skip) 491 callerName := runtime.FuncForPC(pc).Name() 492 493 if i := strings.Index(callerName, ".("); i > -1 { 494 return callerName[:i] 495 } 496 497 if i := strings.LastIndex(callerName, "."); i > -1 { 498 return callerName[:i] 499 } 500 501 return callerName 502 }