support for shm prefixes
[govpp.git] / core / core_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 core_test
16
17 import (
18         "testing"
19
20         "git.fd.io/govpp.git/adapter/mock"
21         "git.fd.io/govpp.git/api"
22         "git.fd.io/govpp.git/core"
23         "git.fd.io/govpp.git/core/bin_api/vpe"
24         "git.fd.io/govpp.git/examples/bin_api/interfaces"
25         "git.fd.io/govpp.git/examples/bin_api/stats"
26
27         . "github.com/onsi/gomega"
28 )
29
30 type testCtx struct {
31         mockVpp *mock.VppAdapter
32         conn    *core.Connection
33         ch      *api.Channel
34 }
35
36 func setupTest(t *testing.T) *testCtx {
37         RegisterTestingT(t)
38
39         ctx := &testCtx{}
40         ctx.mockVpp = &mock.VppAdapter{}
41
42         var err error
43         ctx.conn, err = core.Connect(ctx.mockVpp)
44         Expect(err).ShouldNot(HaveOccurred())
45
46         ctx.ch, err = ctx.conn.NewAPIChannel()
47         Expect(err).ShouldNot(HaveOccurred())
48
49         return ctx
50 }
51
52 func (ctx *testCtx) teardownTest() {
53         ctx.ch.Close()
54         ctx.conn.Disconnect()
55 }
56
57 func TestSimpleRequest(t *testing.T) {
58         ctx := setupTest(t)
59         defer ctx.teardownTest()
60
61         ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: -5})
62
63         req := &vpe.ControlPing{}
64         reply := &vpe.ControlPingReply{}
65
66         // send the request and receive a reply
67         ctx.ch.ReqChan <- &api.VppRequest{Message: req}
68         vppReply := <-ctx.ch.ReplyChan
69
70         Expect(vppReply).ShouldNot(BeNil())
71         Expect(vppReply.Error).ShouldNot(HaveOccurred())
72
73         // decode the message
74         err := ctx.ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
75         Expect(err).ShouldNot(HaveOccurred())
76
77         Expect(reply.Retval).To(BeEquivalentTo(-5))
78 }
79
80 func TestMultiRequest(t *testing.T) {
81         ctx := setupTest(t)
82         defer ctx.teardownTest()
83
84         for m := 0; m < 10; m++ {
85                 ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{})
86         }
87         ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
88
89         // send multipart request
90         ctx.ch.ReqChan <- &api.VppRequest{Message: &interfaces.SwInterfaceDump{}, Multipart: true}
91
92         cnt := 0
93         for {
94                 // receive a reply
95                 vppReply := <-ctx.ch.ReplyChan
96                 if vppReply.LastReplyReceived {
97                         break // break out of the loop
98                 }
99                 Expect(vppReply.Error).ShouldNot(HaveOccurred())
100
101                 // decode the message
102                 reply := &interfaces.SwInterfaceDetails{}
103                 err := ctx.ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
104                 Expect(err).ShouldNot(HaveOccurred())
105                 cnt++
106         }
107
108         Expect(cnt).To(BeEquivalentTo(10))
109 }
110
111 func TestNotifications(t *testing.T) {
112         ctx := setupTest(t)
113         defer ctx.teardownTest()
114
115         // subscribe for notification
116         notifChan := make(chan api.Message, 1)
117         subscription := &api.NotifSubscription{
118                 NotifChan:  notifChan,
119                 MsgFactory: interfaces.NewSwInterfaceSetFlags,
120         }
121         ctx.ch.NotifSubsChan <- &api.NotifSubscribeRequest{
122                 Subscription: subscription,
123                 Subscribe:    true,
124         }
125         err := <-ctx.ch.NotifSubsReplyChan
126         Expect(err).ShouldNot(HaveOccurred())
127
128         // mock the notification and force its delivery
129         ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{
130                 SwIfIndex:   3,
131                 AdminUpDown: 1,
132         })
133         ctx.mockVpp.SendMsg(0, []byte{0})
134
135         // receive the notification
136         notif := (<-notifChan).(*interfaces.SwInterfaceSetFlags)
137
138         Expect(notif.SwIfIndex).To(BeEquivalentTo(3))
139
140         // unsubscribe notification
141         ctx.ch.NotifSubsChan <- &api.NotifSubscribeRequest{
142                 Subscription: subscription,
143                 Subscribe:    false,
144         }
145         err = <-ctx.ch.NotifSubsReplyChan
146         Expect(err).ShouldNot(HaveOccurred())
147 }
148
149 func TestNilConnection(t *testing.T) {
150         RegisterTestingT(t)
151         var conn *core.Connection
152
153         ch, err := conn.NewAPIChannel()
154         Expect(ch).Should(BeNil())
155         Expect(err).Should(HaveOccurred())
156         Expect(err.Error()).To(ContainSubstring("nil"))
157
158         ch, err = conn.NewAPIChannelBuffered(1, 1)
159         Expect(ch).Should(BeNil())
160         Expect(err).Should(HaveOccurred())
161         Expect(err.Error()).To(ContainSubstring("nil"))
162 }
163
164 func TestDoubleConnection(t *testing.T) {
165         ctx := setupTest(t)
166         defer ctx.teardownTest()
167
168         conn, err := core.Connect(ctx.mockVpp)
169         Expect(err).Should(HaveOccurred())
170         Expect(err.Error()).To(ContainSubstring("only one connection per process"))
171         Expect(conn).Should(BeNil())
172 }
173
174 func TestAsyncConnection(t *testing.T) {
175         ctx := setupTest(t)
176         defer ctx.teardownTest()
177
178         ctx.conn.Disconnect()
179         conn, ch, err := core.AsyncConnect(ctx.mockVpp)
180         ctx.conn = conn
181
182         Expect(err).ShouldNot(HaveOccurred())
183         Expect(conn).ShouldNot(BeNil())
184
185         ev := <-ch
186         Expect(ev.State).Should(BeEquivalentTo(core.Connected))
187 }
188
189 func TestFullBuffer(t *testing.T) {
190         ctx := setupTest(t)
191         defer ctx.teardownTest()
192
193         // close the default API channel
194         ctx.ch.Close()
195
196         // create a new channel with limited buffer sizes
197         var err error
198         ctx.ch, err = ctx.conn.NewAPIChannelBuffered(10, 1)
199         Expect(err).ShouldNot(HaveOccurred())
200
201         // send multiple requests, only one reply should be read
202         for i := 0; i < 20; i++ {
203                 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
204                 ctx.ch.ReqChan <- &api.VppRequest{Message: &vpe.ControlPing{}}
205         }
206
207         vppReply := <-ctx.ch.ReplyChan
208         Expect(vppReply).ShouldNot(BeNil())
209
210         var received bool
211         select {
212         case <-ctx.ch.ReplyChan:
213                 received = true // this should not happen
214         default:
215                 received = false // no reply to be received
216         }
217         Expect(received).Should(BeFalse(), "A reply has been recieved, should had been ignored.")
218 }
219
220 func TestCodec(t *testing.T) {
221         RegisterTestingT(t)
222
223         codec := &core.MsgCodec{}
224
225         // request
226         data, err := codec.EncodeMsg(&interfaces.CreateLoopback{MacAddress: []byte{1, 2, 3, 4, 5, 6}}, 11)
227         Expect(err).ShouldNot(HaveOccurred())
228         Expect(data).ShouldNot(BeEmpty())
229
230         msg1 := &interfaces.CreateLoopback{}
231         err = codec.DecodeMsg(data, msg1)
232         Expect(err).ShouldNot(HaveOccurred())
233         Expect(msg1.MacAddress).To(BeEquivalentTo([]byte{1, 2, 3, 4, 5, 6}))
234
235         // reply
236         data, err = codec.EncodeMsg(&vpe.ControlPingReply{Retval: 55}, 22)
237         Expect(err).ShouldNot(HaveOccurred())
238         Expect(data).ShouldNot(BeEmpty())
239
240         msg2 := &vpe.ControlPingReply{}
241         err = codec.DecodeMsg(data, msg2)
242         Expect(err).ShouldNot(HaveOccurred())
243         Expect(msg2.Retval).To(BeEquivalentTo(55))
244
245         // other
246         data, err = codec.EncodeMsg(&stats.VnetIP4FibCounters{VrfID: 77}, 33)
247         Expect(err).ShouldNot(HaveOccurred())
248         Expect(data).ShouldNot(BeEmpty())
249
250         msg3 := &stats.VnetIP4FibCounters{}
251         err = codec.DecodeMsg(data, msg3)
252         Expect(err).ShouldNot(HaveOccurred())
253         Expect(msg3.VrfID).To(BeEquivalentTo(77))
254 }
255
256 func TestCodecNegative(t *testing.T) {
257         RegisterTestingT(t)
258
259         codec := &core.MsgCodec{}
260
261         // nil message for encoding
262         data, err := codec.EncodeMsg(nil, 15)
263         Expect(err).Should(HaveOccurred())
264         Expect(err.Error()).To(ContainSubstring("nil message"))
265         Expect(data).Should(BeNil())
266
267         // nil message for decoding
268         err = codec.DecodeMsg(data, nil)
269         Expect(err).Should(HaveOccurred())
270         Expect(err.Error()).To(ContainSubstring("nil message"))
271
272         // nil data for decoding
273         err = codec.DecodeMsg(nil, &vpe.ControlPingReply{})
274         Expect(err).Should(HaveOccurred())
275         Expect(err.Error()).To(ContainSubstring("EOF"))
276 }