diff --git a/Makefile b/Makefile index 7efef8fa..f716d45e 100644 --- a/Makefile +++ b/Makefile @@ -26,12 +26,14 @@ test: prebuild .PHONY: integration-test integration-test: @echo "+ $@" + @IN_MEMORY_DATABASE=1 go test -race -coverprofile=ims-integration.cov -coverpkg=github.com/ovn-org/libovsdb/... -timeout 60s -v ./test/ovs @go test -race -coverprofile=integration.cov -coverpkg=github.com/ovn-org/libovsdb/... -timeout 60s -v ./test/ovs .PHONY: coverage coverage: test integration-test @sed -i '1d' integration.cov - @cat unit.cov integration.cov > profile.cov + @sed -i '1d' ims-integration.cov + @cat unit.cov integration.cov ims-integration.cov > profile.cov .PHONY: bench bench: install-deps diff --git a/server/server.go b/server/server.go index 3450a8ff..46708d2b 100644 --- a/server/server.go +++ b/server/server.go @@ -18,7 +18,6 @@ import ( type OvsdbServer struct { srv *rpc2.Server listener net.Listener - done chan struct{} db Database ready bool readyMutex sync.RWMutex @@ -36,7 +35,6 @@ type DatabaseModel struct { // NewOvsdbServer returns a new OvsdbServer func NewOvsdbServer(db Database, models ...DatabaseModel) (*OvsdbServer, error) { o := &OvsdbServer{ - done: make(chan struct{}, 1), db: db, models: make(map[string]DatabaseModel), modelsMutex: sync.RWMutex{}, @@ -98,7 +96,6 @@ func (o *OvsdbServer) Close() { o.ready = false o.readyMutex.Unlock() o.listener.Close() - close(o.done) } // Ready returns true if a server is ready to handle connections diff --git a/server/server_integration_test.go b/server/server_integration_test.go deleted file mode 100644 index 24a0a934..00000000 --- a/server/server_integration_test.go +++ /dev/null @@ -1,521 +0,0 @@ -package server - -import ( - "context" - "fmt" - "math/rand" - "os" - "path/filepath" - "reflect" - "sync" - "testing" - "time" - - "github.com/ovn-org/libovsdb/cache" - "github.com/ovn-org/libovsdb/client" - "github.com/ovn-org/libovsdb/model" - "github.com/ovn-org/libovsdb/ovsdb" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -// bridgeType is the simplified ORM model of the Bridge table -type bridgeType struct { - UUID string `ovsdb:"_uuid"` - Name string `ovsdb:"name"` - DatapathType string `ovsdb:"datapath_type"` - DatapathID *string `ovsdb:"datapath_id"` - OtherConfig map[string]string `ovsdb:"other_config"` - ExternalIds map[string]string `ovsdb:"external_ids"` - Ports []string `ovsdb:"ports"` - Status map[string]string `ovsdb:"status"` -} - -// ovsType is the simplified ORM model of the Bridge table -type ovsType struct { - UUID string `ovsdb:"_uuid"` - Bridges []string `ovsdb:"bridges"` -} - -func getSchema() (*ovsdb.DatabaseSchema, error) { - wd, err := os.Getwd() - if err != nil { - return nil, err - } - path := filepath.Join(wd, "testdata", "ovslite.json") - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - schema, err := ovsdb.SchemaFromFile(f) - if err != nil { - return nil, err - } - return schema, nil -} - -func TestClientServerEcho(t *testing.T) { - defDB, err := model.NewDBModel("Open_vSwitch", map[string]model.Model{ - "Open_vSwitch": &ovsType{}, - "Bridge": &bridgeType{}}) - require.Nil(t, err) - - schema, err := getSchema() - require.Nil(t, err) - - ovsDB := NewInMemoryDatabase(map[string]*model.DBModel{"Open_vSwitch": defDB}) - - rand.Seed(time.Now().UnixNano()) - tmpfile := fmt.Sprintf("/tmp/ovsdb-%d.sock", rand.Intn(10000)) - defer os.Remove(tmpfile) - server, err := NewOvsdbServer(ovsDB, DatabaseModel{ - Model: defDB, - Schema: schema, - }) - require.Nil(t, err) - - go func(t *testing.T, o *OvsdbServer) { - if err := o.Serve("unix", tmpfile); err != nil { - t.Error(err) - } - }(t, server) - defer server.Close() - require.Eventually(t, func() bool { - return server.Ready() - }, 1*time.Second, 10*time.Millisecond) - - ovs, err := client.NewOVSDBClient(defDB, client.WithEndpoint(fmt.Sprintf("unix:%s", tmpfile))) - require.NoError(t, err) - err = ovs.Connect(context.Background()) - require.NoError(t, err) - err = ovs.Echo(context.Background()) - assert.Nil(t, err) -} - -func TestClientServerInsert(t *testing.T) { - defDB, err := model.NewDBModel("Open_vSwitch", map[string]model.Model{ - "Open_vSwitch": &ovsType{}, - "Bridge": &bridgeType{}}) - require.Nil(t, err) - - schema, err := getSchema() - require.Nil(t, err) - - ovsDB := NewInMemoryDatabase(map[string]*model.DBModel{"Open_vSwitch": defDB}) - rand.Seed(time.Now().UnixNano()) - tmpfile := fmt.Sprintf("/tmp/ovsdb-%d.sock", rand.Intn(10000)) - defer os.Remove(tmpfile) - server, err := NewOvsdbServer(ovsDB, DatabaseModel{ - Model: defDB, - Schema: schema, - }) - assert.Nil(t, err) - - go func(t *testing.T, o *OvsdbServer) { - if err := o.Serve("unix", tmpfile); err != nil { - t.Error(err) - } - }(t, server) - defer server.Close() - require.Eventually(t, func() bool { - return server.Ready() - }, 1*time.Second, 10*time.Millisecond) - - ovs, err := client.NewOVSDBClient(defDB, client.WithEndpoint(fmt.Sprintf("unix:%s", tmpfile))) - require.NoError(t, err) - err = ovs.Connect(context.Background()) - require.NoError(t, err) - _, err = ovs.MonitorAll(context.Background()) - require.NoError(t, err) - - wallace := "wallace" - bridgeRow := &bridgeType{ - Name: "foo", - DatapathType: "bar", - DatapathID: &wallace, - ExternalIds: map[string]string{"go": "awesome", "docker": "made-for-each-other"}, - } - - ops, err := ovs.Create(bridgeRow) - require.Nil(t, err) - reply, err := ovs.Transact(context.Background(), ops...) - assert.Nil(t, err) - opErr, err := ovsdb.CheckOperationResults(reply, ops) - assert.NoErrorf(t, err, "%+v", opErr) - - uuid := reply[0].UUID.GoUUID - require.Eventually(t, func() bool { - br := &bridgeType{UUID: uuid} - err := ovs.Get(br) - return err == nil - }, 2*time.Second, 500*time.Millisecond) - - br := &bridgeType{UUID: uuid} - err = ovs.Get(br) - require.NoError(t, err) - - assert.Equal(t, bridgeRow.Name, br.Name) - assert.Equal(t, bridgeRow.ExternalIds, br.ExternalIds) - assert.Equal(t, bridgeRow.DatapathType, br.DatapathType) - assert.Equal(t, *bridgeRow.DatapathID, wallace) -} - -func TestClientServerMonitor(t *testing.T) { - defDB, err := model.NewDBModel("Open_vSwitch", map[string]model.Model{ - "Open_vSwitch": &ovsType{}, - "Bridge": &bridgeType{}}) - if err != nil { - t.Fatal(err) - } - - schema, err := getSchema() - if err != nil { - t.Fatal(err) - } - - ovsDB := NewInMemoryDatabase(map[string]*model.DBModel{"Open_vSwitch": defDB}) - rand.Seed(time.Now().UnixNano()) - tmpfile := fmt.Sprintf("/tmp/ovsdb-%d.sock", rand.Intn(10000)) - defer os.Remove(tmpfile) - server, err := NewOvsdbServer(ovsDB, DatabaseModel{ - Model: defDB, - Schema: schema, - }) - assert.Nil(t, err) - - go func(t *testing.T, o *OvsdbServer) { - if err := o.Serve("unix", tmpfile); err != nil { - t.Error(err) - } - }(t, server) - defer server.Close() - require.Eventually(t, func() bool { - return server.Ready() - }, 1*time.Second, 10*time.Millisecond) - - ovs, err := client.NewOVSDBClient(defDB, client.WithEndpoint(fmt.Sprintf("unix:%s", tmpfile))) - require.NoError(t, err) - err = ovs.Connect(context.Background()) - require.NoError(t, err) - - ovsRow := &ovsType{ - UUID: "ovs", - } - bridgeRow := &bridgeType{ - UUID: "foo", - Name: "foo", - ExternalIds: map[string]string{"go": "awesome", "docker": "made-for-each-other"}, - } - - seenMutex := sync.RWMutex{} - seenInsert := false - seenMutation := false - seenInitialOvs := false - ovs.Cache().AddEventHandler(&cache.EventHandlerFuncs{ - AddFunc: func(table string, model model.Model) { - if table == "Bridge" { - br := model.(*bridgeType) - assert.Equal(t, bridgeRow.Name, br.Name) - assert.Equal(t, bridgeRow.ExternalIds, br.ExternalIds) - seenMutex.Lock() - seenInsert = true - seenMutex.Unlock() - } - if table == "Open_vSwitch" { - seenMutex.Lock() - seenInitialOvs = true - seenMutex.Unlock() - } - }, - UpdateFunc: func(table string, old, new model.Model) { - if table == "Open_vSwitch" { - ov := new.(*ovsType) - assert.Equal(t, 1, len(ov.Bridges)) - seenMutex.Lock() - seenMutation = true - seenMutex.Unlock() - } - }, - }) - - var ops []ovsdb.Operation - ovsOps, err := ovs.Create(ovsRow) - require.Nil(t, err) - reply, err := ovs.Transact(context.Background(), ovsOps...) - require.Nil(t, err) - _, err = ovsdb.CheckOperationResults(reply, ovsOps) - require.Nil(t, err) - require.NotEmpty(t, reply[0].UUID.GoUUID) - ovsRow.UUID = reply[0].UUID.GoUUID - - _, err = ovs.MonitorAll(context.Background()) - require.Nil(t, err) - require.Eventually(t, func() bool { - seenMutex.RLock() - defer seenMutex.RUnlock() - return seenInitialOvs - }, 1*time.Second, 10*time.Millisecond) - - bridgeOps, err := ovs.Create(bridgeRow) - require.Nil(t, err) - ops = append(ops, bridgeOps...) - - mutateOps, err := ovs.Where(ovsRow).Mutate(ovsRow, model.Mutation{ - Field: &ovsRow.Bridges, - Mutator: ovsdb.MutateOperationInsert, - Value: []string{"foo"}, - }) - require.Nil(t, err) - ops = append(ops, mutateOps...) - - reply, err = ovs.Transact(context.Background(), ops...) - require.Nil(t, err) - - _, err = ovsdb.CheckOperationResults(reply, ops) - assert.Nil(t, err) - assert.Equal(t, 1, reply[1].Count) - - assert.Eventually(t, func() bool { - seenMutex.RLock() - defer seenMutex.RUnlock() - return seenInsert - }, 1*time.Second, 10*time.Millisecond) - assert.Eventually(t, func() bool { - seenMutex.RLock() - defer seenMutex.RUnlock() - return seenMutation - }, 1*time.Second, 10*time.Millisecond) -} - -func TestClientServerInsertAndDelete(t *testing.T) { - defDB, err := model.NewDBModel("Open_vSwitch", map[string]model.Model{ - "Open_vSwitch": &ovsType{}, - "Bridge": &bridgeType{}}) - require.Nil(t, err) - - schema, err := getSchema() - require.Nil(t, err) - - ovsDB := NewInMemoryDatabase(map[string]*model.DBModel{"Open_vSwitch": defDB}) - rand.Seed(time.Now().UnixNano()) - tmpfile := fmt.Sprintf("/tmp/ovsdb-%d.sock", rand.Intn(10000)) - defer os.Remove(tmpfile) - server, err := NewOvsdbServer(ovsDB, DatabaseModel{ - Model: defDB, - Schema: schema, - }) - assert.Nil(t, err) - - go func(t *testing.T, o *OvsdbServer) { - if err := o.Serve("unix", tmpfile); err != nil { - t.Error(err) - } - }(t, server) - defer server.Close() - require.Eventually(t, func() bool { - return server.Ready() - }, 1*time.Second, 10*time.Millisecond) - - ovs, err := client.NewOVSDBClient(defDB, client.WithEndpoint(fmt.Sprintf("unix:%s", tmpfile))) - require.NoError(t, err) - err = ovs.Connect(context.Background()) - require.NoError(t, err) - _, err = ovs.MonitorAll(context.Background()) - require.NoError(t, err) - - bridgeRow := &bridgeType{ - Name: "foo", - ExternalIds: map[string]string{"go": "awesome", "docker": "made-for-each-other"}, - } - - ops, err := ovs.Create(bridgeRow) - require.Nil(t, err) - reply, err := ovs.Transact(context.Background(), ops...) - require.Nil(t, err) - _, err = ovsdb.CheckOperationResults(reply, ops) - require.Nil(t, err) - - uuid := reply[0].UUID.GoUUID - assert.Eventually(t, func() bool { - br := &bridgeType{UUID: uuid} - err := ovs.Get(br) - return err == nil - }, 2*time.Second, 500*time.Millisecond) - - bridgeRow.UUID = uuid - deleteOp, err := ovs.Where(bridgeRow).Delete() - require.Nil(t, err) - - reply, err = ovs.Transact(context.Background(), deleteOp...) - assert.Nil(t, err) - _, err = ovsdb.CheckOperationResults(reply, ops) - assert.Nil(t, err) - assert.Equal(t, 1, reply[0].Count) -} - -func TestClientServerInsertDuplicate(t *testing.T) { - defDB, err := model.NewDBModel("Open_vSwitch", map[string]model.Model{ - "Open_vSwitch": &ovsType{}, - "Bridge": &bridgeType{}, - }) - require.Nil(t, err) - - schema, err := getSchema() - require.Nil(t, err) - - ovsDB := NewInMemoryDatabase(map[string]*model.DBModel{"Open_vSwitch": defDB}) - rand.Seed(time.Now().UnixNano()) - tmpfile := fmt.Sprintf("/tmp/ovsdb-%d.sock", rand.Intn(10000)) - defer os.Remove(tmpfile) - server, err := NewOvsdbServer(ovsDB, DatabaseModel{ - Model: defDB, - Schema: schema, - }) - assert.Nil(t, err) - - go func(t *testing.T, o *OvsdbServer) { - if err := o.Serve("unix", tmpfile); err != nil { - t.Error(err) - } - }(t, server) - defer server.Close() - require.Eventually(t, func() bool { - return server.Ready() - }, 1*time.Second, 10*time.Millisecond) - - ovs, err := client.NewOVSDBClient(defDB, client.WithEndpoint(fmt.Sprintf("unix:%s", tmpfile))) - require.NoError(t, err) - err = ovs.Connect(context.Background()) - require.NoError(t, err) - - bridgeRow := &bridgeType{ - Name: "foo", - ExternalIds: map[string]string{"go": "awesome", "docker": "made-for-each-other"}, - } - - ops, err := ovs.Create(bridgeRow) - require.Nil(t, err) - reply, err := ovs.Transact(context.Background(), ops...) - require.Nil(t, err) - _, err = ovsdb.CheckOperationResults(reply, ops) - require.Nil(t, err) - - // duplicate - reply, err = ovs.Transact(context.Background(), ops...) - require.Nil(t, err) - opErrs, err := ovsdb.CheckOperationResults(reply, ops) - require.Error(t, err) - require.Error(t, opErrs[0]) - require.IsTypef(t, &ovsdb.ConstraintViolation{}, opErrs[0], opErrs[0].Error()) -} - -func TestClientServerInsertAndUpdate(t *testing.T) { - defDB, err := model.NewDBModel("Open_vSwitch", map[string]model.Model{ - "Open_vSwitch": &ovsType{}, - "Bridge": &bridgeType{}}) - require.Nil(t, err) - - schema, err := getSchema() - require.Nil(t, err) - - ovsDB := NewInMemoryDatabase(map[string]*model.DBModel{"Open_vSwitch": defDB}) - rand.Seed(time.Now().UnixNano()) - tmpfile := fmt.Sprintf("/tmp/ovsdb-%d.sock", rand.Intn(10000)) - defer os.Remove(tmpfile) - server, err := NewOvsdbServer(ovsDB, DatabaseModel{ - Model: defDB, - Schema: schema, - }) - assert.Nil(t, err) - - go func(t *testing.T, o *OvsdbServer) { - if err := o.Serve("unix", tmpfile); err != nil { - t.Error(err) - } - }(t, server) - defer server.Close() - require.Eventually(t, func() bool { - return server.Ready() - }, 1*time.Second, 10*time.Millisecond) - - ovs, err := client.NewOVSDBClient(defDB, client.WithEndpoint(fmt.Sprintf("unix:%s", tmpfile))) - require.NoError(t, err) - err = ovs.Connect(context.Background()) - require.NoError(t, err) - defer ovs.Disconnect() - - _, err = ovs.MonitorAll(context.Background()) - require.NoError(t, err) - - bridgeRow := &bridgeType{ - Name: "br-update", - ExternalIds: map[string]string{"go": "awesome", "docker": "made-for-each-other"}, - } - - ops, err := ovs.Create(bridgeRow) - require.NoError(t, err) - reply, err := ovs.Transact(context.Background(), ops...) - require.NoError(t, err) - _, err = ovsdb.CheckOperationResults(reply, ops) - require.NoError(t, err) - - uuid := reply[0].UUID.GoUUID - assert.Eventually(t, func() bool { - br := &bridgeType{UUID: uuid} - err := ovs.Get(br) - return err == nil - }, 2*time.Second, 500*time.Millisecond) - - // try to modify immutable field - bridgeRow.UUID = uuid - bridgeRow.Name = "br-update2" - _, err = ovs.Where(bridgeRow).Update(bridgeRow, &bridgeRow.Name) - require.Error(t, err) - bridgeRow.Name = "br-update" - - // update many fields - bridgeRow.UUID = uuid - bridgeRow.Name = "br-update" - bridgeRow.ExternalIds["baz"] = "foobar" - bridgeRow.OtherConfig = map[string]string{"foo": "bar"} - ops, err = ovs.Where(bridgeRow).Update(bridgeRow) - require.NoError(t, err) - reply, err = ovs.Transact(context.Background(), ops...) - require.NoError(t, err) - opErrs, err := ovsdb.CheckOperationResults(reply, ops) - require.NoErrorf(t, err, "%+v", opErrs) - - require.Eventually(t, func() bool { - br := &bridgeType{UUID: uuid} - err = ovs.Get(br) - if err != nil { - return false - } - return reflect.DeepEqual(br, bridgeRow) - }, 2*time.Second, 50*time.Millisecond) - - newExternalIds := map[string]string{"foo": "bar"} - bridgeRow.ExternalIds = newExternalIds - ops, err = ovs.Where(bridgeRow).Update(bridgeRow, &bridgeRow.ExternalIds) - require.NoError(t, err) - reply, err = ovs.Transact(context.Background(), ops...) - require.NoError(t, err) - opErr, err := ovsdb.CheckOperationResults(reply, ops) - require.NoErrorf(t, err, "%+v", opErr) - - assert.Eventually(t, func() bool { - br := &bridgeType{UUID: uuid} - err = ovs.Get(br) - if err != nil { - return false - } - return reflect.DeepEqual(br.ExternalIds, bridgeRow.ExternalIds) - }, 2*time.Second, 500*time.Millisecond) - - br := &bridgeType{UUID: uuid} - err = ovs.Get(br) - assert.NoError(t, err) - - assert.Equal(t, bridgeRow, br) -} diff --git a/server/server_test.go b/server/server_test.go index 604300d0..edac14df 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -2,6 +2,8 @@ package server import ( "encoding/json" + "os" + "path/filepath" "testing" "github.com/google/uuid" @@ -11,6 +13,42 @@ import ( "github.com/stretchr/testify/require" ) +// bridgeType is the simplified ORM model of the Bridge table +type bridgeType struct { + UUID string `ovsdb:"_uuid"` + Name string `ovsdb:"name"` + DatapathType string `ovsdb:"datapath_type"` + DatapathID *string `ovsdb:"datapath_id"` + OtherConfig map[string]string `ovsdb:"other_config"` + ExternalIds map[string]string `ovsdb:"external_ids"` + Ports []string `ovsdb:"ports"` + Status map[string]string `ovsdb:"status"` +} + +// ovsType is the simplified ORM model of the Bridge table +type ovsType struct { + UUID string `ovsdb:"_uuid"` + Bridges []string `ovsdb:"bridges"` +} + +func getSchema() (*ovsdb.DatabaseSchema, error) { + wd, err := os.Getwd() + if err != nil { + return nil, err + } + path := filepath.Join(wd, "testdata", "ovslite.json") + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + schema, err := ovsdb.SchemaFromFile(f) + if err != nil { + return nil, err + } + return schema, nil +} + func TestExpandNamedUUID(t *testing.T) { testUUID := uuid.NewString() testUUID1 := uuid.NewString() diff --git a/test/ovs/ovs_integration_test.go b/test/ovs/ovs_integration_test.go index 06796de0..bac2c736 100644 --- a/test/ovs/ovs_integration_test.go +++ b/test/ovs/ovs_integration_test.go @@ -3,6 +3,7 @@ package ovs import ( "context" "os" + "path/filepath" "reflect" "strings" "testing" @@ -15,6 +16,7 @@ import ( "github.com/ovn-org/libovsdb/client" "github.com/ovn-org/libovsdb/model" "github.com/ovn-org/libovsdb/ovsdb" + "github.com/ovn-org/libovsdb/server" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -23,9 +25,11 @@ import ( // OVSIntegrationSuite runs tests against a real Open vSwitch instance type OVSIntegrationSuite struct { suite.Suite - pool *dockertest.Pool - resource *dockertest.Resource - client client.Client + realServer bool + pool *dockertest.Pool + resource *dockertest.Resource + client client.Client + server *server.OvsdbServer } func (suite *OVSIntegrationSuite) SetupSuite() { @@ -38,32 +42,58 @@ func (suite *OVSIntegrationSuite) SetupSuite() { tag = "latest" } - options := &dockertest.RunOptions{ - Repository: "libovsdb/ovs", - Tag: tag, - ExposedPorts: []string{"6640/tcp"}, - PortBindings: map[docker.Port][]docker.PortBinding{ - "6640/tcp": {{HostPort: "56640"}}, - }, - Tty: true, + realServer := os.Getenv("IN_MEMORY_DATABASE") + if realServer != "1" { + suite.realServer = true } - hostConfig := func(config *docker.HostConfig) { - // set AutoRemove to true so that stopped container goes away by itself - config.AutoRemove = true - config.RestartPolicy = docker.RestartPolicy{ - Name: "no", + + if suite.realServer { + options := &dockertest.RunOptions{ + Repository: "libovsdb/ovs", + Tag: tag, + ExposedPorts: []string{"6640/tcp"}, + PortBindings: map[docker.Port][]docker.PortBinding{ + "6640/tcp": {{HostPort: "56640"}}, + }, + Tty: true, + } + hostConfig := func(config *docker.HostConfig) { + // set AutoRemove to true so that stopped container goes away by itself + config.AutoRemove = true + config.RestartPolicy = docker.RestartPolicy{ + Name: "no", + } } - } - suite.resource, err = suite.pool.RunWithOptions(options, hostConfig) - require.NoError(suite.T(), err) + suite.resource, err = suite.pool.RunWithOptions(options, hostConfig) + require.NoError(suite.T(), err) - // set expiry to 90 seconds so containers are cleaned up on test panic - err = suite.resource.Expire(90) - require.NoError(suite.T(), err) + // set expiry to 90 seconds so containers are cleaned up on test panic + err = suite.resource.Expire(90) + require.NoError(suite.T(), err) - // let the container start before we attempt connection - time.Sleep(5 * time.Second) + // let the container start before we attempt connection + time.Sleep(5 * time.Second) + } else { + schema, err := getSchema() + require.Nil(suite.T(), err) + + ovsDB := server.NewInMemoryDatabase(map[string]*model.DBModel{"Open_vSwitch": defDB}) + suite.server, err = server.NewOvsdbServer(ovsDB, server.DatabaseModel{ + Model: defDB, + Schema: schema, + }) + require.Nil(suite.T(), err) + + go func(t *testing.T, o *server.OvsdbServer) { + if err := o.Serve("tcp", ":56640"); err != nil { + t.Error(err) + } + }(suite.T(), suite.server) + require.Eventually(suite.T(), func() bool { + return suite.server.Ready() + }, 1*time.Second, 10*time.Millisecond) + } err = suite.pool.Retry(func() error { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) @@ -72,7 +102,7 @@ func (suite *OVSIntegrationSuite) SetupSuite() { ovs, err := client.NewOVSDBClient( defDB, client.WithEndpoint(endpoint), - client.WithLeaderOnly(true), + // client.WithLeaderOnly(true), ) if err != nil { return err @@ -103,8 +133,13 @@ func (suite *OVSIntegrationSuite) TearDownSuite() { suite.client.Close() suite.client = nil } - err := suite.pool.Purge(suite.resource) - require.NoError(suite.T(), err) + if suite.pool != nil && suite.resource != nil { + err := suite.pool.Purge(suite.resource) + require.NoError(suite.T(), err) + } + if suite.server != nil { + suite.server.Close() + } } func TestOVSIntegrationTestSuite(t *testing.T) { @@ -174,6 +209,24 @@ var defDB, _ = model.NewDBModel("Open_vSwitch", map[string]model.Model{ "Queue": &queueType{}, }) +func getSchema() (*ovsdb.DatabaseSchema, error) { + wd, err := os.Getwd() + if err != nil { + return nil, err + } + path := filepath.Join(wd, "..", "..", "example", "vswitchd", "ovs.ovsschema") + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + schema, err := ovsdb.SchemaFromFile(f) + if err != nil { + return nil, err + } + return schema, nil +} + func (suite *OVSIntegrationSuite) TestConnectReconnect() { assert.True(suite.T(), suite.client.Connected()) err := suite.client.Echo(context.TODO()) @@ -323,9 +376,18 @@ func (suite *OVSIntegrationSuite) TestWithReconnect() { require.Equal(suite.T(), bridgeName, br.Name) // trigger reconnect - err = suite.pool.Client.RestartContainer(suite.resource.Container.ID, 0) - require.NoError(suite.T(), err) - + if suite.realServer { + err = suite.pool.Client.RestartContainer(suite.resource.Container.ID, 0) + require.NoError(suite.T(), err) + } else { + suite.server.Close() + time.Sleep(2 * time.Second) + go func(t *testing.T, o *server.OvsdbServer) { + if err := o.Serve("tcp", ":56640"); err != nil { + t.Error(err) + } + }(suite.T(), suite.server) + } // check that we are automatically reconnected require.Eventually(suite.T(), func() bool { return suite.client.Connected() @@ -553,6 +615,9 @@ func (suite *OVSIntegrationSuite) TestColumnSchemaValidationIntegration() { } func (suite *OVSIntegrationSuite) TestMonitorCancelIntegration() { + if !suite.realServer { + suite.T().Skip("not supported on in-memory ovsdb-server") + } monitorID, err := suite.client.Monitor( context.TODO(), suite.client.NewMonitor( @@ -593,7 +658,11 @@ func (suite *OVSIntegrationSuite) TestInsertDuplicateTransactIntegration() { _, err = suite.createBridge("br-dup") assert.Error(suite.T(), err) - assert.IsType(suite.T(), &ovsdb.ConstraintViolation{}, err) + + // TODO: In-memory server doesn't return a typed error here + if suite.realServer { + assert.IsTypef(suite.T(), &ovsdb.ConstraintViolation{}, err, "got %+v", err) + } } func (suite *OVSIntegrationSuite) TestUpdate() {