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

     1  // Package proxy_test 对 proxy 包的测试
     2  package proxy_test
     3  
     4  import (
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  	"unsafe"
     9  
    10  	"github.com/tencent/goom/internal/bytecode/stub"
    11  	"github.com/tencent/goom/internal/hack"
    12  	"github.com/tencent/goom/internal/iface"
    13  	"github.com/tencent/goom/internal/logger"
    14  	"github.com/tencent/goom/internal/proxy"
    15  )
    16  
    17  // I 接口测试
    18  type I interface {
    19  	Call(int) int
    20  	Call1(string) string
    21  	call2(int32) int32
    22  }
    23  
    24  // TestInterfaceCall 测试接口调用
    25  func TestInterfaceCall(t *testing.T) {
    26  	i := getImpl(1)
    27  	i.Call(99)
    28  }
    29  
    30  func foo(a int) int {
    31  	return a + 1
    32  }
    33  
    34  // TestMakeFunc 测试 MakeFunc
    35  func TestMakeFunc(t *testing.T) {
    36  	funcValue := reflect.ValueOf(foo)
    37  	funcType := funcValue.Type()
    38  	mockFunc := reflect.MakeFunc(funcType, func(args []reflect.Value) (results []reflect.Value) {
    39  		fmt.Println("called, args: ", args[0].Interface())
    40  		return funcValue.Call(args)
    41  	})
    42  	fun := mockFunc.Interface()
    43  	func1, _ := (fun).(func(int) int)
    44  	if func1(3) != 4 {
    45  		t.Errorf("func1 return expect %d", 4)
    46  	}
    47  }
    48  
    49  // TestAutoGen 测试生成任意接口实现
    50  func TestAutoGen(t *testing.T) {
    51  	logger.LogLevel = logger.DebugLevel
    52  	logger.SetLog2Console(true)
    53  	const strResult = "not ok"
    54  
    55  	gen := (I)(nil)
    56  
    57  	ctx := iface.NewContext()
    58  
    59  	_ = proxy.Interface(&gen, ctx, "Call", func(ctx *iface.IContext, a int) int {
    60  		t.Log("called Call")
    61  		return 1
    62  	}, nil)
    63  
    64  	_ = proxy.Interface(&gen, ctx, "Call1", func(ctx *iface.IContext, a string) string {
    65  		t.Log("called Call1")
    66  		return strResult
    67  	}, nil)
    68  
    69  	_ = proxy.Interface(&gen, ctx, "call2", func(ctx *iface.IContext, a int32) int32 {
    70  		t.Log("called call2")
    71  		return 99
    72  	}, nil)
    73  
    74  	// 调用接口方法
    75  	if r := gen.Call(2); r != 1 {
    76  		t.Fatalf("want result: %d, real: %d", 1, r)
    77  	}
    78  	if r := gen.Call1("ok"); r != strResult {
    79  		t.Fatalf("want result: %s, real: %s", "not ok", r)
    80  	}
    81  	if r := gen.call2(33); r != 99 {
    82  		t.Fatalf("want result: %d, real: %d", 99, r)
    83  	}
    84  }
    85  
    86  // TestGenCancel 测试取消接口代理
    87  func TestGenCancel(t *testing.T) {
    88  	gen := getImpl(1)
    89  	ctx := iface.NewContext()
    90  
    91  	_ = proxy.Interface(&gen, ctx, "Call", func(ctx *iface.IContext, a int) int {
    92  		t.Log("called Call")
    93  		return 0
    94  	}, nil)
    95  
    96  	if r := gen.Call(2); r != 0 {
    97  		t.Fatalf("want result: %d, real: %d", 0, r)
    98  	}
    99  
   100  	ctx.Cancel()
   101  
   102  	if r := gen.Call(0); r != 1 {
   103  		t.Fatalf("want result: %d, real: %d", 1, r)
   104  	}
   105  }
   106  
   107  // TestNilImpl 测试空实现结构体方法列表
   108  func TestNilImpl(t *testing.T) {
   109  	gen := (*I)(nil)
   110  	typ := reflect.TypeOf(gen).Elem()
   111  
   112  	for i := 0; i < typ.NumMethod(); i++ {
   113  		fmt.Println(typ.Method(i).Name, typ.Method(i).Type)
   114  	}
   115  }
   116  
   117  // TestGenImpl 测试生成接口实现
   118  func TestGenImpl(t *testing.T) {
   119  	gen := (I)(nil)
   120  	typ := reflect.TypeOf(&gen).Elem()
   121  
   122  	for i := 0; i < typ.NumMethod(); i++ {
   123  		fmt.Println(typ.Method(i).Name, typ.Method(i).Type)
   124  	}
   125  
   126  	genInterfaceImpl(&gen, func(data *Impl2, a int) int {
   127  		fmt.Println("proxy")
   128  		return 3
   129  	})
   130  
   131  	// 调用接口方法
   132  	r := (gen).Call(1)
   133  	if r != 3 {
   134  		t.Fatalf("want result: %d, real: %d", 3, r)
   135  	}
   136  
   137  	fmt.Println("ok", r)
   138  }
   139  
   140  // genInterfaceImpl 生成接口实现
   141  func genInterfaceImpl(i interface{}, proxy interface{}) {
   142  	gen := hack.UnpackEFace(i).Data
   143  	// mock 接口方法
   144  	mockFunc := reflect.ValueOf(proxy)
   145  	ifc := *(*uintptr)(gen)
   146  	fmt.Println(ifc)
   147  
   148  	// 伪装 iface
   149  	*(*hack.Iface)(gen) = hack.Iface{
   150  		Tab: &hack.Itab{
   151  			Fun: [hack.MaxMethod]uintptr{mockFunc.Pointer(), uintptr(0), uintptr(0)},
   152  		},
   153  		Data: unsafe.Pointer(&Impl2{
   154  			field1: "ok",
   155  		}),
   156  	}
   157  	ifc = *(*uintptr)(gen)
   158  	fmt.Println(ifc)
   159  }
   160  
   161  // TestAutoProxyGenImpl 测试生成任意接口实现
   162  func TestAutoProxyGenImpl(t *testing.T) {
   163  	logger.LogLevel = logger.DebugLevel
   164  	logger.SetLog2Console(true)
   165  
   166  	gen := (I)(nil)
   167  
   168  	dynamicGenImpl(t, &gen)
   169  
   170  	// 调用接口方法
   171  	if r := gen.Call(1); r != 3 {
   172  		t.Fatalf("want result: %d, real: %d", 3, r)
   173  	}
   174  
   175  	fmt.Println("ok")
   176  }
   177  
   178  // dynamicGenImpl 生成任意接口实现
   179  func dynamicGenImpl(t *testing.T, i interface{}) {
   180  	typ := reflect.TypeOf(i).Elem()
   181  	for i := 0; i < typ.NumMethod(); i++ {
   182  		fmt.Println(typ.Method(i).Name, typ.Method(i).Type)
   183  	}
   184  
   185  	gen := hack.UnpackEFace(i).Data
   186  
   187  	// mock 接口方法
   188  	methodTyp := reflect.TypeOf(func(data *Impl2, a int) int {
   189  		fmt.Println("proxy")
   190  		return 3
   191  	})
   192  
   193  	mockFunc := reflect.MakeFunc(methodTyp, func(args []reflect.Value) (results []reflect.Value) {
   194  		return []reflect.Value{reflect.ValueOf(3)}
   195  	})
   196  	ifc := *(*uintptr)(gen)
   197  	fmt.Println(ifc)
   198  
   199  	callStub := reflect.ValueOf(stub.MakeFuncStub).Pointer()
   200  	mockFuncPtr := (*hack.Value)(unsafe.Pointer(&mockFunc)).Ptr
   201  	genStub, err := iface.MakeMethodCallerWithCtx(mockFuncPtr, callStub)
   202  
   203  	if err != nil {
   204  		panic(err)
   205  	}
   206  
   207  	fmt.Printf("genstub: 0x%x callstub: 0x%x\n", genStub, callStub)
   208  
   209  	// 伪装 iface
   210  	*(*hack.Iface)(gen) = hack.Iface{
   211  		Tab: &hack.Itab{
   212  			Fun: [hack.MaxMethod]uintptr{genStub, uintptr(0), uintptr(0)},
   213  		},
   214  		Data: (*hack.Value)(unsafe.Pointer(&mockFunc)).Ptr,
   215  	}
   216  	ifc = *(*uintptr)(gen)
   217  
   218  	fmt.Println(ifc)
   219  	fmt.Println(uintptr(getPtr(reflect.ValueOf(mockFunc.Interface()))))
   220  	fmt.Println(mockFunc.Pointer())
   221  }
   222  
   223  // getPtr 获取函数的调用地址(和函数的指令地址不一样)
   224  func getPtr(v reflect.Value) unsafe.Pointer {
   225  	return (*hack.Value)(unsafe.Pointer(&v)).Ptr
   226  }
   227  
   228  func getImpl(n int) I {
   229  	if n == 1 {
   230  		return &Impl1{}
   231  	} else if n == 2 {
   232  		return &Impl2{}
   233  	}
   234  	return nil
   235  }
   236  
   237  type Impl1 struct {
   238  	// nolint
   239  	field1 string
   240  }
   241  
   242  func (i Impl1) Call(a int) int {
   243  	fmt.Println("Impl1 called ")
   244  	return 1 + a
   245  }
   246  
   247  func (i Impl1) Call1(string) string {
   248  	return "ok"
   249  }
   250  
   251  func (i Impl1) call2(int32) int32 {
   252  	return 11
   253  }
   254  
   255  type Impl2 struct {
   256  	field1 string
   257  }
   258  
   259  func (i Impl2) Call(a int) int {
   260  	fmt.Println("Impl2 called ")
   261  	return 2 + a
   262  }
   263  
   264  func (i Impl2) Call1(string) string {
   265  	return "!ok"
   266  }
   267  
   268  func (i Impl2) call2(int32) int32 {
   269  	return 22
   270  }
   271  
   272  // TestTraceBack 测试生成任意接口实现的 traceback
   273  func TestTraceBack(t *testing.T) {
   274  	gen := (I)(nil)
   275  	dynamicGenImpl(t, &gen)
   276  
   277  	// 调用接口方法
   278  	for i := 0; i < 1000; i++ {
   279  		gen.Call(1)
   280  	}
   281  	fmt.Println("ok")
   282  }