Add WaitReady to VppAdapter 07/9607/1
authorOndrej Fabry <ofabry@cisco.com>
Tue, 28 Nov 2017 18:53:14 +0000 (19:53 +0100)
committerOndrej Fabry <ofabry@cisco.com>
Tue, 28 Nov 2017 18:53:14 +0000 (19:53 +0100)
- this fixes issue with mocked adapter during AsyncConnect

Change-Id: I952025fec865422f9e83cec9383d96f79a639c90
Signed-off-by: Ondrej Fabry <ofabry@cisco.com>
adapter/adapter.go
adapter/mock/mock_adapter.go
adapter/vppapiclient/empty_adapter.go
adapter/vppapiclient/vppapiclient_adapter.go
cmd/binapi-generator/generator_test.go
core/core.go

index 2843d2c..d8f29c9 100644 (file)
@@ -30,4 +30,7 @@ type VppAdapter interface {
 
        // SetMsgCallback sets a callback function that will be called by the adapter whenever a message comes from VPP.
        SetMsgCallback(func(context uint32, msgId uint16, data []byte))
+
+       // WaitReady returns func which waits until adapter is ready.
+       WaitReady() func() error
 }
index 8c88030..f85f17d 100644 (file)
@@ -294,6 +294,11 @@ func (a *VppAdapter) SetMsgCallback(cb func(context uint32, msgID uint16, data [
        a.callback = cb
 }
 
+// WaitReady mocks waiting for VPP
+func (a *VppAdapter) WaitReady() func() error {
+       return func() error { return nil }
+}
+
 // MockReply stores a message to be returned when the next request comes. It is a FIFO queue - multiple replies
 // can be pushed into it, the first one will be popped when some request comes.
 // Using of this method automatically switches the mock into th useRepliesQueue mode.
index 14f804d..7249864 100644 (file)
@@ -50,3 +50,7 @@ func (a *vppAPIClientAdapter) SendMsg(clientID uint32, data []byte) error {
 func (a *vppAPIClientAdapter) SetMsgCallback(cb func(context uint32, msgID uint16, data []byte)) {
        // no op
 }
+
+func (a *vppAPIClientAdapter) WaitReady() func() error {
+       return func() error { return nil }
+}
index 74f0118..dfdd973 100644 (file)
@@ -79,10 +79,21 @@ import "C"
 import (
        "errors"
        "fmt"
+       "os"
        "reflect"
        "unsafe"
 
        "git.fd.io/govpp.git/adapter"
+       "github.com/fsnotify/fsnotify"
+)
+
+const (
+       // watchedFolder is a folder where vpp's shared memory is supposed to be created.
+       // File system events are monitored in this folder.
+       watchedFolder = "/dev/shm/"
+       // watchedFile is a name of the file in the watchedFolder. Once the file is present
+       // the vpp is ready to accept a new connection.
+       watchedFile = watchedFolder + "vpe-api"
 )
 
 // vppAPIClientAdapter is the opaque context of the adapter.
@@ -139,6 +150,44 @@ func (a *vppAPIClientAdapter) SetMsgCallback(cb func(context uint32, msgID uint1
        a.callback = cb
 }
 
+// WaitReady returns func which blocks until shared memory
+// for sending bin api calls is present on the file system.
+func (a *vppAPIClientAdapter) WaitReady() func() error {
+       return func() error {
+               watcher, err := fsnotify.NewWatcher()
+               if err != nil {
+                       return err
+               }
+               defer watcher.Close()
+
+               err = watcher.Add(watchedFolder)
+               if err != nil {
+                       return err
+               }
+
+               if fileExists(watchedFile) {
+                       return nil
+               }
+
+               for {
+                       ev := <-watcher.Events
+                       if ev.Name == watchedFile && (ev.Op&fsnotify.Create) == fsnotify.Create {
+                               break
+                       }
+               }
+               return nil
+       }
+}
+
+func fileExists(name string) bool {
+       if _, err := os.Stat(name); err != nil {
+               if os.IsNotExist(err) {
+                       return false
+               }
+       }
+       return true
+}
+
 //export go_msg_callback
 func go_msg_callback(msgID C.uint16_t, context C.uint32_t, data unsafe.Pointer, size C.size_t) {
        // convert unsafe.Pointer to byte slice
index c7d89ce..a42e794 100644 (file)
@@ -245,7 +245,7 @@ func TestGenerateMessageFieldTypes(t *testing.T) {
                for j := 0; j < types.At(i).Len(); j++ {
                        field := types.At(i).At(j)
                        if jsongo.TypeArray == field.GetType() {
-                               err := processMessageField(testCtx, &fields, field, otherMessage)
+                               err := processMessageField(testCtx, &fields, field, false)
                                Expect(err).ShouldNot(HaveOccurred())
                                Expect(fields[j-1]).To(BeEquivalentTo(expectedTypes[j-1]))
                        }
@@ -282,7 +282,7 @@ func TestGenerateMessageFieldMessages(t *testing.T) {
                                        specificFieldName == "client_index" || specificFieldName == "context" {
                                        continue
                                }
-                               err := processMessageField(testCtx, &fields, field, requestMessage)
+                               err := processMessageField(testCtx, &fields, field, false)
                                Expect(err).ShouldNot(HaveOccurred())
                                Expect(fields[customIndex]).To(BeEquivalentTo(expectedTypes[customIndex]))
                                customIndex++
index a045e60..c254214 100644 (file)
@@ -28,7 +28,6 @@ import (
        "git.fd.io/govpp.git/adapter"
        "git.fd.io/govpp.git/api"
        "git.fd.io/govpp.git/core/bin_api/vpe"
-       "github.com/fsnotify/fsnotify"
 )
 
 const (
@@ -54,15 +53,6 @@ const (
        Disconnected = iota
 )
 
-const (
-       // watchedFolder is a folder where vpp's shared memory is supposed to be created.
-       // File system events are monitored in this folder.
-       watchedFolder = "/dev/shm/"
-       // watchedFile is a name of the file in the watchedFolder. Once the file is present
-       // the vpp is ready to accept a new connection.
-       watchedFile = watchedFolder + "vpe-api"
-)
-
 // ConnectionEvent is a notification about change in the VPP connection state.
 type ConnectionEvent struct {
        // Timestamp holds the time when the event has been generated.
@@ -197,10 +187,13 @@ func newConnection(vppAdapter adapter.VppAdapter) (*Connection, error) {
                return nil, errors.New("only one connection per process is supported")
        }
 
-       conn = &Connection{vpp: vppAdapter, codec: &MsgCodec{}}
-       conn.channels = make(map[uint32]*api.Channel)
-       conn.msgIDs = make(map[string]uint16)
-       conn.notifSubscriptions = make(map[uint16][]*api.NotifSubscription)
+       conn = &Connection{
+               vpp:                vppAdapter,
+               codec:              &MsgCodec{},
+               channels:           make(map[uint32]*api.Channel),
+               msgIDs:             make(map[string]uint16),
+               notifSubscriptions: make(map[uint16][]*api.NotifSubscription),
+       }
 
        conn.vpp.SetMsgCallback(msgCallback)
        return conn, nil
@@ -235,50 +228,14 @@ func (c *Connection) disconnectVPP() {
        }
 }
 
-func fileExists(name string) bool {
-       if _, err := os.Stat(name); err != nil {
-               if os.IsNotExist(err) {
-                       return false
-               }
-       }
-       return true
-}
-
-// waitForVpp blocks until shared memory for sending bin api calls
-// is present on the file system.
-func waitForVpp() error {
-       watcher, err := fsnotify.NewWatcher()
-       if err != nil {
-               return err
-       }
-       defer watcher.Close()
-
-       err = watcher.Add(watchedFolder)
-       if err != nil {
-               return err
-       }
-
-       if fileExists(watchedFile) {
-               return nil
-       }
-
-       for {
-               ev := <-watcher.Events
-               if ev.Name == watchedFile && (ev.Op&fsnotify.Create) == fsnotify.Create {
-                       break
-               }
-       }
-       return nil
-}
-
 // connectLoop attempts to connect to VPP until it succeeds.
 // Then it continues with healthCheckLoop.
 func (c *Connection) connectLoop(connChan chan ConnectionEvent) {
        // loop until connected
+       waitForVpp := c.vpp.WaitReady()
        for {
                waitForVpp()
-               err := c.connectVPP()
-               if err == nil {
+               if err := c.connectVPP(); err == nil {
                        // signal connected event
                        connChan <- ConnectionEvent{Timestamp: time.Now(), State: Connected}
                        break