aboutsummaryrefslogtreecommitdiffstats
path: root/core/core_test.go
diff options
context:
space:
mode:
authorVladimir Lavor <vlavor@cisco.com>2018-07-03 10:39:21 +0200
committerVladimir Lavor <vlavor@cisco.com>2018-07-06 13:18:01 +0200
commitf1bef4a3c66f4408afdeb64cda62ccd8562d0fc6 (patch)
tree5767c18051f97362a00b1a4dfe90ec9480247032 /core/core_test.go
parent5276b9439d0f902e125a5113bfa4f1b6622aea18 (diff)
make api.Channel as interface
Change-Id: I052d241ab09043b1195beebeee99df4d8536621f Signed-off-by: Vladimir Lavor <vlavor@cisco.com>
Diffstat (limited to 'core/core_test.go')
-rw-r--r--core/core_test.go542
1 files changed, 0 insertions, 542 deletions
diff --git a/core/core_test.go b/core/core_test.go
deleted file mode 100644
index e4fbf63..0000000
--- a/core/core_test.go
+++ /dev/null
@@ -1,542 +0,0 @@
-// Copyright (c) 2017 Cisco and/or its affiliates.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at:
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package core_test
-
-import (
- "testing"
-
- "git.fd.io/govpp.git/adapter/mock"
- "git.fd.io/govpp.git/api"
- "git.fd.io/govpp.git/core"
- "git.fd.io/govpp.git/core/bin_api/vpe"
- "git.fd.io/govpp.git/examples/bin_api/interfaces"
- "git.fd.io/govpp.git/examples/bin_api/stats"
-
- . "github.com/onsi/gomega"
-)
-
-type testCtx struct {
- mockVpp *mock.VppAdapter
- conn *core.Connection
- ch *api.Channel
-}
-
-func setupTest(t *testing.T, bufferedChan bool) *testCtx {
- RegisterTestingT(t)
-
- ctx := &testCtx{}
- ctx.mockVpp = &mock.VppAdapter{}
-
- var err error
- ctx.conn, err = core.Connect(ctx.mockVpp)
- Expect(err).ShouldNot(HaveOccurred())
-
- if bufferedChan {
- ctx.ch, err = ctx.conn.NewAPIChannelBuffered(100, 100)
- } else {
- ctx.ch, err = ctx.conn.NewAPIChannel()
- }
- Expect(err).ShouldNot(HaveOccurred())
-
- return ctx
-}
-
-func (ctx *testCtx) teardownTest() {
- ctx.ch.Close()
- ctx.conn.Disconnect()
-}
-
-func TestSimpleRequest(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: -5})
-
- req := &vpe.ControlPing{}
- reply := &vpe.ControlPingReply{}
-
- // send the request and receive a reply
- ctx.ch.ReqChan <- &api.VppRequest{Message: req}
- vppReply := <-ctx.ch.ReplyChan
-
- Expect(vppReply).ShouldNot(BeNil())
- Expect(vppReply.Error).ShouldNot(HaveOccurred())
-
- // decode the message
- err := ctx.ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
- Expect(err).ShouldNot(HaveOccurred())
-
- Expect(reply.Retval).To(BeEquivalentTo(-5))
-}
-
-func TestMultiRequest(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- msgs := []api.Message{}
- for m := 0; m < 10; m++ {
- msgs = append(msgs, &interfaces.SwInterfaceDetails{})
- }
- ctx.mockVpp.MockReply(msgs...)
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
-
- // send multipart request
- ctx.ch.ReqChan <- &api.VppRequest{Message: &interfaces.SwInterfaceDump{}, Multipart: true}
-
- cnt := 0
- for {
- // receive a reply
- vppReply := <-ctx.ch.ReplyChan
- if vppReply.LastReplyReceived {
- break // break out of the loop
- }
- Expect(vppReply.Error).ShouldNot(HaveOccurred())
-
- // decode the message
- reply := &interfaces.SwInterfaceDetails{}
- err := ctx.ch.MsgDecoder.DecodeMsg(vppReply.Data, reply)
- Expect(err).ShouldNot(HaveOccurred())
- cnt++
- }
-
- Expect(cnt).To(BeEquivalentTo(10))
-}
-
-func TestNotifications(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- // subscribe for notification
- notifChan := make(chan api.Message, 1)
- subscription := &api.NotifSubscription{
- NotifChan: notifChan,
- MsgFactory: interfaces.NewSwInterfaceSetFlags,
- }
- ctx.ch.NotifSubsChan <- &api.NotifSubscribeRequest{
- Subscription: subscription,
- Subscribe: true,
- }
- err := <-ctx.ch.NotifSubsReplyChan
- Expect(err).ShouldNot(HaveOccurred())
-
- // mock the notification and force its delivery
- ctx.mockVpp.MockReply(&interfaces.SwInterfaceSetFlags{
- SwIfIndex: 3,
- AdminUpDown: 1,
- })
- ctx.mockVpp.SendMsg(0, []byte{0})
-
- // receive the notification
- notif := (<-notifChan).(*interfaces.SwInterfaceSetFlags)
-
- Expect(notif.SwIfIndex).To(BeEquivalentTo(3))
-
- // unsubscribe notification
- ctx.ch.NotifSubsChan <- &api.NotifSubscribeRequest{
- Subscription: subscription,
- Subscribe: false,
- }
- err = <-ctx.ch.NotifSubsReplyChan
- Expect(err).ShouldNot(HaveOccurred())
-}
-
-func TestNilConnection(t *testing.T) {
- RegisterTestingT(t)
- var conn *core.Connection
-
- ch, err := conn.NewAPIChannel()
- Expect(ch).Should(BeNil())
- Expect(err).Should(HaveOccurred())
- Expect(err.Error()).To(ContainSubstring("nil"))
-
- ch, err = conn.NewAPIChannelBuffered(1, 1)
- Expect(ch).Should(BeNil())
- Expect(err).Should(HaveOccurred())
- Expect(err.Error()).To(ContainSubstring("nil"))
-}
-
-func TestDoubleConnection(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- conn, err := core.Connect(ctx.mockVpp)
- Expect(err).Should(HaveOccurred())
- Expect(err.Error()).To(ContainSubstring("only one connection per process"))
- Expect(conn).Should(BeNil())
-}
-
-func TestAsyncConnection(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- ctx.conn.Disconnect()
- conn, ch, err := core.AsyncConnect(ctx.mockVpp)
- ctx.conn = conn
-
- Expect(err).ShouldNot(HaveOccurred())
- Expect(conn).ShouldNot(BeNil())
-
- ev := <-ch
- Expect(ev.State).Should(BeEquivalentTo(core.Connected))
-}
-
-func TestFullBuffer(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- // close the default API channel
- ctx.ch.Close()
-
- // create a new channel with limited buffer sizes
- var err error
- ctx.ch, err = ctx.conn.NewAPIChannelBuffered(10, 1)
- Expect(err).ShouldNot(HaveOccurred())
-
- // send multiple requests, only one reply should be read
- for i := 0; i < 20; i++ {
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
- ctx.ch.ReqChan <- &api.VppRequest{Message: &vpe.ControlPing{}}
- }
-
- vppReply := <-ctx.ch.ReplyChan
- Expect(vppReply).ShouldNot(BeNil())
-
- var received bool
- select {
- case <-ctx.ch.ReplyChan:
- received = true // this should not happen
- default:
- received = false // no reply to be received
- }
- Expect(received).Should(BeFalse(), "A reply has been recieved, should had been ignored.")
-}
-
-func TestCodec(t *testing.T) {
- RegisterTestingT(t)
-
- codec := &core.MsgCodec{}
-
- // request
- data, err := codec.EncodeMsg(&interfaces.CreateLoopback{MacAddress: []byte{1, 2, 3, 4, 5, 6}}, 11)
- Expect(err).ShouldNot(HaveOccurred())
- Expect(data).ShouldNot(BeEmpty())
-
- msg1 := &interfaces.CreateLoopback{}
- err = codec.DecodeMsg(data, msg1)
- Expect(err).ShouldNot(HaveOccurred())
- Expect(msg1.MacAddress).To(BeEquivalentTo([]byte{1, 2, 3, 4, 5, 6}))
-
- // reply
- data, err = codec.EncodeMsg(&vpe.ControlPingReply{Retval: 55}, 22)
- Expect(err).ShouldNot(HaveOccurred())
- Expect(data).ShouldNot(BeEmpty())
-
- msg2 := &vpe.ControlPingReply{}
- err = codec.DecodeMsg(data, msg2)
- Expect(err).ShouldNot(HaveOccurred())
- Expect(msg2.Retval).To(BeEquivalentTo(55))
-
- // other
- data, err = codec.EncodeMsg(&stats.VnetIP4FibCounters{VrfID: 77}, 33)
- Expect(err).ShouldNot(HaveOccurred())
- Expect(data).ShouldNot(BeEmpty())
-
- msg3 := &stats.VnetIP4FibCounters{}
- err = codec.DecodeMsg(data, msg3)
- Expect(err).ShouldNot(HaveOccurred())
- Expect(msg3.VrfID).To(BeEquivalentTo(77))
-}
-
-func TestCodecNegative(t *testing.T) {
- RegisterTestingT(t)
-
- codec := &core.MsgCodec{}
-
- // nil message for encoding
- data, err := codec.EncodeMsg(nil, 15)
- Expect(err).Should(HaveOccurred())
- Expect(err.Error()).To(ContainSubstring("nil message"))
- Expect(data).Should(BeNil())
-
- // nil message for decoding
- err = codec.DecodeMsg(data, nil)
- Expect(err).Should(HaveOccurred())
- Expect(err.Error()).To(ContainSubstring("nil message"))
-
- // nil data for decoding
- err = codec.DecodeMsg(nil, &vpe.ControlPingReply{})
- Expect(err).Should(HaveOccurred())
- Expect(err.Error()).To(ContainSubstring("EOF"))
-}
-
-func TestSimpleRequestsWithSequenceNumbers(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- var reqCtx []*api.RequestCtx
- for i := 0; i < 10; i++ {
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: int32(i)})
- req := &vpe.ControlPing{}
- reqCtx = append(reqCtx, ctx.ch.SendRequest(req))
- }
-
- for i := 0; i < 10; i++ {
- reply := &vpe.ControlPingReply{}
- err := reqCtx[i].ReceiveReply(reply)
- Expect(err).ShouldNot(HaveOccurred())
- Expect(reply.Retval).To(BeEquivalentTo(i))
- }
-}
-
-func TestMultiRequestsWithSequenceNumbers(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- msgs := []api.Message{}
- for i := 0; i < 10; i++ {
- msgs = append(msgs, &interfaces.SwInterfaceDetails{SwIfIndex: uint32(i)})
- }
- ctx.mockVpp.MockReply(msgs...)
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{})
-
- // send multipart request
- reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
-
- cnt := 0
- for {
- Expect(cnt < 11).To(BeTrue())
-
- // receive a reply
- reply := &interfaces.SwInterfaceDetails{}
- lastReplyReceived, err := reqCtx.ReceiveReply(reply)
-
- if lastReplyReceived {
- break // break out of the loop
- }
-
- Expect(err).ShouldNot(HaveOccurred())
- Expect(reply.SwIfIndex).To(BeEquivalentTo(cnt))
-
- cnt++
- }
-
- Expect(cnt).To(BeEquivalentTo(10))
-}
-
-func TestSimpleRequestWithTimeout(t *testing.T) {
- ctx := setupTest(t, true)
- defer ctx.teardownTest()
-
- // reply for a previous timeouted requests to be ignored
- ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{
- Msg: &vpe.ControlPingReply{Retval: 1},
- SeqNum: 0,
- })
-
- // send reply later
- req1 := &vpe.ControlPing{}
- reqCtx1 := ctx.ch.SendRequest(req1)
-
- reply := &vpe.ControlPingReply{}
- err := reqCtx1.ReceiveReply(reply)
- Expect(err).ToNot(BeNil())
- Expect(err.Error()).To(HavePrefix("no reply received within the timeout period"))
-
- ctx.mockVpp.MockReplyWithContext(
- // reply for the previous request
- mock.MsgWithContext{
- Msg: &vpe.ControlPingReply{Retval: 1},
- SeqNum: 1,
- },
- // reply for the next request
- mock.MsgWithContext{
- Msg: &vpe.ControlPingReply{Retval: 2},
- SeqNum: 2,
- })
-
- // next request
- req2 := &vpe.ControlPing{}
- reqCtx2 := ctx.ch.SendRequest(req2)
-
- // second request should ignore the first reply and return the second one
- reply = &vpe.ControlPingReply{}
- err = reqCtx2.ReceiveReply(reply)
- Expect(err).To(BeNil())
- Expect(reply.Retval).To(BeEquivalentTo(2))
-}
-
-func TestSimpleRequestsWithMissingReply(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- // request without reply
- req1 := &vpe.ControlPing{}
- reqCtx1 := ctx.ch.SendRequest(req1)
-
- // another request without reply
- req2 := &vpe.ControlPing{}
- reqCtx2 := ctx.ch.SendRequest(req2)
-
- // third request with reply
- ctx.mockVpp.MockReplyWithContext(mock.MsgWithContext{
- Msg: &vpe.ControlPingReply{Retval: 3},
- SeqNum: 3,
- })
- req3 := &vpe.ControlPing{}
- reqCtx3 := ctx.ch.SendRequest(req3)
-
- // the first two should fail, but not consume reply for the 3rd
- reply := &vpe.ControlPingReply{}
- err := reqCtx1.ReceiveReply(reply)
- Expect(err).ToNot(BeNil())
- Expect(err.Error()).To(Equal("missing binary API reply with sequence number: 1"))
-
- reply = &vpe.ControlPingReply{}
- err = reqCtx2.ReceiveReply(reply)
- Expect(err).ToNot(BeNil())
- Expect(err.Error()).To(Equal("missing binary API reply with sequence number: 2"))
-
- // the second request should succeed
- reply = &vpe.ControlPingReply{}
- err = reqCtx3.ReceiveReply(reply)
- Expect(err).To(BeNil())
- Expect(reply.Retval).To(BeEquivalentTo(3))
-}
-
-func TestMultiRequestsWithErrors(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- // replies for a previous timeouted requests to be ignored
- msgs := []mock.MsgWithContext{}
- msgs = append(msgs,
- mock.MsgWithContext{
- Msg: &vpe.ControlPingReply{Retval: 1},
- SeqNum: 0xffff - 1,
- },
- mock.MsgWithContext{
- Msg: &vpe.ControlPingReply{Retval: 1},
- SeqNum: 0xffff,
- },
- mock.MsgWithContext{
- Msg: &vpe.ControlPingReply{Retval: 1},
- SeqNum: 0,
- })
-
- for i := 0; i < 10; i++ {
- msgs = append(msgs,
- mock.MsgWithContext{
- Msg: &interfaces.SwInterfaceDetails{SwIfIndex: uint32(i)},
- SeqNum: 1,
- Multipart: true,
- })
- }
- // missing finalizing control ping
-
- // reply for a next request
- msgs = append(msgs,
- mock.MsgWithContext{
- Msg: &vpe.ControlPingReply{Retval: 2},
- SeqNum: 2,
- Multipart: false,
- })
-
- // queue replies
- ctx.mockVpp.MockReplyWithContext(msgs...)
-
- // send multipart request
- reqCtx := ctx.ch.SendMultiRequest(&interfaces.SwInterfaceDump{})
-
- for i := 0; i < 10; i++ {
- // receive multi-part replies
- reply := &interfaces.SwInterfaceDetails{}
- lastReplyReceived, err := reqCtx.ReceiveReply(reply)
-
- Expect(lastReplyReceived).To(BeFalse())
- Expect(err).ShouldNot(HaveOccurred())
- Expect(reply.SwIfIndex).To(BeEquivalentTo(i))
- }
-
- // missing closing control ping
- reply := &interfaces.SwInterfaceDetails{}
- _, err := reqCtx.ReceiveReply(reply)
- Expect(err).ToNot(BeNil())
- Expect(err.Error()).To(Equal("missing binary API reply with sequence number: 1"))
-
- // try again - still fails and nothing consumed
- _, err = reqCtx.ReceiveReply(reply)
- Expect(err).ToNot(BeNil())
- Expect(err.Error()).To(Equal("missing binary API reply with sequence number: 1"))
-
- // reply for the second request has not been consumed
- reqCtx2 := ctx.ch.SendRequest(&vpe.ControlPing{})
- reply2 := &vpe.ControlPingReply{}
- err = reqCtx2.ReceiveReply(reply2)
- Expect(err).To(BeNil())
- Expect(reply2.Retval).To(BeEquivalentTo(2))
-}
-
-func TestRequestsOrdering(t *testing.T) {
- ctx := setupTest(t, false)
- defer ctx.teardownTest()
-
- // the orderings of SendRequest and ReceiveReply calls should match, otherwise
- // some replies will get thrown away
-
- // first request
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: 1})
- req1 := &vpe.ControlPing{}
- reqCtx1 := ctx.ch.SendRequest(req1)
-
- // second request
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: 2})
- req2 := &vpe.ControlPing{}
- reqCtx2 := ctx.ch.SendRequest(req2)
-
- // if reply for the second request is read first, the reply for the first
- // request gets thrown away.
- reply2 := &vpe.ControlPingReply{}
- err := reqCtx2.ReceiveReply(reply2)
- Expect(err).To(BeNil())
- Expect(reply2.Retval).To(BeEquivalentTo(2))
-
- // first request has already been considered closed
- reply1 := &vpe.ControlPingReply{}
- err = reqCtx1.ReceiveReply(reply1)
- Expect(err).ToNot(BeNil())
- Expect(err.Error()).To(HavePrefix("no reply received within the timeout period"))
-}
-
-func TestCycleOverSetOfSequenceNumbers(t *testing.T) {
- ctx := setupTest(t, true)
- defer ctx.teardownTest()
-
- numIters := 0xffff + 100
- reqCtx := make(map[int]*api.RequestCtx)
-
- for i := 0; i < numIters+30; /* receiver is 30 reqs behind */ i++ {
- if i < numIters {
- ctx.mockVpp.MockReply(&vpe.ControlPingReply{Retval: int32(i)})
- req := &vpe.ControlPing{}
- reqCtx[i] = ctx.ch.SendRequest(req)
- }
- if i > 30 {
- reply := &vpe.ControlPingReply{}
- err := reqCtx[i-30].ReceiveReply(reply)
- Expect(err).ShouldNot(HaveOccurred())
- Expect(reply.Retval).To(BeEquivalentTo(i - 30))
- }
- }
-}