github.com/tencent/goom@v1.0.1/internal/proxy/func_fixins_test.go (about)

     1  package proxy
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"runtime/debug"
     7  	"testing"
     8  
     9  	"github.com/tencent/goom/internal/logger"
    10  )
    11  
    12  // Caller 测试函数
    13  //
    14  //go:noinline
    15  func Caller(i int) int {
    16  	if i <= 0 {
    17  		return 1
    18  	}
    19  	return i * Caller(i-1)
    20  }
    21  
    22  // Caller1 测试函数
    23  //
    24  //go:noinline
    25  func Caller1(i int) int {
    26  	if i <= 0 {
    27  		return 1
    28  	}
    29  	return i
    30  }
    31  
    32  // Caller2 测试函数
    33  //
    34  //go:noinline
    35  func Caller2(i int) int {
    36  	for j := 0; j < 10; j++ {
    37  		i += j
    38  	}
    39  	return i
    40  }
    41  
    42  // Arg 测试参数
    43  type Arg struct {
    44  	field1 string
    45  	field2 map[string]int
    46  }
    47  
    48  // Caller3 测试函数
    49  //
    50  //go:noinline
    51  func Caller3(arg Arg) int {
    52  	//if len(arg.field2) > 0 {
    53  	//	fmt.Println(len(arg.field2))
    54  	//}
    55  	return 2 + len(arg.field1) + len(arg.field2)
    56  }
    57  
    58  // Caller4 测试函数
    59  //
    60  //go:noinline
    61  func Caller4(arg *Arg) int {
    62  	return 0
    63  }
    64  
    65  // Caller5 测试函数
    66  //
    67  //go:noinline
    68  func Caller5() int {
    69  	logger.Trace(string(debug.Stack()))
    70  	return 0
    71  }
    72  
    73  // Caller6 测试函数
    74  //
    75  //go:noinline
    76  func Caller6(a int) func() int {
    77  	return func() int {
    78  		return a + 1
    79  	}
    80  }
    81  
    82  // Caller7 测试函数
    83  //
    84  //go:noinline
    85  func Caller7(i int) {
    86  }
    87  
    88  // Caller8 测试函数
    89  // nolint
    90  //
    91  //go:noinline
    92  func Caller8(i int) int {
    93  tag:
    94  	return i
    95  tag1:
    96  	return -i
    97  	if i < 0 {
    98  		goto tag
    99  	} else {
   100  		goto tag1
   101  	}
   102  }
   103  
   104  var testCases1 = []struct {
   105  	funcName   string
   106  	funcDef    interface{}
   107  	eval       func(t *testing.T)
   108  	trampoline func() interface{}
   109  	proxy      func(interface{}) interface{}
   110  	wantError  bool
   111  }{
   112  	{
   113  		funcName: "Caller",
   114  		funcDef:  Caller,
   115  		eval: func(t *testing.T) {
   116  			if r := Caller(5); r != 120 {
   117  				t.Fatalf("want result: %d, real: %d", 120, r)
   118  			}
   119  		},
   120  		trampoline: func() interface{} {
   121  			var result = func(i int) int {
   122  				fmt.Println("trampoline")
   123  				return i + 10
   124  			}
   125  			return &result
   126  		},
   127  		proxy: func(origin interface{}) interface{} {
   128  			return func(i int) int {
   129  				logger.Trace("proxy Caller called, args", i)
   130  				originFunc, _ := origin.(*func(i int) int)
   131  				return (*originFunc)(i)
   132  			}
   133  		},
   134  	},
   135  	{
   136  		funcName: "Caller1",
   137  		funcDef:  Caller1,
   138  		eval: func(t *testing.T) {
   139  			if r := Caller1(-1); r != 1 {
   140  				t.Fatalf("want result: %d, real: %d", 1, r)
   141  			}
   142  		},
   143  		trampoline: func() interface{} {
   144  			var result = func(i int) int {
   145  				fmt.Println("trampoline")
   146  				return i + 20
   147  			}
   148  			return &result
   149  		},
   150  		proxy: func(origin interface{}) interface{} {
   151  			var origin1 = origin
   152  			return func(i int) int {
   153  				logger.Trace("proxy Caller1 called, args", i)
   154  				originFunc, _ := origin1.(*func(i int) int)
   155  				return (*originFunc)(i)
   156  			}
   157  		},
   158  	},
   159  	{
   160  		funcName:  "Caller2",
   161  		funcDef:   Caller2,
   162  		wantError: true,
   163  		eval: func(t *testing.T) {
   164  			if r := Caller2(5); r != 50 {
   165  				t.Fatalf("want result: %d, real: %d", 50, r)
   166  			}
   167  
   168  		},
   169  		trampoline: func() interface{} {
   170  			var result = func(i int) int {
   171  				fmt.Println("trampoline")
   172  				return i + 30
   173  			}
   174  			return &result
   175  		},
   176  		proxy: func(origin interface{}) interface{} {
   177  			var origin1 = origin
   178  			return func(i int) int {
   179  				logger.Trace("proxy Caller2 called, args", i)
   180  				originFunc, _ := origin1.(*func(i int) int)
   181  				return (*originFunc)(i)
   182  			}
   183  		},
   184  	},
   185  	{
   186  		funcName: "Caller3",
   187  		funcDef:  Caller3,
   188  		eval: func(t *testing.T) {
   189  			if r := Caller3(Arg{
   190  				field1: "field1",
   191  				field2: nil,
   192  			}); r != 8 {
   193  				t.Fatalf("want result: %d, real: %d", 8, r)
   194  			}
   195  		},
   196  		trampoline: func() interface{} {
   197  			var result = func(arg Arg) int {
   198  				fmt.Println("trampoline")
   199  				return 40
   200  			}
   201  			return &result
   202  		},
   203  		proxy: func(origin interface{}) interface{} {
   204  			var origin1 = origin
   205  			return func(arg Arg) int {
   206  				fmt.Println("Caller3")
   207  				logger.Trace("proxy Caller3 called, args", arg)
   208  				originFunc, _ := origin1.(*func(arg Arg) int)
   209  				fmt.Println("Caller3-1")
   210  				result := (*originFunc)(arg)
   211  				fmt.Println("Caller3-2")
   212  				return result
   213  			}
   214  		},
   215  	},
   216  	{
   217  		funcName: "Caller4",
   218  		funcDef:  Caller4,
   219  		eval: func(t *testing.T) {
   220  			if r := Caller4(&Arg{
   221  				field1: "field1",
   222  				field2: make(map[string]int),
   223  			}); r != 0 {
   224  				t.Fatalf("want result: %d, real: %d", 0, r)
   225  			}
   226  		},
   227  		trampoline: func() interface{} {
   228  			var result = func(arg *Arg) int {
   229  				fmt.Println("trampoline")
   230  				return 50
   231  			}
   232  			return &result
   233  		},
   234  		proxy: func(origin interface{}) interface{} {
   235  			var origin1 = origin
   236  			return func(arg *Arg) int {
   237  				logger.Trace("proxy Caller4 called, args", arg)
   238  				originFunc, _ := origin1.(*func(arg *Arg) int)
   239  				return (*originFunc)(arg)
   240  			}
   241  		},
   242  	},
   243  	{
   244  		funcName: "Caller5",
   245  		funcDef:  Caller5,
   246  		eval: func(t *testing.T) {
   247  			if r := Caller5(); r != 0 {
   248  				t.Fatalf("want result: %d, real: %d", 0, r)
   249  			}
   250  		},
   251  		trampoline: func() interface{} {
   252  			var result = func() int {
   253  				return 60 + rand.Int()
   254  			}
   255  			return &result
   256  		},
   257  		proxy: func(origin interface{}) interface{} {
   258  			var origin1 = origin
   259  			return func() int {
   260  				logger.Trace("proxy Caller5 called, no args")
   261  				originFunc, _ := origin1.(*func() int)
   262  				return (*originFunc)()
   263  			}
   264  		},
   265  	},
   266  	{
   267  		funcName: "Caller6",
   268  		funcDef:  Caller6,
   269  		eval: func(t *testing.T) {
   270  			if r := Caller6(3)(); r != 4 {
   271  				t.Fatalf("want result: %d, real: %d", 4, r)
   272  			}
   273  		},
   274  		trampoline: func() interface{} {
   275  			var result = func(a int) func() int {
   276  				return func() int {
   277  					return a + 70
   278  				}
   279  			}
   280  			return &result
   281  		},
   282  		proxy: func(origin interface{}) interface{} {
   283  			var origin1 = origin
   284  			return func(a int) func() int {
   285  				logger.Trace("proxy Caller6 called, args", a)
   286  				originFunc, _ := origin1.(*func(a int) func() int)
   287  				return (*originFunc)(a)
   288  			}
   289  		},
   290  	},
   291  	{
   292  		funcName: "Caller7",
   293  		funcDef:  Caller7,
   294  		eval: func(t *testing.T) {
   295  			Caller7(2)
   296  		},
   297  		trampoline: func() interface{} {
   298  			var result = func(i int) {
   299  				fmt.Println("trampoline")
   300  			}
   301  			return &result
   302  		},
   303  		proxy: func(origin interface{}) interface{} {
   304  			var origin1 = origin
   305  			return func(i int) {
   306  				logger.Trace("proxy Caller7 called, args", i)
   307  				originFunc, _ := origin1.(*func(i int))
   308  				(*originFunc)(i)
   309  			}
   310  		},
   311  	},
   312  	{ // TODO 排查不同环境结果不一致的原因
   313  		funcName: "Caller8",
   314  		funcDef:  Caller8,
   315  		eval: func(t *testing.T) {
   316  			if r := Caller8(-1); r != -1 {
   317  				t.Fatalf("want result: %d, real: %d", -1, r)
   318  			}
   319  		},
   320  		trampoline: func() interface{} {
   321  			var result = func(i int) int {
   322  				fmt.Println("trampoline")
   323  				return 99
   324  			}
   325  			return &result
   326  		},
   327  		proxy: func(origin interface{}) interface{} {
   328  			var origin1 = origin
   329  			return func(i int) int {
   330  				logger.Trace("proxy Caller8 called, args", i)
   331  				originFunc, _ := origin1.(*func(int) int)
   332  				return (*originFunc)(i)
   333  			}
   334  		},
   335  	},
   336  }
   337  
   338  // main 测试静态代理
   339  func TestProxy_fixIns(t *testing.T) {
   340  	logger.LogLevel = logger.TraceLevel
   341  	logger.SetLog2Console(true)
   342  	for _, tc := range testCases1 {
   343  
   344  		trampoline := tc.trampoline()
   345  
   346  		// 静态代理函数
   347  		patch, err := FuncName("github.com/tencent/goom/internal/proxy."+
   348  			tc.funcName, tc.proxy(trampoline), trampoline)
   349  		if tc.wantError && err != nil {
   350  			continue
   351  		}
   352  
   353  		if err != nil {
   354  			t.Fatalf("mock func %s err: %v", tc.funcName, err)
   355  		}
   356  
   357  		patch.Apply()
   358  
   359  		tc.eval(t)
   360  		patch.Unpatch()
   361  	}
   362  	fmt.Println("all test is ok")
   363  }