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"
26 . "github.com/onsi/gomega"
30 mockVpp *mock.VppAdapter
35 func setupTest(t *testing.T) *testCtx {
39 ctx.mockVpp = &mock.VppAdapter{}
42 ctx.conn, err = core.Connect(ctx.mockVpp)
43 Expect(err).ShouldNot(HaveOccurred())
45 ctx.ch, err = ctx.conn.NewAPIChannel()
46 Expect(err).ShouldNot(HaveOccurred())
51 func (ctx *testCtx) teardownTest() {
56 func TestSimpleRequest(t *testing.T) {
58 defer ctx.teardownTest()
60 ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: -5})
62 req := &vpe.ControlPing{}
63 reply := &vpe.ControlPingReply{}
65 // send the request and receive a reply
66 ctx.ch.ReqChan <- &api.VppRequest{Message: req}
67 vppReply := <-ctx.ch.ReplyChan
69 Expect(vppReply).ShouldNot(BeNil())
70 Expect(vppReply.Error).ShouldNot(HaveOccurred())
73 err := ctx.ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
74 Expect(err).ShouldNot(HaveOccurred())
76 Expect(reply.Retval).To(BeEquivalentTo(-5))
79 func TestMultiRequest(t *testing.T) {
81 defer ctx.teardownTest()
83 for m := 0; m < 10; m++ {
84 ctx.mockVpp.MockReply(&interfaces.SwInterfaceDetails{})
86 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
88 // send multipart request
89 ctx.ch.ReqChan <- &api.VppRequest{Message: &interfaces.SwInterfaceDump{}, Multipart: true}
94 vppReply := <-ctx.ch.ReplyChan
95 if vppReply.LastReplyReceived {
96 break // break out of the loop
98 Expect(vppReply.Error).ShouldNot(HaveOccurred())
100 // decode the message
101 reply := &interfaces.SwInterfaceDetails{}
102 err := ctx.ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
103 Expect(err).ShouldNot(HaveOccurred())
107 Expect(cnt).To(BeEquivalentTo(10))
110 func TestNotifications(t *testing.T) {
112 defer ctx.teardownTest()
114 // subscribe for notification
115 notifChan := make(chan api.Message, 1)
116 subscription := &api.NotifSubscription{
117 NotifChan: notifChan,
118 MsgFactory: interfaces.NewSwInterfaceSetFlags,
120 ctx.ch.NotifSubsChan <- &api.NotifSubscribeRequest{
121 Subscription: subscription,
124 err := <-ctx.ch.NotifSubsReplyChan
125 Expect(err).ShouldNot(HaveOccurred())
127 // mock the notification and force its delivery
128 ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{
132 ctx.mockVpp.SendMsg(0, []byte{0})
134 // receive the notification
135 notif := (<-notifChan).(*interfaces.SwInterfaceSetFlags)
137 Expect(notif.SwIfIndex).To(BeEquivalentTo(3))
139 // unsubscribe notification
140 ctx.ch.NotifSubsChan <- &api.NotifSubscribeRequest{
141 Subscription: subscription,
144 err = <-ctx.ch.NotifSubsReplyChan
145 Expect(err).ShouldNot(HaveOccurred())
148 func TestNilConnection(t *testing.T) {
150 var conn *core.Connection
152 ch, err := conn.NewAPIChannel()
153 Expect(ch).Should(BeNil())
154 Expect(err).Should(HaveOccurred())
155 Expect(err.Error()).To(ContainSubstring("nil"))
157 ch, err = conn.NewAPIChannelBuffered(1, 1)
158 Expect(ch).Should(BeNil())
159 Expect(err).Should(HaveOccurred())
160 Expect(err.Error()).To(ContainSubstring("nil"))
163 func TestDoubleConnection(t *testing.T) {
165 defer ctx.teardownTest()
167 conn, err := core.Connect(ctx.mockVpp)
168 Expect(err).Should(HaveOccurred())
169 Expect(err.Error()).To(ContainSubstring("only one connection per process"))
170 Expect(conn).Should(BeNil())
173 func TestAsyncConnection(t *testing.T) {
175 defer ctx.teardownTest()
177 ctx.conn.Disconnect()
178 conn, ch, err := core.AsyncConnect(ctx.mockVpp)
181 Expect(err).ShouldNot(HaveOccurred())
182 Expect(conn).ShouldNot(BeNil())
185 Expect(ev.State).Should(BeEquivalentTo(core.Connected))
188 func TestFullBuffer(t *testing.T) {
190 defer ctx.teardownTest()
192 // close the default API channel
195 // create a new channel with limited buffer sizes
197 ctx.ch, err = ctx.conn.NewAPIChannelBuffered(10, 1)
198 Expect(err).ShouldNot(HaveOccurred())
200 // send multiple requests, only one reply should be read
201 for i := 0; i < 20; i++ {
202 ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
203 ctx.ch.ReqChan <- &api.VppRequest{Message: &vpe.ControlPing{}}
206 vppReply := <-ctx.ch.ReplyChan
207 Expect(vppReply).ShouldNot(BeNil())
211 case vppReply = <-ctx.ch.ReplyChan:
212 received = true // this should not happen
214 received = false // no reply to be received
216 Expect(received).Should(BeFalse(), "A reply has been recieved, should had been ignored.")
219 func TestCodec(t *testing.T) {
222 codec := &core.MsgCodec{}
225 data, err := codec.EncodeMsg(&vpe.CreateLoopback{MacAddress: []byte{1, 2, 3, 4, 5, 6}}, 11)
226 Expect(err).ShouldNot(HaveOccurred())
227 Expect(data).ShouldNot(BeEmpty())
229 msg1 := &vpe.CreateLoopback{}
230 err = codec.DecodeMsg(data, msg1)
231 Expect(err).ShouldNot(HaveOccurred())
232 Expect(msg1.MacAddress).To(BeEquivalentTo([]byte{1, 2, 3, 4, 5, 6}))
235 data, err = codec.EncodeMsg(&vpe.ControlPingReply{Retval: 55}, 22)
236 Expect(err).ShouldNot(HaveOccurred())
237 Expect(data).ShouldNot(BeEmpty())
239 msg2 := &vpe.ControlPingReply{}
240 err = codec.DecodeMsg(data, msg2)
241 Expect(err).ShouldNot(HaveOccurred())
242 Expect(msg2.Retval).To(BeEquivalentTo(55))
245 data, err = codec.EncodeMsg(&vpe.VnetIP4FibCounters{VrfID: 77}, 33)
246 Expect(err).ShouldNot(HaveOccurred())
247 Expect(data).ShouldNot(BeEmpty())
249 msg3 := &vpe.VnetIP4FibCounters{}
250 err = codec.DecodeMsg(data, msg3)
251 Expect(err).ShouldNot(HaveOccurred())
252 Expect(msg3.VrfID).To(BeEquivalentTo(77))
255 func TestCodecNegative(t *testing.T) {
258 codec := &core.MsgCodec{}
260 // nil message for encoding
261 data, err := codec.EncodeMsg(nil, 15)
262 Expect(err).Should(HaveOccurred())
263 Expect(err.Error()).To(ContainSubstring("nil message"))
264 Expect(data).Should(BeNil())
266 // nil message for decoding
267 err = codec.DecodeMsg(data, nil)
268 Expect(err).Should(HaveOccurred())
269 Expect(err.Error()).To(ContainSubstring("nil message"))
271 // nil data for decoding
272 err = codec.DecodeMsg(nil, &vpe.ControlPingReply{})
273 Expect(err).Should(HaveOccurred())
274 Expect(err.Error()).To(ContainSubstring("EOF"))