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