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