client_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. package zrpc
  2. import (
  3. "context"
  4. "fmt"
  5. "log"
  6. "net"
  7. "testing"
  8. "time"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/wuntsong-org/go-zero-plus/core/discov"
  11. "github.com/wuntsong-org/go-zero-plus/core/logx"
  12. "github.com/wuntsong-org/go-zero-plus/internal/mock"
  13. "google.golang.org/grpc"
  14. "google.golang.org/grpc/codes"
  15. "google.golang.org/grpc/credentials/insecure"
  16. "google.golang.org/grpc/status"
  17. "google.golang.org/grpc/test/bufconn"
  18. )
  19. func init() {
  20. logx.Disable()
  21. }
  22. func dialer() func(context.Context, string) (net.Conn, error) {
  23. listener := bufconn.Listen(1024 * 1024)
  24. server := grpc.NewServer()
  25. mock.RegisterDepositServiceServer(server, &mock.DepositServer{})
  26. go func() {
  27. if err := server.Serve(listener); err != nil {
  28. log.Fatal(err)
  29. }
  30. }()
  31. return func(context.Context, string) (net.Conn, error) {
  32. return listener.Dial()
  33. }
  34. }
  35. func TestDepositServer_Deposit(t *testing.T) {
  36. tests := []struct {
  37. name string
  38. amount float32
  39. timeout time.Duration
  40. res *mock.DepositResponse
  41. errCode codes.Code
  42. errMsg string
  43. }{
  44. {
  45. name: "invalid request with negative amount",
  46. amount: -1.11,
  47. errCode: codes.InvalidArgument,
  48. errMsg: fmt.Sprintf("cannot deposit %v", -1.11),
  49. },
  50. {
  51. name: "valid request with non negative amount",
  52. res: &mock.DepositResponse{Ok: true},
  53. errCode: codes.OK,
  54. },
  55. {
  56. name: "valid request with long handling time",
  57. amount: 2000.00,
  58. errCode: codes.DeadlineExceeded,
  59. errMsg: "context deadline exceeded",
  60. },
  61. {
  62. name: "valid request with timeout call option",
  63. amount: 2000.00,
  64. timeout: time.Second * 3,
  65. res: &mock.DepositResponse{Ok: true},
  66. errCode: codes.OK,
  67. errMsg: "",
  68. },
  69. }
  70. directClient := MustNewClient(
  71. RpcClientConf{
  72. Endpoints: []string{"foo"},
  73. App: "foo",
  74. Token: "bar",
  75. Timeout: 1000,
  76. Middlewares: ClientMiddlewaresConf{
  77. Trace: true,
  78. Duration: true,
  79. Prometheus: true,
  80. Breaker: true,
  81. Timeout: true,
  82. },
  83. },
  84. WithDialOption(grpc.WithContextDialer(dialer())),
  85. WithUnaryClientInterceptor(func(ctx context.Context, method string, req, reply any,
  86. cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  87. return invoker(ctx, method, req, reply, cc, opts...)
  88. }),
  89. )
  90. nonBlockClient := MustNewClient(
  91. RpcClientConf{
  92. Endpoints: []string{"foo"},
  93. App: "foo",
  94. Token: "bar",
  95. Timeout: 1000,
  96. NonBlock: true,
  97. Middlewares: ClientMiddlewaresConf{
  98. Trace: true,
  99. Duration: true,
  100. Prometheus: true,
  101. Breaker: true,
  102. Timeout: true,
  103. },
  104. },
  105. WithDialOption(grpc.WithContextDialer(dialer())),
  106. WithUnaryClientInterceptor(func(ctx context.Context, method string, req, reply any,
  107. cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  108. return invoker(ctx, method, req, reply, cc, opts...)
  109. }),
  110. )
  111. tarConfClient := MustNewClient(
  112. RpcClientConf{
  113. Target: "foo",
  114. App: "foo",
  115. Token: "bar",
  116. Timeout: 1000,
  117. KeepaliveTime: time.Second * 15,
  118. Middlewares: ClientMiddlewaresConf{
  119. Trace: true,
  120. Duration: true,
  121. Prometheus: true,
  122. Breaker: true,
  123. Timeout: true,
  124. },
  125. },
  126. WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
  127. WithDialOption(grpc.WithContextDialer(dialer())),
  128. WithUnaryClientInterceptor(func(ctx context.Context, method string, req, reply any,
  129. cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  130. return invoker(ctx, method, req, reply, cc, opts...)
  131. }),
  132. )
  133. targetClient, err := NewClientWithTarget("foo",
  134. WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
  135. WithDialOption(grpc.WithContextDialer(dialer())), WithUnaryClientInterceptor(
  136. func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn,
  137. invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  138. return invoker(ctx, method, req, reply, cc, opts...)
  139. }), WithTimeout(1000*time.Millisecond))
  140. assert.Nil(t, err)
  141. clients := []Client{
  142. directClient,
  143. nonBlockClient,
  144. tarConfClient,
  145. targetClient,
  146. }
  147. DontLogClientContentForMethod("foo")
  148. SetClientSlowThreshold(time.Second)
  149. for _, tt := range tests {
  150. tt := tt
  151. for _, client := range clients {
  152. client := client
  153. t.Run(tt.name, func(t *testing.T) {
  154. t.Parallel()
  155. cli := mock.NewDepositServiceClient(client.Conn())
  156. request := &mock.DepositRequest{Amount: tt.amount}
  157. var (
  158. ctx = context.Background()
  159. response *mock.DepositResponse
  160. err error
  161. )
  162. if tt.timeout > 0 {
  163. response, err = cli.Deposit(ctx, request, WithCallTimeout(tt.timeout))
  164. } else {
  165. response, err = cli.Deposit(ctx, request)
  166. }
  167. if response != nil {
  168. assert.True(t, len(response.String()) > 0)
  169. if response.GetOk() != tt.res.GetOk() {
  170. t.Error("response: expected", tt.res.GetOk(), "received", response.GetOk())
  171. }
  172. }
  173. if err != nil {
  174. if e, ok := status.FromError(err); ok {
  175. if e.Code() != tt.errCode {
  176. t.Error("error code: expected", codes.InvalidArgument, "received", e.Code())
  177. }
  178. if e.Message() != tt.errMsg {
  179. t.Error("error message: expected", tt.errMsg, "received", e.Message())
  180. }
  181. }
  182. }
  183. })
  184. }
  185. }
  186. }
  187. func TestNewClientWithError(t *testing.T) {
  188. _, err := NewClient(
  189. RpcClientConf{
  190. App: "foo",
  191. Token: "bar",
  192. Timeout: 1000,
  193. },
  194. WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
  195. WithDialOption(grpc.WithContextDialer(dialer())),
  196. WithUnaryClientInterceptor(func(ctx context.Context, method string, req, reply any,
  197. cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  198. return invoker(ctx, method, req, reply, cc, opts...)
  199. }),
  200. )
  201. assert.NotNil(t, err)
  202. _, err = NewClient(
  203. RpcClientConf{
  204. Etcd: discov.EtcdConf{
  205. Hosts: []string{"localhost:2379"},
  206. Key: "mock",
  207. },
  208. App: "foo",
  209. Token: "bar",
  210. Timeout: 1,
  211. },
  212. WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
  213. WithDialOption(grpc.WithContextDialer(dialer())),
  214. WithUnaryClientInterceptor(func(ctx context.Context, method string, req, reply any,
  215. cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  216. return invoker(ctx, method, req, reply, cc, opts...)
  217. }),
  218. )
  219. assert.NotNil(t, err)
  220. }
  221. func TestNewClientWithTarget(t *testing.T) {
  222. _, err := NewClientWithTarget("",
  223. WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
  224. WithDialOption(grpc.WithContextDialer(dialer())),
  225. WithUnaryClientInterceptor(func(ctx context.Context, method string, req, reply any,
  226. cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  227. return invoker(ctx, method, req, reply, cc, opts...)
  228. }))
  229. assert.NotNil(t, err)
  230. }