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  }