Skip to content
Snippets Groups Projects
Commit a6e918ca authored by Manuel Kieweg's avatar Manuel Kieweg
Browse files

tests for unmarshal and adjusted old tests

parent 0adf41c3
No related branches found
No related tags found
2 merge requests!106Resolve "Job Failed #240443",!90Develop
Pipeline #66522 passed with warnings
......@@ -46,7 +46,7 @@ func main() {
device.Transport = transport
p := []string{"/interfaces/interface"}
p := []string{"/interfaces"}
errors := 0
for _, path := range p {
err := pnd.RequestAll(path)
......
......@@ -19,7 +19,7 @@ var tapProto bool
func init() {
// tapProto taps gpb.getResponse and gpb.Getrequests
// to binary file
// CAUTION only set true if you know what you do
// CAUTION only set true if you know what you're doing
tapProto = false
}
......@@ -94,10 +94,6 @@ func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Sch
return err
}
}
modelKey := extractModelKey(fullPath)
log.Debug(modelKey)
schema := models[modelKey]
val,ok := update.Val.Value.(*gpb.TypedValue_JsonIetfVal)
if ok {
opts := []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}}
......@@ -106,6 +102,8 @@ func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Sch
}
return nil
}
// TODO(mk): Evaluate hardcoded model key
schema := models["Device"]
opts := []ytypes.SetNodeOpt{&ytypes.InitMissingElements{}, &ytypes.TolerateJSONInconsistencies{}}
if err := g.SetNode(schema, root, update.Path, update.Val, opts...); err != nil {
return err
......
......@@ -5,7 +5,6 @@ import (
"code.fbi.h-da.de/cocsn/gosdn/mocks"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/util"
"code.fbi.h-da.de/cocsn/gosdn/test"
"code.fbi.h-da.de/cocsn/yang-models/generated/arista"
"code.fbi.h-da.de/cocsn/yang-models/generated/openconfig"
"context"
log "github.com/golang/glog"
......@@ -24,6 +23,7 @@ func TestMain(m *testing.M) {
testSetupGnmi()
testSetupPnd()
testSetupStore()
testSetupSbi()
os.Exit(m.Run())
}
......@@ -76,9 +76,11 @@ func TestGnmi_Capabilities(t *testing.T) {
capabilityRequest := &gpb.CapabilityRequest{}
ctx := context.Background()
transport.client.(*mocks.GNMIClient).
On("Capabilities", ctx, capabilityRequest).
On("NewContext", mockContext, mock.Anything).
Return(mockContext)
transport.client.(*mocks.GNMIClient).
On("Capabilities", mockContext, capabilityRequest).
Return(capabilityResponse, nil)
type fields struct {
......@@ -281,37 +283,28 @@ func TestGnmi_ProcessResponse(t *testing.T) {
wantErr bool
}{
{
name: "Arista Full Node",
fields: fields{Sbi: &Arista{}},
name: "Interfaces Interface",
fields: fields{Sbi: &OpenConfig{}},
args: args{
path: "../test/resp-full-node",
root: &arista.Device{},
},
wantErr: false,
},
{
name: "Arista Interfaces Wildcard",
fields: fields{Sbi: &Arista{}},
args: args{
path: "../test/resp-interfaces-wildcard",
root: &arista.Device{},
root: &openconfig.Device{},
},
wantErr: false,
wantErr: true,
},
{
name: "OC Full Node",
name: "Interfaces Wildcard",
fields: fields{Sbi: &OpenConfig{}},
args: args{
path: "../test/resp-full-node",
path: "../test/resp-interfaces-wildcard",
root: &openconfig.Device{},
},
wantErr: false,
},
{
name: "OC Interfaces Wildcard",
name: "Root",
fields: fields{Sbi: &OpenConfig{}},
args: args{
path: "../test/resp-interfaces-wildcard",
path: "../test/resp-full-node-arista-ceos",
root: &openconfig.Device{},
},
wantErr: false,
......@@ -321,6 +314,7 @@ func TestGnmi_ProcessResponse(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
g := &Gnmi{
SetNode: tt.fields.Sbi.SetNode(),
Unmarshal: tt.fields.Sbi.(*OpenConfig).Unmarshal(),
}
s := tt.fields.Sbi.Schema()
resp := &gpb.GetResponse{}
......@@ -563,7 +557,7 @@ func Test_extractModelKey(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := extraxtPathElements(tt.args.path); got != tt.want {
if got := extractModelKey(tt.args.path); got != tt.want {
t.Errorf("extraxtPathElements() = %v, want %v", got, tt.want)
}
})
......
......@@ -73,33 +73,52 @@ func (oc *OpenConfig) SetNode() func(schema *yang.Entry, root interface{}, path
// representation to the transport.
// Needed for type assertion.
func (oc *OpenConfig) Unmarshal() func([]byte, []string, interface{}, ...ytypes.UnmarshalOpt) error {
return func(bytes []byte, fields []string, goStruct interface{}, opt ...ytypes.UnmarshalOpt) error {
switch l := len(fields); l {
case 0:
return openconfig.Unmarshal(bytes, goStruct.(*openconfig.Device), opt...)
case 1:
default:
return &ErrUnsupportedPath{fields}
}
var c ygot.GoStruct
var field string
// Load SBI definition
d := openconfig.Device{}
c, field = iter(&d, fields)
if err := openconfig.Unmarshal(bytes, c, opt...); err != nil {
log.Error(err)
return unmarshal
}
// unmarshal parses a root or 1st level gNMI response to a go struct
// Named return due to how recover works here
func unmarshal(bytes []byte, fields []string, goStruct interface{}, opt ...ytypes.UnmarshalOpt) (err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
reflect.ValueOf(goStruct.(*openconfig.Device)).Elem().FieldByName(field).Set(reflect.ValueOf(c))
return nil
}()
switch l := len(fields); l {
case 0:
return openconfig.Unmarshal(bytes, goStruct.(*openconfig.Device), opt...)
case 1:
default:
return &ErrUnsupportedPath{fields}
}
var c ygot.GoStruct
var field string
// Load SBI definition
d := openconfig.Device{}
c, field, err = iter(&d, fields)
if err != nil {
return
}
if err := openconfig.Unmarshal(bytes, c, opt...); err != nil {
log.Error(err)
}
reflect.ValueOf(goStruct.(*openconfig.Device)).Elem().FieldByName(field).Set(reflect.ValueOf(c))
return nil
}
func iter(a ygot.GoStruct, fields []string) (ygot.GoStruct, string) {
var b ygot.GoStruct
// iter walks down the provided paths and initializes the ygot.GoStruct. It only works for
// the root level. Watch out for named returns here
// TODO(mk): Fix deeper layers
func iter(a ygot.GoStruct, fields []string) (b ygot.GoStruct, f string, err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
var c ygot.GoStruct
var configStruct reflect.Value
f := fields[0]
f = fields[0]
s := reflect.ValueOf(a).Elem()
h := s.FieldByName(f)
configStruct = reflect.New(h.Type())
......@@ -122,12 +141,12 @@ func iter(a ygot.GoStruct, fields []string) (ygot.GoStruct, string) {
b = configStruct.Elem().Interface().(ygot.GoStruct)
}
if len(fields) > 1 {
c, _ = iter(b, fields[1:])
c, _, _ = iter(b, fields[1:])
} else {
return b, f
return
}
reflect.ValueOf(b).Elem().FieldByName(f).Set(reflect.ValueOf(c))
return b, f
return
}
func (oc *OpenConfig) Id() uuid.UUID {
......
package nucleus
import (
"code.fbi.h-da.de/cocsn/gosdn/nucleus/util"
"code.fbi.h-da.de/cocsn/yang-models/generated/openconfig"
"github.com/google/uuid"
gpb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/openconfig/ygot/ygot"
"github.com/openconfig/ygot/ytypes"
log "github.com/sirupsen/logrus"
"reflect"
"testing"
)
func testSetupSbi() {
var err error
aristaUUID, err = uuid.Parse("d3795249-579c-4be7-8818-29f113cb86ee")
if err != nil {
log.Fatal(err)
}
ocUUID, err = uuid.Parse("5e252b70-38f2-4c99-a0bf-1b16af4d7e67")
if err != nil {
log.Fatal(err)
}
}
var aristaUUID uuid.UUID
var ocUUID uuid.UUID
func TestOpenConfig_Id(t *testing.T) {
type fields struct {
transport Transport
schema *ytypes.Schema
id uuid.UUID
}
tests := []struct {
name string
fields fields
want uuid.UUID
}{
{
name: "default",
fields: fields{
transport: nil,
schema: nil,
id: ocUUID,
},
want: ocUUID,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
oc := &OpenConfig{
transport: tt.fields.transport,
schema: tt.fields.schema,
id: tt.fields.id,
}
if got := oc.Id(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Id() = %v, want %v", got, tt.want)
}
})
}
}
func TestOpenConfig_SbiIdentifier(t *testing.T) {
type fields struct {
transport Transport
schema *ytypes.Schema
id uuid.UUID
}
tests := []struct {
name string
fields fields
want string
}{
{name: "default", fields: fields{}, want: "openconfig"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
oc := &OpenConfig{
transport: tt.fields.transport,
schema: tt.fields.schema,
id: tt.fields.id,
}
if got := oc.SbiIdentifier(); got != tt.want {
t.Errorf("SbiIdentifier() = %v, want %v", got, tt.want)
}
})
}
}
func TestOpenConfig_Schema(t *testing.T) {
schema, err := openconfig.Schema()
if err != nil {
t.Error(err)
}
type fields struct {
transport Transport
schema *ytypes.Schema
id uuid.UUID
}
tests := []struct {
name string
fields fields
want *ytypes.Schema
}{
{name: "default", fields: fields{}, want: schema},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
oc := &OpenConfig{
transport: tt.fields.transport,
schema: tt.fields.schema,
id: tt.fields.id,
}
if got := oc.Schema(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Schema() = %v, want %v", got, tt.want)
}
})
}
}
func Test_unmarshal(t *testing.T) {
type args struct {
path string
goStruct interface{}
opt []ytypes.UnmarshalOpt
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "fail",
args: args{
goStruct: &openconfig.Device{},
path: "../test/resp-interfaces-interface-arista-ceos",
},
wantErr: true,
},
{
name: "root w/opts",
args: args{
path: "../test/resp-full-node-arista-ceos",
goStruct: &openconfig.Device{},
opt: []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}},
},
wantErr: false,
},
{
name: "root w/o opts",
args: args{
path: "../test/resp-full-node-arista-ceos",
goStruct: &openconfig.Device{},
opt: nil,
},
wantErr: true,
},
{
name: "interfaces w/opts",
args: args{
path: "../test/resp-interfaces-arista-ceos",
goStruct: &openconfig.Device{},
opt: []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}},
},
wantErr: false,
},
{
name: "interfaces w/o opts",
args: args{
path: "../test/resp-interfaces-arista-ceos",
goStruct: &openconfig.Device{},
opt: nil,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resp := &gpb.GetResponse{}
err := util.Read(tt.args.path, resp)
if err != nil {
t.Error(err)
}
fields := extraxtPathElements(resp.Notification[0].Update[0].Path)
bytes := resp.Notification[0].Update[0].Val.GetJsonIetfVal()
if err := unmarshal(bytes, fields, tt.args.goStruct, tt.args.opt...); (err != nil) != tt.wantErr {
t.Errorf("unmarshal() error = %v, wantErr %v", err, tt.wantErr)
}
if tt.args.goStruct.(*openconfig.Device).Interfaces == nil && tt.args.opt != nil{
t.Errorf("unmarshal() error: field Interfaces must not be nil")
}
})
}
}
func Test_iter(t *testing.T) {
type args struct {
a ygot.GoStruct
fields []string
}
tests := []struct {
name string
args args
wantB ygot.GoStruct
wantField string
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotB, gotField, err := iter(tt.args.a, tt.args.fields)
if (err != nil) != tt.wantErr {
t.Errorf("iter() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotB, tt.wantB) {
t.Errorf("iter() gotB = %v, want %v", gotB, tt.wantB)
}
if gotField != tt.wantField {
t.Errorf("iter() gotField = %v, want %v", gotField, tt.wantField)
}
})
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment