diff options
-rw-r--r-- | adapter/mock/mock_adapter.go | 121 | ||||
-rw-r--r-- | api/api.go | 16 | ||||
-rw-r--r-- | api/api_test.go | 113 | ||||
-rw-r--r-- | core/core_test.go | 94 |
4 files changed, 222 insertions, 122 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 } @@ -87,7 +87,7 @@ type MessageIdentifier interface { // 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 @@ -134,13 +134,13 @@ type NotifSubscription struct { // 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 } @@ -151,7 +151,7 @@ const defaultReplyTimeout = time.Second * 1 // default timeout for replies from // 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, } } @@ -175,7 +175,7 @@ func (ch *Channel) SendRequest(msg Message) *RequestCtx { ch.lastSeqNum++ ch.ReqChan <- &VppRequest{ Message: msg, - SeqNum: ch.lastSeqNum, + SeqNum: ch.lastSeqNum, } return &RequestCtx{ch: ch, seqNum: ch.lastSeqNum} } @@ -266,7 +266,7 @@ func (ch *Channel) processReply(reply *VppReply, expSeqNum uint16, msg Message) 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 @@ -298,8 +298,8 @@ func (ch *Channel) processReply(reply *VppReply, expSeqNum uint16, msg Message) 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 } diff --git a/api/api_test.go b/api/api_test.go index a83b1cc..7cbd9f0 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -64,7 +64,7 @@ func TestRequestReplyTapConnect(t *testing.T) { ctx.mockVpp.MockReply(&tap.TapConnectReply{ Retval: 10, SwIfIndex: 1, - }, false) + }) request := &tap.TapConnect{ TapName: []byte("test-tap-name"), UseRandomMac: 1, @@ -84,7 +84,7 @@ func TestRequestReplyTapModify(t *testing.T) { ctx.mockVpp.MockReply(&tap.TapModifyReply{ Retval: 15, SwIfIndex: 2, - }, false) + }) request := &tap.TapModify{ TapName: []byte("test-tap-modify"), UseRandomMac: 1, @@ -104,7 +104,7 @@ func TestRequestReplyTapDelete(t *testing.T) { ctx.mockVpp.MockReply(&tap.TapDeleteReply{ Retval: 20, - }, false) + }) request := &tap.TapDelete{ SwIfIndex: 3, } @@ -123,7 +123,7 @@ func TestRequestReplySwInterfaceTapDump(t *testing.T) { ctx.mockVpp.MockReply(&tap.SwInterfaceTapDetails{ SwIfIndex: 25, DevName: byteName, - }, false) + }) request := &tap.SwInterfaceTapDump{} reply := &tap.SwInterfaceTapDetails{} @@ -140,7 +140,7 @@ func TestRequestReplyMemifCreate(t *testing.T) { ctx.mockVpp.MockReply(&memif.MemifCreateReply{ Retval: 22, SwIfIndex: 4, - }, false) + }) request := &memif.MemifCreate{ Role: 10, ID: 12, @@ -161,7 +161,7 @@ func TestRequestReplyMemifDelete(t *testing.T) { ctx.mockVpp.MockReply(&memif.MemifDeleteReply{ Retval: 24, - }, false) + }) request := &memif.MemifDelete{ SwIfIndex: 15, } @@ -180,7 +180,7 @@ func TestRequestReplyMemifDetails(t *testing.T) { SwIfIndex: 25, IfName: []byte("memif-name"), Role: 0, - }, false) + }) request := &memif.MemifDump{} reply := &memif.MemifDetails{} @@ -196,13 +196,15 @@ func TestMultiRequestReplySwInterfaceTapDump(t *testing.T) { 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 @@ -223,12 +225,14 @@ func TestMultiRequestReplySwInterfaceMemifDump(t *testing.T) { 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 @@ -257,7 +261,7 @@ func TestNotifications(t *testing.T) { ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{ SwIfIndex: 3, AdminUpDown: 1, - }, false) + }) ctx.mockVpp.SendMsg(0, []byte("")) // receive the notification @@ -292,7 +296,7 @@ func TestNotificationEvent(t *testing.T) { ctx.mockVpp.MockReply(&interfaces.SwInterfaceEvent{ SwIfIndex: 2, LinkUpDown: 1, - }, false) + }) ctx.mockVpp.SendMsg(0, []byte("")) // receive the notification @@ -328,7 +332,7 @@ func TestSetReplyTimeout(t *testing.T) { 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()) @@ -344,13 +348,15 @@ func TestSetReplyTimeoutMultiRequest(t *testing.T) { 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 { @@ -409,20 +415,33 @@ func TestMultiRequestDouble(t *testing.T) { 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 { @@ -457,7 +476,7 @@ func TestReceiveReplyAfterTimeout(t *testing.T) { 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()) @@ -465,11 +484,11 @@ func TestReceiveReplyAfterTimeout(t *testing.T) { 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"), @@ -497,7 +516,7 @@ func TestReceiveReplyAfterTimeoutMultiRequest(t *testing.T) { 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()) @@ -524,16 +543,22 @@ func TestReceiveReplyAfterTimeoutMultiRequest(t *testing.T) { 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"), @@ -551,12 +576,12 @@ func TestInvalidMessageID(t *testing.T) { 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")) diff --git a/core/core_test.go b/core/core_test.go index 981ff19..e4fbf63 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -62,7 +62,7 @@ func TestSimpleRequest(t *testing.T) { 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{} @@ -85,10 +85,12 @@ func TestMultiRequest(t *testing.T) { 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} @@ -133,7 +135,7 @@ func TestNotifications(t *testing.T) { ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{ SwIfIndex: 3, AdminUpDown: 1, - }, false) + }) ctx.mockVpp.SendMsg(0, []byte{0}) // receive the notification @@ -204,7 +206,7 @@ func TestFullBuffer(t *testing.T) { // 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{}} } @@ -285,7 +287,7 @@ func TestSimpleRequestsWithSequenceNumbers(t *testing.T) { 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)) } @@ -302,10 +304,12 @@ func TestMultiRequestsWithSequenceNumbers(t *testing.T) { 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{}) @@ -336,7 +340,10 @@ func TestSimpleRequestWithTimeout(t *testing.T) { 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{} @@ -347,11 +354,19 @@ func TestSimpleRequestWithTimeout(t *testing.T) { 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) @@ -375,7 +390,10 @@ func TestSimpleRequestsWithMissingReply(t *testing.T) { 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) @@ -401,18 +419,42 @@ func TestMultiRequestsWithErrors(t *testing.T) { 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{}) @@ -454,12 +496,12 @@ func TestRequestsOrdering(t *testing.T) { // 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) @@ -484,11 +526,9 @@ func TestCycleOverSetOfSequenceNumbers(t *testing.T) { 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) } @@ -496,7 +536,7 @@ func TestCycleOverSetOfSequenceNumbers(t *testing.T) { 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 +} |