github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/retryrpc/retryrpc_test.go (about) 1 // Copyright (c) 2015-2021, NVIDIA CORPORATION. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package retryrpc 5 6 import ( 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/swiftstack/ProxyFS/bucketstats" 12 "github.com/swiftstack/ProxyFS/retryrpc/rpctest" 13 ) 14 15 // Test basic retryrpc primitives 16 // 17 // This unit test exists here since it uses jrpcfs which would be a 18 // circular dependency if the test was in retryrpc. 19 func TestRetryRPC(t *testing.T) { 20 21 testServer(t) 22 testBtree(t) 23 testStatsAndBucketstats(t) 24 } 25 26 type MyType struct { 27 field1 int 28 } 29 30 type MyRequest struct { 31 Field1 int 32 } 33 34 type MyResponse struct { 35 Error error 36 } 37 38 func (m *MyType) ExportedFunction(request MyRequest, response *MyResponse) (err error) { 39 request.Field1 = 1 40 return 41 } 42 43 func (m *MyType) unexportedFunction(i int) { 44 m.field1 = i 45 } 46 47 func getNewServer(lt time.Duration, dontStartTrimmers bool) (rrSvr *Server, ip string, p int) { 48 var ( 49 ipaddr = "127.0.0.1" 50 port = 24456 51 ) 52 config := &ServerConfig{LongTrim: lt, ShortTrim: 100 * time.Millisecond, IPAddr: "127.0.0.1", 53 Port: 24456, DeadlineIO: 5 * time.Second, dontStartTrimmers: dontStartTrimmers} 54 55 // Create a new RetryRPC Server. Completed request will live on 56 // completedRequests for 10 seconds. 57 rrSvr = NewServer(config) 58 ip = ipaddr 59 p = port 60 return 61 } 62 63 // Test basic Server creation and deletion 64 func testServer(t *testing.T) { 65 assert := assert.New(t) 66 zero := 0 67 assert.Equal(0, zero) 68 69 // Create new rpctest server - needed for calling 70 // RPCs 71 myJrpcfs := rpctest.NewServer() 72 73 rrSvr, ipaddr, port := getNewServer(10*time.Second, false) 74 assert.NotNil(rrSvr) 75 76 // Register the Server - sets up the methods supported by the 77 // server 78 err := rrSvr.Register(myJrpcfs) 79 assert.Nil(err) 80 81 // Start listening for requests on the ipaddr/port 82 startErr := rrSvr.Start() 83 assert.Nil(startErr, "startErr is not nil") 84 85 // Tell server to start accepting and processing requests 86 rrSvr.Run() 87 88 // Now - setup a client to send requests to the server 89 clientConfig := &ClientConfig{MyUniqueID: "client 1", IPAddr: ipaddr, Port: port, RootCAx509CertificatePEM: rrSvr.Creds.RootCAx509CertificatePEM, 90 Callbacks: nil, DeadlineIO: 5 * time.Second} 91 rrClnt, newErr := NewClient(clientConfig) 92 assert.NotNil(rrClnt) 93 assert.Nil(newErr) 94 95 // Send an RPC which should return success 96 pingRequest := &rpctest.PingReq{Message: "Ping Me!"} 97 pingReply := &rpctest.PingReply{} 98 sendErr := rrClnt.Send("RpcPing", pingRequest, pingReply) 99 assert.Nil(sendErr) 100 assert.Equal("pong 8 bytes", pingReply.Message) 101 assert.Equal(1, rrSvr.CompletedCnt()) 102 103 // Send an RPC which should return an error 104 pingRequest = &rpctest.PingReq{Message: "Ping Me!"} 105 pingReply = &rpctest.PingReply{} 106 sendErr = rrClnt.Send("RpcPingWithError", pingRequest, pingReply) 107 assert.NotNil(sendErr) 108 109 assert.Equal(2, rrSvr.CompletedCnt()) 110 111 // Send an RPC which should return an error 112 pingRequest = &rpctest.PingReq{Message: "Ping Me!"} 113 pingReply = &rpctest.PingReply{} 114 sendErr = rrClnt.Send("RpcInvalidMethod", pingRequest, pingReply) 115 assert.NotNil(sendErr) 116 117 assert.Equal(3, rrSvr.CompletedCnt()) 118 119 // Stop the client before exiting 120 rrClnt.Close() 121 122 // Stop the server before exiting 123 rrSvr.Close() 124 } 125 126 func testBtree(t *testing.T) { 127 assert := assert.New(t) 128 129 rrSvr, ipaddr, port := getNewServer(10*time.Second, false) 130 assert.NotNil(rrSvr) 131 132 // Setup a client - we only will be targeting the btree 133 clientConfig := &ClientConfig{MyUniqueID: "client 1", IPAddr: ipaddr, Port: port, RootCAx509CertificatePEM: rrSvr.Creds.RootCAx509CertificatePEM, 134 Callbacks: nil, DeadlineIO: 5 * time.Second} 135 client, newErr := NewClient(clientConfig) 136 assert.NotNil(client) 137 assert.Nil(newErr) 138 139 // Simulate requests completing out of order 140 client.updateHighestConsecutiveNum(requestID(10)) 141 client.updateHighestConsecutiveNum(requestID(5)) 142 client.updateHighestConsecutiveNum(requestID(11)) 143 144 client.setHighestConsecutive() 145 assert.Equal(requestID(0), client.highestConsecutive) 146 147 // Now fillin first gap 148 client.updateHighestConsecutiveNum(requestID(4)) 149 client.updateHighestConsecutiveNum(requestID(3)) 150 client.updateHighestConsecutiveNum(requestID(2)) 151 client.updateHighestConsecutiveNum(requestID(1)) 152 assert.Equal(int(3), client.bt.Len()) 153 154 client.setHighestConsecutive() 155 assert.Equal(int(3), client.bt.Len()) 156 assert.Equal(requestID(5), client.highestConsecutive) 157 158 // Now fillin next set of gaps 159 client.updateHighestConsecutiveNum(requestID(6)) 160 client.updateHighestConsecutiveNum(requestID(7)) 161 client.updateHighestConsecutiveNum(requestID(8)) 162 client.updateHighestConsecutiveNum(requestID(9)) 163 assert.Equal(int(1), client.bt.Len()) 164 165 client.setHighestConsecutive() 166 assert.Equal(int(1), client.bt.Len()) 167 assert.Equal(requestID(11), client.highestConsecutive) 168 } 169 170 // Per pfsagent statistics 171 type clientStats struct { 172 AddCompleted bucketstats.Total // Number added to completed list 173 RmCompleted bucketstats.Total // Number removed from completed list 174 RPCLenUsec bucketstats.BucketLog2Round // Average times of RPCs 175 LongestRPCMethod string // Method of longest RPC 176 ReplySize bucketstats.BucketLog2Round // Largest RPC reply size completed 177 LargestReplySizeMethod string // Method of largest RPC reply size completed 178 RPCcompleted bucketstats.Total // Number of RPCs which completed - incremented after call returns 179 RPCretried bucketstats.Total // Number of RPCs which were just pulled from completed list 180 RPCattempted bucketstats.Total // Number of RPCs attempted - may be completed or in process 181 RPCinprocess bucketstats.Total // Number of RPCs presently calling RPC - decremented when completed 182 } 183 184 // Test use of bucketstats package 185 func testStatsAndBucketstats(t *testing.T) { 186 var ( 187 myClient1 clientStats 188 myUniqueClient1 = "1111111" 189 190 myClient2 clientStats 191 myUniqueClient2 = "2222222" 192 ) 193 194 // Register from bucketstats from pfsagent #1 195 bucketstats.Register("proxyfs.retryrpc", myUniqueClient1, &myClient1) 196 197 // Register from bucketstats from pfsagent #2 198 bucketstats.Register("proxyfs.retryrpc", myUniqueClient2, &myClient2) 199 200 // Completed list stats 201 myClient1.AddCompleted.Add(1) 202 myClient1.RmCompleted.Add(1) 203 204 // RPC counts 205 myClient1.RPCcompleted.Add(1) 206 myClient1.RPCretried.Add(1) 207 myClient1.RPCattempted.Add(1) 208 myClient1.RPCinprocess.Add(1) 209 210 // Track duration of all RPCs in a graph 211 start := time.Now() 212 time.Sleep(10 * time.Millisecond) 213 myClient1.RPCLenUsec.Add(uint64(time.Since(start) / time.Microsecond)) 214 myClient1.ReplySize.Add(8192) 215 216 // Example of pfsagent #2 217 myClient2.RPCcompleted.Add(1) 218 myClient2.RPCretried.Add(1) 219 myClient2.RPCattempted.Add(1) 220 myClient2.RPCinprocess.Add(1) 221 222 // Dump stats 223 /* DEBUG ONLY - 224 fmt.Printf("pfsagent #1: %s\n", bucketstats.SprintStats(bucketstats.StatFormatParsable1, "proxyfs.retryrpc", myUniqueClient1)) 225 fmt.Printf("pfsagent #2: %s\n", bucketstats.SprintStats(bucketstats.StatFormatParsable1, "proxyfs.retryrpc", myUniqueClient2)) 226 */ 227 228 // Unregister clients from bucketstats 229 bucketstats.UnRegister("proxyfs.retryrpc", myUniqueClient1) 230 bucketstats.UnRegister("proxyfs.retryrpc", myUniqueClient2) 231 }