gitee.com/KyleChenSource/lib-robot@v1.0.2/robottest/testcaseimp/proto_wait_send.go (about)

     1  package testcaseimp
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"gitee.com/KyleChenSource/lib-robot/robottest/robot/statistic"
     8  	"gitee.com/KyleChenSource/lib-robot/robottest/robot/testcase"
     9  
    10  	"gitee.com/KyleChenSource/lib-robot/robottest/protos"
    11  
    12  	"gitee.com/KyleChenSource/lib-robot/robottest/log"
    13  
    14  	"gitee.com/KyleChenSource/lib-robot/robottest/common"
    15  )
    16  
    17  type ProtoWaitSendCnf struct {
    18  	WaitId      protos.ProtoID `json:"wait_id"`      // 预期返回协议ID, 0无返回
    19  	WaitTimeout int            `json:"wait_timeout"` // 预期等待时间,单位ms. ResponseId != 0时有效
    20  
    21  	// 预期返回协议的校验. ResponseId != 0时有效. key -> value
    22  	// key: Respone协议校验路径
    23  	// value: 对应路径校验逻辑判定
    24  	// 具体参考logic.y注释说明
    25  	// 关键字:	 Length(容器长度)
    26  	//			Value当前值
    27  	//			None: Value==nil
    28  	// 操作符:	<, <=, ==, >, >=
    29  	// 			&&, ||, not
    30  	WaitChecks map[string]protos.CheckData `json:"wait_checks"`
    31  
    32  	ProtoSendWaitCnf
    33  }
    34  
    35  type ProtoWaitSendFactory struct {
    36  }
    37  
    38  func (this *ProtoWaitSendFactory) Cnf() testcase.TestcaseActionCnf {
    39  	return &ProtoWaitSendCnf{}
    40  }
    41  
    42  func (this *ProtoWaitSendFactory) New(id testcase.TestActionID, tf testcase.ITestFlow, cnf testcase.TestcaseActionCnf) (testcase.ITestcaseAction, error) {
    43  	return &ProtoWaitSend{
    44  		_id:    id,
    45  		_tf:    tf,
    46  		_cnf:   cnf.(*ProtoWaitSendCnf),
    47  		_state: ProtoWaitSendState_Wait,
    48  	}, nil
    49  }
    50  
    51  func init() {
    52  	testcase.TESTCASEACTION_MGR.Register("ProtoWaitSend", &ProtoWaitSendFactory{})
    53  }
    54  
    55  type ProtoWaitSendState int
    56  
    57  const (
    58  	ProtoWaitSendState_Wait ProtoWaitSendState = iota // 初始化
    59  	ProtoWaitSendState_Send
    60  )
    61  
    62  type ProtoWaitSend struct {
    63  	_id       testcase.TestActionID
    64  	_tf       testcase.ITestFlow
    65  	_cnf      *ProtoWaitSendCnf
    66  	_state    ProtoWaitSendState
    67  	_timer    *common.TimeInterface
    68  	_timeSend int64 // 发送时间
    69  }
    70  
    71  // 启动
    72  // 目前仅仅支持定时器和消息两种驱动模式
    73  func (this *ProtoWaitSend) Start() error {
    74  	if this._cnf.WaitId <= 0 {
    75  		return fmt.Errorf("wait_id:%d", this._cnf.WaitId)
    76  	}
    77  
    78  	this._tf.TestCtx().MsgHandleReg(this._cnf.WaitId, this)
    79  
    80  	for _, m := range this._cnf.MonitorMsgs {
    81  		this._tf.TestCtx().MsgHandleReg(m.MsgId, this)
    82  	}
    83  
    84  	if this._cnf.WaitTimeout > 0 {
    85  		log.LogInfo("%s wait timeOut:%d", this._tf.LogPre(), this._cnf.WaitTimeout)
    86  		// 定时器超时
    87  		t, err := this._tf.TestCtx().TimerAdd(int64(this._cnf.WaitTimeout), this.OnTimerWaitTimeout, nil)
    88  
    89  		if err != nil {
    90  			this.end(err)
    91  			return fmt.Errorf("wait_time err:%s", err.Error())
    92  		}
    93  
    94  		this._timer = t
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  // 停止,需要删除目前所有的驱动注册
   101  func (this *ProtoWaitSend) Stop() {
   102  	if this._timer != nil {
   103  		this._tf.TestCtx().TimerDel(this._timer)
   104  	}
   105  
   106  	if this._cnf.WaitId > 0 {
   107  		this._tf.TestCtx().MsgHandleUnreg(this._cnf.WaitId, this)
   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 *ProtoWaitSend) ID() testcase.TestActionID {
   120  	return this._id
   121  }
   122  
   123  func (this *ProtoWaitSend) Name() string {
   124  	return this._cnf.ActionName()
   125  }
   126  
   127  func (this *ProtoWaitSend) Testflow() testcase.ITestFlow {
   128  	return this._tf
   129  }
   130  
   131  func (this *ProtoWaitSend) 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 *ProtoWaitSend) OnMsg(protoId protos.ProtoID, header protos.JsonString, data protos.JsonString) {
   149  	log.LogDebug("%s action:%d OnMsg:%d header:%s data:%s", this._tf.LogPre(), this._id, protoId, header, data)
   150  
   151  	if protoId != this._cnf.ResponseId && protoId != this._cnf.WaitId {
   152  		this.onMonitor(protoId, header, data)
   153  		return
   154  	}
   155  
   156  	switch this._state {
   157  	case ProtoWaitSendState_Wait:
   158  		if protoId != this._cnf.WaitId {
   159  			log.LogError("%s action:%d OnMsg:%d header:%s data:%s err:id not %d", this._tf.LogPre(), this._id, protoId, header, data, protoId)
   160  			this._tf.OnActionEnd(this, fmt.Errorf("id not %d", protoId), this._cnf.FailContinue)
   161  			return
   162  		}
   163  
   164  		b, _, err := protos.JsonCheck(string(data), this._cnf.WaitChecks, this._tf.TestCtx())
   165  		if err != nil {
   166  			return
   167  		}
   168  
   169  		if !b {
   170  			return
   171  		}
   172  
   173  		this._tf.TestCtx().MsgHandleUnreg(this._cnf.WaitId, this)
   174  		this._tf.TestCtx().MsgHandleReg(this._cnf.ResponseId, this)
   175  
   176  		this.onMonitor(protoId, header, data)
   177  
   178  		// 检测成功,发消息了
   179  		this.msgSend()
   180  		return
   181  	case ProtoWaitSendState_Send:
   182  		tCost := time.Now().UnixMilli() - this._timeSend
   183  		b, bContinue, err := protos.JsonCheck(string(data), this._cnf.Checks, this._tf.TestCtx())
   184  		if err != nil {
   185  			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())
   186  			statistic.Record(&statistic.StatisticEvent{
   187  				Type: statistic.StatisticType_Msg_Err,
   188  				ID:   int(protoId),
   189  			})
   190  			this._tf.OnActionEnd(this, err, this._cnf.FailContinue)
   191  			return
   192  		}
   193  
   194  		if !b {
   195  			if !bContinue {
   196  				log.LogError("MsgResponse CheckFailed. %s action:%d OnMsg:%d header:%s data:%s timeCost:%d", this._tf.LogPre(), this._id, protoId, header, data, tCost)
   197  				statistic.Record(&statistic.StatisticEvent{
   198  					Type: statistic.StatisticType_Msg_Fail,
   199  					ID:   int(protoId),
   200  				})
   201  				this._tf.OnActionEnd(this, fmt.Errorf("checks failed"), this._cnf.FailContinue)
   202  			}
   203  			return
   204  		}
   205  
   206  		this.onMonitor(protoId, header, data)
   207  
   208  		log.LogInfo("MsgResponse OK. %s action:%d OnMsg:%d header:%s data:%s timeCost:%d", this._tf.LogPre(), this._id, protoId, header, data, tCost)
   209  		this._tf.OnActionEnd(this, nil, this._cnf.FailContinue)
   210  		statistic.Record(&statistic.StatisticEvent{
   211  			Type: statistic.StatisticType_Msg_Success,
   212  			ID:   int(protoId),
   213  			Time: tCost,
   214  		})
   215  	}
   216  }
   217  
   218  func (this *ProtoWaitSend) end(err error) {
   219  	this._tf.OnActionEnd(this, err, this._cnf.FailContinue)
   220  }
   221  
   222  func (this *ProtoWaitSend) msgSend() {
   223  	if this._state != ProtoWaitSendState_Wait {
   224  		this._tf.OnActionEnd(this, fmt.Errorf("%s SendMsg %s:%s err:state is %d", this._cnf.Name, this._cnf.MsgFile, this._cnf.MsgKey, this._state), this._cnf.FailContinue)
   225  		return
   226  	}
   227  
   228  	if this._timer != nil {
   229  		this._tf.TestCtx().TimerDel(this._timer)
   230  		this._timer = nil
   231  	}
   232  
   233  	this._state = ProtoWaitSendState_Send
   234  	pCnf, err := protos.NetworkProtoData(this._cnf.MsgFile, this._cnf.MsgKey)
   235  	if err != nil {
   236  		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)
   237  		return
   238  	}
   239  
   240  	if pCnf == nil {
   241  		this._tf.OnActionEnd(this, fmt.Errorf("%s SendMsg %s:%s NULL", this._cnf.Name, this._cnf.MsgFile, this._cnf.MsgKey), this._cnf.FailContinue)
   242  		return
   243  	}
   244  
   245  	// 实现json数据替换
   246  	data, err := protos.JsonReplace(pCnf.Data, this._tf.TestCtx())
   247  	if err != nil {
   248  		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)
   249  		return
   250  	}
   251  
   252  	err = this._tf.TestCtx().Send(pCnf.ID, data)
   253  	if err != nil {
   254  		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)
   255  		return
   256  	}
   257  
   258  	log.LogInfo("%s action:%d msgSend:%d data:%s", this._tf.LogPre(), this._id, pCnf.ID, data)
   259  	// 发送成功,开始等待需要的回包
   260  	if this._cnf.Timeout == 0 && this._cnf.ResponseId == 0 {
   261  		// 结束
   262  		statistic.Record(&statistic.StatisticEvent{
   263  			Type: statistic.StatisticType_Msg_Success,
   264  			ID:   int(pCnf.ID),
   265  			Time: 0,
   266  		})
   267  		this.end(nil)
   268  		return
   269  	}
   270  
   271  	if this._cnf.Timeout > 0 {
   272  		log.LogDebug("%s timeOut:%d", this._tf.LogPre(), this._cnf.Timeout)
   273  		// 定时器超时
   274  		t, err := this._tf.TestCtx().TimerAdd(int64(this._cnf.Timeout), this.OnTimerResponseTimeout, nil)
   275  
   276  		if err != nil {
   277  			this.end(err)
   278  			return
   279  		}
   280  
   281  		this._timer = t
   282  	}
   283  
   284  	this._timeSend = time.Now().UnixMilli()
   285  }
   286  
   287  func (this *ProtoWaitSend) OnTimerWaitTimeout(t *common.TimeInterface, data any) int64 {
   288  	log.LogInfo("Wait Timeout. %s action:%d OnMsg:%d timeOut:%d", this._tf.LogPre(), this._id, this._cnf.WaitId, this._cnf.WaitTimeout)
   289  	this._timer = nil
   290  
   291  	this._tf.OnActionEnd(this, fmt.Errorf("timeout:%d msg:%d Wait", this._cnf.Timeout, this._cnf.WaitId), this._cnf.FailContinue)
   292  	statistic.Record(&statistic.StatisticEvent{
   293  		Type: statistic.StatisticType_Msg_Timeout,
   294  		ID:   int(this._cnf.WaitId),
   295  	})
   296  	return 0
   297  }
   298  
   299  func (this *ProtoWaitSend) OnTimerResponseTimeout(t *common.TimeInterface, data any) int64 {
   300  	log.LogInfo("MsgResponse Timeout. %s action:%d OnMsg:%d timeOut:%d", this._tf.LogPre(), this._id, this._cnf.ResponseId, this._cnf.Timeout)
   301  	this._timer = nil
   302  
   303  	this._tf.OnActionEnd(this, fmt.Errorf("timeout:%d msg:%d", this._cnf.Timeout, this._cnf.ResponseId), this._cnf.FailContinue)
   304  	statistic.Record(&statistic.StatisticEvent{
   305  		Type: statistic.StatisticType_Msg_Timeout,
   306  		ID:   int(this._cnf.ResponseId),
   307  	})
   308  	return 0
   309  }