github.com/Aoi-hosizora/ahlib@v1.5.1-0.20230404072829-241b93cf91c7/xruntime/xruntime_test.go (about) 1 package xruntime 2 3 import ( 4 "fmt" 5 "github.com/Aoi-hosizora/ahlib/xtesting" 6 "net" 7 "os" 8 "reflect" 9 "runtime/pprof" 10 "strings" 11 "syscall" 12 "testing" 13 "unsafe" 14 ) 15 16 func testA() {} 17 18 var testB = func() {} // glob..func1 19 20 var testC = func() {} // glob..func2 21 22 type testStruct struct{} 23 24 func (t testStruct) testD() {} 25 26 func (t *testStruct) testE() {} 27 28 func TestNameOfFunction(t *testing.T) { 29 var testF = func() {} // TestNameOfFunction.func1 30 testG := func() {} // TestNameOfFunction.func2 31 ts1 := testStruct{} 32 ts2 := &testStruct{} 33 34 for _, tc := range []struct { 35 give interface{} 36 want string 37 }{ 38 {testA, "github.com/Aoi-hosizora/ahlib/xruntime.testA"}, 39 {testB, "github.com/Aoi-hosizora/ahlib/xruntime.glob..func1"}, 40 {testC, "github.com/Aoi-hosizora/ahlib/xruntime.glob..func2"}, 41 {testStruct.testD, "github.com/Aoi-hosizora/ahlib/xruntime.testStruct.testD"}, 42 {(*testStruct).testE, "github.com/Aoi-hosizora/ahlib/xruntime.(*testStruct).testE"}, 43 {ts1.testD, "github.com/Aoi-hosizora/ahlib/xruntime.testStruct.testD-fm"}, 44 {ts2.testD, "github.com/Aoi-hosizora/ahlib/xruntime.testStruct.testD-fm"}, 45 {ts1.testE, "github.com/Aoi-hosizora/ahlib/xruntime.(*testStruct).testE-fm"}, 46 {ts2.testE, "github.com/Aoi-hosizora/ahlib/xruntime.(*testStruct).testE-fm"}, 47 {testF, "github.com/Aoi-hosizora/ahlib/xruntime.TestNameOfFunction.func1"}, 48 {testG, "github.com/Aoi-hosizora/ahlib/xruntime.TestNameOfFunction.func2"}, 49 } { 50 xtesting.Equal(t, NameOfFunction(tc.give), tc.want) 51 } 52 53 xtesting.Panic(t, func() { NameOfFunction(nil) }) 54 xtesting.Panic(t, func() { NameOfFunction(0) }) 55 xtesting.Panic(t, func() { NameOfFunction("x") }) 56 } 57 58 func printSharp(s string) { 59 fmt.Printf("\n%s\n", strings.Repeat("#", len(s)+8)) 60 fmt.Printf("### %s ###", s) 61 fmt.Printf("\n%s\n\n", strings.Repeat("#", len(s)+8)) 62 } 63 64 func TestRawStack(t *testing.T) { 65 printSharp("RawStack(false)") 66 _, _ = os.Stdout.Write(RawStack(false)) 67 68 /* 69 goroutine 19 [running]: 70 github.com/Aoi-hosizora/ahlib/xruntime.RawStack(0x7?) 71 C:/Files/Codes/Projects/ahlib/xruntime/xruntime.go:46 +0x6a 72 github.com/Aoi-hosizora/ahlib/xruntime.TestRawStack(0x0?) 73 C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:65 +0x30 74 testing.tRunner(0xc000085380, 0xf682b0) 75 C:/Developments/Go/src/testing/testing.go:1439 +0x102 76 created by testing.(*T).Run 77 C:/Developments/Go/src/testing/testing.go:1486 +0x35f 78 */ 79 80 printSharp("RawStack(true)") 81 _, _ = os.Stdout.Write(RawStack(true)) 82 83 /* 84 goroutine 19 [running]: 85 github.com/Aoi-hosizora/ahlib/xruntime.RawStack(0xdd?) 86 C:/Files/Codes/Projects/ahlib/xruntime/xruntime.go:46 +0x6a 87 github.com/Aoi-hosizora/ahlib/xruntime.TestRawStack(0x0?) 88 C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:80 +0x65 89 testing.tRunner(0xc000085380, 0xf682b0) 90 C:/Developments/Go/src/testing/testing.go:1439 +0x102 91 created by testing.(*T).Run 92 C:/Developments/Go/src/testing/testing.go:1486 +0x35f 93 94 goroutine 1 [chan receive]: 95 testing.(*T).Run(0xc0000851e0, {0xf5d0db?, 0xe87fd3?}, 0xf682b0) 96 C:/Developments/Go/src/testing/testing.go:1487 +0x37a 97 testing.runTests.func1(0xc0000b8720?) 98 C:/Developments/Go/src/testing/testing.go:1839 +0x6e 99 testing.tRunner(0xc0000851e0, 0xc0000c3cd8) 100 C:/Developments/Go/src/testing/testing.go:1439 +0x102 101 testing.runTests(0xc000094280?, {0x104a8a0, 0x8, 0x8}, {0x265fd440598?, 0x40?, 0x0?}) 102 C:/Developments/Go/src/testing/testing.go:1837 +0x457 103 testing.(*M).Run(0xc000094280) 104 C:/Developments/Go/src/testing/testing.go:1719 +0x5d9 105 main.main() 106 _testmain.go:61 +0x1aa 107 */ 108 109 printSharp("RawStack(false)_2") 110 var f func(a int) 111 f = func(a int) { 112 if a > 0 { 113 f(a - 1) 114 } else if a == 0 { 115 _, _ = os.Stdout.Write(RawStack(false)) 116 return 117 } 118 } 119 f(25) 120 121 /* 122 goroutine 19 [running]: 123 github.com/Aoi-hosizora/ahlib/xruntime.RawStack(0x0?) 124 C:/Files/Codes/Projects/ahlib/xruntime/xruntime.go:46 +0x6a 125 github.com/Aoi-hosizora/ahlib/xruntime.TestRawStack.func1(0x0?) 126 C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:114 +0x26 127 github.com/Aoi-hosizora/ahlib/xruntime.TestRawStack.func1(0x0?) 128 C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:112 +0x53 129 ...... 130 github.com/Aoi-hosizora/ahlib/xruntime.TestRawStack.func1(0xf5e51a?) 131 C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:112 +0x53 132 github.com/Aoi-hosizora/ahlib/xruntime.TestRawStack(0x0?) 133 C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:118 +0xc9 134 testing.tRunner(0xc000085380, 0xf682b0) 135 C:/Developments/Go/src/testing/testing.go:1439 +0x102 136 created by testing.(*T).Run 137 C:/Developments/Go/src/testing/testing.go:1486 +0x35f 138 */ 139 140 printSharp("TestRawStack end") 141 } 142 143 func TestTraceStack(t *testing.T) { 144 func() { 145 printSharp("RuntimeTraceStack(0)") 146 stack := RuntimeTraceStack(0) 147 fmt.Println(stack.String()) 148 }() 149 150 /* 151 File: C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:145 152 Func: github.com/Aoi-hosizora/ahlib/xruntime.TestTraceStack.func1 153 stack := RuntimeTraceStack(0) 154 File: C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:147 155 Func: github.com/Aoi-hosizora/ahlib/xruntime.TestTraceStack 156 }() 157 File: C:/Developments/Go/src/testing/testing.go:1439 158 Func: testing.tRunner 159 fn(t) 160 File: C:/Developments/Go/src/runtime/asm_amd64.s:1571 161 Func: runtime.goexit 162 BYTE $0x90 // NOP 163 */ 164 165 printSharp("RuntimeTraceStack(1)") 166 stack := RuntimeTraceStack(1) 167 fmt.Println(stack.String()) 168 169 /* 170 File: C:/Developments/Go/src/testing/testing.go:1439 171 Func: testing.tRunner 172 fn(t) 173 File: C:/Developments/Go/src/runtime/asm_amd64.s:1571 174 Func: runtime.goexit 175 BYTE $0x90 // NOP 176 */ 177 178 printSharp("RuntimeTraceStackWithInfo(0)") 179 s, filename, funcName, lineIndex, lineText := RuntimeTraceStackWithInfo(0) 180 fmt.Println("filename:", filename) 181 fmt.Println("funcName:", funcName) 182 fmt.Println("lineIndex:", lineIndex) 183 fmt.Println("lineText:", lineText) 184 fmt.Println("======") 185 fmt.Println(s[0].String()) 186 fmt.Println(s[1].String()) 187 188 /* 189 filename: C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go 190 funcName: xruntime.TestTraceStack 191 lineIndex: 178 192 lineText: s, filename, funcName, lineIndex, lineText := RuntimeTraceStackWithInfo(0) 193 ====== 194 File: C:/Files/Codes/Projects/ahlib/xruntime/xruntime_test.go:178 195 Func: github.com/Aoi-hosizora/ahlib/xruntime.TestTraceStack 196 s, filename, funcName, lineIndex, lineText := RuntimeTraceStackWithInfo(0) 197 File: C:/Developments/Go/src/testing/testing.go:1439 198 Func: testing.tRunner 199 fn(t) 200 */ 201 202 s, filename, funcName, lineIndex, lineText = RuntimeTraceStackWithInfo(5000) 203 xtesting.Equal(t, len(s), 0) 204 xtesting.Equal(t, filename, "") 205 xtesting.Equal(t, funcName, "") 206 xtesting.Equal(t, lineIndex, 0) 207 xtesting.Equal(t, lineText, "") 208 209 printSharp("TestTraceStack end") 210 } 211 212 func TestHackHideAndGetString(t *testing.T) { 213 handler := func() {} 214 funcSize := int(reflect.TypeOf(func() {}).Size()) 215 handlerFn := (*struct{ fn uintptr })(unsafe.Pointer(&handler)).fn 216 hackedFn := HackHideString(handlerFn, funcSize, "handlerName") 217 hackedHandler := *(*func())(unsafe.Pointer(&struct{ fn uintptr }{fn: hackedFn})) 218 xtesting.Equal(t, HackGetHiddenString(hackedFn, funcSize), "handlerName") 219 xtesting.NotPanic(t, func() { hackedHandler() }) 220 221 handler2 := func(i int) int { return i + 1000 } 222 funcSize2 := int(reflect.TypeOf(func(int) int { return 0 }).Size()) 223 handlerFn2 := (*struct{ fn uintptr })(unsafe.Pointer(&handler2)).fn 224 hackedFn2 := HackHideString(handlerFn2, funcSize2, "测试") 225 hackedHandler2 := *(*func(int) int)(unsafe.Pointer(&struct{ fn uintptr }{fn: hackedFn2})) 226 xtesting.Equal(t, HackGetHiddenString(hackedFn2, funcSize2), "测试") 227 xtesting.NotPanic(t, func() { xtesting.Equal(t, hackedHandler2(123), 1123) }) 228 229 slice := []int{1, 2, 3} 230 sliceSize := int(reflect.TypeOf([3]int{}).Size()) 231 sliceData := (*reflect.SliceHeader)(unsafe.Pointer(&slice)).Data 232 hackedData := HackHideString(sliceData, sliceSize, "handlerName") 233 hackedSlice := *(*[]int)(unsafe.Pointer(&reflect.SliceHeader{Data: hackedData, Len: 3, Cap: 3})) 234 xtesting.Equal(t, HackGetHiddenString(hackedData, sliceSize), "handlerName") 235 xtesting.Equal(t, hackedSlice, []int{1, 2, 3}) 236 237 slice2 := []string{"AAA", "BBB", "CCC", "DDD"} 238 sliceSize2 := int(reflect.TypeOf([4]string{}).Size()) 239 sliceData2 := (*reflect.SliceHeader)(unsafe.Pointer(&slice2)).Data 240 hackedData2 := HackHideString(sliceData2, sliceSize2, "テスト") 241 hackedSlice2 := *(*[]string)(unsafe.Pointer(&reflect.SliceHeader{Data: hackedData2, Len: 4, Cap: 4})) 242 xtesting.Equal(t, HackGetHiddenString(hackedData2, sliceSize2), "テスト") 243 xtesting.Equal(t, hackedSlice2, []string{"AAA", "BBB", "CCC", "DDD"}) 244 245 httpMethod := "GET" 246 hackedMethod := HackHideStringAfterString(httpMethod, "handlerName") 247 xtesting.Equal(t, HackGetHiddenStringAfterString(hackedMethod), "handlerName") 248 xtesting.Equal(t, hackedMethod, "GET") 249 250 httpMethod2 := "中文测试" 251 hackedMethod2 := HackHideStringAfterString(httpMethod2, "日本語のテスト") 252 xtesting.Equal(t, HackGetHiddenStringAfterString(hackedMethod2), "日本語のテスト") 253 xtesting.Equal(t, hackedMethod2, "中文测试") 254 255 xtesting.Equal(t, HackGetHiddenString((*struct{ fn uintptr })(unsafe.Pointer(&handler)).fn, funcSize), "") 256 xtesting.Equal(t, HackGetHiddenString((*struct{ fn uintptr })(unsafe.Pointer(&handler2)).fn, funcSize2), "") 257 xtesting.Equal(t, HackGetHiddenString((*struct{ fn uintptr })(unsafe.Pointer(&slice)).fn, sliceSize), "") 258 xtesting.Equal(t, HackGetHiddenString((*struct{ fn uintptr })(unsafe.Pointer(&slice2)).fn, sliceSize2), "") 259 xtesting.Equal(t, HackGetHiddenStringAfterString(httpMethod), "") 260 xtesting.Equal(t, HackGetHiddenStringAfterString(httpMethod2), "") 261 } 262 263 func TestPprofProfile(t *testing.T) { 264 for _, tc := range []struct { 265 give string 266 want bool 267 }{ 268 {"", false}, 269 {PprofAllocsProfile, true}, 270 {PprofBlockProfle, true}, 271 {PprofGoroutineProfile, true}, 272 {PprofHeapProfile, true}, 273 {PprofMutexProfile, true}, 274 {PprofThreadcreateProfile, true}, 275 {"index", false}, 276 {"cmdline", false}, 277 {"profile", false}, 278 {"symbol", false}, 279 {"trace", false}, 280 } { 281 xtesting.Equal(t, pprof.Lookup(tc.give) != nil, tc.want) 282 } 283 } 284 285 func TestSignalName(t *testing.T) { 286 for _, tc := range []struct { 287 give syscall.Signal 288 want string 289 }{ 290 {-1, "signal -1"}, 291 {0, "signal 0"}, 292 {syscall.SIGHUP, "SIGHUP"}, 293 {syscall.SIGINT, "SIGINT"}, 294 {syscall.SIGQUIT, "SIGQUIT"}, 295 {syscall.SIGILL, "SIGILL"}, 296 {syscall.SIGTRAP, "SIGTRAP"}, 297 {syscall.SIGABRT, "SIGABRT"}, 298 {syscall.SIGBUS, "SIGBUS"}, 299 {syscall.SIGFPE, "SIGFPE"}, 300 {syscall.SIGKILL, "SIGKILL"}, 301 {10, "SIGUSR1"}, 302 {syscall.SIGSEGV, "SIGSEGV"}, 303 {12, "SIGUSR2"}, 304 {syscall.SIGPIPE, "SIGPIPE"}, 305 {syscall.SIGALRM, "SIGALRM"}, 306 {syscall.SIGTERM, "SIGTERM"}, 307 {16, "signal 16"}, 308 } { 309 t.Run(tc.want, func(t *testing.T) { 310 xtesting.Equal(t, SignalName(tc.give), tc.want) 311 }) 312 } 313 314 for _, tc := range []struct { 315 give syscall.Signal 316 want string 317 }{ 318 {-1, "signal -1"}, 319 {0, "signal 0"}, 320 {syscall.SIGHUP, "hangup"}, 321 {syscall.SIGINT, "interrupt"}, 322 {syscall.SIGQUIT, "quit"}, 323 {syscall.SIGILL, "illegal instruction"}, 324 {syscall.SIGTRAP, "trace/breakpoint trap"}, 325 {syscall.SIGABRT, "aborted"}, 326 {syscall.SIGBUS, "bus error"}, 327 {syscall.SIGFPE, "floating point exception"}, 328 {syscall.SIGKILL, "killed"}, 329 {10, "user defined signal 1"}, 330 {syscall.SIGSEGV, "segmentation fault"}, 331 {12, "user defined signal 2"}, 332 {syscall.SIGPIPE, "broken pipe"}, 333 {syscall.SIGALRM, "alarm clock"}, 334 {syscall.SIGTERM, "terminated"}, 335 {16, "signal 16"}, 336 } { 337 t.Run(tc.want, func(t *testing.T) { 338 xtesting.Equal(t, SignalReadableName(tc.give), tc.want) 339 }) 340 } 341 } 342 343 func TestGetProxyEnv(t *testing.T) { 344 envs := map[string]string{} 345 for _, key := range []string{"no_proxy", "http_proxy", "https_proxy", "socks_proxy"} { 346 if env, ok := os.LookupEnv(key); ok { 347 envs[key] = env 348 } 349 } 350 defer func() { 351 for key, env := range envs { 352 os.Setenv(key, env) 353 } 354 }() 355 356 os.Setenv("no_proxy", "") 357 os.Setenv("http_proxy", "") 358 os.Setenv("https_proxy", "") 359 os.Setenv("socks_proxy", "") 360 env := GetProxyEnv() 361 xtesting.Equal(t, env.NoProxy, "") 362 xtesting.Equal(t, env.HttpProxy, "") 363 xtesting.Equal(t, env.HttpsProxy, "") 364 xtesting.Equal(t, env.SocksProxy, "") 365 sb := &strings.Builder{} 366 env.PrintLog(func(s string) { sb.WriteString(s + "\n") }, "[XXX] ") 367 xtesting.Equal(t, sb.String(), "") 368 369 os.Setenv("no_proxy", "localhost,127.0.0.1,::1") 370 os.Setenv("http_proxy", "http://localhost:9000") 371 os.Setenv("https_proxy", "https://localhost:9000") 372 os.Setenv("socks_proxy", "socks://localhost:9000") 373 env = GetProxyEnv() 374 xtesting.Equal(t, env.NoProxy, "localhost,127.0.0.1,::1") 375 xtesting.Equal(t, env.HttpProxy, "http://localhost:9000") 376 xtesting.Equal(t, env.HttpsProxy, "https://localhost:9000") 377 xtesting.Equal(t, env.SocksProxy, "socks://localhost:9000") 378 sb.Reset() 379 env.PrintLog(func(s string) { sb.WriteString(s) }, "[XXX] ") 380 lines := []string{ 381 "[XXX] Using no_proxy: localhost,127.0.0.1,::1", 382 "[XXX] Using http_proxy: http://localhost:9000", 383 "[XXX] Using https_proxy: https://localhost:9000", 384 "[XXX] Using socks_proxy: socks://localhost:9000", 385 } 386 xtesting.Equal(t, sb.String(), strings.Join(lines, "")) 387 env.PrintLog(nil, "") // log 388 389 os.Setenv("no_proxy", "") 390 os.Setenv("http_proxy", "") 391 os.Setenv("https_proxy", "") 392 os.Setenv("socks_proxy", "") 393 env = GetProxyEnv() 394 xtesting.Equal(t, env.NoProxy, "") 395 xtesting.Equal(t, env.HttpProxy, "") 396 xtesting.Equal(t, env.HttpsProxy, "") 397 xtesting.Equal(t, env.SocksProxy, "") 398 sb.Reset() 399 env.PrintLog(func(s string) { sb.WriteString(s + "\n") }, "[XXX] ") 400 xtesting.Equal(t, sb.String(), "") 401 } 402 403 func TestParseNetAddr(t *testing.T) { 404 for _, tc := range []struct { 405 give NetAddrType 406 want string 407 }{ 408 {TCPAddrType, "TCPAddr"}, 409 {UDPAddrType, "UDPAddr"}, 410 {IPAddrType, "IPAddr"}, 411 {UnixAddrType, "UnixAddr"}, 412 } { 413 xtesting.Equal(t, tc.give.String(), tc.want) 414 } 415 416 tcpAddr := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12345, Zone: "test ipv6 zone"} 417 udpAddr := &net.UDPAddr{IP: net.ParseIP("::1"), Port: 12, Zone: "test zone"} 418 ipAddr := &net.IPAddr{IP: net.ParseIP("192.168.3.255"), Zone: ""} 419 ipAddr2 := &net.IPAddr{IP: net.ParseIP("192.168.1.999"), Zone: "123"} 420 unixAddr := &net.UnixAddr{Name: "test.socks", Net: "net"} 421 unsupportedAddr := &net.IPNet{} 422 for _, tc := range []struct { 423 giveAddr net.Addr 424 wantOk bool 425 wantType NetAddrType 426 wantIP string 427 wantPort int 428 wantZone string 429 wantName string 430 wantNet string 431 }{ 432 {nil, false, "", "", 0, "", "", ""}, 433 {tcpAddr, true, TCPAddrType, "127.0.0.1", 12345, "test ipv6 zone", "", ""}, 434 {udpAddr, true, UDPAddrType, "::1", 12, "test zone", "", ""}, 435 {ipAddr, true, IPAddrType, "192.168.3.255", 0, "", "", ""}, 436 {ipAddr2, true, IPAddrType, "", 0, "123", "", ""}, 437 {unixAddr, true, UnixAddrType, "", 0, "", "test.socks", "net"}, 438 {unsupportedAddr, false, "", "", 0, "", "", ""}, 439 } { 440 t.Run(tc.wantType.String(), func(t *testing.T) { 441 addr, ok := ParseNetAddr(tc.giveAddr) 442 xtesting.Equal(t, ok, tc.wantOk) 443 if !tc.wantOk { 444 xtesting.Nil(t, addr) 445 } else { 446 xtesting.Equal(t, addr.Type, tc.wantType) 447 switch tc.wantType { 448 case TCPAddrType: 449 xtesting.Equal(t, addr.TCPAddr, tc.giveAddr.(*net.TCPAddr)) 450 case UDPAddrType: 451 xtesting.Equal(t, addr.UDPAddr, tc.giveAddr.(*net.UDPAddr)) 452 case IPAddrType: 453 xtesting.Equal(t, addr.IPAddr, tc.giveAddr.(*net.IPAddr)) 454 case UnixAddrType: 455 xtesting.Equal(t, addr.UnixAddr, tc.giveAddr.(*net.UnixAddr)) 456 } 457 if tc.wantIP != "" { 458 xtesting.Equal(t, addr.IP.String(), tc.wantIP) 459 } else { 460 xtesting.Equal(t, addr.IP, (net.IP)(nil)) 461 } 462 xtesting.Equal(t, addr.Port, tc.wantPort) 463 xtesting.Equal(t, addr.Zone, tc.wantZone) 464 xtesting.Equal(t, addr.Name, tc.wantName) 465 xtesting.Equal(t, addr.Net, tc.wantNet) 466 } 467 }) 468 } 469 }