13
"mosn.io/mosn/pkg/log"
14
"mosn.io/mosn/pkg/protocol"
15
"mosn.io/mosn/pkg/protocol/xprotocol/bolt"
18
type BoltServerConfig struct {
19
Addr string `json:"address"`
20
Mux map[string]*ResponseConfig `json:"mux_config"`
23
func NewBoltServerConfig(config interface{}) (*BoltServerConfig, error) {
24
b, err := json.Marshal(config)
28
cfg := &BoltServerConfig{}
29
if err := json.Unmarshal(b, cfg); err != nil {
35
type ResponseConfig struct {
36
Condition *Condition `json:"condition"`
37
CommonBuilder *ResponseBuilder `json:"common_builder"`
38
ErrorBuilder *ResponseBuilder `json:"error_buidler"`
41
func (c *ResponseConfig) HandleRequest(req *bolt.Request, engine api.XProtocol) (resp api.XRespFrame, status int16) {
43
case bolt.CmdCodeHeartbeat:
45
resp = engine.Reply(context.TODO(), req)
46
status = int16(bolt.ResponseStatusSuccess) // heartbeat must be success
47
case bolt.CmdCodeRpcRequest:
49
resp, status = DefaultErrorBuilder.Build(req)
52
if c.Condition.Match(req) {
53
resp, status = c.CommonBuilder.Build(req)
55
resp, status = c.ErrorBuilder.Build(req)
58
log.DefaultLogger.Errorf("invalid cmd code: %d", req.CmdCode)
63
type Condition struct {
64
// If a request contains the expected header, matched this condition.
65
// A request must have the configured header key and value, and can have others headers
66
// which will be ingored.
67
ExpectedHeader map[string]string `json:"expected_header"`
68
// If a request contains the unexpected header, matched failed.
69
UnexpectedHeaderKey []string `json:"unexpected_header_key"`
70
// TODO: Add more condition
73
func (cond *Condition) Match(req *bolt.Request) bool {
77
for key, value := range cond.ExpectedHeader {
78
if v, ok := req.Get(key); !ok || !strings.EqualFold(v, value) {
82
for _, key := range cond.UnexpectedHeaderKey {
83
if _, ok := req.Get(key); ok {
90
// ResponseBuilder builds a bolt response based on the bolt request
91
type ResponseBuilder struct {
92
// The response status code
93
StatusCode int16 `json:"status_code"`
94
// The response header that not contains the protocol header part.
95
Header map[string]string `json:"header"`
96
// The repsonse body content
97
Body json.RawMessage `json:"body"`
100
func (b *ResponseBuilder) Build(req *bolt.Request) (*bolt.Response, int16) {
101
reqId := uint32(req.GetRequestId())
102
cmd := bolt.NewRpcResponse(reqId, uint16(b.StatusCode), protocol.CommonHeader(b.Header), nil)
104
cmd.Content = buffer.NewIoBufferBytes(b.Body)
106
return cmd, b.StatusCode
109
var DefaultSucessBuilder = &ResponseBuilder{
110
StatusCode: int16(bolt.ResponseStatusSuccess),
113
var DefaultErrorBuilder = &ResponseBuilder{
114
StatusCode: int16(bolt.ResponseStatusError),
117
type BoltClientConfig struct {
118
TargetAddr string `json:"target_address"`
119
MaxConn uint32 `json:"max_connection"`
120
Request *RequestConfig `json:"request_config"`
121
Verify *VerifyConfig `json:"verify_config"`
124
func NewBoltClientConfig(config interface{}) (*BoltClientConfig, error) {
125
b, err := json.Marshal(config)
129
cfg := &BoltClientConfig{}
130
if err := json.Unmarshal(b, cfg); err != nil {
136
// RequestConfig decides what request to send
137
type RequestConfig struct {
138
Header map[string]string `json:"header"`
139
Body json.RawMessage `json:"body"`
140
Timeout time.Duration `json:"timeout"` // request timeout
143
func (c *RequestConfig) BuildRequest(id uint32) (api.HeaderMap, buffer.IoBuffer) {
145
return buildRequest(id, map[string]string{
146
"service": "mosn-test-default-service", // must have service
149
return buildRequest(id, c.Header, c.Body, c.Timeout)
152
func buildRequest(id uint32, header map[string]string, body []byte, timeout time.Duration) (api.HeaderMap, buffer.IoBuffer) {
153
var buf buffer.IoBuffer
155
buf = buffer.NewIoBufferBytes(body)
157
req := bolt.NewRpcRequest(id, protocol.CommonHeader(header), buf)
159
req.Timeout = int32(int64(timeout) / 1e6)
161
return req, req.Content
164
// VerifyConfig describes what response want
165
type VerifyConfig struct {
166
ExpectedStatusCode int16
167
// if ExepctedHeader is nil, means do not care about header
168
// if ExepctedHeader is exists, means resposne header should contain all the ExpectedHeader
169
// If response header contain keys not in ExpectedHeader, we ignore it.
170
// TODO: support regex
171
ExpectedHeader map[string]string
172
// if ExpectedBody is nil, means do not care about body
173
// TODO: support regex
175
// if MaxExpectedRT is zero, means do not care about rt
176
// if MaxExpectedRT is not zero, means response's rt should no more than it
177
MaxExpectedRT time.Duration
178
// if MinExpectedRT is zero means do not care about it
179
// if MinExpectedRT is not zero, means response's rt should more than it
180
MinExpectedRT time.Duration
183
func (c *VerifyConfig) Verify(resp *Response) bool {
187
if resp.GetResponseStatus() != c.ExpectedStatusCode {
188
log.DefaultLogger.Errorf("status is not expected: %d, %d", resp.GetResponseStatus(), c.ExpectedStatusCode)
191
for k, v := range c.ExpectedHeader {
192
if value, ok := resp.Header.Get(k); !ok || !strings.EqualFold(v, value) {
193
log.DefaultLogger.Errorf("header key %s is not expected, got: %s, %t, value: %s", k, v, ok, value)
197
// if ExpectedBody is not nil, but length is zero, means expected empty content
198
if c.ExpectedBody != nil {
199
if !bytes.Equal(c.ExpectedBody, resp.Content.Bytes()) {
200
log.DefaultLogger.Errorf("body is not expected: %v, %v", string(c.ExpectedBody), string(resp.Content.Bytes()))
204
if c.MaxExpectedRT > 0 {
205
if resp.Cost > c.MaxExpectedRT {
206
log.DefaultLogger.Errorf("rt is %s, max expected is %s", resp.Cost, c.MaxExpectedRT)
210
if c.MinExpectedRT > 0 {
211
if resp.Cost < c.MinExpectedRT {
212
log.DefaultLogger.Errorf("rt is %s, min expected is %s", resp.Cost, c.MaxExpectedRT)