From 497671b485ab211f6f8d005cf1f7b58872ca4c03 Mon Sep 17 00:00:00 2001 From: Manuel Kieweg <mail@manuelkieweg.de> Date: Thu, 11 Mar 2021 13:19:45 +0000 Subject: [PATCH] increased test coverage --- cmd/gnmi-capabilities/capabilities.go | 4 +- cmd/gnmi-telemetry/telemetry.go | 2 +- cmd/gosdn/main.go | 2 +- forks/goarista/gnmi/client.go | 2 +- nucleus/cli-handling_test.go | 2 +- nucleus/device_test.go | 92 ++++++++++++++ nucleus/errors.go | 8 +- nucleus/gnmi_transport.go | 41 +----- nucleus/gnmi_transport_test.go | 174 ++++++++++++++++---------- nucleus/integration_test.go | 145 +++++++++++++-------- nucleus/restconf_transport.go | 10 +- nucleus/restconf_transport_test.go | 126 +++++++++++++++++++ nucleus/southbound_test.go | 6 +- nucleus/store_test.go | 2 +- 14 files changed, 443 insertions(+), 173 deletions(-) create mode 100644 nucleus/restconf_transport_test.go diff --git a/cmd/gnmi-capabilities/capabilities.go b/cmd/gnmi-capabilities/capabilities.go index de9475197..54601b8a7 100644 --- a/cmd/gnmi-capabilities/capabilities.go +++ b/cmd/gnmi-capabilities/capabilities.go @@ -17,7 +17,7 @@ func main() { Password: "arista", Encoding: gpb.Encoding_JSON_IETF, } - transport,err := nucleus.NewGnmiTransport(cfg) + transport, err := nucleus.NewGnmiTransport(cfg) if err != nil { log.Error(err) } @@ -27,7 +27,7 @@ func main() { } modelData := resp.(*gpb.CapabilityResponse).SupportedModels b := strings.Builder{} - for _,elem := range modelData { + for _, elem := range modelData { _, err := b.WriteString(elem.Name) if err != nil { log.Error(err) diff --git a/cmd/gnmi-telemetry/telemetry.go b/cmd/gnmi-telemetry/telemetry.go index 3cb85fd50..5064e40e0 100644 --- a/cmd/gnmi-telemetry/telemetry.go +++ b/cmd/gnmi-telemetry/telemetry.go @@ -39,7 +39,7 @@ func main() { Password: "arista", Encoding: gpb.Encoding_JSON_IETF, } - transport,_ := nucleus.NewGnmiTransport(cfg) + transport, _ := nucleus.NewGnmiTransport(cfg) device.Transport = transport diff --git a/cmd/gosdn/main.go b/cmd/gosdn/main.go index 4356fbc6a..367250512 100644 --- a/cmd/gosdn/main.go +++ b/cmd/gosdn/main.go @@ -16,5 +16,5 @@ func main() { IsRunningChannel := make(chan bool) // hand off to cmd for further processing - nucleus.StartAndRun(IsRunningChannel) + nucleus.StartAndRun(IsRunningChannel) } diff --git a/forks/goarista/gnmi/client.go b/forks/goarista/gnmi/client.go index bfb404ada..33c3023b7 100644 --- a/forks/goarista/gnmi/client.go +++ b/forks/goarista/gnmi/client.go @@ -235,7 +235,7 @@ func DialContext(ctx context.Context, cfg *Config) (pb.GNMIClient, error) { return pb.NewGNMIClient(grpcconn), nil } -// Dial connects to a gnmi service and returns a ciena +// Dial connects to a gnmi service and returns a client func Dial(cfg *Config) (pb.GNMIClient, error) { return DialContext(context.Background(), cfg) } diff --git a/nucleus/cli-handling_test.go b/nucleus/cli-handling_test.go index 6a5a49d39..522de1a0c 100644 --- a/nucleus/cli-handling_test.go +++ b/nucleus/cli-handling_test.go @@ -374,4 +374,4 @@ func Test_server_Shutdown(t *testing.T) { } }) } -} \ No newline at end of file +} diff --git a/nucleus/device_test.go b/nucleus/device_test.go index 0fa4ffa90..443744d8c 100644 --- a/nucleus/device_test.go +++ b/nucleus/device_test.go @@ -1 +1,93 @@ package nucleus + +import ( + "code.fbi.h-da.de/cocsn/yang-models/generated/openconfig" + "github.com/google/uuid" + "github.com/openconfig/ygot/ygot" + "reflect" + "testing" +) + +func TestDevice_Id(t *testing.T) { + type fields struct { + GoStruct ygot.GoStruct + SBI SouthboundInterface + Config DeviceConfig + Transport Transport + } + tests := []struct { + name string + fields fields + want uuid.UUID + }{ + { + name: "default", + fields: fields{ + Config: DeviceConfig{ + Uuid: did, + }, + }, + want: did, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := &Device{ + GoStruct: tt.fields.GoStruct, + SBI: tt.fields.SBI, + Config: tt.fields.Config, + Transport: tt.fields.Transport, + } + if got := d.Id(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Id() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewDevice(t *testing.T) { + sbi := &OpenConfig{} + type args struct { + sbi SouthboundInterface + addr string + username string + password string + transport Transport + } + tests := []struct { + name string + args args + want *Device + }{ + { + name: "default", + args: args{ + sbi: sbi, + addr: "testdevice", + username: "testuser", + password: "testpassword", + transport: &Gnmi{}, + }, + want: &Device{ + GoStruct: &openconfig.Device{}, + SBI: sbi, + Config: DeviceConfig{ + Uuid: uuid.UUID{}, + Address: "testdevice", + Username: "testuser", + Password: "testpassword", + }, + Transport: &Gnmi{}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NewDevice(tt.args.sbi, tt.args.addr, tt.args.username, tt.args.password, tt.args.transport) + tt.want.Config.Uuid = got.Id() + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewDevice() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/nucleus/errors.go b/nucleus/errors.go index 9a92bf9e7..93097feda 100644 --- a/nucleus/errors.go +++ b/nucleus/errors.go @@ -40,4 +40,10 @@ type ErrUnsupportedPath struct { func (e ErrUnsupportedPath) Error() string { return fmt.Sprintf("path %v is not supported", e.p) -} \ No newline at end of file +} + +type ErrNotYetImplemented struct{} + +func (e ErrNotYetImplemented) Error() string { + return fmt.Sprintf("function not yet implemented") +} diff --git a/nucleus/gnmi_transport.go b/nucleus/gnmi_transport.go index 8a2c22f5d..2efb387ad 100644 --- a/nucleus/gnmi_transport.go +++ b/nucleus/gnmi_transport.go @@ -4,7 +4,6 @@ import ( "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" "code.fbi.h-da.de/cocsn/gosdn/nucleus/util" "context" - "errors" gpb "github.com/openconfig/gnmi/proto/gnmi" "github.com/openconfig/gnmi/proto/gnmi_ext" "github.com/openconfig/goyang/pkg/yang" @@ -84,17 +83,9 @@ func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Sch rn := r.Notification for _, msg := range rn { for _, update := range msg.Update { - prefix := msg.Prefix path := update.Path fullPath := path - if prefix != nil { - var err error - fullPath, err = gnmiFullPath(prefix, path) - if err != nil { - return err - } - } - val,ok := update.Val.Value.(*gpb.TypedValue_JsonIetfVal) + val, ok := update.Val.Value.(*gpb.TypedValue_JsonIetfVal) if ok { opts := []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}} if err := g.Unmarshal(val.JsonIetfVal, extraxtPathElements(fullPath), root, opts...); err != nil { @@ -115,40 +106,12 @@ func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Sch func extraxtPathElements(path *gpb.Path) []string { elems := make([]string, len(path.Elem)) - for i,e := range path.Elem { + for i, e := range path.Elem { elems[i] = strings.Title(e.Name) } return elems } -// extractModelKey extracts the model's key from the full path. Highly model specific for now -// TODO: Remove hard coded model prefix -// TODO: Figure out why path.Elem() is empty but path.Elememt() is deprecated -func extractModelKey(path *gpb.Path) string { - var b strings.Builder - delim := "_" - b.WriteString("OpenconfigInterfaces") - for i := 0; i < len(path.Elem); i++ { - pathElement := path.Elem[i] - b.WriteString(delim) - b.WriteString(strings.Title(pathElement.Name)) - } - return b.String() -} - -// gnmiFullPath builds the full path from the prefix and path. -// Copycat from forks/google/gnmi/server.go -func gnmiFullPath(prefix, path *gpb.Path) (*gpb.Path, error) { - fullPath := &gpb.Path{Origin: path.Origin} - if path.GetElement() != nil { - return nil, errors.New("deprecated path element type is unsupported") - } - if path.GetElem() != nil { - fullPath.Elem = append(prefix.GetElem(), path.GetElem()...) - } - return fullPath, nil -} - // Capabilities calls GNMI capabilities func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) { ctx = gnmi.NewContext(ctx, g.config) diff --git a/nucleus/gnmi_transport_test.go b/nucleus/gnmi_transport_test.go index e54dff7b9..5ca60936c 100644 --- a/nucleus/gnmi_transport_test.go +++ b/nucleus/gnmi_transport_test.go @@ -8,6 +8,7 @@ import ( "code.fbi.h-da.de/cocsn/yang-models/generated/openconfig" "context" log "github.com/golang/glog" + "github.com/golang/protobuf/proto" gpb "github.com/openconfig/gnmi/proto/gnmi" "github.com/openconfig/goyang/pkg/yang" "github.com/openconfig/ygot/ytypes" @@ -20,10 +21,29 @@ import ( // TestMain bootstraps all tests. Humongous beast // TODO: Move somewhere more sensible func TestMain(m *testing.M) { + gnmiMessages = map[string]proto.Message{ + "../test/cap-resp-arista-ceos": &gpb.CapabilityResponse{}, + "../test/req-full-node": &gpb.GetRequest{}, + "../test/req-full-node-arista-ceos": &gpb.GetRequest{}, + "../test/req-interfaces-arista-ceos": &gpb.GetRequest{}, + "../test/req-interfaces-interface-arista-ceos": &gpb.GetRequest{}, + "../test/req-interfaces-wildcard": &gpb.GetRequest{}, + "../test/resp-full-node": &gpb.GetResponse{}, + "../test/resp-full-node-arista-ceos": &gpb.GetResponse{}, + "../test/resp-interfaces-arista-ceos": &gpb.GetResponse{}, + "../test/resp-interfaces-interface-arista-ceos": &gpb.GetResponse{}, + "../test/resp-interfaces-wildcard": &gpb.GetResponse{}, + } + for k, v := range gnmiMessages { + if err := util.Read(k, v); err != nil { + log.Fatalf("error parsing %v: %v", k, err) + } + } testSetupGnmi() testSetupPnd() testSetupStore() testSetupSbi() + testSetupIntegration() os.Exit(m.Run()) } @@ -60,6 +80,7 @@ func mockTransport() Gnmi { } } +var gnmiMessages map[string]proto.Message var gnmiConfig *gnmi.Config var startGnmiTarget chan string var stopGnmiTarget chan bool @@ -286,7 +307,7 @@ func TestGnmi_ProcessResponse(t *testing.T) { name: "Interfaces Interface", fields: fields{Sbi: &OpenConfig{}}, args: args{ - path: "../test/resp-full-node", + path: "../test/resp-interfaces-interface-arista-ceos", root: &openconfig.Device{}, }, wantErr: true, @@ -313,14 +334,11 @@ func TestGnmi_ProcessResponse(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { g := &Gnmi{ - SetNode: tt.fields.Sbi.SetNode(), + SetNode: tt.fields.Sbi.SetNode(), Unmarshal: tt.fields.Sbi.(*OpenConfig).Unmarshal(), } s := tt.fields.Sbi.Schema() - resp := &gpb.GetResponse{} - if err := util.Read(tt.args.path, resp); err != nil { - t.Errorf("error reading file %v,", err) - } + resp := gnmiMessages[tt.args.path] if err := g.ProcessResponse(resp, tt.args.root, s); (err != nil) != tt.wantErr { t.Errorf("ProcessResponse() error = %v, wantErr %v", err, tt.wantErr) } @@ -382,11 +400,29 @@ func TestGnmi_SetConfig(t *testing.T) { fields fields args args }{ - // TODO: Add test cases. + { + name: "default", + fields: fields{ + SetNode: nil, + RespChan: nil, + config: nil, + }, + args: args{ + config: &gnmi.Config{ + Addr: "test:///", + Password: "test", + Username: "test", + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - + g := &Gnmi{} + g.SetConfig(tt.args.config) + if !reflect.DeepEqual(g.config, tt.args.config) { + t.Errorf("Type() = %v, want %v", g.config, tt.args.config) + } }) } } @@ -407,15 +443,11 @@ func TestGnmi_Subscribe(t *testing.T) { args args wantErr bool }{ - // TODO: Add test cases. + {name: "nil client", fields: fields{}, args: args{}, wantErr: true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - g := &Gnmi{ - SetNode: tt.fields.SetNode, - RespChan: tt.fields.RespChan, - config: tt.fields.config, - } + g := &Gnmi{} if err := g.Subscribe(tt.args.ctx, tt.args.params...); (err != nil) != tt.wantErr { t.Errorf("Subscribe() error = %v, wantErr %v", err, tt.wantErr) } @@ -456,30 +488,10 @@ func TestGnmi_get(t *testing.T) { func TestGnmi_getWithRequest(t *testing.T) { transport := mockTransport() - reqFullNode := &gpb.GetRequest{} - reqInterfacesWildcard := &gpb.GetRequest{} - respFullNode := &gpb.GetResponse{} - respInterfacesWildcard := &gpb.GetResponse{} - respInterfacesWildcardExp := &gpb.GetResponse{} - respFullNodeExp := &gpb.GetResponse{} - if err := util.Read("../test/req-full-node", reqFullNode); err != nil { - t.Errorf("error parsing req-full-node: %v", err) - } - if err := util.Read("../test/req-interfaces-wildcard", reqInterfacesWildcard); err != nil { - t.Errorf("error parsing req-interfaces-wildcard: %v", err) - } - if err := util.Read("../test/resp-full-node", respFullNode); err != nil { - t.Errorf("error parsing getFullNode: %v", err) - } - if err := util.Read("../test/resp-full-node", respFullNodeExp); err != nil { - t.Errorf("error parsing getFullNode: %v", err) - } - if err := util.Read("../test/resp-interfaces-wildcard", respInterfacesWildcard); err != nil { - t.Errorf("error parsing getFullNode: %v", err) - } - if err := util.Read("../test/resp-interfaces-wildcard", respInterfacesWildcardExp); err != nil { - t.Errorf("error parsing getFullNode: %v", err) - } + reqFullNode := gnmiMessages["../test/req-full-node"].(*gpb.GetRequest) + reqInterfacesWildcard := gnmiMessages["../test/req-interfaces-wildcard"].(*gpb.GetRequest) + respFullNode := gnmiMessages["../test/resp-full-node"].(*gpb.GetResponse) + respInterfacesWildcard := gnmiMessages["../test/resp-interfaces-wildcard"].(*gpb.GetResponse) transport.client.(*mocks.GNMIClient). On("Get", mockContext, reqFullNode). @@ -509,7 +521,7 @@ func TestGnmi_getWithRequest(t *testing.T) { args: args{ request: reqFullNode, }, - want: respFullNodeExp, + want: respFullNode, wantErr: false, }, { @@ -518,7 +530,7 @@ func TestGnmi_getWithRequest(t *testing.T) { args: args{ request: reqInterfacesWildcard, }, - want: respInterfacesWildcardExp, + want: respInterfacesWildcard, wantErr: false, }, } @@ -544,48 +556,74 @@ func TestGnmi_subscribe(t *testing.T) { // TODO: Design integration test for this one } -func Test_extractModelKey(t *testing.T) { +func TestNewGnmiTransport(t *testing.T) { + oc := &OpenConfig{} + respChan := make(chan *gpb.SubscribeResponse) type args struct { - path *gpb.Path - } - tests := []struct { - name string - args args - want string - }{ - // TODO: Add test cases. - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := extractModelKey(tt.args.path); got != tt.want { - t.Errorf("extraxtPathElements() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_gnmiFullPath(t *testing.T) { - type args struct { - prefix *gpb.Path - path *gpb.Path + config *gnmi.Config } tests := []struct { name string args args - want *gpb.Path + want *Gnmi wantErr bool }{ - // TODO: Add test cases. + { + name: "default", + args: args{config: &gnmi.Config{ + Username: "test", + Password: "test", + Addr: "localhost:13371", + Encoding: gpb.Encoding_PROTO, + }}, + want: &Gnmi{ + SetNode: oc.SetNode(), + Unmarshal: oc.Unmarshal(), + RespChan: respChan, + config: &gnmi.Config{ + Username: "test", + Password: "test", + Addr: "localhost:13371", + Encoding: gpb.Encoding_PROTO, + }, + client: nil, + }, + wantErr: false, + }, + { + name: "unsupported compression", + args: args{config: &gnmi.Config{Compression: "brotli"}}, + want: nil, + wantErr: true, + }, + { + name: "certificate error no key file", + args: args{config: &gnmi.Config{TLS: true, CertFile: "invalid", KeyFile: ""}}, + want: nil, + wantErr: true, + }, + { + name: "certificate error no ca file", + args: args{config: &gnmi.Config{TLS: true, CAFile: "invalid"}}, + want: nil, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := gnmiFullPath(tt.args.prefix, tt.args.path) + if tt.name == "defaul" { + startGnmiTarget <- gnmiConfig.Addr + } + got, err := NewGnmiTransport(tt.args.config) if (err != nil) != tt.wantErr { - t.Errorf("gnmiFullPath() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("NewGnmiTransport() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("gnmiFullPath() got = %v, want %v", got, tt.want) + t.Errorf("NewGnmiTransport() got = %v, want %v", got, tt.want) + } + if tt.name == "defaul" { + stopGnmiTarget <- true } }) } diff --git a/nucleus/integration_test.go b/nucleus/integration_test.go index c92ef12fd..caed6e9d9 100644 --- a/nucleus/integration_test.go +++ b/nucleus/integration_test.go @@ -2,27 +2,37 @@ package nucleus import ( "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" - "code.fbi.h-da.de/cocsn/gosdn/nucleus/util" "context" gpb "github.com/openconfig/gnmi/proto/gnmi" + "os" + "reflect" "testing" "time" ) var address = "141.100.70.171:6030" +var cfg *gnmi.Config + +func testSetupIntegration() { + a := os.Getenv("GOSDN_TEST_ENDPOINT") + if a != "" { + address = a + } + + cfg = &gnmi.Config{ + Addr: address, + Username: "admin", + Password: "arista", + Encoding: gpb.Encoding_JSON_IETF, + } +} func TestGnmi_SetIntegration(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - t.Run("Test GNMI Set", func(t *testing.T){ - cfg := &gnmi.Config{ - Addr: address, - Username: "admin", - Password: "arista", - Encoding: gpb.Encoding_JSON_IETF, - } - transport,err := NewGnmiTransport(cfg) + t.Run("Test GNMI Set", func(t *testing.T) { + transport, err := NewGnmiTransport(cfg) if err != nil { t.Error(err) } @@ -41,14 +51,8 @@ func TestGnmi_GetIntegration(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - t.Run("Test GNMI Get", func(t *testing.T){ - cfg := &gnmi.Config{ - Addr: address, - Username: "admin", - Password: "arista", - Encoding: gpb.Encoding_JSON_IETF, - } - transport,err := NewGnmiTransport(cfg) + t.Run("Test GNMI Get", func(t *testing.T) { + transport, err := NewGnmiTransport(cfg) if err != nil { t.Error(err) } @@ -67,14 +71,12 @@ func TestGnmi_SubscribeIntegration(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - t.Run("Test GNMI Subscribe", func(t *testing.T){ - cfg := &gnmi.Config{ - Addr: address, - Username: "admin", - Password: "arista", - Encoding: gpb.Encoding_JSON_IETF, - } - transport,err := NewGnmiTransport(cfg) + if os.Getenv("GOSDN_TEST_ENDPOINT") != "" { + t.Skip("skipping locally running integration test") + } + + t.Run("Test GNMI Subscribe", func(t *testing.T) { + transport, err := NewGnmiTransport(cfg) if err != nil { t.Error(err) } @@ -95,15 +97,14 @@ func TestGnmi_SubscribeIntegration(t *testing.T) { Target: address, } ctx := context.WithValue(context.Background(), "opts", opts) - d := time.Now().Add(60 * time.Second) - ctx, cancel := context.WithDeadline(ctx, d) - defer cancel() go func() { if err := transport.Subscribe(ctx); err != nil { t.Error(err) } }() - time.Sleep(time.Second * 50) + time.Sleep(time.Second * 30) + ctx.Done() + time.Sleep(time.Second * 5) }) } @@ -111,31 +112,75 @@ func TestGnmi_CapabilitiesIntegration(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } - respones := map[string]*gpb.CapabilityResponse{ - "../test/cap-resp-arista-ceos": {}, + type fields struct { + config *gnmi.Config } - for k,v := range respones { - if err := util.Read(k, v); err != nil { - t.Errorf("error parsing %v: %v", k, err) - } - - t.Run("Test GNMI Capabilities", func(t *testing.T) { - cfg := &gnmi.Config{ - Addr: address, - Username: "admin", - Password: "arista", - Encoding: gpb.Encoding_JSON_IETF, - } - transport, err := NewGnmiTransport(cfg) + type args struct { + ctx context.Context + } + tests := []struct { + name string + fields fields + args args + want interface{} + wantErr bool + }{ + { + name: "supported models", + fields: fields{config: cfg}, + args: args{ctx: context.Background()}, + want: gnmiMessages["../test/cap-resp-arista-ceos"].(*gpb.CapabilityResponse).SupportedModels, + wantErr: false, + }, + { + name: "supported encodings", + fields: fields{config: cfg}, + args: args{ctx: context.Background()}, + want: gnmiMessages["../test/cap-resp-arista-ceos"].(*gpb.CapabilityResponse).SupportedEncodings, + wantErr: false, + }, + { + name: "gnmi version", + fields: fields{config: cfg}, + args: args{ctx: context.Background()}, + want: gnmiMessages["../test/cap-resp-arista-ceos"].(*gpb.CapabilityResponse).GNMIVersion, + wantErr: false, + }, + { + name: "destination unreachable", + fields: fields{config: &gnmi.Config{ + Addr: "203.0.113.10:6030", + }, + }, + args: args{ctx: context.Background()}, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g, err := NewGnmiTransport(tt.fields.config) if err != nil { t.Error(err) + return } - resp, err := transport.Capabilities(context.Background()) - if err != nil { - t.Error(err) + resp, err := g.Capabilities(tt.args.ctx) + if (err != nil) != tt.wantErr { + t.Errorf("Capabilities() error = %v, wantErr %v", err, tt.wantErr) + return } - if resp != v { - t.Error("resp is nil") + var got interface{} + switch tt.name { + case "supported encodings": + got = resp.(*gpb.CapabilityResponse).SupportedEncodings + case "supported models": + got = resp.(*gpb.CapabilityResponse).SupportedModels + case "gnmi version": + got = resp.(*gpb.CapabilityResponse).GNMIVersion + default: + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Type() = %v, want %v", got, tt.want) } }) } @@ -153,4 +198,4 @@ func TestPndImplementation_RequestIntegration(t *testing.T) { t.Skip("skipping integration test") } t.Fail() -} \ No newline at end of file +} diff --git a/nucleus/restconf_transport.go b/nucleus/restconf_transport.go index 84d904a56..606f818ff 100644 --- a/nucleus/restconf_transport.go +++ b/nucleus/restconf_transport.go @@ -9,21 +9,21 @@ type Restconf struct { } func (r Restconf) Get(ctx context.Context, params ...string) (interface{}, error) { - panic("implement me") + return nil, &ErrNotYetImplemented{} } func (r Restconf) Set(ctx context.Context, params ...string) (interface{}, error) { - panic("implement me") + return nil, &ErrNotYetImplemented{} } func (r Restconf) Subscribe(ctx context.Context, params ...string) error { - panic("implement me") + return &ErrNotYetImplemented{} } func (r Restconf) Type() string { - panic("implement me") + return "restconf" } func (r Restconf) ProcessResponse(resp interface{}, root interface{}, models *ytypes.Schema) error { - panic("implement me") + return &ErrNotYetImplemented{} } diff --git a/nucleus/restconf_transport_test.go b/nucleus/restconf_transport_test.go new file mode 100644 index 000000000..5f1eb1e35 --- /dev/null +++ b/nucleus/restconf_transport_test.go @@ -0,0 +1,126 @@ +package nucleus + +import ( + "context" + "github.com/openconfig/ygot/ytypes" + "reflect" + "testing" +) + +func TestRestconf_Get(t *testing.T) { + type args struct { + ctx context.Context + params []string + } + tests := []struct { + name string + args args + want interface{} + wantErr bool + }{ + {name: "not implemented", args: args{}, want: nil, wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := Restconf{} + got, err := r.Get(tt.args.ctx, 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) + } + }) + } +} + +func TestRestconf_ProcessResponse(t *testing.T) { + type args struct { + resp interface{} + root interface{} + models *ytypes.Schema + } + tests := []struct { + name string + args args + wantErr bool + }{ + {name: "not implemented", args: args{}, wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := Restconf{} + if err := r.ProcessResponse(tt.args.resp, tt.args.root, tt.args.models); (err != nil) != tt.wantErr { + t.Errorf("ProcessResponse() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestRestconf_Set(t *testing.T) { + type args struct { + ctx context.Context + params []string + } + tests := []struct { + name string + args args + want interface{} + wantErr bool + }{ + {name: "not implemented", args: args{}, want: nil, wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := Restconf{} + got, err := r.Set(tt.args.ctx, tt.args.params...) + if (err != nil) != tt.wantErr { + t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Set() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestRestconf_Subscribe(t *testing.T) { + type args struct { + ctx context.Context + params []string + } + tests := []struct { + name string + args args + wantErr bool + }{ + {name: "not implemented", args: args{}, wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := Restconf{} + if err := r.Subscribe(tt.args.ctx, tt.args.params...); (err != nil) != tt.wantErr { + t.Errorf("Subscribe() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestRestconf_Type(t *testing.T) { + tests := []struct { + name string + want string + }{ + {name: "not implemented", want: "restconf"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := Restconf{} + if got := r.Type(); got != tt.want { + t.Errorf("Type() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/nucleus/southbound_test.go b/nucleus/southbound_test.go index 8063b8120..6938452e1 100644 --- a/nucleus/southbound_test.go +++ b/nucleus/southbound_test.go @@ -123,7 +123,7 @@ func TestOpenConfig_Schema(t *testing.T) { func Test_unmarshal(t *testing.T) { type args struct { - path string + path string goStruct interface{} opt []ytypes.UnmarshalOpt } @@ -136,7 +136,7 @@ func Test_unmarshal(t *testing.T) { name: "fail", args: args{ goStruct: &openconfig.Device{}, - path: "../test/resp-interfaces-interface-arista-ceos", + path: "../test/resp-interfaces-interface-arista-ceos", }, wantErr: true, }, @@ -189,7 +189,7 @@ func Test_unmarshal(t *testing.T) { 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{ + if tt.args.goStruct.(*openconfig.Device).Interfaces == nil && tt.args.opt != nil { t.Errorf("unmarshal() error: field Interfaces must not be nil") } }) diff --git a/nucleus/store_test.go b/nucleus/store_test.go index 8a393efd6..8319b4bb7 100644 --- a/nucleus/store_test.go +++ b/nucleus/store_test.go @@ -357,7 +357,7 @@ func Test_pndStore_get(t *testing.T) { }, }, }, - args: args{id: defaultPndId}, + args: args{id: did}, wantErr: true, }, } -- GitLab