Newer
Older
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/change"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/types"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
"code.fbi.h-da.de/danet/gosdn/controller/mocks"
"code.fbi.h-da.de/danet/gosdn/forks/goarista/gnmi"
"code.fbi.h-da.de/danet/gosdn/models/generated/openconfig"
gpb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/ygot"
"github.com/stretchr/testify/mock"
// testSetupGnmi bootstraps tests for gnmi transport.
func testSetupGnmi() {
// TODO: Set sane defaults
gnmiConfig = &gnmi.Config{
Username: "test",
Password: "test",
Addr: "localhost:13371",
Encoding: gpb.Encoding_PROTO,
}
startGnmiTarget = make(chan string)
stopGnmiTarget = make(chan bool)
go targetRunner()
}
func TestGnmi_Capabilities(t *testing.T) {
capabilityResponse := &gpb.CapabilityResponse{
SupportedModels: nil,
SupportedEncodings: []gpb.Encoding{gpb.Encoding_PROTO, gpb.Encoding_JSON_IETF, gpb.Encoding_JSON},
GNMIVersion: "0.6.0",
Extension: nil,
}
capabilityRequest := &gpb.CapabilityRequest{}
transport.client.(*mocks.GNMIClient).
On("NewContext", mockContext, mock.Anything).
Return(mockContext)
transport.client.(*mocks.GNMIClient).
On("Capabilities", mockContext, capabilityRequest).
Return(capabilityResponse, nil)
}
tests := []struct {
name string
fields fields
args args
want *gpb.CapabilityResponse
wantErr bool
}{
{
fields: fields{transport: &transport},
endpoint: gnmiConfig.Addr,
want: capabilityResponse,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.runEndpoint {
startGnmiTarget <- tt.args.endpoint
}
got, err := tt.fields.transport.Capabilities(context.Background())
if (err != nil) != tt.wantErr {
t.Errorf("Capabilities() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Get() got = %v, want %v", got, tt.want)
if tt.args.runEndpoint {
stopGnmiTarget <- true
}
})
}
}
func TestGnmi_Close(t *testing.T) {
type fields struct {
SetNode func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
RespChan chan *gpb.SubscribeResponse
}
tests := []struct {
name string
fields fields
wantErr bool
}{
{name: "dummy", fields: fields{}, wantErr: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := &Gnmi{
SetNode: tt.fields.SetNode,
RespChan: tt.fields.RespChan,
}
if err := g.Close(); (err != nil) != tt.wantErr {
t.Errorf("Close() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestGnmi_Get(t *testing.T) {
getRequest := &gpb.GetRequest{
Prefix: nil,
Path: nil,
Type: 0,
Encoding: 0,
UseModels: nil,
Extension: nil,
}
getResponse := &gpb.GetResponse{
Notification: nil,
Error: nil,
Extension: nil,
}
transport.client.(*mocks.GNMIClient).
On("NewContext", mockContext, mock.Anything).
Return(mockContext)
transport.client.(*mocks.GNMIClient).
On("NewGetRequest", mockContext, mock.Anything, mock.Anything).
Return(getRequest, nil)
transport.client.(*mocks.GNMIClient).
On("Get", mockContext, mock.Anything).
Return(getResponse, nil)
}
tests := []struct {
name string
fields fields
args args
want interface{}
wantErr bool
}{
fields: fields{&Gnmi{}},
args: args{
params: nil,
},
fields: fields{transport: &transport},
args: args{},
want: getResponse,
fields: fields{transport: &transport},
args: args{
runEndpoint: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.runEndpoint {
got, err := tt.fields.transport.Get(context.Background(), tt.args.params...)
if (err != nil) != tt.wantErr {
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Get() got = %v, want %v", got, tt.want)
}
if tt.args.runEndpoint {
stopGnmiTarget <- true
}
})
}
}
func TestGnmi_ProcessResponse(t *testing.T) {
type fields struct {
root interface{}
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
name: "Interfaces Interface",
fields: fields{Sbi: &OpenConfig{}},
path: "../test/proto/resp-interfaces-interface-arista-ceos",
Malte Bauch
committed
wantErr: false,
fields: fields{Sbi: &OpenConfig{}},
args: args{
path: "../test/proto/resp-interfaces-wildcard",
root: &openconfig.Device{},
},
wantErr: false,
},
{
fields: fields{Sbi: &OpenConfig{}},
args: args{
path: "../test/proto/resp-full-node-arista-ceos",
root: &openconfig.Device{},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := &Gnmi{
SetNode: tt.fields.Sbi.SetNode,
Unmarshal: tt.fields.Sbi.(*OpenConfig).Unmarshal,
s, err := tt.fields.Sbi.Schema()
if err != nil {
t.Errorf("ProcessResponse() error = %v", err)
}
if err := g.ProcessResponse(resp, tt.args.root, s); (err != nil) != tt.wantErr {
t.Errorf("ProcessResponse() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestGnmi_Set(t *testing.T) {
schema, err := openconfig.Schema()
if err != nil {
t.Errorf("Set() error = %v", err)
}
setResponse := &gpb.SetResponse{}
transport Gnmi
mockArgumentMatcher any
path string
ctx context.Context
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
fields: fields{transport: mockTransport()},
path: "/",
ctx: context.WithValue(context.Background(), types.CtxKeyOperation, ppb.ApiOperation_API_OPERATION_UPDATE), // nolint
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
{
name: "updateValue",
fields: fields{
transport: mockTransport(),
mockArgumentMatcher: mock.MatchedBy(func(input *gpb.SetRequest) bool {
if len(input.Update) == 0 {
return false
}
test, _ := ygot.PathToString(input.Update[0].Path)
return test == "/system/config/hostname"
}),
},
args: args{
payload: change.Payload{
Original: &openconfig.Device{
System: &openconfig.OpenconfigSystem_System{
Config: &openconfig.OpenconfigSystem_System_Config{
Hostname: ygot.String("oldName"),
},
},
},
Modified: &openconfig.Device{
System: &openconfig.OpenconfigSystem_System{
Config: &openconfig.OpenconfigSystem_System_Config{
Hostname: ygot.String("newName"),
},
},
},
},
path: "/system/config/hostname",
ctx: context.WithValue(context.Background(), types.CtxKeyOperation, ppb.ApiOperation_API_OPERATION_UPDATE), // nolint
},
wantErr: false,
},
{
name: "removeValue",
fields: fields{
transport: mockTransport(),
mockArgumentMatcher: mock.MatchedBy(func(input *gpb.SetRequest) bool {
if len(input.Delete) == 0 {
return false
}
test, _ := ygot.PathToString(input.Delete[0])
return test == "/system/config/hostname"
}),
},
args: args{
payload: change.Payload{
Original: &openconfig.Device{
System: &openconfig.OpenconfigSystem_System{
Config: &openconfig.OpenconfigSystem_System_Config{
Hostname: ygot.String("oldName"),
},
},
},
Modified: &openconfig.Device{
System: &openconfig.OpenconfigSystem_System{
Config: &openconfig.OpenconfigSystem_System_Config{
Hostname: nil,
},
},
},
},
path: "/system/config/hostname",
ctx: context.WithValue(context.Background(), types.CtxKeyOperation, ppb.ApiOperation_API_OPERATION_DELETE), // nolint
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.fields.transport.client.(*mocks.GNMIClient).
On("Set", mockContext, tt.fields.mockArgumentMatcher).Return(setResponse, nil)
err := tt.fields.transport.Set(tt.args.ctx, tt.args.payload, tt.args.path, schema)
if (err != nil) != tt.wantErr {
t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestGnmi_Subscribe(t *testing.T) {
type fields struct {
SetNode func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
RespChan chan *gpb.SubscribeResponse
}
type args struct {
ctx context.Context
params []string
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{name: "nil client", fields: fields{}, args: args{}, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := g.Subscribe(tt.args.ctx, tt.args.params...); (err != nil) != tt.wantErr {
t.Errorf("Subscribe() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestGnmi_Type(t *testing.T) {
type fields struct {
SetNode func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
RespChan chan *gpb.SubscribeResponse
}
tests := []struct {
name string
fields fields
want string
}{
{name: "dummy", fields: fields{}, want: "gnmi"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := &Gnmi{
SetNode: tt.fields.SetNode,
RespChan: tt.fields.RespChan,
}
if got := g.Type(); got != tt.want {
t.Errorf("Type() = %v, want %v", got, tt.want)
}
})
}
}
//nolint:errcheck
func TestGnmi_getWithRequest(t *testing.T) {
reqFullNode := gnmiMessages["../test/proto/req-full-node"].(*gpb.GetRequest)
reqInterfacesWildcard := gnmiMessages["../test/proto/req-interfaces-wildcard"].(*gpb.GetRequest)
respFullNode := gnmiMessages["../test/proto/resp-full-node"].(*gpb.GetResponse)
respInterfacesWildcard := gnmiMessages["../test/proto/resp-interfaces-wildcard"].(*gpb.GetResponse)
transport.client.(*mocks.GNMIClient).
On("Get", mockContext, reqFullNode).
Return(respFullNode, nil)
transport.client.(*mocks.GNMIClient).
On("Get", mockContext, reqInterfacesWildcard).
Return(respInterfacesWildcard, nil)
transport.client.(*mocks.GNMIClient).
On("Get", mockContext, mock.Anything).
Return(nil, errors.New("expected mock gnmi error"))
}
tests := []struct {
name string
fields fields
args args
want interface{}
wantErr bool
}{
fields: fields{transport: &transport},
name: "getInterfacesWildcard",
fields: fields{transport: &transport},
args: args{
request: reqInterfacesWildcard,
},
{
name: "invalid request",
fields: fields{transport: &transport},
args: args{
request: nil,
runEndpoint: false,
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.fields.transport.getWithRequest(context.Background(), tt.args.request)
if (err != nil) != tt.wantErr {
t.Errorf("getWithRequest() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getWithRequest() got = %v, want %v", got, tt.want)
}
})
}
}
func TestNewGnmiTransport(t *testing.T) {
type args struct {
}
tests := []struct {
name string
args args
want *Gnmi
wantErr bool
}{
{
name: "unsupported compression",
args: args{
opts: &tpb.TransportOption{
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{
Compression: "brotli",
},
}}},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.name == "default" {
startGnmiTarget <- gnmiConfig.Addr
}
sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG)
if err != nil {
t.Errorf("NewSBI() error = %v", err)
return
got, err := newGnmiTransport(tt.args.opts, sbi)
if (err != nil) != tt.wantErr {
t.Errorf("NewGnmiTransport() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.name == "default" && got != nil {
tt.want.client = got.client
tt.want.config = got.config
tt.want.SetNode = got.SetNode
tt.want.RespChan = got.RespChan
t.Errorf("NewGnmiTransport() got = %#v, want %#v", got, tt.want)
}
if tt.name == "default" {
stopGnmiTarget <- true
}
})
}