Sequence numbers are now used to match requests with replies.
Mock adapter thus has to be able to tell how many messages
from the head of the queue with mock replies belong to the currently
processed request. Then they can be given the right context and
the rest of the queued replies are postponed to be delivered later
(when context of their request is known).
All replies for one request are now therefore queued together.
This affects just multipart requests for which replies have to
be pushed all at once. The trailling control ping reply is still
queued separately, however, because that is actualy another request,
e.g.:
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 exactly twice:
mockVpp.MockReply() // zero multipart messages
mockVpp.MockReply(&vpe.ControlPingReply{})
Change-Id: I28c15d2f52d14dca0b7fb06033d7270a7da2bde6
Signed-off-by: Milan Lenco <milan.lenco@pantheon.tech>
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.
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
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
}
// methods provided inside of this package. Do not use the same channel from multiple goroutines concurrently,
// otherwise the responses could mix! Use multiple channels instead.
type Channel struct {
- ID uint16 // channel ID
+ ID uint16 // channel ID
ReqChan chan *VppRequest // channel for sending the requests to VPP, closing this channel releases all resources in the ChannelProvider
ReplyChan chan *VppReply // channel where VPP replies are delivered to
// RequestCtx is a context of a ongoing request (simple one - only one response is expected).
type RequestCtx struct {
- ch *Channel
+ ch *Channel
seqNum uint16
}
// MultiRequestCtx is a context of a ongoing multipart request (multiple responses are expected).
type MultiRequestCtx struct {
- ch *Channel
+ ch *Channel
seqNum uint16
}
// Use ChannelProvider to get an API channel ready for communication with VPP.
func NewChannelInternal(id uint16) *Channel {
return &Channel{
- ID: id,
+ ID: id,
replyTimeout: defaultReplyTimeout,
}
}
ch.lastSeqNum++
ch.ReqChan <- &VppRequest{
Message: msg,
- SeqNum: ch.lastSeqNum,
+ SeqNum: ch.lastSeqNum,
}
return &RequestCtx{ch: ch, seqNum: ch.lastSeqNum}
}
ignore = true
return
}
- if cmpSeqNums == 1 {
+ if cmpSeqNums == 1 {
ch.delayedReply = reply
err = fmt.Errorf("missing binary API reply with sequence number: %d", expSeqNum)
return
msgNameCrc = nameCrc
}
- err = fmt.Errorf("received invalid message ID (seq-num=%d), expected %d (%s), but got %d (%s) " +
- "(check if multiple goroutines are not sharing single GoVPP channel)",
+ err = fmt.Errorf("received invalid message ID (seq-num=%d), expected %d (%s), but got %d (%s) "+
+ "(check if multiple goroutines are not sharing single GoVPP channel)",
reply.SeqNum, expMsgID, msg.GetMessageName(), reply.MessageID, msgNameCrc)
return
}
ctx.mockVpp.MockReply(&tap.TapConnectReply{
Retval: 10,
SwIfIndex: 1,
- }, false)
+ })
request := &tap.TapConnect{
TapName: []byte("test-tap-name"),
UseRandomMac: 1,
ctx.mockVpp.MockReply(&tap.TapModifyReply{
Retval: 15,
SwIfIndex: 2,
- }, false)
+ })
request := &tap.TapModify{
TapName: []byte("test-tap-modify"),
UseRandomMac: 1,
ctx.mockVpp.MockReply(&tap.TapDeleteReply{
Retval: 20,
- }, false)
+ })
request := &tap.TapDelete{
SwIfIndex: 3,
}
ctx.mockVpp.MockReply(&tap.SwInterfaceTapDetails{
SwIfIndex: 25,
DevName: byteName,
- }, false)
+ })
request := &tap.SwInterfaceTapDump{}
reply := &tap.SwInterfaceTapDetails{}
ctx.mockVpp.MockReply(&memif.MemifCreateReply{
Retval: 22,
SwIfIndex: 4,
- }, false)
+ })
request := &memif.MemifCreate{
Role: 10,
ID: 12,
ctx.mockVpp.MockReply(&memif.MemifDeleteReply{
Retval: 24,
- }, false)
+ })
request := &memif.MemifDelete{
SwIfIndex: 15,
}
SwIfIndex: 25,
IfName: []byte("memif-name"),
Role: 0,
- }, false)
+ })
request := &memif.MemifDump{}
reply := &memif.MemifDetails{}
defer ctx.teardownTest()
// mock reply
+ msgs := []api.Message{}
for i := 1; i <= 10; i++ {
- ctx.mockVpp.MockReply(&tap.SwInterfaceTapDetails{
+ msgs = append(msgs, &tap.SwInterfaceTapDetails{
SwIfIndex: uint32(i),
DevName: []byte("dev-name-test"),
- }, true)
+ })
}
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{}, true)
+ ctx.mockVpp.MockReply(msgs...)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
reqCtx := ctx.ch.SendMultiRequest(&tap.SwInterfaceTapDump{})
cnt := 0
defer ctx.teardownTest()
// mock reply
+ msgs := []api.Message{}
for i := 1; i <= 10; i++ {
- ctx.mockVpp.MockReply(&memif.MemifDetails{
+ msgs = append(msgs, &memif.MemifDetails{
SwIfIndex: uint32(i),
- }, true)
+ })
}
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{}, true)
+ ctx.mockVpp.MockReply(msgs...)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
reqCtx := ctx.ch.SendMultiRequest(&memif.MemifDump{})
cnt := 0
ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{
SwIfIndex: 3,
AdminUpDown: 1,
- }, false)
+ })
ctx.mockVpp.SendMsg(0, []byte(""))
// receive the notification
ctx.mockVpp.MockReply(&interfaces.SwInterfaceEvent{
SwIfIndex: 2,
LinkUpDown: 1,
- }, false)
+ })
ctx.mockVpp.SendMsg(0, []byte(""))
// receive the notification
ctx.ch.SetReplyTimeout(time.Millisecond)
// first one request should work
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{}, false)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
err := ctx.ch.SendRequest(&vpe.ControlPing{}).ReceiveReply(&vpe.ControlPingReply{})
Expect(err).ShouldNot(HaveOccurred())
ctx.ch.SetReplyTimeout(time.Millisecond)
+ msgs := []api.Message{}
for i := 1; i <= 3; i++ {
- ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{
+ msgs = append(msgs, &interfaces.SwInterfaceDetails{
SwIfIndex: uint32(i),
InterfaceName: []byte("if-name-test"),
- }, true)
+ })
}
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{}, true)
+ ctx.mockVpp.MockReply(msgs...)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
cnt := 0
sendMultiRequest := func() error {
defer ctx.teardownTest()
// mock reply
+ msgs := []mock.MsgWithContext{}
for i := 1; i <= 3; i++ {
- ctx.mockVpp.MockReplyWithSeqNum(&interfaces.SwInterfaceDetails{
- SwIfIndex: uint32(i),
- InterfaceName: []byte("if-name-test"),
- }, true, 1)
+ msgs = append(msgs, mock.MsgWithContext{
+ Msg: &interfaces.SwInterfaceDetails{
+ SwIfIndex: uint32(i),
+ InterfaceName: []byte("if-name-test"),
+ },
+ Multipart: true,
+ SeqNum: 1,
+ })
}
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{}, true, 1)
+ msgs = append(msgs, mock.MsgWithContext{Msg: &vpe.ControlPingReply{}, Multipart: true, SeqNum: 1})
+
for i := 1; i <= 3; i++ {
- ctx.mockVpp.MockReplyWithSeqNum(&interfaces.SwInterfaceDetails{
- SwIfIndex: uint32(i),
- InterfaceName: []byte("if-name-test"),
- }, true, 2)
+ msgs = append(msgs,
+ mock.MsgWithContext{
+ Msg: &interfaces.SwInterfaceDetails{
+ SwIfIndex: uint32(i),
+ InterfaceName: []byte("if-name-test"),
+ },
+ Multipart: true,
+ SeqNum: 2,
+ })
}
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{}, true,2)
+ msgs = append(msgs, mock.MsgWithContext{Msg: &vpe.ControlPingReply{}, Multipart: true, SeqNum: 2})
+
+ ctx.mockVpp.MockReplyWithContext(msgs...)
cnt := 0
var sendMultiRequest = func() error {
ctx.ch.SetReplyTimeout(time.Millisecond)
// first one request should work
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{}, false,1)
+ ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{Msg: &vpe.ControlPingReply{}, SeqNum: 1})
err := ctx.ch.SendRequest(&vpe.ControlPing{}).ReceiveReply(&vpe.ControlPingReply{})
Expect(err).ShouldNot(HaveOccurred())
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("timeout"))
- // simulating late reply
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{}, false,2)
-
- // normal reply for next request
- ctx.mockVpp.MockReplyWithSeqNum(&tap.TapConnectReply{}, false,3)
+ ctx.mockVpp.MockReplyWithContext(
+ // simulating late reply
+ mock.MsgWithContext{Msg: &vpe.ControlPingReply{}, SeqNum: 2},
+ // normal reply for next request
+ mock.MsgWithContext{Msg: &tap.TapConnectReply{}, SeqNum: 3})
req := &tap.TapConnect{
TapName: []byte("test-tap-name"),
ctx.ch.SetReplyTimeout(time.Millisecond * 100)
// first one request should work
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{}, false, 1)
+ ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{Msg: &vpe.ControlPingReply{}, SeqNum: 1})
err := ctx.ch.SendRequest(&vpe.ControlPing{}).ReceiveReply(&vpe.ControlPingReply{})
Expect(err).ShouldNot(HaveOccurred())
Expect(cnt).To(BeEquivalentTo(0))
// simulating late replies
+ msgs := []mock.MsgWithContext{}
for i := 1; i <= 3; i++ {
- ctx.mockVpp.MockReplyWithSeqNum(&interfaces.SwInterfaceDetails{
- SwIfIndex: uint32(i),
- InterfaceName: []byte("if-name-test"),
- }, true, 2)
+ msgs = append(msgs, mock.MsgWithContext{
+ Msg: &interfaces.SwInterfaceDetails{
+ SwIfIndex: uint32(i),
+ InterfaceName: []byte("if-name-test"),
+ },
+ Multipart: true,
+ SeqNum: 2,
+ })
}
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{}, true, 2)
+ msgs = append(msgs, mock.MsgWithContext{Msg: &vpe.ControlPingReply{}, Multipart: true, SeqNum: 2})
+ ctx.mockVpp.MockReplyWithContext(msgs...)
// normal reply for next request
- ctx.mockVpp.MockReplyWithSeqNum(&tap.TapConnectReply{}, false, 3)
+ ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{Msg: &tap.TapConnectReply{}, SeqNum: 3})
req := &tap.TapConnect{
TapName: []byte("test-tap-name"),
defer ctx.teardownTest()
// first one request should work
- ctx.mockVpp.MockReply(&vpe.ShowVersionReply{}, false)
+ ctx.mockVpp.MockReply(&vpe.ShowVersionReply{})
err := ctx.ch.SendRequest(&vpe.ShowVersion{}).ReceiveReply(&vpe.ShowVersionReply{})
Expect(err).ShouldNot(HaveOccurred())
// second should fail with error invalid message ID
- ctx.mockVpp.MockReply(&vpe.ShowVersionReply{}, false)
+ ctx.mockVpp.MockReply(&vpe.ShowVersionReply{})
err = ctx.ch.SendRequest(&vpe.ControlPing{}).ReceiveReply(&vpe.ControlPingReply{})
Expect(err).Should(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("invalid message ID"))
ctx := setupTest(t, false)
defer ctx.teardownTest()
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: -5}, false)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: -5})
req := &vpe.ControlPing{}
reply := &vpe.ControlPingReply{}
ctx := setupTest(t, false)
defer ctx.teardownTest()
+ msgs := []api.Message{}
for m := 0; m < 10; m++ {
- ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{}, true)
+ msgs = append(msgs, &interfaces.SwInterfaceDetails{})
}
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{}, true)
+ ctx.mockVpp.MockReply(msgs...)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
// send multipart request
ctx.ch.ReqChan <- &api.VppRequest{Message: &interfaces.SwInterfaceDump{}, Multipart: true}
ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{
SwIfIndex: 3,
AdminUpDown: 1,
- }, false)
+ })
ctx.mockVpp.SendMsg(0, []byte{0})
// receive the notification
// send multiple requests, only one reply should be read
for i := 0; i < 20; i++ {
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{}, false)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
ctx.ch.ReqChan <- &api.VppRequest{Message: &vpe.ControlPing{}}
}
var reqCtx []*api.RequestCtx
for i := 0; i < 10; i++ {
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: int32(i)}, false)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: int32(i)})
req := &vpe.ControlPing{}
reqCtx = append(reqCtx, ctx.ch.SendRequest(req))
}
ctx := setupTest(t, false)
defer ctx.teardownTest()
+ msgs := []api.Message{}
for i := 0; i < 10; i++ {
- ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{SwIfIndex: uint32(i)}, true)
+ msgs = append(msgs, &interfaces.SwInterfaceDetails{SwIfIndex: uint32(i)})
}
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{}, true)
+ ctx.mockVpp.MockReply(msgs...)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
// send multipart request
reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
defer ctx.teardownTest()
// reply for a previous timeouted requests to be ignored
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{Retval: 1}, false,0)
+ ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{
+ Msg: &vpe.ControlPingReply{Retval: 1},
+ SeqNum: 0,
+ })
// send reply later
req1 := &vpe.ControlPing{}
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(HavePrefix("no reply received within the timeout period"))
- // reply for the previous request
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{Retval: 1}, false,1)
+ ctx.mockVpp.MockReplyWithContext(
+ // reply for the previous request
+ mock.MsgWithContext{
+ Msg: &vpe.ControlPingReply{Retval: 1},
+ SeqNum: 1,
+ },
+ // reply for the next request
+ mock.MsgWithContext{
+ Msg: &vpe.ControlPingReply{Retval: 2},
+ SeqNum: 2,
+ })
// next request
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: 2}, false)
req2 := &vpe.ControlPing{}
reqCtx2 := ctx.ch.SendRequest(req2)
reqCtx2 := ctx.ch.SendRequest(req2)
// third request with reply
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{Retval: 3}, false, 3)
+ ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{
+ Msg: &vpe.ControlPingReply{Retval: 3},
+ SeqNum: 3,
+ })
req3 := &vpe.ControlPing{}
reqCtx3 := ctx.ch.SendRequest(req3)
ctx := setupTest(t, false)
defer ctx.teardownTest()
- // reply for a previous timeouted requests to be ignored
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{Retval: 1}, false,0xffff - 1)
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{Retval: 1}, false,0xffff)
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{Retval: 1}, false,0)
+ // replies for a previous timeouted requests to be ignored
+ msgs := []mock.MsgWithContext{}
+ msgs = append(msgs,
+ mock.MsgWithContext{
+ Msg: &vpe.ControlPingReply{Retval: 1},
+ SeqNum: 0xffff - 1,
+ },
+ mock.MsgWithContext{
+ Msg: &vpe.ControlPingReply{Retval: 1},
+ SeqNum: 0xffff,
+ },
+ mock.MsgWithContext{
+ Msg: &vpe.ControlPingReply{Retval: 1},
+ SeqNum: 0,
+ })
for i := 0; i < 10; i++ {
- ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{SwIfIndex: uint32(i)}, true)
+ msgs = append(msgs,
+ mock.MsgWithContext{
+ Msg: &interfaces.SwInterfaceDetails{SwIfIndex: uint32(i)},
+ SeqNum: 1,
+ Multipart: true,
+ })
}
// missing finalizing control ping
// reply for a next request
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{Retval: 2}, false,2)
+ msgs = append(msgs,
+ mock.MsgWithContext{
+ Msg: &vpe.ControlPingReply{Retval: 2},
+ SeqNum: 2,
+ Multipart: false,
+ })
+
+ // queue replies
+ ctx.mockVpp.MockReplyWithContext(msgs...)
// send multipart request
reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
// some replies will get thrown away
// first request
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: 1}, false)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: 1})
req1 := &vpe.ControlPing{}
reqCtx1 := ctx.ch.SendRequest(req1)
// second request
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: 2}, false)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: 2})
req2 := &vpe.ControlPing{}
reqCtx2 := ctx.ch.SendRequest(req2)
numIters := 0xffff + 100
reqCtx := make(map[int]*api.RequestCtx)
- var seqNum uint16 = 0
- for i := 0; i < numIters + 30 /* receiver is 30 reqs behind */; i++ {
- seqNum++
+ for i := 0; i < numIters+30; /* receiver is 30 reqs behind */ i++ {
if i < numIters {
- ctx.mockVpp.MockReplyWithSeqNum(&vpe.ControlPingReply{Retval: int32(i)}, false, seqNum)
+ ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: int32(i)})
req := &vpe.ControlPing{}
reqCtx[i] = ctx.ch.SendRequest(req)
}
reply := &vpe.ControlPingReply{}
err := reqCtx[i-30].ReceiveReply(reply)
Expect(err).ShouldNot(HaveOccurred())
- Expect(reply.Retval).To(BeEquivalentTo(i-30))
+ Expect(reply.Retval).To(BeEquivalentTo(i - 30))
}
}
-}
\ No newline at end of file
+}