diff options
Diffstat (limited to 'adapter/mock')
-rw-r--r-- | adapter/mock/mock_adapter.go | 121 |
1 files changed, 78 insertions, 43 deletions
diff --git a/adapter/mock/mock_adapter.go b/adapter/mock/mock_adapter.go index ae4caf0..959fd86 100644 --- a/adapter/mock/mock_adapter.go +++ b/adapter/mock/mock_adapter.go @@ -67,11 +67,19 @@ type MessageDTO struct { Data []byte } +// reply for one request (can be multipart, contain replies to previously timeouted requests, etc.) type reply struct { - msg api.Message - multipart bool - hasSeqNum bool - seqNum uint16 + msgs []MsgWithContext +} + +// MsgWithContext encapsulates reply message with possibly sequence number and is-multipart flag. +type MsgWithContext struct { + Msg api.Message + SeqNum uint16 + Multipart bool + + /* set by mock adapter */ + hasCtx bool } // ReplyHandler is a type that allows to extend the behaviour of VPP mock. @@ -253,37 +261,32 @@ func (a *VppAdapter) SendMsg(clientID uint32, data []byte) error { a.repliesLock.Lock() defer a.repliesLock.Unlock() - // pop all replies from queue - withSeqNums := false - for i, reply := range a.replies { - if i > 0 && reply.msg.GetMessageName() == "control_ping_reply" && !withSeqNums { - // hack - do not send control_ping_reply immediately, leave it for the the next callback - a.replies = a.replies[i:] - return nil - } - msgID, _ := a.GetMsgID(reply.msg.GetMessageName(), reply.msg.GetCrcString()) - buf := new(bytes.Buffer) - context := clientID - context = setMultipart(context, reply.multipart) - if reply.hasSeqNum { - withSeqNums = true - context = setSeqNum(context, reply.seqNum) - } - if reply.msg.GetMessageType() == api.ReplyMessage { - struc.Pack(buf, &core.VppReplyHeader{VlMsgID: msgID, Context: context}) - } else if reply.msg.GetMessageType() == api.EventMessage { - struc.Pack(buf, &core.VppEventHeader{VlMsgID: msgID, Context: context}) - } else if reply.msg.GetMessageType() == api.RequestMessage { - struc.Pack(buf, &core.VppRequestHeader{VlMsgID: msgID, Context: context}) - } else { - struc.Pack(buf, &core.VppOtherHeader{VlMsgID: msgID}) - } - struc.Pack(buf, reply.msg) - a.callback(context, msgID, buf.Bytes()) - } + // pop the first reply if len(a.replies) > 0 { - a.replies = []reply{} - if len(a.replyHandlers) > 0 { + reply := a.replies[0] + for _, msg := range reply.msgs { + msgID, _ := a.GetMsgID(msg.Msg.GetMessageName(), msg.Msg.GetCrcString()) + buf := new(bytes.Buffer) + context := clientID + if msg.hasCtx { + context = setMultipart(context, msg.Multipart) + context = setSeqNum(context, msg.SeqNum) + } + if msg.Msg.GetMessageType() == api.ReplyMessage { + struc.Pack(buf, &core.VppReplyHeader{VlMsgID: msgID, Context: context}) + } else if msg.Msg.GetMessageType() == api.EventMessage { + struc.Pack(buf, &core.VppEventHeader{VlMsgID: msgID, Context: context}) + } else if msg.Msg.GetMessageType() == api.RequestMessage { + struc.Pack(buf, &core.VppRequestHeader{VlMsgID: msgID, Context: context}) + } else { + struc.Pack(buf, &core.VppOtherHeader{VlMsgID: msgID}) + } + struc.Pack(buf, msg.Msg) + a.callback(context, msgID, buf.Bytes()) + } + + a.replies = a.replies[1:] + if len(a.replies) == 0 && len(a.replyHandlers) > 0 { // Switch back to handlers once the queue is empty to revert back // the fallthrough effect. a.mode = useReplyHandlers @@ -313,24 +316,56 @@ func (a *VppAdapter) WaitReady() error { return nil } -// MockReply stores a message to be returned when the next request comes. It is a FIFO queue - multiple replies -// can be pushed into it, the first one will be popped when some request comes. -// Using of this method automatically switches the mock into th useRepliesQueue mode. -func (a *VppAdapter) MockReply(replyMsg api.Message, isMultipart bool) { +// MockReply stores a message or a list of multipart messages to be returned when +// the next request comes. It is a FIFO queue - multiple replies can be pushed into it, +// the first message or the first set of multi-part messages will be popped when +// some request comes. +// Using of this method automatically switches the mock into the useRepliesQueue mode. +// +// Note: multipart requests are implemented using two requests actually - the multipart +// request itself followed by control ping used to tell which multipart message +// is the last one. A mock reply to a multipart request has to thus consist of +// exactly two calls of this method. +// For example: +// +// mockVpp.MockReply( // push multipart messages all at once +// &interfaces.SwInterfaceDetails{SwIfIndex:1}, +// &interfaces.SwInterfaceDetails{SwIfIndex:2}, +// &interfaces.SwInterfaceDetails{SwIfIndex:3}, +// ) +// mockVpp.MockReply(&vpe.ControlPingReply{}) +// +// Even if the multipart request has no replies, MockReply has to be called twice: +// +// mockVpp.MockReply() // zero multipart messages +// mockVpp.MockReply(&vpe.ControlPingReply{}) +func (a *VppAdapter) MockReply(msgs ...api.Message) { a.repliesLock.Lock() defer a.repliesLock.Unlock() - a.replies = append(a.replies, reply{msg: replyMsg, multipart: isMultipart, hasSeqNum: false}) + r := reply{} + for _, msg := range msgs { + r.msgs = append(r.msgs, MsgWithContext{Msg: msg, hasCtx: false}) + } + a.replies = append(a.replies, r) a.mode = useRepliesQueue } -// MockReplyWithSeqNum queues next reply like MockReply() does, except that the -// sequence number can be customized and not necessarily match with the request. -func (a *VppAdapter) MockReplyWithSeqNum(replyMsg api.Message, isMultipart bool, sequenceNum uint16) { +// MockReplyWithContext queues next reply like MockReply() does, except that the +// sequence number and multipart flag (= context minus channel ID) can be customized +// and not necessarily match with the request. +// The purpose of this function is to test handling of sequence numbers and as such +// it is not really meant to be used outside the govpp UTs. +func (a *VppAdapter) MockReplyWithContext(msgs ...MsgWithContext) { a.repliesLock.Lock() defer a.repliesLock.Unlock() - a.replies = append(a.replies, reply{msg: replyMsg, multipart: isMultipart, hasSeqNum: true, seqNum: sequenceNum}) + r := reply{} + for _, msg := range msgs { + r.msgs = append(r.msgs, + MsgWithContext{Msg: msg.Msg, SeqNum: msg.SeqNum, Multipart: msg.Multipart, hasCtx: true}) + } + a.replies = append(a.replies, r) a.mode = useRepliesQueue } |