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 }