github.com/nyan233/littlerpc@v0.4.6-0.20230316182519-0c8d5c48abaf/test/feature_test.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"github.com/nyan233/littlerpc/core/client"
     7  	"github.com/nyan233/littlerpc/core/common/logger"
     8  	"github.com/nyan233/littlerpc/core/common/metadata"
     9  	server2 "github.com/nyan233/littlerpc/core/server"
    10  	"github.com/nyan233/littlerpc/plugins/metrics"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/zbh255/bilog"
    13  	"log"
    14  	"net/http"
    15  	_ "net/http/pprof"
    16  	"os"
    17  	"sync"
    18  	"sync/atomic"
    19  	"testing"
    20  	"time"
    21  )
    22  
    23  type User struct {
    24  	Id   int
    25  	Name string
    26  }
    27  
    28  func (u *User) Reset() {
    29  	u.Id = 0
    30  	u.Name = ""
    31  }
    32  
    33  type HelloTest struct {
    34  	count int64
    35  	// 社区旗下的一些用户
    36  	userMap sync.Map
    37  	t       *testing.T
    38  	server2.RpcServer
    39  }
    40  
    41  func (t *HelloTest) Setup() {
    42  	err := t.HijackProcess("GetCount", func(stub *server2.Stub) {
    43  		assert.NoError(t.t, stub.Write(atomic.LoadInt64(&t.count)))
    44  		assert.NoError(t.t, stub.Write(nil))
    45  		assert.NoError(t.t, stub.WriteErr(nil))
    46  	})
    47  	assert.NoError(t.t, err)
    48  	err = t.HijackProcess("WaitSelectUserHijack", func(stub *server2.Stub) {
    49  		var uid int
    50  		assert.NoError(t.t, stub.Read(&uid))
    51  		// wait
    52  		<-stub.Done()
    53  		user, _, err := t.SelectUser(stub, uid)
    54  		assert.NoError(t.t, stub.Write(&user))
    55  		assert.NoError(t.t, stub.WriteErr(err))
    56  	})
    57  	assert.NoError(t.t, err)
    58  }
    59  
    60  func (t *HelloTest) GetCount() (int64, *User, error) {
    61  	return atomic.LoadInt64(&t.count), nil, nil
    62  }
    63  
    64  func (t *HelloTest) Add(i int64) error {
    65  	atomic.AddInt64(&t.count, i)
    66  	return nil
    67  }
    68  
    69  func (t *HelloTest) CreateUser(ctx context.Context, user *User) error {
    70  	t.userMap.Store(user.Id, *user)
    71  	return nil
    72  }
    73  
    74  func (t *HelloTest) DeleteUser(ctx context.Context, uid int) error {
    75  	t.userMap.Delete(uid)
    76  	return nil
    77  }
    78  
    79  func (t *HelloTest) SelectUser(ctx context.Context, uid int) (User, bool, error) {
    80  	u, ok := t.userMap.Load(uid)
    81  	if ok {
    82  		return u.(User), ok, nil
    83  	}
    84  	return User{}, false, nil
    85  }
    86  
    87  func (t *HelloTest) ModifyUser(ctx context.Context, uid int, user User) (bool, error) {
    88  	_, ok := t.userMap.LoadOrStore(uid, user)
    89  	return ok, nil
    90  }
    91  
    92  func (t *HelloTest) WaitSelectUser(ctx context.Context, uid int) (*User, error) {
    93  	<-ctx.Done()
    94  	user, _, err := t.SelectUser(ctx, uid)
    95  	return &user, err
    96  }
    97  
    98  func (t *HelloTest) WaitSelectUserHijack(ctx context.Context, uid int) (*User, error) {
    99  	return nil, nil
   100  }
   101  
   102  func TestServerAndClient(t *testing.T) {
   103  	go func() {
   104  		log.Println(http.ListenAndServe("127.0.0.1:7878", nil))
   105  	}()
   106  	// 关闭服务器烦人的日志
   107  	logger.SetOpenLogger(false)
   108  	baseServerOpts := []server2.Option{
   109  		server2.WithAddressServer(":1234"),
   110  		server2.WithStackTrace(),
   111  		server2.WithLogger(logger.New(bilog.NewLogger(os.Stdout, bilog.PANIC,
   112  			bilog.WithLowBuffer(0), bilog.WithTopBuffer(0)))),
   113  		server2.WithOpenLogger(false),
   114  		server2.WithDebug(false),
   115  		// server2.WithMessageParserOnRead(),
   116  		// server2.WithPlugin(pLogger.New(os.Stdout)),
   117  	}
   118  	baseClientOpts := []client.Option{
   119  		client.WithAddress(":1234"),
   120  		client.WithMuxConnectionNumber(16),
   121  		client.WithStackTrace(),
   122  	}
   123  	testRunConfigs := []struct {
   124  		TestName                         string
   125  		NoAbleUsageNoTransactionProtocol bool
   126  		ServerOptions                    []server2.Option
   127  		ClientOptions                    []client.Option
   128  		CallOptions                      map[string][]client.CallOption
   129  	}{
   130  		{
   131  			TestName:      "TestLRPCProtocol-%s-NoMux-NonTls",
   132  			ServerOptions: append(baseServerOpts),
   133  			ClientOptions: append(baseClientOpts, client.WithNoMuxWriter()),
   134  			CallOptions: map[string][]client.CallOption{
   135  				"SelectUser": {
   136  					client.WithCallLRPCMuxWriter(),
   137  					client.WithCallPacker("gzip"),
   138  				},
   139  			},
   140  		},
   141  		{
   142  			TestName:      "TestLRPCProtocol-%s-Mux-NonTls",
   143  			ServerOptions: append(baseServerOpts),
   144  			ClientOptions: append(baseClientOpts, client.WithMuxWriter()),
   145  			CallOptions: map[string][]client.CallOption{
   146  				"SelectUser": {
   147  					client.WithCallLRPCNoMuxWriter(),
   148  					client.WithCallPacker("gzip"),
   149  				},
   150  			},
   151  		},
   152  		{
   153  			TestName:      "TestLRPCProtocol-%s-NoMux-Gzip-NonTls",
   154  			ServerOptions: append(baseServerOpts),
   155  			ClientOptions: append(baseClientOpts, client.WithNoMuxWriter(), client.WithPacker("gzip")),
   156  		},
   157  		{
   158  			TestName:      "TestLRPCProtocol-%s-Mux-Gzip-NonTls",
   159  			ServerOptions: append(baseServerOpts),
   160  			ClientOptions: append(baseClientOpts, client.WithMuxWriter(), client.WithPacker("gzip")),
   161  		},
   162  		{
   163  			TestName:                         "TestJsonRPC2-%s-SingleProtocol-NonTls",
   164  			ServerOptions:                    append(baseServerOpts),
   165  			ClientOptions:                    append(baseClientOpts, client.WithJsonRpc2Writer()),
   166  			NoAbleUsageNoTransactionProtocol: true,
   167  		},
   168  	}
   169  	networks := []string{"nbio_tcp", "std_tcp", "nbio_ws"}
   170  	for _, network := range networks {
   171  		for _, runConfig := range testRunConfigs {
   172  			if runConfig.NoAbleUsageNoTransactionProtocol {
   173  				switch network {
   174  				case "nbio_tcp":
   175  					continue
   176  				case "std_tcp":
   177  					continue
   178  				}
   179  			}
   180  			t.Run(fmt.Sprintf(runConfig.TestName, network), func(t *testing.T) {
   181  				testServerAndClient(t,
   182  					append([]server2.Option{server2.WithNetwork(network)}, runConfig.ServerOptions...),
   183  					append([]client.Option{client.WithNetWork(network)}, runConfig.ClientOptions...),
   184  					runConfig.CallOptions)
   185  			})
   186  		}
   187  	}
   188  }
   189  
   190  func testServerAndClient(t *testing.T, serverOpts []server2.Option, clientOpts []client.Option,
   191  	ccSet map[string][]client.CallOption) {
   192  	sm := metrics.NewServer()
   193  	server := server2.New(append(serverOpts, server2.WithPlugin(sm))...)
   194  	h := &HelloTest{
   195  		t: t,
   196  	}
   197  	err := server.RegisterClass("", h, map[string]metadata.ProcessOption{
   198  		"SelectUser": {
   199  			SyncCall:        true,
   200  			CompleteReUsage: true,
   201  		},
   202  		"CreateUser": {
   203  			SyncCall:        true,
   204  			CompleteReUsage: true,
   205  		},
   206  		"Add": {
   207  			SyncCall:        true,
   208  			CompleteReUsage: true,
   209  		},
   210  		"WaitSelectUser": {
   211  			CompleteReUsage: false,
   212  			UseRawGoroutine: true,
   213  		},
   214  	})
   215  	assert.NoError(t, err, "server register class failed")
   216  	go server.Service()
   217  
   218  	defer server.Stop()
   219  
   220  	var wg sync.WaitGroup
   221  	// 启动多少的客户端
   222  	nGoroutine := 50
   223  	// 一个客户端连续发送多少次消息
   224  	sendN := 50
   225  	addV := 65536
   226  	wg.Add(nGoroutine)
   227  	cm := metrics.NewClient()
   228  	c, err := client.New(append(clientOpts, client.WithPlugin(cm))...)
   229  	assert.NoError(t, err, "client start failed")
   230  	proxy := NewHelloTest(c)
   231  	for i := 0; i < nGoroutine; i++ {
   232  		j := i
   233  		go func() {
   234  			for k := 0; k < sendN; k++ {
   235  				assert.NoError(t, proxy.Add(int64(addV)), "add failed")
   236  				var opts []client.CallOption
   237  				opts, _ = ccSet["CreateUser"]
   238  				assert.NoError(t, proxy.CreateUser(context.Background(), &User{
   239  					Id:   j + 100,
   240  					Name: "Jeni",
   241  				}, opts...), "create user failed")
   242  				opts, _ = ccSet["SelectUser"]
   243  				user, _, err := proxy.SelectUser(context.Background(), j+100, opts...)
   244  				assert.NoError(t, err, "select user failed")
   245  				assert.Equal(t, user.Name, "Jeni", "the no value")
   246  				opts, _ = ccSet["ModifyUser"]
   247  				_, err = proxy.ModifyUser(context.Background(), j+100, User{
   248  					Id:   j + 100,
   249  					Name: "Tony",
   250  				}, opts...)
   251  				assert.NoError(t, err, "modify user failed")
   252  				opts, _ = ccSet["GetCount"]
   253  				_, _, err = proxy.GetCount(opts...)
   254  				assert.NoError(t, err, "get count failed")
   255  				opts, _ = ccSet["DeleteUser"]
   256  				assert.NoError(t, proxy.DeleteUser(context.Background(), j+100, opts...), "delete user failed")
   257  				// 构造一次错误的请求
   258  				_, err = c.Call("HelloTest.DeleteUser", nil, context.Background(), "string")
   259  				assert.Error(t, err, "call error is equal nil")
   260  				// 构造一次取消的请求
   261  				ctx, _ := context.WithTimeout(context.Background(), time.Millisecond)
   262  				var rep User
   263  				opts, _ = ccSet["WaitSelectUser"]
   264  				assert.NoError(t, c.Request("HelloTest.WaitSelectUser", ctx, j+100, &rep, opts...), "cancel request failed")
   265  				// test hijack context
   266  				ctx, _ = context.WithTimeout(context.Background(), time.Millisecond)
   267  				_, err = proxy.WaitSelectUserHijack(ctx, 10)
   268  				assert.NoError(t, err, "cancel request failed")
   269  			}
   270  			wg.Done()
   271  		}()
   272  	}
   273  	wg.Wait()
   274  	assert.Equal(t, atomic.LoadInt64(&h.count), int64(addV*nGoroutine)*int64(sendN), "h.count no correct")
   275  
   276  	assert.Equal(t, cm.Call.LoadFailed(), sm.Call.LoadFailed())
   277  	//assert.Equal(t, cm.Call.LoadComplete(), sm.Call.LoadComplete())
   278  	//assert.Equal(t, cm.Call.LoadAll(), sm.Call.LoadAll())
   279  	//assert.Equal(t, cm.Call.LoadCount(), sm.Call.LoadCount())
   280  
   281  	assert.Equal(t, cm.Call.LoadFailed(), int64(nGoroutine)*int64(sendN), "errCount size not correct")
   282  }
   283  
   284  func TestBalance(t *testing.T) {
   285  	// 关闭服务器烦人的日志
   286  	logger.SetOpenLogger(false)
   287  	server := server2.New(server2.WithAddressServer("127.0.0.1:9090", "127.0.0.1:8080"),
   288  		server2.WithOpenLogger(false))
   289  	err := server.RegisterClass("", new(HelloTest), nil)
   290  	if err != nil {
   291  		t.Fatal(err)
   292  	}
   293  	go server.Service()
   294  	time.Sleep(time.Second)
   295  	defer server.Stop()
   296  	c1, err := client.New(
   297  		client.WithBalancerScheme("roundRobin"),
   298  		client.WithOpenLoadBalance(),
   299  		client.WithLiveResolver("127.0.0.1:8080;127.0.0.1:9090"),
   300  	)
   301  	if err != nil {
   302  		t.Fatal(err)
   303  	}
   304  	p1 := NewHelloTest(c1)
   305  	c2, err := client.New(
   306  		client.WithBalancerScheme("roundRobin"),
   307  		client.WithOpenLoadBalance(),
   308  		client.WithLiveResolver("127.0.0.1:8080;127.0.0.1:9090"),
   309  	)
   310  	if err != nil {
   311  		t.Fatal(err)
   312  	}
   313  	p2 := NewHelloTest(c2)
   314  	p1.Add(1024)
   315  	p2.Add(1023)
   316  }