github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/netpoll/http_client_handler_test.go (about) 1 /* 2 * Copyright 2021 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package netpoll 18 19 import ( 20 "context" 21 "net/http" 22 "strings" 23 "testing" 24 "time" 25 26 "github.com/cloudwego/netpoll" 27 28 "github.com/cloudwego/kitex/internal/mocks" 29 "github.com/cloudwego/kitex/internal/test" 30 "github.com/cloudwego/kitex/pkg/remote" 31 "github.com/cloudwego/kitex/pkg/remote/trans" 32 "github.com/cloudwego/kitex/pkg/rpcinfo" 33 "github.com/cloudwego/kitex/pkg/serviceinfo" 34 ) 35 36 var ( 37 cliTransHdlr remote.ClientTransHandler 38 httpCilTransHdlr remote.ClientTransHandler 39 cilopt *remote.ClientOption 40 ) 41 42 func init() { 43 cilopt = &remote.ClientOption{ 44 SvcInfo: mocks.ServiceInfo(), 45 Codec: &MockCodec{ 46 EncodeFunc: nil, 47 DecodeFunc: nil, 48 }, 49 Dialer: NewDialer(), 50 } 51 52 cliTransHdlr, _ = NewCliTransHandlerFactory().NewTransHandler(cilopt) 53 httpCilTransHdlr, _ = NewHTTPCliTransHandlerFactory().NewTransHandler(cilopt) 54 } 55 56 // TestHTTPWrite test http_client_handler Write return err 57 func TestHTTPWrite(t *testing.T) { 58 // 1. prepare mock data 59 conn := &MockNetpollConn{} 60 rwTimeout := time.Second 61 cfg := rpcinfo.NewRPCConfig() 62 rpcinfo.AsMutableRPCConfig(cfg).SetReadWriteTimeout(rwTimeout) 63 to := rpcinfo.NewEndpointInfo("", "", nil, map[string]string{ 64 rpcinfo.HTTPURL: "https://example.com", 65 }) 66 ri := rpcinfo.NewRPCInfo(nil, to, nil, cfg, rpcinfo.NewRPCStats()) 67 ctx := context.Background() 68 msg := remote.NewMessage(nil, mocks.ServiceInfo(), ri, remote.Reply, remote.Client) 69 70 // 2. test 71 ctx, err := httpCilTransHdlr.Write(ctx, conn, msg) 72 // check ctx/err not nil 73 test.Assert(t, ctx != nil) 74 test.Assert(t, err != nil) 75 } 76 77 // TestHTTPRead test http_client_handler Read return err 78 func TestHTTPRead(t *testing.T) { 79 // 1. prepare mock data 80 rwTimeout := time.Second 81 82 var readTimeout time.Duration 83 var isReaderBufReleased bool 84 conn := &MockNetpollConn{ 85 SetReadTimeoutFunc: func(timeout time.Duration) (e error) { 86 readTimeout = timeout 87 return nil 88 }, 89 ReaderFunc: func() (r netpoll.Reader) { 90 reader := &MockNetpollReader{ 91 ReleaseFunc: func() (err error) { 92 isReaderBufReleased = true 93 return nil 94 }, 95 } 96 return reader 97 }, 98 } 99 100 cfg := rpcinfo.NewRPCConfig() 101 rpcinfo.AsMutableRPCConfig(cfg).SetRPCTimeout(rwTimeout) 102 ri := rpcinfo.NewRPCInfo(nil, nil, nil, cfg, rpcinfo.NewRPCStats()) 103 ctx := context.Background() 104 msg := remote.NewMessage(nil, mocks.ServiceInfo(), ri, remote.Reply, remote.Client) 105 106 // 2. test 107 ctx, err := httpCilTransHdlr.Read(ctx, conn, msg) 108 // check ctx/err not nil 109 test.Assert(t, ctx != nil) 110 test.Assert(t, err != nil) 111 112 rpcinfo.AsMutableRPCConfig(cfg).SetRPCTimeout(rwTimeout) 113 httpCilTransHdlr.OnError(ctx, err, conn) 114 test.Assert(t, readTimeout == trans.GetReadTimeout(ri.Config())) 115 test.Assert(t, isReaderBufReleased) 116 } 117 118 // TestHTTPPanicAfterRead test http_client_handler OnMessage success 119 func TestHTTPOnMessage(t *testing.T) { 120 // 1. prepare mock data 121 svcInfo := mocks.ServiceInfo() 122 svcSearchMap := map[string]*serviceinfo.ServiceInfo{ 123 remote.BuildMultiServiceKey(mocks.MockServiceName, mocks.MockMethod): svcInfo, 124 remote.BuildMultiServiceKey(mocks.MockServiceName, mocks.MockExceptionMethod): svcInfo, 125 remote.BuildMultiServiceKey(mocks.MockServiceName, mocks.MockErrorMethod): svcInfo, 126 remote.BuildMultiServiceKey(mocks.MockServiceName, mocks.MockOnewayMethod): svcInfo, 127 mocks.MockMethod: svcInfo, 128 mocks.MockExceptionMethod: svcInfo, 129 mocks.MockErrorMethod: svcInfo, 130 mocks.MockOnewayMethod: svcInfo, 131 } 132 ri := rpcinfo.NewRPCInfo(nil, nil, rpcinfo.NewInvocation(svcInfo.ServiceName, method), nil, rpcinfo.NewRPCStats()) 133 ctx := rpcinfo.NewCtxWithRPCInfo(context.Background(), ri) 134 recvMsg := remote.NewMessageWithNewer(svcInfo, svcSearchMap, ri, remote.Call, remote.Server, false) 135 sendMsg := remote.NewMessage(svcInfo.MethodInfo(method).NewResult(), svcInfo, ri, remote.Reply, remote.Server) 136 137 // 2. test 138 _, err := httpCilTransHdlr.OnMessage(ctx, recvMsg, sendMsg) 139 test.Assert(t, err == nil, err) 140 } 141 142 // TestAddMetaInfo test http_client_handler addMetaInfo success 143 func TestAddMetaInfo(t *testing.T) { 144 // 1. prepare mock data 145 cfg := rpcinfo.NewRPCConfig() 146 ri := rpcinfo.NewRPCInfo(nil, nil, nil, cfg, rpcinfo.NewRPCStats()) 147 var req interface{} 148 msg := remote.NewMessage(req, mocks.ServiceInfo(), ri, remote.Reply, remote.Client) 149 h := http.Header{} 150 151 // 2. test 152 head, wantHead := "Head", "HTTP/1.1 200 OK" 153 msg.Tags()[rpcinfo.HTTPHeader] = http.Header{ 154 head: []string{wantHead}, 155 } 156 err := addMetaInfo(msg, h) 157 getHead := h.Get(head) 158 test.Assert(t, err == nil) 159 test.Assert(t, getHead == wantHead) 160 } 161 162 // TestReadLine test http_client_handler readLine success 163 func TestReadLine(t *testing.T) { 164 // 1. prepare mock data 165 wantHead := "HTTP/1.1 200 OK" 166 body := "{\"code\":0,\"data\":[\"mobile\",\"xxxxxxx\"],\"msg\":\"ok\"}" 167 resp := []byte(wantHead + "\r\nDate: Thu, 16 Aug 2018 03:10:03 GMT\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nTransfer-Encoding: chunked\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n" + body) 168 reader := remote.NewReaderBuffer(resp) 169 170 // 2. test 171 getHead, _ := readLine(reader) 172 test.Assert(t, strings.Compare(string(getHead), wantHead) == 0) 173 } 174 175 // TestSkipToBody test http_client_handler skipToBody success 176 func TestSkipToBody(t *testing.T) { 177 // 1. prepare mock data 178 head := "HTTP/1.1 200 OK" 179 wantBody := "{\"code\":0,\"data\":[\"mobile\",\"xxxxxxx\"],\"msg\":\"ok\"}" 180 resp := []byte(head + "\r\nDate: Thu, 16 Aug 2018 03:10:03 GMT\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nTransfer-Encoding: chunked\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n" + wantBody) 181 reader := remote.NewReaderBuffer(resp) 182 183 // 2. test 184 err := skipToBody(reader) 185 test.Assert(t, err == nil) 186 187 getBody, err := reader.ReadBinary(reader.ReadableLen()) 188 test.Assert(t, err == nil) 189 test.Assert(t, strings.Compare(string(getBody), wantBody) == 0) 190 } 191 192 // TestParseHTTPResponseHead test http_client_handler parseHTTPResponseHead success 193 func TestParseHTTPResponseHead(t *testing.T) { 194 // 1. prepare mock data 195 head := "HTTP/1.1 200 OK" 196 197 // 2. test 198 major, minor, statusCode, err := parseHTTPResponseHead(head) 199 test.Assert(t, err == nil) 200 test.Assert(t, !(major != 1 || minor != 1 || statusCode != 200)) 201 } 202 203 // TestGetBodyBufReader test http_client_handler getBodyBufReader return err 204 func TestGetBodyBufReader(t *testing.T) { 205 // 1. prepare mock data 206 head := "HTTP/1.1 200 OK" 207 body := "{\"code\":0,\"data\":[\"mobile\",\"xxxxxxx\"],\"msg\":\"ok\"}" 208 resp := []byte(head + "\r\nDate: Thu, 16 Aug 2018 03:10:03 GMT\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nTransfer-Encoding: chunked\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n" + body) 209 reader := remote.NewReaderBuffer(resp) 210 211 // 2. test 212 _, err := getBodyBufReader(reader) 213 // check err not nil 214 test.Assert(t, err != nil) 215 }