1 // Copyright (c) 2017 Cisco and/or its affiliates.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
21 . "github.com/onsi/gomega"
23 "git.fd.io/govpp.git/adapter/mock"
24 "git.fd.io/govpp.git/api"
25 "git.fd.io/govpp.git/examples/binapi/interfaces"
26 "git.fd.io/govpp.git/examples/binapi/memif"
27 "git.fd.io/govpp.git/examples/binapi/vpe"
31 mockVpp *mock.VppAdapter
36 func setupTest(t *testing.T) *testCtx {
40 mockVpp: mock.NewVppAdapter(),
44 ctx.conn, err = Connect(ctx.mockVpp)
45 Expect(err).ShouldNot(HaveOccurred())
47 ctx.ch, err = ctx.conn.NewAPIChannel()
48 Expect(err).ShouldNot(HaveOccurred())
53 func (ctx *testCtx) teardownTest() {
58 func TestRequestReplyMemifCreate(t *testing.T) {
60 defer ctx.teardownTest()
63 ctx.mockVpp.MockReply(&memif.MemifCreateReply{
67 request := &memif.MemifCreate{
73 reply := &memif.MemifCreateReply{}
75 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
76 Expect(err).ShouldNot(HaveOccurred())
77 Expect(reply.Retval).To(BeEquivalentTo(0),
78 "Incorrect Retval value for MemifCreate")
79 Expect(reply.SwIfIndex).To(BeEquivalentTo(4),
80 "Incorrect SwIfIndex value for MemifCreate")
83 func TestRequestReplyMemifDelete(t *testing.T) {
85 defer ctx.teardownTest()
88 ctx.mockVpp.MockReply(&memif.MemifDeleteReply{})
90 request := &memif.MemifDelete{
93 reply := &memif.MemifDeleteReply{}
95 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
96 Expect(err).ShouldNot(HaveOccurred())
99 func TestRequestReplyMemifDetails(t *testing.T) {
101 defer ctx.teardownTest()
104 ctx.mockVpp.MockReply(&memif.MemifDetails{
106 IfName: []byte("memif-name"),
110 request := &memif.MemifDump{}
111 reply := &memif.MemifDetails{}
113 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
114 Expect(err).ShouldNot(HaveOccurred())
115 Expect(reply.SwIfIndex).To(BeEquivalentTo(25),
116 "Incorrect SwIfIndex value for MemifDetails")
117 Expect(reply.IfName).ToNot(BeEmpty(),
118 "MemifDetails IfName is empty byte array")
119 Expect(reply.Role).To(BeEquivalentTo(0),
120 "Incorrect Role value for MemifDetails")
123 func TestMultiRequestReplySwInterfaceMemifDump(t *testing.T) {
125 defer ctx.teardownTest()
128 var msgs []api.Message
129 for i := 1; i <= 10; i++ {
130 msgs = append(msgs, &memif.MemifDetails{
131 SwIfIndex: uint32(i),
134 ctx.mockVpp.MockReply(msgs...)
135 ctx.mockVpp.MockReply(&ControlPingReply{})
137 reqCtx := ctx.ch.SendMultiRequest(&memif.MemifDump{})
140 msg := &memif.MemifDetails{}
141 stop, err := reqCtx.ReceiveReply(msg)
145 Expect(err).ShouldNot(HaveOccurred())
148 Expect(cnt).To(BeEquivalentTo(10))
151 func TestNotificationEvent(t *testing.T) {
153 defer ctx.teardownTest()
155 // subscribe for notification
156 notifChan := make(chan api.Message, 1)
157 sub, err := ctx.ch.SubscribeNotification(notifChan, &interfaces.SwInterfaceEvent{})
158 Expect(err).ShouldNot(HaveOccurred())
160 // mock event and force its delivery
161 ctx.mockVpp.MockReply(&interfaces.SwInterfaceEvent{
165 ctx.mockVpp.SendMsg(0, []byte(""))
167 // receive the notification
168 var notif *interfaces.SwInterfaceEvent
169 Eventually(func() *interfaces.SwInterfaceEvent {
171 case n := <-notifChan:
172 notif = n.(*interfaces.SwInterfaceEvent)
177 }).ShouldNot(BeNil())
179 // verify the received notifications
180 Expect(notif.SwIfIndex).To(BeEquivalentTo(2), "Incorrect SwIfIndex value for SwInterfaceSetFlags")
181 Expect(notif.LinkUpDown).To(BeEquivalentTo(1), "Incorrect LinkUpDown value for SwInterfaceSetFlags")
183 err = sub.Unsubscribe()
184 Expect(err).ShouldNot(HaveOccurred())
187 func TestSetReplyTimeout(t *testing.T) {
189 defer ctx.teardownTest()
191 ctx.ch.SetReplyTimeout(time.Millisecond)
194 ctx.mockVpp.MockReply(&ControlPingReply{})
196 // first one request should work
197 err := ctx.ch.SendRequest(&ControlPing{}).ReceiveReply(&ControlPingReply{})
198 Expect(err).ShouldNot(HaveOccurred())
200 // no other reply ready - expect timeout
201 err = ctx.ch.SendRequest(&ControlPing{}).ReceiveReply(&ControlPingReply{})
202 Expect(err).Should(HaveOccurred())
203 Expect(err.Error()).To(ContainSubstring("timeout"))
206 func TestSetReplyTimeoutMultiRequest(t *testing.T) {
208 defer ctx.teardownTest()
210 ctx.ch.SetReplyTimeout(time.Millisecond * 100)
213 ctx.mockVpp.MockReply(
214 &interfaces.SwInterfaceDetails{
216 InterfaceName: []byte("if-name-test"),
218 &interfaces.SwInterfaceDetails{
220 InterfaceName: []byte("if-name-test"),
222 &interfaces.SwInterfaceDetails{
224 InterfaceName: []byte("if-name-test"),
227 ctx.mockVpp.MockReply(&ControlPingReply{})
230 sendMultiRequest := func() error {
231 reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
233 msg := &interfaces.SwInterfaceDetails{}
234 stop, err := reqCtx.ReceiveReply(msg)
246 // first one request should work
247 err := sendMultiRequest()
248 Expect(err).ShouldNot(HaveOccurred())
250 // no other reply ready - expect timeout
251 err = sendMultiRequest()
252 Expect(err).Should(HaveOccurred())
253 Expect(err.Error()).To(ContainSubstring("timeout"))
255 Expect(cnt).To(BeEquivalentTo(3))
258 func TestReceiveReplyNegative(t *testing.T) {
260 defer ctx.teardownTest()
263 reqCtx1 := &requestCtx{}
264 err := reqCtx1.ReceiveReply(&ControlPingReply{})
265 Expect(err).Should(HaveOccurred())
266 Expect(err.Error()).To(ContainSubstring("invalid request context"))
269 reqCtx2 := &multiRequestCtx{}
270 _, err = reqCtx2.ReceiveReply(&ControlPingReply{})
271 Expect(err).Should(HaveOccurred())
272 Expect(err.Error()).To(ContainSubstring("invalid request context"))
275 reqCtx3 := &requestCtx{}
276 err = reqCtx3.ReceiveReply(nil)
277 Expect(err).Should(HaveOccurred())
278 Expect(err.Error()).To(ContainSubstring("invalid request context"))
281 func TestMultiRequestDouble(t *testing.T) {
283 defer ctx.teardownTest()
286 var msgs []mock.MsgWithContext
287 for i := 1; i <= 3; i++ {
288 msgs = append(msgs, mock.MsgWithContext{
289 Msg: &interfaces.SwInterfaceDetails{
290 SwIfIndex: uint32(i),
291 InterfaceName: []byte("if-name-test"),
297 msgs = append(msgs, mock.MsgWithContext{Msg: &ControlPingReply{}, Multipart: true, SeqNum: 1})
299 for i := 1; i <= 3; i++ {
302 Msg: &interfaces.SwInterfaceDetails{
303 SwIfIndex: uint32(i),
304 InterfaceName: []byte("if-name-test"),
310 msgs = append(msgs, mock.MsgWithContext{Msg: &ControlPingReply{}, Multipart: true, SeqNum: 2})
312 ctx.mockVpp.MockReplyWithContext(msgs...)
315 var sendMultiRequest = func() error {
316 reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
318 msg := &interfaces.SwInterfaceDetails{}
319 stop, err := reqCtx.ReceiveReply(msg)
331 err := sendMultiRequest()
332 Expect(err).ShouldNot(HaveOccurred())
334 err = sendMultiRequest()
335 Expect(err).ShouldNot(HaveOccurred())
337 Expect(cnt).To(BeEquivalentTo(6))
340 func TestReceiveReplyAfterTimeout(t *testing.T) {
342 defer ctx.teardownTest()
344 ctx.ch.SetReplyTimeout(time.Millisecond)
347 ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{Msg: &ControlPingReply{}, SeqNum: 1})
348 // first one request should work
350 err := ctx.ch.SendRequest(&ControlPing{}).ReceiveReply(&ControlPingReply{})
351 Expect(err).ShouldNot(HaveOccurred())
353 err = ctx.ch.SendRequest(&ControlPing{}).ReceiveReply(&ControlPingReply{})
354 Expect(err).Should(HaveOccurred())
355 Expect(err.Error()).To(ContainSubstring("timeout"))
357 ctx.mockVpp.MockReplyWithContext(
358 // simulating late reply
360 Msg: &ControlPingReply{},
363 // normal reply for next request
365 Msg: &interfaces.SwInterfaceSetFlagsReply{},
370 req := &interfaces.SwInterfaceSetFlags{
374 reply := &interfaces.SwInterfaceSetFlagsReply{}
377 err = ctx.ch.SendRequest(req).ReceiveReply(reply)
378 Expect(err).ShouldNot(HaveOccurred())
381 func TestReceiveReplyAfterTimeoutMultiRequest(t *testing.T) {
383 TODO: fix mock adapter
384 This test will fail because mock adapter will stop sending replies
385 when it encounters control_ping_reply from multi request,
386 thus never sending reply for next request
391 defer ctx.teardownTest()
393 ctx.ch.SetReplyTimeout(time.Millisecond * 100)
396 ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{Msg: &ControlPingReply{}, SeqNum: 1})
398 // first one request should work
399 err := ctx.ch.SendRequest(&ControlPing{}).ReceiveReply(&ControlPingReply{})
400 Expect(err).ShouldNot(HaveOccurred())
403 var sendMultiRequest = func() error {
404 reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
406 msg := &interfaces.SwInterfaceDetails{}
407 stop, err := reqCtx.ReceiveReply(msg)
419 err = sendMultiRequest()
420 Expect(err).Should(HaveOccurred())
421 Expect(err.Error()).To(ContainSubstring("timeout"))
422 Expect(cnt).To(BeEquivalentTo(0))
424 // simulating late replies
425 var msgs []mock.MsgWithContext
426 for i := 1; i <= 3; i++ {
427 msgs = append(msgs, mock.MsgWithContext{
428 Msg: &interfaces.SwInterfaceDetails{
429 SwIfIndex: uint32(i),
430 InterfaceName: []byte("if-name-test"),
436 msgs = append(msgs, mock.MsgWithContext{Msg: &ControlPingReply{}, Multipart: true, SeqNum: 2})
437 ctx.mockVpp.MockReplyWithContext(msgs...)
439 // normal reply for next request
440 ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{Msg: &interfaces.SwInterfaceSetFlagsReply{}, SeqNum: 3})
442 req := &interfaces.SwInterfaceSetFlags{
446 reply := &interfaces.SwInterfaceSetFlagsReply{}
449 err = ctx.ch.SendRequest(req).ReceiveReply(reply)
450 Expect(err).ShouldNot(HaveOccurred())
453 func TestInvalidMessageID(t *testing.T) {
455 defer ctx.teardownTest()
458 ctx.mockVpp.MockReply(&vpe.ShowVersionReply{})
459 ctx.mockVpp.MockReply(&vpe.ShowVersionReply{})
461 // first one request should work
462 err := ctx.ch.SendRequest(&vpe.ShowVersion{}).ReceiveReply(&vpe.ShowVersionReply{})
463 Expect(err).ShouldNot(HaveOccurred())
465 // second should fail with error invalid message ID
466 err = ctx.ch.SendRequest(&ControlPing{}).ReceiveReply(&ControlPingReply{})
467 Expect(err).Should(HaveOccurred())
468 Expect(err.Error()).To(ContainSubstring("invalid message ID"))