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.
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"
27 . "github.com/onsi/gomega"
31 mockVpp *mock.VppAdapter
36 func setupTest(t *testing.T) *testCtx {
40 ctx.mockVpp = &mock.VppAdapter{}
43 ctx.conn, err = core.Connect(ctx.mockVpp)
44 Expect(err).ShouldNot(HaveOccurred())
46 ctx.ch, err = ctx.conn.NewAPIChannel()
47 Expect(err).ShouldNot(HaveOccurred())
52 func (ctx *testCtx) teardownTest() {
57 func TestSimpleRequest(t *testing.T) {
59 defer ctx.teardownTest()
61 ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: -5})
63 req := &vpe.ControlPing{}
64 reply := &vpe.ControlPingReply{}
66 // send the request and receive a reply
67 ctx.ch.ReqChan <- &api.VppRequest{Message: req}
68 vppReply := <-ctx.ch.ReplyChan
70 Expect(vppReply).ShouldNot(BeNil())
71 Expect(vppReply.Error).ShouldNot(HaveOccurred())
74 err := ctx.ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
75 Expect(err).ShouldNot(HaveOccurred())
77 Expect(reply.Retval).To(BeEquivalentTo(-5))
80 func TestMultiRequest(t *testing.T) {
82 defer ctx.teardownTest()
84 for m := 0; m < 10; m++ {
85 ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{})
87 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
89 // send multipart request
90 ctx.ch.ReqChan <- &api.VppRequest{Message: &interfaces.SwInterfaceDump{}, Multipart: true}
95 vppReply := <-ctx.ch.ReplyChan
96 if vppReply.LastReplyReceived {
97 break // break out of the loop
99 Expect(vppReply.Error).ShouldNot(HaveOccurred())
101 // decode the message
102 reply := &interfaces.SwInterfaceDetails{}
103 err := ctx.ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
104 Expect(err).ShouldNot(HaveOccurred())
108 Expect(cnt).To(BeEquivalentTo(10))
111 func TestNotifications(t *testing.T) {
113 defer ctx.teardownTest()
115 // subscribe for notification
116 notifChan := make(chan api.Message, 1)
117 subscription := &api.NotifSubscription{
118 NotifChan: notifChan,
119 MsgFactory: interfaces.NewSwInterfaceSetFlags,
121 ctx.ch.NotifSubsChan <- &api.NotifSubscribeRequest{
122 Subscription: subscription,
125 err := <-ctx.ch.NotifSubsReplyChan
126 Expect(err).ShouldNot(HaveOccurred())
128 // mock the notification and force its delivery
129 ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{
133 ctx.mockVpp.SendMsg(0, []byte{0})
135 // receive the notification
136 notif := (<-notifChan).(*interfaces.SwInterfaceSetFlags)
138 Expect(notif.SwIfIndex).To(BeEquivalentTo(3))
140 // unsubscribe notification
141 ctx.ch.NotifSubsChan <- &api.NotifSubscribeRequest{
142 Subscription: subscription,
145 err = <-ctx.ch.NotifSubsReplyChan
146 Expect(err).ShouldNot(HaveOccurred())
149 func TestNilConnection(t *testing.T) {
151 var conn *core.Connection
153 ch, err := conn.NewAPIChannel()
154 Expect(ch).Should(BeNil())
155 Expect(err).Should(HaveOccurred())
156 Expect(err.Error()).To(ContainSubstring("nil"))
158 ch, err = conn.NewAPIChannelBuffered(1, 1)
159 Expect(ch).Should(BeNil())
160 Expect(err).Should(HaveOccurred())
161 Expect(err.Error()).To(ContainSubstring("nil"))
164 func TestDoubleConnection(t *testing.T) {
166 defer ctx.teardownTest()
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())
174 func TestAsyncConnection(t *testing.T) {
176 defer ctx.teardownTest()
178 ctx.conn.Disconnect()
179 conn, ch, err := core.AsyncConnect(ctx.mockVpp)
182 Expect(err).ShouldNot(HaveOccurred())
183 Expect(conn).ShouldNot(BeNil())
186 Expect(ev.State).Should(BeEquivalentTo(core.Connected))
189 func TestFullBuffer(t *testing.T) {
191 defer ctx.teardownTest()
193 // close the default API channel
196 // create a new channel with limited buffer sizes
198 ctx.ch, err = ctx.conn.NewAPIChannelBuffered(10, 1)
199 Expect(err).ShouldNot(HaveOccurred())
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{}}
207 vppReply := <-ctx.ch.ReplyChan
208 Expect(vppReply).ShouldNot(BeNil())
212 case <-ctx.ch.ReplyChan:
213 received = true // this should not happen
215 received = false // no reply to be received
217 Expect(received).Should(BeFalse(), "A reply has been recieved, should had been ignored.")
220 func TestCodec(t *testing.T) {
223 codec := &core.MsgCodec{}
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())
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}))
236 data, err = codec.EncodeMsg(&vpe.ControlPingReply{Retval: 55}, 22)
237 Expect(err).ShouldNot(HaveOccurred())
238 Expect(data).ShouldNot(BeEmpty())
240 msg2 := &vpe.ControlPingReply{}
241 err = codec.DecodeMsg(data, msg2)
242 Expect(err).ShouldNot(HaveOccurred())
243 Expect(msg2.Retval).To(BeEquivalentTo(55))
246 data, err = codec.EncodeMsg(&stats.VnetIP4FibCounters{VrfID: 77}, 33)
247 Expect(err).ShouldNot(HaveOccurred())
248 Expect(data).ShouldNot(BeEmpty())
250 msg3 := &stats.VnetIP4FibCounters{}
251 err = codec.DecodeMsg(data, msg3)
252 Expect(err).ShouldNot(HaveOccurred())
253 Expect(msg3.VrfID).To(BeEquivalentTo(77))
256 func TestCodecNegative(t *testing.T) {
259 codec := &core.MsgCodec{}
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())
267 // nil message for decoding
268 err = codec.DecodeMsg(data, nil)
269 Expect(err).Should(HaveOccurred())
270 Expect(err.Error()).To(ContainSubstring("nil message"))
272 // nil data for decoding
273 err = codec.DecodeMsg(nil, &vpe.ControlPingReply{})
274 Expect(err).Should(HaveOccurred())
275 Expect(err.Error()).To(ContainSubstring("EOF"))