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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
opt := &tpb.TransportOption{
Address: testAddress,
Username: testUsername,
Password: testPassword,
TransportOption: &tpb.TransportOption_GnmiTransportOption{
GnmiTransportOption: &tpb.GnmiTransportOption{},
},
}
pnd, err := nucleus.NewPND("test", "test", uuid.New(), sbi, nil, nil)
if err != nil {
t.Error(err)
return
}
if err := pnd.AddDevice("test", opt, sbi.ID()); 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",
214
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
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
})