Skip to content

Commit

Permalink
Add merge to Ops and ReconcileOps; UseStub to client.
Browse files Browse the repository at this point in the history
 * (M) rib/reconcile/reconcile(_test)?.go
   - Add support for merging Ops and ReconcileOps instances together.
 * (M) rib/reconcile/remote(_rtest)?.go
   - Add support for a client that takes an existing gRIBI client stub.
  • Loading branch information
robshakir committed Nov 1, 2023
1 parent 9a293da commit 3f936ef
Show file tree
Hide file tree
Showing 4 changed files with 334 additions and 0 deletions.
20 changes: 20 additions & 0 deletions rib/reconciler/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ type Ops struct {
TopLevel []*spb.AFTOperation
}

// Merge adds the operations from the "in" operations to the receiver ops.
func (o *Ops) Merge(in *Ops) {
if in == nil {
return
}
o.NH = append(o.NH, in.NH...)
o.NHG = append(o.NHG, in.NHG...)
o.TopLevel = append(o.TopLevel, in.TopLevel...)
}

// ReconcileOps stores the operations that are required for a specific reconciliation
// run.
type ReconcileOps struct {
Expand All @@ -146,6 +156,16 @@ type ReconcileOps struct {
Delete *Ops
}

// Merge adds the operations from the "in" operations to the receiver operations.
func (r *ReconcileOps) Merge(in *ReconcileOps) {
if in == nil {
return
}
r.Add.Merge(in.Add)
r.Replace.Merge(in.Replace)
r.Delete.Merge(in.Delete)
}

// NewReconcileOps returns a new reconcileOps struct with the fields initialised.
func NewReconcileOps() *ReconcileOps {
return &ReconcileOps{
Expand Down
259 changes: 259 additions & 0 deletions rib/reconciler/reconcile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1333,3 +1333,262 @@ func TestReconcileRemote(t *testing.T) {
})
}
}

func TestMergeOps(t *testing.T) {
tests := []struct {
desc string
inOriginal *Ops
inInput *Ops
want *Ops
}{{
desc: "merging to empty",
inOriginal: &Ops{},
inInput: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
NHG: []*spb.AFTOperation{{
Id: 2,
}},
NH: []*spb.AFTOperation{{
Id: 3,
}},
},
want: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
NHG: []*spb.AFTOperation{{
Id: 2,
}},
NH: []*spb.AFTOperation{{
Id: 3,
}},
},
}, {
desc: "merging to populated",
inOriginal: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 10,
}},
NHG: []*spb.AFTOperation{{
Id: 20,
}},
NH: []*spb.AFTOperation{{
Id: 30,
}},
},
inInput: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
NHG: []*spb.AFTOperation{{
Id: 2,
}},
NH: []*spb.AFTOperation{{
Id: 3,
}},
},
want: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 10,
}, {
Id: 1,
}},
NHG: []*spb.AFTOperation{{
Id: 20,
}, {
Id: 2,
}},
NH: []*spb.AFTOperation{{
Id: 30,
}, {
Id: 3,
}},
},
}, {
desc: "nil merged in",
inOriginal: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 10,
}},
NHG: []*spb.AFTOperation{{
Id: 20,
}},
NH: []*spb.AFTOperation{{
Id: 30,
}},
},
inInput: nil,
want: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 10,
}},
NHG: []*spb.AFTOperation{{
Id: 20,
}},
NH: []*spb.AFTOperation{{
Id: 30,
}},
},
}}

for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
tt.inOriginal.Merge(tt.inInput)
if diff := cmp.Diff(tt.inOriginal, tt.want, protocmp.Transform()); diff != "" {
t.Fatalf("&Ops{}.Merge(): did not get expected result, diff(-got,+want):\n%s", diff)
}
})
}
}

func TestMergeReconcileOps(t *testing.T) {
tests := []struct {
desc string
inOriginal *ReconcileOps
inInput *ReconcileOps
want *ReconcileOps
}{{
desc: "merging to empty",
inOriginal: NewReconcileOps(),
inInput: &ReconcileOps{
Add: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
Delete: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
Replace: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
},
want: &ReconcileOps{
Add: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
Delete: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
Replace: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
},
}, {
desc: "merging to populated",
inOriginal: &ReconcileOps{
Add: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 10,
}},
},
Delete: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 101,
}},
},
Replace: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1001,
}},
},
},
inInput: &ReconcileOps{
Add: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
Delete: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
Replace: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1,
}},
},
},
want: &ReconcileOps{
Add: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 10,
}, {
Id: 1,
}},
},
Delete: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 101,
}, {
Id: 1,
}},
},
Replace: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1001,
}, {
Id: 1,
}},
},
},
}, {
desc: "merging nil in",
inOriginal: &ReconcileOps{
Add: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 10,
}},
},
Delete: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 101,
}},
},
Replace: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1001,
}},
},
},
want: &ReconcileOps{
Add: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 10,
}},
},
Delete: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 101,
}},
},
Replace: &Ops{
TopLevel: []*spb.AFTOperation{{
Id: 1001,
}},
},
},
}}

for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
tt.inOriginal.Merge(tt.inInput)
if diff := cmp.Diff(tt.inOriginal, tt.want, protocmp.Transform()); diff != "" {
t.Fatalf("&ReconcileOps.Merge(): did not get expected result, diff(-got,want):\n%s", diff)
}
})
}
}
17 changes: 17 additions & 0 deletions rib/reconciler/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ func NewRemoteRIB(ctx context.Context, defName, addr string) (*RemoteRIB, error)
return r, nil
}

// NewRemoteRIBWithStub creates a new remote RIB using the specified default network
// instance name, and the provided stub client. It returns an error if the
// client cannot be created.
func NewRemoteRIBWithStub(defName string, stub spb.GRIBIClient) (*RemoteRIB, error) {
c, err := client.New()
if err != nil {
return nil, fmt.Errorf("cannot create gRIBI client, %v", err)
}
if err := c.UseStub(stub); err != nil {
return nil, fmt.Errorf("cannot set gRIBI client within wrapper client, %v", err)
}
return &RemoteRIB{
c: c,
defaultName: defName,
}, nil
}

// CleanUp closes the remote connection to the gRIBI server.
func (r *RemoteRIB) CleanUp() {
r.c.Close()
Expand Down
38 changes: 38 additions & 0 deletions rib/reconciler/remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package reconciler

import (
"context"
"crypto/tls"
"net"
"testing"
"time"
Expand Down Expand Up @@ -77,6 +78,43 @@ func TestNewRemoteRIB(t *testing.T) {
}
}

func TestNewRemoteRIBWithStub(t *testing.T) {
tests := []struct {
desc string
inDefName string
wantErr bool
}{{
desc: "successful dial",
inDefName: "DEFAULT",
}}

for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
addr, stop := newServer(t, nil)
defer stop()

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()

tlsc := credentials.NewTLS(&tls.Config{
InsecureSkipVerify: true,
})

c, err := grpc.DialContext(ctx, addr,
grpc.WithTransportCredentials(tlsc),
grpc.WithBlock(),
)
if err != nil {
t.Fatalf("grpc.DialContext(%s): cannot dial server, %v", addr, err)
}

if _, err := NewRemoteRIBWithStub(tt.inDefName, spb.NewGRIBIClient(c)); err != nil {
t.Fatalf("NewRemoteRIBWIthStub(...): cannot create client, %v", err)
}
})
}
}

type badGRIBI struct {
*spb.UnimplementedGRIBIServer
}
Expand Down

0 comments on commit 3f936ef

Please sign in to comment.