Merge "Remove map usage via pointers"
[govpp.git] / api / api_test.go
1 // Copyright (c) 2017 Cisco and/or its affiliates.
2 //
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:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 package api_test
16
17 import (
18         "testing"
19         "time"
20
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"
28
29         . "github.com/onsi/gomega"
30 )
31
32 type testCtx struct {
33         mockVpp *mock.VppAdapter
34         conn    *core.Connection
35         ch      *api.Channel
36 }
37
38 func setupTest(t *testing.T) *testCtx {
39         RegisterTestingT(t)
40
41         ctx := &testCtx{
42                 mockVpp: &mock.VppAdapter{},
43         }
44
45         var err error
46         ctx.conn, err = core.Connect(ctx.mockVpp)
47         Expect(err).ShouldNot(HaveOccurred())
48
49         ctx.ch, err = ctx.conn.NewAPIChannel()
50         Expect(err).ShouldNot(HaveOccurred())
51
52         return ctx
53 }
54
55 func (ctx *testCtx) teardownTest() {
56         ctx.ch.Close()
57         ctx.conn.Disconnect()
58 }
59
60 func TestRequestReplyTapConnect(t *testing.T) {
61         ctx := setupTest(t)
62         defer ctx.teardownTest()
63
64         ctx.mockVpp.MockReply(&tap.TapConnectReply{
65                 Retval:    10,
66                 SwIfIndex: 1,
67         })
68         request := &tap.TapConnect{
69                 TapName:      []byte("test-tap-name"),
70                 UseRandomMac: 1,
71         }
72         reply := &tap.TapConnectReply{}
73
74         err := ctx.ch.SendRequest(request).ReceiveReply(reply)
75         Expect(err).ShouldNot(HaveOccurred())
76         Expect(reply.Retval).To(BeEquivalentTo(10), "Incorrect retval value for TapConnectReply")
77         Expect(reply.SwIfIndex).To(BeEquivalentTo(1), "Incorrect SwIfIndex value for TapConnectReply")
78 }
79
80 func TestRequestReplyTapModify(t *testing.T) {
81         ctx := setupTest(t)
82         defer ctx.teardownTest()
83
84         ctx.mockVpp.MockReply(&tap.TapModifyReply{
85                 Retval:    15,
86                 SwIfIndex: 2,
87         })
88         request := &tap.TapModify{
89                 TapName:           []byte("test-tap-modify"),
90                 UseRandomMac:      1,
91                 CustomDevInstance: 1,
92         }
93         reply := &tap.TapModifyReply{}
94
95         err := ctx.ch.SendRequest(request).ReceiveReply(reply)
96         Expect(err).ShouldNot(HaveOccurred())
97         Expect(reply.Retval).To(BeEquivalentTo(15), "Incorrect retval value for TapModifyReply")
98         Expect(reply.SwIfIndex).To(BeEquivalentTo(2), "Incorrect SwIfIndex value for TapModifyReply")
99 }
100
101 func TestRequestReplyTapDelete(t *testing.T) {
102         ctx := setupTest(t)
103         defer ctx.teardownTest()
104
105         ctx.mockVpp.MockReply(&tap.TapDeleteReply{
106                 Retval: 20,
107         })
108         request := &tap.TapDelete{
109                 SwIfIndex: 3,
110         }
111         reply := &tap.TapDeleteReply{}
112
113         err := ctx.ch.SendRequest(request).ReceiveReply(reply)
114         Expect(err).ShouldNot(HaveOccurred())
115         Expect(reply.Retval).To(BeEquivalentTo(20), "Incorrect retval value for TapDeleteReply")
116 }
117
118 func TestRequestReplySwInterfaceTapDump(t *testing.T) {
119         ctx := setupTest(t)
120         defer ctx.teardownTest()
121
122         byteName := []byte("dev-name-test")
123         ctx.mockVpp.MockReply(&tap.SwInterfaceTapDetails{
124                 SwIfIndex: 25,
125                 DevName:   byteName,
126         })
127         request := &tap.SwInterfaceTapDump{}
128         reply := &tap.SwInterfaceTapDetails{}
129
130         err := ctx.ch.SendRequest(request).ReceiveReply(reply)
131         Expect(err).ShouldNot(HaveOccurred())
132         Expect(reply.SwIfIndex).To(BeEquivalentTo(25), "Incorrect SwIfIndex value for SwInterfaceTapDetails")
133         Expect(reply.DevName).ToNot(BeNil(), "Incorrect DevName value for SwInterfaceTapDetails")
134 }
135
136 func TestRequestReplyMemifCreate(t *testing.T) {
137         ctx := setupTest(t)
138         defer ctx.teardownTest()
139
140         ctx.mockVpp.MockReply(&memif.MemifCreateReply{
141                 Retval:    22,
142                 SwIfIndex: 4,
143         })
144         request := &memif.MemifCreate{
145                 Role:       10,
146                 ID:         12,
147                 RingSize:   8000,
148                 BufferSize: 50,
149         }
150         reply := &memif.MemifCreateReply{}
151
152         err := ctx.ch.SendRequest(request).ReceiveReply(reply)
153         Expect(err).ShouldNot(HaveOccurred())
154         Expect(reply.Retval).To(BeEquivalentTo(22), "Incorrect Retval value for MemifCreate")
155         Expect(reply.SwIfIndex).To(BeEquivalentTo(4), "Incorrect SwIfIndex value for MemifCreate")
156 }
157
158 func TestRequestReplyMemifDelete(t *testing.T) {
159         ctx := setupTest(t)
160         defer ctx.teardownTest()
161
162         ctx.mockVpp.MockReply(&memif.MemifDeleteReply{
163                 Retval: 24,
164         })
165         request := &memif.MemifDelete{
166                 SwIfIndex: 15,
167         }
168         reply := &memif.MemifDeleteReply{}
169
170         err := ctx.ch.SendRequest(request).ReceiveReply(reply)
171         Expect(err).ShouldNot(HaveOccurred())
172         Expect(reply.Retval).To(BeEquivalentTo(24), "Incorrect Retval value for MemifDelete")
173 }
174
175 func TestRequestReplyMemifDetails(t *testing.T) {
176         ctx := setupTest(t)
177         defer ctx.teardownTest()
178
179         ctx.mockVpp.MockReply(&memif.MemifDetails{
180                 SwIfIndex: 25,
181                 IfName:    []byte("memif-name"),
182                 Role:      0,
183         })
184         request := &memif.MemifDump{}
185         reply := &memif.MemifDetails{}
186
187         err := ctx.ch.SendRequest(request).ReceiveReply(reply)
188         Expect(err).ShouldNot(HaveOccurred())
189         Expect(reply.SwIfIndex).To(BeEquivalentTo(25), "Incorrect SwIfIndex value for MemifDetails")
190         Expect(reply.IfName).ToNot(BeEmpty(), "MemifDetails IfName is empty byte array")
191         Expect(reply.Role).To(BeEquivalentTo(0), "Incorrect Role value for MemifDetails")
192 }
193
194 func TestMultiRequestReplySwInterfaceTapDump(t *testing.T) {
195         ctx := setupTest(t)
196         defer ctx.teardownTest()
197
198         // mock reply
199         for i := 1; i <= 10; i++ {
200                 byteName := []byte("dev-name-test")
201                 ctx.mockVpp.MockReply(&tap.SwInterfaceTapDetails{
202                         SwIfIndex: uint32(i),
203                         DevName:   byteName,
204                 })
205         }
206         ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
207
208         reqCtx := ctx.ch.SendMultiRequest(&tap.SwInterfaceTapDump{})
209         cnt := 0
210         for {
211                 msg := &tap.SwInterfaceTapDetails{}
212                 stop, err := reqCtx.ReceiveReply(msg)
213                 if stop {
214                         break // break out of the loop
215                 }
216                 Expect(err).ShouldNot(HaveOccurred())
217                 cnt++
218         }
219         Expect(cnt).To(BeEquivalentTo(10))
220 }
221
222 func TestMultiRequestReplySwInterfaceMemifDump(t *testing.T) {
223         ctx := setupTest(t)
224         defer ctx.teardownTest()
225
226         // mock reply
227         for i := 1; i <= 10; i++ {
228                 ctx.mockVpp.MockReply(&memif.MemifDetails{
229                         SwIfIndex: uint32(i),
230                 })
231         }
232         ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
233
234         reqCtx := ctx.ch.SendMultiRequest(&memif.MemifDump{})
235         cnt := 0
236         for {
237                 msg := &memif.MemifDetails{}
238                 stop, err := reqCtx.ReceiveReply(msg)
239                 if stop {
240                         break // break out of the loop
241                 }
242                 Expect(err).ShouldNot(HaveOccurred())
243                 cnt++
244         }
245         Expect(cnt).To(BeEquivalentTo(10))
246 }
247
248 func TestNotifications(t *testing.T) {
249         ctx := setupTest(t)
250         defer ctx.teardownTest()
251
252         // subscribe for notification
253         notifChan := make(chan api.Message, 1)
254         subs, err := ctx.ch.SubscribeNotification(notifChan, interfaces.NewSwInterfaceSetFlags)
255         Expect(err).ShouldNot(HaveOccurred())
256
257         // mock the notification and force its delivery
258         ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{
259                 SwIfIndex:   3,
260                 AdminUpDown: 1,
261         })
262         ctx.mockVpp.SendMsg(0, []byte(""))
263
264         // receive the notification
265         var notif *interfaces.SwInterfaceSetFlags
266         Eventually(func() *interfaces.SwInterfaceSetFlags {
267                 select {
268                 case n := <-notifChan:
269                         notif = n.(*interfaces.SwInterfaceSetFlags)
270                         return notif
271                 default:
272                         return nil
273                 }
274         }).ShouldNot(BeNil())
275
276         // verify the received notifications
277         Expect(notif.SwIfIndex).To(BeEquivalentTo(3), "Incorrect SwIfIndex value for SwInterfaceSetFlags")
278         Expect(notif.AdminUpDown).To(BeEquivalentTo(1), "Incorrect AdminUpDown value for SwInterfaceSetFlags")
279
280         ctx.ch.UnsubscribeNotification(subs)
281 }
282
283 func TestNotificationEvent(t *testing.T) {
284         ctx := setupTest(t)
285         defer ctx.teardownTest()
286
287         // subscribe for notification
288         notifChan := make(chan api.Message, 1)
289         subs, err := ctx.ch.SubscribeNotification(notifChan, interfaces.NewSwInterfaceEvent)
290         Expect(err).ShouldNot(HaveOccurred())
291
292         // mock the notification and force its delivery
293         ctx.mockVpp.MockReply(&interfaces.SwInterfaceEvent{
294                 SwIfIndex:  2,
295                 LinkUpDown: 1,
296         })
297         ctx.mockVpp.SendMsg(0, []byte(""))
298
299         // receive the notification
300         var notif *interfaces.SwInterfaceEvent
301         Eventually(func() *interfaces.SwInterfaceEvent {
302                 select {
303                 case n := <-notifChan:
304                         notif = n.(*interfaces.SwInterfaceEvent)
305                         return notif
306                 default:
307                         return nil
308                 }
309         }).ShouldNot(BeNil())
310
311         // verify the received notifications
312         Expect(notif.SwIfIndex).To(BeEquivalentTo(2), "Incorrect SwIfIndex value for SwInterfaceSetFlags")
313         Expect(notif.LinkUpDown).To(BeEquivalentTo(1), "Incorrect LinkUpDown value for SwInterfaceSetFlags")
314
315         ctx.ch.UnsubscribeNotification(subs)
316 }
317
318 func TestCheckMessageCompatibility(t *testing.T) {
319         ctx := setupTest(t)
320         defer ctx.teardownTest()
321
322         err := ctx.ch.CheckMessageCompatibility(&interfaces.SwInterfaceSetFlags{})
323         Expect(err).ShouldNot(HaveOccurred())
324 }
325
326 func TestSetReplyTimeout(t *testing.T) {
327         ctx := setupTest(t)
328         defer ctx.teardownTest()
329
330         ctx.ch.SetReplyTimeout(time.Millisecond)
331
332         // first one request should work
333         ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
334         err := ctx.ch.SendRequest(&vpe.ControlPing{}).ReceiveReply(&vpe.ControlPingReply{})
335         Expect(err).ShouldNot(HaveOccurred())
336
337         // no other reply ready - expect timeout
338         err = ctx.ch.SendRequest(&vpe.ControlPing{}).ReceiveReply(&vpe.ControlPingReply{})
339         Expect(err).Should(HaveOccurred())
340         Expect(err.Error()).To(ContainSubstring("timeout"))
341 }
342
343 func TestReceiveReplyNegative(t *testing.T) {
344         ctx := setupTest(t)
345         defer ctx.teardownTest()
346
347         // invalid context 1
348         reqCtx1 := &api.RequestCtx{}
349         err := reqCtx1.ReceiveReply(&vpe.ControlPingReply{})
350         Expect(err).Should(HaveOccurred())
351         Expect(err.Error()).To(ContainSubstring("invalid request context"))
352
353         // invalid context 2
354         reqCtx2 := &api.MultiRequestCtx{}
355         _, err = reqCtx2.ReceiveReply(&vpe.ControlPingReply{})
356         Expect(err).Should(HaveOccurred())
357         Expect(err.Error()).To(ContainSubstring("invalid request context"))
358
359         // NU
360         reqCtx3 := &api.RequestCtx{}
361         err = reqCtx3.ReceiveReply(nil)
362         Expect(err).Should(HaveOccurred())
363         Expect(err.Error()).To(ContainSubstring("invalid request context"))
364 }