gitee.com/KyleChenSource/lib-robot@v1.0.2/robottest/testcaseimp/proto_send_wait.go (about) 1 package testcaseimp 2 3 import ( 4 "fmt" 5 "math/rand" 6 "time" 7 8 "gitee.com/KyleChenSource/lib-robot/robottest/protos" 9 "gitee.com/KyleChenSource/lib-robot/robottest/robot/statistic" 10 "gitee.com/KyleChenSource/lib-robot/robottest/robot/testcase" 11 12 "gitee.com/KyleChenSource/lib-robot/robottest/log" 13 14 "gitee.com/KyleChenSource/lib-robot/robottest/common" 15 ) 16 17 type MonitorMsg struct { 18 MsgId protos.ProtoID `json:"msg_id"` 19 Sets map[string]string `json:"sets"` // 对消息进行设置 20 } 21 22 type ProtoSendWaitCnf struct { 23 testcase.TestcaseActionConfig_ 24 25 MsgFile string `json:"msg_file"` // 协议的配置文件 26 MsgKey string `json:"msg_key"` // 协议的文件中的key 27 28 MonitorMsgs []MonitorMsg `json:"monitor_msgs"` 29 ResponseId protos.ProtoID `json:"response_id"` // 预期返回协议ID, 0无返回 30 Timeout int `json:"timeout"` // 预期等待时间,单位ms. ResponseId != 0时有效 31 32 CheckFailedExit bool `json:"check_failexit"` // 是否检测失败就Action失败 33 // 预期返回协议的校验. ResponseId != 0时有效. key -> value 34 // key: Respone协议校验路径 35 // value: 对应路径校验逻辑判定 36 // 具体参考logic.y注释说明 37 // 关键字: Length(容器长度) 38 // Value当前值 39 // None: Value==nil 40 // 操作符: <, <=, ==, >, >= 41 // &&, ||, not 42 Checks map[string]protos.CheckData `json:"checks"` 43 } 44 45 type ProtoSendWaitFactory struct { 46 } 47 48 func (this *ProtoSendWaitFactory) Cnf() testcase.TestcaseActionCnf { 49 return &ProtoSendWaitCnf{} 50 } 51 52 func (this *ProtoSendWaitFactory) New(id testcase.TestActionID, tf testcase.ITestFlow, cnf testcase.TestcaseActionCnf) (testcase.ITestcaseAction, error) { 53 return &ProtoSendWait{ 54 _id: id, 55 _tf: tf, 56 _cnf: cnf.(*ProtoSendWaitCnf), 57 }, nil 58 } 59 60 func init() { 61 testcase.TESTCASEACTION_MGR.Register("ProtoSendWait", &ProtoSendWaitFactory{}) 62 } 63 64 type ProtoSendWait struct { 65 _id testcase.TestActionID 66 _tf testcase.ITestFlow 67 _cnf *ProtoSendWaitCnf 68 _timer *common.TimeInterface 69 _timeSend int64 // 发送时间 70 } 71 72 // 启动 73 // 目前仅仅支持定时器和消息两种驱动模式 74 func (this *ProtoSendWait) Start() error { 75 for _, m := range this._cnf.MonitorMsgs { 76 this._tf.TestCtx().MsgHandleReg(m.MsgId, this) 77 } 78 79 delay := int64(this._cnf.Delay) 80 if this._cnf.RandMin > 0 { 81 delay += (*this._cnf).RandMin 82 } 83 if this._cnf.RandMax > this._cnf.RandMin { 84 delay += rand.Int63n((*this._cnf).RandMax - (*this._cnf).RandMin) 85 } 86 87 if delay > 0 { 88 log.LogDebug("%s delay:%d", this._tf.LogPre(), delay) 89 t, err := this._tf.TestCtx().TimerAdd(delay, this.OnTimerMsgSend, nil) 90 91 if err != nil { 92 return err 93 } 94 95 this._timer = t 96 return nil 97 } 98 99 this.msgSend() 100 101 return nil 102 } 103 104 // 停止,需要删除目前所有的驱动注册 105 func (this *ProtoSendWait) Stop() { 106 if this._timer != nil { 107 this._tf.TestCtx().TimerDel(this._timer) 108 } 109 110 if this._cnf.ResponseId > 0 { 111 this._tf.TestCtx().MsgHandleUnreg(this._cnf.ResponseId, this) 112 } 113 114 for _, m := range this._cnf.MonitorMsgs { 115 this._tf.TestCtx().MsgHandleUnreg(m.MsgId, this) 116 } 117 } 118 119 func (this *ProtoSendWait) ID() testcase.TestActionID { 120 return this._id 121 } 122 123 func (this *ProtoSendWait) Name() string { 124 return this._cnf.ActionName() 125 } 126 127 func (this *ProtoSendWait) Testflow() testcase.ITestFlow { 128 return this._tf 129 } 130 131 func (this *ProtoSendWait) onMonitor(protoId protos.ProtoID, header protos.JsonString, data protos.JsonString) { 132 for _, m := range this._cnf.MonitorMsgs { 133 if m.MsgId != protoId { 134 continue 135 } 136 137 err := protos.JsonSet(string(data), &m.Sets, this._tf.TestCtx()) 138 if err != nil { 139 log.LogError("MsgMonitor SetErr. %s action:%d OnMsg:%d header:%s data:%s err:%s", this._tf.LogPre(), this._id, protoId, header, data, err.Error()) 140 this._tf.OnActionEnd(this, err, this._cnf.FailContinue) 141 return 142 } 143 144 log.LogInfo("MsgMonitor OK. %s action:%d OnMsg:%d header:%s data:%s", this._tf.LogPre(), this._id, protoId, header, data) 145 } 146 } 147 148 func (this *ProtoSendWait) OnMsg(protoId protos.ProtoID, header protos.JsonString, data protos.JsonString) { 149 tCost := time.Now().UnixMilli() - this._timeSend 150 151 if protoId != this._cnf.ResponseId { 152 this.onMonitor(protoId, header, data) 153 return 154 } 155 156 if len(this._cnf.Checks) > 0 { 157 b, bContinue, err := protos.JsonCheck(string(data), this._cnf.Checks, this._tf.TestCtx()) 158 if err != nil { 159 log.LogError("MsgResponse CheckErr. %s action:%d OnMsg:%d header:%s data:%s timeCost:%d err:%s", this._tf.LogPre(), this._id, protoId, header, data, tCost, err.Error()) 160 statistic.Record(&statistic.StatisticEvent{ 161 Type: statistic.StatisticType_Msg_Err, 162 ID: int(protoId), 163 }) 164 this._tf.OnActionEnd(this, err, this._cnf.FailContinue) 165 return 166 } 167 168 if !b { 169 if !bContinue { 170 log.LogError("MsgResponse CheckFailed. %s action:%d OnMsg:%d header:%s data:%s timeCost:%d", this._tf.LogPre(), this._id, protoId, header, data, tCost) 171 statistic.Record(&statistic.StatisticEvent{ 172 Type: statistic.StatisticType_Msg_Fail, 173 ID: int(protoId), 174 }) 175 this._tf.OnActionEnd(this, fmt.Errorf("checks failed"), this._cnf.FailContinue) 176 } 177 return 178 } 179 } 180 181 this.onMonitor(protoId, header, data) 182 log.LogInfo("MsgResponse OK. %s action:%d OnMsg:%d header:%s data:%s timeCost:%d", this._tf.LogPre(), this._id, protoId, header, data, tCost) 183 this._tf.OnActionEnd(this, nil, this._cnf.FailContinue) 184 185 statistic.Record(&statistic.StatisticEvent{ 186 Type: statistic.StatisticType_Msg_Success, 187 ID: int(protoId), 188 Time: tCost, 189 }) 190 } 191 192 func (this *ProtoSendWait) end(err error) { 193 this._tf.OnActionEnd(this, err, this._cnf.FailContinue) 194 } 195 196 func (this *ProtoSendWait) msgSend() { 197 pCnf, err := protos.NetworkProtoData(this._cnf.MsgFile, this._cnf.MsgKey) 198 if err != nil { 199 this._tf.OnActionEnd(this, fmt.Errorf("%s SendMsg %s:%s err:%s", this._cnf.Name, this._cnf.MsgFile, this._cnf.MsgKey, err.Error()), this._cnf.FailContinue) 200 return 201 } 202 203 if pCnf == nil { 204 this._tf.OnActionEnd(this, fmt.Errorf("%s SendMsg %s:%s NULL", this._cnf.Name, this._cnf.MsgFile, this._cnf.MsgKey), this._cnf.FailContinue) 205 return 206 } 207 208 // 实现json数据替换 209 data, err := protos.JsonReplace(pCnf.Data, this._tf.TestCtx()) 210 if err != nil { 211 this._tf.OnActionEnd(this, fmt.Errorf("%s JsonReplace %s:%s err:%s", this._cnf.Name, this._cnf.MsgFile, this._cnf.MsgKey, err.Error()), this._cnf.FailContinue) 212 return 213 } 214 215 err = this._tf.TestCtx().Send(pCnf.ID, data) 216 if err != nil { 217 this._tf.OnActionEnd(this, fmt.Errorf("%s SendMsg %s:%s err:%s", this._cnf.Name, this._cnf.MsgFile, this._cnf.MsgKey, err.Error()), this._cnf.FailContinue) 218 return 219 } 220 221 log.LogInfo("%s action:%d msgSend:%d data:%s", this._tf.LogPre(), this._id, pCnf.ID, data) 222 // 发送成功,开始等待需要的回包 223 if this._cnf.Timeout == 0 && this._cnf.ResponseId == 0 { 224 // 结束 225 statistic.Record(&statistic.StatisticEvent{ 226 Type: statistic.StatisticType_Msg_Success, 227 ID: int(pCnf.ID), 228 Time: 0, 229 }) 230 this.end(nil) 231 return 232 } 233 234 if this._cnf.ResponseId > 0 { 235 this._tf.TestCtx().MsgHandleReg(this._cnf.ResponseId, this) 236 } 237 238 if this._cnf.Timeout > 0 { 239 log.LogDebug("%s timeOut:%d", this._tf.LogPre(), this._cnf.Timeout) 240 // 定时器超时 241 t, err := this._tf.TestCtx().TimerAdd(int64(this._cnf.Timeout), this.OnTimerResponseTimeout, nil) 242 243 if err != nil { 244 this.end(err) 245 return 246 } 247 248 this._timer = t 249 } 250 251 this._timeSend = time.Now().UnixMilli() 252 } 253 254 func (this *ProtoSendWait) OnTimerMsgSend(t *common.TimeInterface, data any) int64 { 255 log.LogInfo("action:%d OnTimerMsgSend\n", this.ID()) 256 this._timer = nil 257 258 this.msgSend() 259 return 0 260 } 261 262 func (this *ProtoSendWait) OnTimerResponseTimeout(t *common.TimeInterface, data any) int64 { 263 log.LogInfo("MsgResponse Timeout. %s action:%d OnMsg:%d timeOut:%d", this._tf.LogPre(), this._id, this._cnf.ResponseId, this._cnf.Timeout) 264 this._timer = nil 265 266 this._tf.OnActionEnd(this, fmt.Errorf("timeout:%d msg:%d", this._cnf.Timeout, this._cnf.ResponseId), this._cnf.FailContinue) 267 statistic.Record(&statistic.StatisticEvent{ 268 Type: statistic.StatisticType_Msg_Timeout, 269 ID: int(this._cnf.ResponseId), 270 }) 271 return 0 272 }