Newer
Older
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/interfaces/change"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/types"
"code.fbi.h-da.de/danet/gosdn/controller/nucleus/util/proto"
log "github.com/sirupsen/logrus"
const unreachable = "203.0.113.10:6030"
const testPath = "/system/config/hostname"
var modifiedHostname = "ceos3000"
var testAddress = "10.254.254.105:6030"
var testUsername = "admin"
var testPassword = "arista"
var opt *tpb.TransportOption
var gnmiMessages map[string]pb.Message
func TestMain(m *testing.M) {
testSetupIntegration()
os.Exit(m.Run())
}
func testSetupIntegration() {
if os.Getenv("GOSDN_LOG") == "nolog" {
log.SetLevel(log.PanicLevel)
}
if addr != "" {
testAddress = addr
log.Infof("CEOS_TEST_ENDPOINT set to %v", testAddress)
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
}
u := os.Getenv("GOSDN_TEST_USER")
if u != "" {
testUsername = u
log.Infof("GOSDN_TEST_USER set to %v", testUsername)
}
p := os.Getenv("GOSDN_TEST_PASSWORD")
if p != "" {
testPassword = p
log.Infof("GOSDN_TEST_PASSWORD set to %v", testPassword)
}
gnmiMessages = map[string]pb.Message{
"../proto/cap-resp-arista-ceos": &gpb.CapabilityResponse{},
"../proto/req-full-node": &gpb.GetRequest{},
"../proto/req-full-node-arista-ceos": &gpb.GetRequest{},
"../proto/req-interfaces-arista-ceos": &gpb.GetRequest{},
"../proto/req-interfaces-interface-arista-ceos": &gpb.GetRequest{},
"../proto/req-interfaces-wildcard": &gpb.GetRequest{},
"../proto/resp-full-node": &gpb.GetResponse{},
"../proto/resp-full-node-arista-ceos": &gpb.GetResponse{},
"../proto/resp-interfaces-arista-ceos": &gpb.GetResponse{},
"../proto/resp-interfaces-interface-arista-ceos": &gpb.GetResponse{},
"../proto/resp-interfaces-wildcard": &gpb.GetResponse{},
"../proto/resp-set-system-config-hostname": &gpb.SetResponse{},
}
for k, v := range gnmiMessages {
if err := proto.Read(k, v); err != nil {
log.Fatalf("error parsing %v: %v", k, err)
}
}
opt = &tpb.TransportOption{
Address: testAddress,
Username: testUsername,
Password: testPassword,
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{},
},
}
}
func TestGnmi_SetInvalidIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
type fields struct {
ctx context.Context
payload change.Payload
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
name: "destination unreachable",
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{}},
ctx: context.Background(),
payload: change.Payload{},
{
name: "invalid update",
fields: fields{opt: opt},
args: args{
ctx: context.Background(),
payload: change.Payload{},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sbi, err := nucleus.NewSBI(spb.Type_TYPE_OPENCONFIG)
t.Errorf("SetInvalidIntegration() error = %v", err)
return
g, err := nucleus.NewTransport(tt.fields.opt, sbi)
if (err != nil) != tt.wantErr {
t.Errorf("SetInvalidIntegration() error = %v, wantErr %v", err, tt.wantErr)
err = g.Set(tt.args.ctx, tt.args.payload)
t.Errorf("SetInvalidIntegration() error = %v, wantErr %v", err, tt.wantErr)
func TestGnmi_SetValidIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
sbi, err := nucleus.NewSBI(spb.Type_TYPE_OPENCONFIG)
if err != nil {
t.Errorf("SetValidIntegration() err = %v", err)
return
opt := &tpb.TransportOption{
Address: testAddress,
Username: testUsername,
Password: testPassword,
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{},
},
}
pnd, err := nucleus.NewPND("test", "test", uuid.New(), nil, nil)
if err != nil {
t.Error(err)
return
}
_, err = pnd.AddDevice("test", opt, sbi.ID())
if err != nil {
t.Error(err)
return
}
device, err := pnd.GetDevice("test")
if err != nil {
t.Error(err)
return
}
tests := []struct {
name string
apiOp ppb.ApiOperation
path string
value string
want string
}{
{
name: "update",
path: testPath,
value: modifiedHostname,
want: modifiedHostname,
},
{
name: "replace",
path: "/system/config/domain-name",
value: modifiedHostname,
want: modifiedHostname,
},
{
name: "delete",
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
path: testPath,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cuid, err := pnd.ChangeOND(device.ID(), tt.apiOp, tt.path, tt.value)
if err != nil {
t.Error(err)
return
}
if err := pnd.Commit(cuid); err != nil {
t.Error(err)
return
}
if err := pnd.Confirm(cuid); err != nil {
t.Error(err)
return
}
if tt.name != "delete" {
resp, err := pnd.Request(device.ID(), tt.path)
if err != nil {
t.Error(err)
return
}
r, ok := resp.(*gpb.GetResponse)
if !ok {
t.Error(&errors.ErrInvalidTypeAssertion{
Value: resp,
Type: &gpb.GetResponse{},
})
return
}
got := r.Notification[0].Update[0].Val.GetStringVal()
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetDevice() got = %v, want %v", got, tt.want)
}
}
})
}
}
func TestGnmi_GetIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
paths := []string{
"/interfaces/interface",
"system/config/hostname",
}
type fields struct {
}
type args struct {
ctx context.Context
params []string
}
tests := []struct {
name string
fields fields
args args
want interface{}
wantErr bool
}{
{
name: "default",
fields: fields{opt: opt},
args: args{
ctx: context.Background(),
params: paths[:1],
},
want: gnmiMessages["../proto/resp-interfaces-arista-ceos"],
wantErr: false,
},
{
name: "destination unreachable",
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{}},
},
},
args: args{
ctx: context.Background(),
params: paths,
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sbi, err := nucleus.NewSBI(spb.Type_TYPE_OPENCONFIG)
if err != nil {
t.Errorf("Get() error = %v", err)
return
}
g, err := nucleus.NewTransport(tt.fields.opt, sbi)
if err != nil {
t.Error(err)
return
}
got, err := g.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.TypeOf(got) != reflect.TypeOf(tt.want) {
t.Errorf("Get() got = %v, want %v", got, tt.want)
}
})
}
}
func TestGnmi_SubscribeIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
}
type args struct {
ctx context.Context
opts *gnmi.SubscribeOptions
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
name: "default",
fields: fields{
Address: testAddress,
Username: testUsername,
Password: testPassword,
Tls: false,
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{
Compression: "",
GrpcDialOptions: nil,
Token: "",
Encoding: 0,
},
},
},
},
args: args{
ctx: context.Background(),
opts: &gnmi.SubscribeOptions{
Mode: "stream",
StreamMode: "sample",
SampleInterval: uint64(1 * time.Second),
HeartbeatInterval: uint64(100 * time.Millisecond),
Paths: gnmi.SplitPaths([]string{
"/interfaces/interface/name",
"/system/config/hostname",
}),
},
},
wantErr: false,
},
{
name: "wrong path",
fields: fields{
opt: &tpb.TransportOption{
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{}},
},
},
args: args{
opts: &gnmi.SubscribeOptions{
Mode: "stream",
StreamMode: "sample",
SampleInterval: uint64(1 * time.Second),
HeartbeatInterval: uint64(100 * time.Millisecond),
Paths: gnmi.SplitPaths([]string{
"interfaces/interface/name",
"ystem/config/hostname",
}),
},
},
wantErr: true,
},
{
name: "destination unreachable",
fields: fields{
opt: &tpb.TransportOption{
Address: "203.0.113.10:6030",
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{}},
},
},
args: args{
opts: &gnmi.SubscribeOptions{},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sbi, err := nucleus.NewSBI(spb.Type_TYPE_OPENCONFIG)
if err != nil {
t.Errorf("Subscribe() error = %v", err)
return
}
g, err := nucleus.NewTransport(tt.fields.opt, sbi)
ctx := context.WithValue(context.Background(), types.CtxKeyOpts, tt.args.opts) //nolint
ctx, cancel := context.WithCancel(ctx)
go func() {
subErr := g.Subscribe(ctx)
if (subErr != nil) != wantErr {
if subErr.Error() != "rpc error: code = Canceled desc = context canceled" {
t.Errorf("Subscribe() error = %v, wantErr %v", subErr, tt.wantErr)
}
}
}
}()
time.Sleep(time.Second * 3)
cancel()
time.Sleep(time.Second * 1)
})
}
}
func TestGnmi_CapabilitiesIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
type fields struct {
}
type args struct {
ctx context.Context
}
tests := []struct {
name string
fields fields
args args
want interface{}
wantErr bool
}{
{
name: "supported models",
fields: fields{opt: opt},
args: args{ctx: context.Background()},
want: gnmiMessages["../proto/cap-resp-arista-ceos"].(*gpb.CapabilityResponse).SupportedModels,
wantErr: false,
},
{
name: "supported encodings",
fields: fields{opt: opt},
args: args{ctx: context.Background()},
want: gnmiMessages["../proto/cap-resp-arista-ceos"].(*gpb.CapabilityResponse).SupportedEncodings,
wantErr: false,
},
{
name: "gnmi version",
fields: fields{opt: opt},
args: args{ctx: context.Background()},
want: gnmiMessages["../proto/cap-resp-arista-ceos"].(*gpb.CapabilityResponse).GNMIVersion,
wantErr: false,
},
{
name: "destination unreachable",
fields: fields{opt: &tpb.TransportOption{
Address: "203.0.113.10:6030",
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{}},
},
},
args: args{ctx: context.Background()},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sbi, err := nucleus.NewSBI(spb.Type_TYPE_OPENCONFIG)
if err != nil {
t.Errorf("Capabilities() error = %v", err)
return
}
tr, err := nucleus.NewTransport(tt.fields.opt, sbi)
if err != nil {
t.Error(err)
return
}
g, ok := tr.(*nucleus.Gnmi)
if !ok {
t.Error(&errors.ErrInvalidTypeAssertion{
Value: tr,
Type: &nucleus.Gnmi{},
})
resp, err := g.Capabilities(tt.args.ctx)
if (err != nil) != tt.wantErr {
t.Errorf("Capabilities() error = %v, wantErr %v", err, tt.wantErr)
return
}
var got interface{}
switch tt.name {
case "supported encodings":
got = resp.(*gpb.CapabilityResponse).SupportedEncodings
case "supported models":
got = resp.(*gpb.CapabilityResponse).SupportedModels
sort.Slice(got.([]*gpb.ModelData), func(i, j int) bool {
return got.([]*gpb.ModelData)[i].Name < got.([]*gpb.ModelData)[j].Name
})
sort.Slice(tt.want.([]*gpb.ModelData), func(i, j int) bool {
return tt.want.([]*gpb.ModelData)[i].Name < tt.want.([]*gpb.ModelData)[j].Name
})