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  }