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 "git.fd.io/govpp.git/adapter/mock"
22 "git.fd.io/govpp.git/api"
23 "git.fd.io/govpp.git/core"
24 "git.fd.io/govpp.git/core/bin_api/vpe"
25 "git.fd.io/govpp.git/examples/bin_api/interfaces"
26 "git.fd.io/govpp.git/examples/bin_api/memif"
27 "git.fd.io/govpp.git/examples/bin_api/tap"
29 . "github.com/onsi/gomega"
33 mockVpp *mock.VppAdapter
38 func setupTest(t *testing.T) *testCtx {
42 mockVpp: &mock.VppAdapter{},
46 ctx.conn, err = core.Connect(ctx.mockVpp)
47 Expect(err).ShouldNot(HaveOccurred())
49 ctx.ch, err = ctx.conn.NewAPIChannel()
50 Expect(err).ShouldNot(HaveOccurred())
52 ctx.ch.SetReplyTimeout(time.Millisecond)
57 func (ctx *testCtx) teardownTest() {
62 func TestRequestReplyTapConnect(t *testing.T) {
64 defer ctx.teardownTest()
66 ctx.mockVpp.MockReply(&tap.TapConnectReply{
70 request := &tap.TapConnect{
71 TapName: []byte("test-tap-name"),
74 reply := &tap.TapConnectReply{}
76 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
77 Expect(err).ShouldNot(HaveOccurred())
78 Expect(reply.Retval).To(BeEquivalentTo(10), "Incorrect retval value for TapConnectReply")
79 Expect(reply.SwIfIndex).To(BeEquivalentTo(1), "Incorrect SwIfIndex value for TapConnectReply")
82 func TestRequestReplyTapModify(t *testing.T) {
84 defer ctx.teardownTest()
86 ctx.mockVpp.MockReply(&tap.TapModifyReply{
90 request := &tap.TapModify{
91 TapName: []byte("test-tap-modify"),
95 reply := &tap.TapModifyReply{}
97 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
98 Expect(err).ShouldNot(HaveOccurred())
99 Expect(reply.Retval).To(BeEquivalentTo(15), "Incorrect retval value for TapModifyReply")
100 Expect(reply.SwIfIndex).To(BeEquivalentTo(2), "Incorrect SwIfIndex value for TapModifyReply")
103 func TestRequestReplyTapDelete(t *testing.T) {
105 defer ctx.teardownTest()
107 ctx.mockVpp.MockReply(&tap.TapDeleteReply{
110 request := &tap.TapDelete{
113 reply := &tap.TapDeleteReply{}
115 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
116 Expect(err).ShouldNot(HaveOccurred())
117 Expect(reply.Retval).To(BeEquivalentTo(20), "Incorrect retval value for TapDeleteReply")
120 func TestRequestReplySwInterfaceTapDump(t *testing.T) {
122 defer ctx.teardownTest()
124 byteName := []byte("dev-name-test")
125 ctx.mockVpp.MockReply(&tap.SwInterfaceTapDetails{
129 request := &tap.SwInterfaceTapDump{}
130 reply := &tap.SwInterfaceTapDetails{}
132 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
133 Expect(err).ShouldNot(HaveOccurred())
134 Expect(reply.SwIfIndex).To(BeEquivalentTo(25), "Incorrect SwIfIndex value for SwInterfaceTapDetails")
135 Expect(reply.DevName).ToNot(BeNil(), "Incorrect DevName value for SwInterfaceTapDetails")
138 func TestRequestReplyMemifCreate(t *testing.T) {
140 defer ctx.teardownTest()
142 ctx.mockVpp.MockReply(&memif.MemifCreateReply{
146 request := &memif.MemifCreate{
152 reply := &memif.MemifCreateReply{}
154 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
155 Expect(err).ShouldNot(HaveOccurred())
156 Expect(reply.Retval).To(BeEquivalentTo(22), "Incorrect Retval value for MemifCreate")
157 Expect(reply.SwIfIndex).To(BeEquivalentTo(4), "Incorrect SwIfIndex value for MemifCreate")
160 func TestRequestReplyMemifDelete(t *testing.T) {
162 defer ctx.teardownTest()
164 ctx.mockVpp.MockReply(&memif.MemifDeleteReply{
167 request := &memif.MemifDelete{
170 reply := &memif.MemifDeleteReply{}
172 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
173 Expect(err).ShouldNot(HaveOccurred())
174 Expect(reply.Retval).To(BeEquivalentTo(24), "Incorrect Retval value for MemifDelete")
177 func TestRequestReplyMemifDetails(t *testing.T) {
179 defer ctx.teardownTest()
181 ctx.mockVpp.MockReply(&memif.MemifDetails{
183 IfName: []byte("memif-name"),
186 request := &memif.MemifDump{}
187 reply := &memif.MemifDetails{}
189 err := ctx.ch.SendRequest(request).ReceiveReply(reply)
190 Expect(err).ShouldNot(HaveOccurred())
191 Expect(reply.SwIfIndex).To(BeEquivalentTo(25), "Incorrect SwIfIndex value for MemifDetails")
192 Expect(reply.IfName).ToNot(BeEmpty(), "MemifDetails IfName is empty byte array")
193 Expect(reply.Role).To(BeEquivalentTo(0), "Incorrect Role value for MemifDetails")
196 func TestMultiRequestReplySwInterfaceTapDump(t *testing.T) {
198 defer ctx.teardownTest()
201 for i := 1; i <= 10; i++ {
202 ctx.mockVpp.MockReply(&tap.SwInterfaceTapDetails{
203 SwIfIndex: uint32(i),
204 DevName: []byte("dev-name-test"),
207 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
209 reqCtx := ctx.ch.SendMultiRequest(&tap.SwInterfaceTapDump{})
212 msg := &tap.SwInterfaceTapDetails{}
213 stop, err := reqCtx.ReceiveReply(msg)
215 break // break out of the loop
217 Expect(err).ShouldNot(HaveOccurred())
220 Expect(cnt).To(BeEquivalentTo(10))
223 func TestMultiRequestReplySwInterfaceMemifDump(t *testing.T) {
225 defer ctx.teardownTest()
228 for i := 1; i <= 10; i++ {
229 ctx.mockVpp.MockReply(&memif.MemifDetails{
230 SwIfIndex: uint32(i),
233 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
235 reqCtx := ctx.ch.SendMultiRequest(&memif.MemifDump{})
238 msg := &memif.MemifDetails{}
239 stop, err := reqCtx.ReceiveReply(msg)
241 break // break out of the loop
243 Expect(err).ShouldNot(HaveOccurred())
246 Expect(cnt).To(BeEquivalentTo(10))
249 func TestNotifications(t *testing.T) {
251 defer ctx.teardownTest()
253 // subscribe for notification
254 notifChan := make(chan api.Message, 1)
255 subs, err := ctx.ch.SubscribeNotification(notifChan, interfaces.NewSwInterfaceSetFlags)
256 Expect(err).ShouldNot(HaveOccurred())
258 // mock the notification and force its delivery
259 ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{
263 ctx.mockVpp.SendMsg(0, []byte(""))
265 // receive the notification
266 var notif *interfaces.SwInterfaceSetFlags
267 Eventually(func() *interfaces.SwInterfaceSetFlags {
269 case n := <-notifChan:
270 notif = n.(*interfaces.SwInterfaceSetFlags)
275 }).ShouldNot(BeNil())
277 // verify the received notifications
278 Expect(notif.SwIfIndex).To(BeEquivalentTo(3), "Incorrect SwIfIndex value for SwInterfaceSetFlags")
279 Expect(notif.AdminUpDown).To(BeEquivalentTo(1), "Incorrect AdminUpDown value for SwInterfaceSetFlags")
281 ctx.ch.UnsubscribeNotification(subs)
284 func TestNotificationEvent(t *testing.T) {
286 defer ctx.teardownTest()
288 // subscribe for notification
289 notifChan := make(chan api.Message, 1)
290 subs, err := ctx.ch.SubscribeNotification(notifChan, interfaces.NewSwInterfaceEvent)
291 Expect(err).ShouldNot(HaveOccurred())
293 // mock the notification and force its delivery
294 ctx.mockVpp.MockReply(&interfaces.SwInterfaceEvent{
298 ctx.mockVpp.SendMsg(0, []byte(""))
300 // receive the notification
301 var notif *interfaces.SwInterfaceEvent
302 Eventually(func() *interfaces.SwInterfaceEvent {
304 case n := <-notifChan:
305 notif = n.(*interfaces.SwInterfaceEvent)
310 }).ShouldNot(BeNil())
312 // verify the received notifications
313 Expect(notif.SwIfIndex).To(BeEquivalentTo(2), "Incorrect SwIfIndex value for SwInterfaceSetFlags")
314 Expect(notif.LinkUpDown).To(BeEquivalentTo(1), "Incorrect LinkUpDown value for SwInterfaceSetFlags")
316 ctx.ch.UnsubscribeNotification(subs)
319 func TestCheckMessageCompatibility(t *testing.T) {
321 defer ctx.teardownTest()
323 err := ctx.ch.CheckMessageCompatibility(&interfaces.SwInterfaceSetFlags{})
324 Expect(err).ShouldNot(HaveOccurred())
327 func TestSetReplyTimeout(t *testing.T) {
329 defer ctx.teardownTest()
331 // first one request should work
332 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
333 err := ctx.ch.SendRequest(&vpe.ControlPing{}).ReceiveReply(&vpe.ControlPingReply{})
334 Expect(err).ShouldNot(HaveOccurred())
336 // no other reply ready - expect timeout
337 err = ctx.ch.SendRequest(&vpe.ControlPing{}).ReceiveReply(&vpe.ControlPingReply{})
338 Expect(err).Should(HaveOccurred())
339 Expect(err.Error()).To(ContainSubstring("timeout"))
342 func TestSetReplyTimeoutMultiRequest(t *testing.T) {
344 defer ctx.teardownTest()
346 for i := 1; i <= 3; i++ {
347 ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{
348 SwIfIndex: uint32(i),
349 InterfaceName: []byte("if-name-test"),
352 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
355 sendMultiRequest := func() error {
356 reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
358 msg := &interfaces.SwInterfaceDetails{}
359 stop, err := reqCtx.ReceiveReply(msg)
361 break // break out of the loop
371 // first one request should work
372 err := sendMultiRequest()
373 Expect(err).ShouldNot(HaveOccurred())
375 // no other reply ready - expect timeout
376 err = sendMultiRequest()
377 Expect(err).Should(HaveOccurred())
378 Expect(err.Error()).To(ContainSubstring("timeout"))
380 Expect(cnt).To(BeEquivalentTo(3))
383 func TestReceiveReplyNegative(t *testing.T) {
385 defer ctx.teardownTest()
388 reqCtx1 := &api.RequestCtx{}
389 err := reqCtx1.ReceiveReply(&vpe.ControlPingReply{})
390 Expect(err).Should(HaveOccurred())
391 Expect(err.Error()).To(ContainSubstring("invalid request context"))
394 reqCtx2 := &api.MultiRequestCtx{}
395 _, err = reqCtx2.ReceiveReply(&vpe.ControlPingReply{})
396 Expect(err).Should(HaveOccurred())
397 Expect(err.Error()).To(ContainSubstring("invalid request context"))
400 reqCtx3 := &api.RequestCtx{}
401 err = reqCtx3.ReceiveReply(nil)
402 Expect(err).Should(HaveOccurred())
403 Expect(err.Error()).To(ContainSubstring("invalid request context"))
406 func TestMultiRequestDouble(t *testing.T) {
408 defer ctx.teardownTest()
411 for i := 1; i <= 3; i++ {
412 ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{
413 SwIfIndex: uint32(i),
414 InterfaceName: []byte("if-name-test"),
417 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
418 for i := 1; i <= 3; i++ {
419 ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{
420 SwIfIndex: uint32(i),
421 InterfaceName: []byte("if-name-test"),
424 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
427 sendMultiRequest := func() error {
428 reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
430 msg := &interfaces.SwInterfaceDetails{}
431 stop, err := reqCtx.ReceiveReply(msg)
433 break // break out of the loop
443 err := sendMultiRequest()
444 Expect(err).ShouldNot(HaveOccurred())
446 err = sendMultiRequest()
447 Expect(err).ShouldNot(HaveOccurred())
449 Expect(cnt).To(BeEquivalentTo(6))