Skip to content
Snippets Groups Projects
principalNetworkDomain_test.go 25 KiB
Newer Older
  • Learn to ignore specific revisions
  • Manuel Kieweg's avatar
    Manuel Kieweg committed
    package nucleus
    
    Andre Sterba's avatar
    Andre Sterba committed
    	"errors"
    
    Andre Sterba's avatar
    Andre Sterba committed
    	"reflect"
    	"testing"
    
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	ppb "code.fbi.h-da.de/danet/api/go/gosdn/pnd"
    	spb "code.fbi.h-da.de/danet/api/go/gosdn/southbound"
    	tpb "code.fbi.h-da.de/danet/api/go/gosdn/transport"
    	"code.fbi.h-da.de/danet/gosdn/interfaces/device"
    	"code.fbi.h-da.de/danet/gosdn/interfaces/networkdomain"
    	"code.fbi.h-da.de/danet/gosdn/interfaces/southbound"
    	"code.fbi.h-da.de/danet/gosdn/mocks"
    
    	"code.fbi.h-da.de/danet/gosdn/store"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"code.fbi.h-da.de/danet/yang-models/generated/openconfig"
    
    	"github.com/google/uuid"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	gpb "github.com/openconfig/gnmi/proto/gnmi"
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	"github.com/openconfig/ygot/ygot"
    
    	log "github.com/sirupsen/logrus"
    
    	"github.com/stretchr/testify/mock"
    )
    
    
    func removeExistingPNDStore() {
    	os.Remove(fmt.Sprintf("stores/device-store-%s.json", defaultPndID))
    }
    
    
    func TestNewPND(t *testing.T) {
    
    	p := newPnd()
    	if err := p.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
    
    	type args struct {
    		name        string
    		description string
    
    		sbi         southbound.SouthboundInterface
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		pid         uuid.UUID
    
    		name    string
    		args    args
    
    		want    networkdomain.NetworkDomain
    
    		wantErr bool
    
    	}{
    		{
    			name: "default",
    			args: args{
    				name:        "default",
    				description: "default test pnd",
    
    				sbi:         &OpenConfig{id: defaultSbiID},
    				pid:         defaultPndID,
    
    			want:    &p,
    
    			wantErr: false,
    
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			got, err := NewPND(tt.args.name, tt.args.description, tt.args.pid, tt.args.sbi, nil, nil)
    
    			if (err != nil) != tt.wantErr {
    				t.Errorf("NewPND() error = %v, wantErr %v", err, tt.wantErr)
    				return
    			}
    			if !reflect.DeepEqual(got, tt.want) {
    
    				t.Errorf("NewPND() = %v, want %v", got, tt.want)
    			}
    		})
    	}
    }
    
    func Test_destroy(t *testing.T) {
    	tests := []struct {
    		name    string
    		wantErr bool
    	}{
    		{name: "dummy", wantErr: false},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    			if err := destroy(); (err != nil) != tt.wantErr {
    				t.Errorf("destroy() error = %v, wantErr %v", err, tt.wantErr)
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_AddDevice(t *testing.T) {
    	type args struct {
    
    Malte Bauch's avatar
    Malte Bauch committed
    		device interface{}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		name   string
    		opts   *tpb.TransportOption
    
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    		{
    			name: "default",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				name: "fridolin",
    				opts: &tpb.TransportOption{
    					TransportOption: &tpb.TransportOption_GnmiTransportOption{
    						GnmiTransportOption: &tpb.GnmiTransportOption{},
    					},
    
    			wantErr: false,
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			pnd := newPnd()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			if err := pnd.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
    				t.Error(err)
    			}
    
    			if tt.name == "already exists" {
    
    				pnd.devices.Store[did] = tt.args.device.(device.Device)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			err := pnd.AddDevice(tt.args.name, tt.args.opts, defaultSbiID)
    
    			if (err != nil) != tt.wantErr {
    				t.Errorf("AddDevice() error = %v, wantErr %v", err, tt.wantErr)
    
    			if tt.name != "fails wrong type" {
    				if err == nil {
    
    					d, err := pnd.devices.GetDevice(store.FromString(tt.args.name))
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    					if err != nil {
    						t.Errorf("AddDevice() error = %v", err)
    						return
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    					if d.Name() != tt.args.name {
    						t.Errorf("AddDevice() got = %v, want %v", d.Name(), tt.args.name)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    					}
    					if err := pnd.devices.Delete(d.ID()); err != nil {
    
    // TODO: refactor test to use store interface instead if direct access.
    
    func Test_pndImplementation_AddSbi(t *testing.T) {
    	type args struct {
    
    		sbi southbound.SouthboundInterface
    
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    
    		{
    			name: "default",
    			args: args{
    				sbi: &OpenConfig{
    
    					id: defaultSbiID,
    
    		{
    			name: "already exists",
    			args: args{
    				sbi: &OpenConfig{
    
    					id: defaultSbiID,
    
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			pnd := newPnd()
    
    			if tt.name == "already exists" {
    
    				pnd.sbic.Store[defaultSbiID] = tt.args.sbi
    
    			err := pnd.AddSbi(tt.args.sbi)
    			if (err != nil) != tt.wantErr {
    				t.Errorf("AddSbi() error = %v, wantErr %v", err, tt.wantErr)
    
    			if tt.name != "fails wrong type" {
    				if err == nil {
    
    					_, ok := pnd.sbic.Store[defaultSbiID]
    
    					if !ok {
    						t.Errorf("AddSbi() SBI %v not in device store %v",
    							tt.args.sbi, pnd.GetSBIs())
    					}
    
    					if err := pnd.sbic.Delete(defaultSbiID); err != nil {
    
    		})
    	}
    }
    
    func Test_pndImplementation_ContainsDevice(t *testing.T) {
    
    	type args struct {
    		uuid   uuid.UUID
    
    		device device.Device
    
    	}
    	tests := []struct {
    		name string
    		args args
    		want bool
    	}{
    		{name: "default", args: args{
    			uuid:   did,
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			device: &CommonDevice{UUID: did},
    
    		}, want: true},
    		{name: "fails", args: args{
    			uuid:   uuid.New(),
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			device: &CommonDevice{UUID: did},
    
    		{name: "fails empty", args: args{
    			uuid:   uuid.New(),
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			device: &CommonDevice{UUID: did},
    
    		}, want: false},
    
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			pnd := newPnd()
    			if tt.name != "fails empty" {
    
    				if err := pnd.devices.Add(tt.args.device, "test"); err != nil {
    
    			if got := pnd.ContainsDevice(tt.args.uuid); got != tt.want {
    
    				t.Errorf("ContainsDevice() = %v, want %v", got, tt.want)
    			}
    
    			if err := pnd.devices.Delete(did); err != nil && tt.name != "fails empty" {
    
    		})
    	}
    }
    
    func Test_pndImplementation_Destroy(t *testing.T) {
    	type fields struct {
    		name        string
    		description string
    
    		sbi         *store.SbiStore
    		devices     *store.DeviceStore
    
    	}
    	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) {
    			pnd := &pndImplementation{
    
    				Name:        tt.fields.name,
    				Description: tt.fields.description,
    
    				sbic:        tt.fields.sbi,
    
    				devices:     tt.fields.devices,
    			}
    			if err := pnd.Destroy(); (err != nil) != tt.wantErr {
    				t.Errorf("Destroy() error = %v, wantErr %v", err, tt.wantErr)
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_GetDescription(t *testing.T) {
    	tests := []struct {
    		name string
    		want string
    	}{
    		{name: "default", want: "default test pnd"},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			pnd := newPnd()
    
    			if got := pnd.GetDescription(); got != tt.want {
    
    				t.Errorf("GetDescription() = %v, want %v", got, tt.want)
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_GetName(t *testing.T) {
    	tests := []struct {
    		name string
    		want string
    	}{
    		{name: "default", want: "default"},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			pnd := newPnd()
    
    			if got := pnd.GetName(); got != tt.want {
    
    				t.Errorf("GetName() = %v, want %v", got, tt.want)
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_GetSBIs(t *testing.T) {
    
    	pnd := newPnd()
    
    	tests := []struct {
    		name string
    
    		want *store.SbiStore
    
    		{name: "default", want: pnd.sbic},
    
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			if got := pnd.GetSBIs(); !reflect.DeepEqual(got, tt.want) {
    
    				t.Errorf("GetSBIs() = %v, want %v", got, tt.want)
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_MarshalDevice(t *testing.T) {
    
    	type args struct {
    		uuid uuid.UUID
    	}
    	tests := []struct {
    		name    string
    		args    args
    		want    string
    		wantErr bool
    	}{
    
    Malte Bauch's avatar
    Malte Bauch committed
    		{
    			name:    "default",
    			args:    args{did},
    			want:    "{\n\t\"Acl\": null,\n\t\"Bgp\": null,\n\t\"Components\": null,\n\t\"Interfaces\": null,\n\t\"LocalRoutes\": null,\n\t\"Messages\": null,\n\t\"NetworkInstances\": null,\n\t\"RoutingPolicy\": null,\n\t\"System\": null\n}",
    			wantErr: false,
    		},
    
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			pnd := newPnd()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			d := &CommonDevice{
    
    				UUID:      tt.args.uuid,
    
    				GoStruct:  &openconfig.Device{},
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				sbi:       nil,
    				transport: nil,
    
    			if err := pnd.addDevice(d); err != nil {
    				t.Error(err)
    			}
    
    			got, err := pnd.MarshalDevice(tt.args.uuid.String())
    
    			if (err != nil) != tt.wantErr {
    				t.Errorf("MarshalDevice() error = %v, wantErr %v", err, tt.wantErr)
    				return
    			}
    			if got != tt.want {
    				t.Errorf("MarshalDevice() got = %v, want %v", got, tt.want)
    			}
    
    			if err := pnd.devices.Delete(did); err != nil {
    
    		})
    	}
    }
    
    func Test_pndImplementation_RemoveDevice(t *testing.T) {
    
    	type args struct {
    		uuid uuid.UUID
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    		{name: "default", args: args{uuid: did}, wantErr: false},
    
    		{name: "fails", args: args{uuid: uuid.New()}, wantErr: true},
    		{name: "fails empty", args: args{uuid: did}, wantErr: true},
    
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			pnd := newPnd()
    			if tt.name != "fails empty" {
    
    Malte Bauch's avatar
    Malte Bauch committed
    				d := &CommonDevice{
    					UUID: did,
    					sbi:  NewSBI(spb.Type_OPENCONFIG),
    				}
    
    				if err := pnd.addDevice(d); err != nil {
    					t.Error(err)
    				}
    			}
    
    			if err := pnd.RemoveDevice(tt.args.uuid); (err != nil) != tt.wantErr {
    
    				t.Errorf("RemoveDevice() error = %v, wantErr %v", err, tt.wantErr)
    			}
    
    			if pnd.devices.Exists(did) && tt.name == "default" {
    
    				t.Errorf("RemoveDevice() device still in device store %v", pnd.devices)
    
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_RemoveSbi(t *testing.T) {
    
    	opts := &tpb.TransportOption{
    		TransportOption: &tpb.TransportOption_GnmiTransportOption{
    			GnmiTransportOption: &tpb.GnmiTransportOption{},
    		},
    	}
    
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    
    		{name: "default", args: args{id: defaultSbiID}, wantErr: false},
    
    		{name: "fails", args: args{id: uuid.New()}, wantErr: true},
    
    		{name: "fails empty", args: args{id: defaultSbiID}, wantErr: true},
    
    		{name: "exclusively remove associated devices", args: args{id: defaultSbiID}, wantErr: false},
    
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			pnd := &pndImplementation{
    
    				Name:        "test-remove-sbi",
    				Description: "test-remove-sbi",
    
    				sbic:        store.NewSbiStore(),
    
    				devices:     store.NewDeviceStore(defaultPndID),
    				Id:          defaultPndID,
    
    			if tt.name != "fails empty" && tt.name != "fails" {
    
    				if err := pnd.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
    
    				if err := pnd.AddDevice("associatedDevice", opts, tt.args.id); err != nil {
    					t.Error(err)
    				}
    				if err := pnd.AddDevice("associatedDevice2", opts, tt.args.id); err != nil {
    					t.Error(err)
    				}
    				if tt.name == "exclusively remove associated devices" {
    					newID := uuid.New()
    					if err := pnd.addSbi(&OpenConfig{id: newID}); err != nil {
    						t.Error(err)
    					}
    					if err := pnd.AddDevice("associatedDevice2", opts, newID); err != nil {
    						t.Error(err)
    					}
    				}
    
    			if err := pnd.RemoveSbi(tt.args.id); (err != nil) != tt.wantErr {
    
    				t.Errorf("RemoveSbi() error = %v, wantErr %v", err, tt.wantErr)
    			}
    
    			if pnd.sbic.Exists(tt.args.id) {
    
    				t.Errorf("RemoveSbi() SBI still in SBI store %v", pnd.sbic)
    			}
    
    			if tt.name == "exclusively remove associated devices" {
    				if len(pnd.devices.Store) != 1 {
    					t.Errorf("RemoveSbi() non associated devices should remain in the storage %v", pnd.devices)
    				}
    			} else {
    				if len(pnd.devices.Store) != 0 {
    					t.Errorf("RemoveSbi() associated devices have not been removed correctly %v", len(pnd.devices.Store))
    				}
    
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_Request(t *testing.T) {
    
    	type args struct {
    		uuid uuid.UUID
    		path string
    		rErr error
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    		{
    			name: "default",
    			args: args{
    				uuid: mdid,
    				path: "",
    				rErr: nil,
    			},
    			wantErr: false,
    		},
    		{
    			name: "error",
    			args: args{
    				uuid: did,
    				path: "",
    				rErr: errors.New("deliberate test fail"),
    			},
    			wantErr: true,
    		},
    	}
    
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			deviceWithMockTransport := mockDevice()
    
    			pnd := newPnd()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			tr := deviceWithMockTransport.Transport().(*mocks.Transport)
    			tr.On("Get", mockContext, mock.Anything).Return(&gpb.GetResponse{}, tt.args.rErr)
    
    			tr.On("ProcessResponse", mock.Anything, mock.Anything, mock.Anything).Return(tt.args.rErr)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			_ = pnd.addDevice(deviceWithMockTransport)
    
    			_, err := pnd.Request(tt.args.uuid, tt.args.path)
    			if (err != nil) != tt.wantErr {
    
    				t.Errorf("Request() error = %v, wantErr %v", err, tt.wantErr)
    			}
    
    			if err := pnd.devices.Delete(mdid); err != nil {
    
    		})
    	}
    }
    
    func Test_pndImplementation_RequestAll(t *testing.T) {
    
    	type args struct {
    		uuid uuid.UUID
    		path string
    		rErr error
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    		{
    			name: "default",
    			args: args{
    				uuid: mdid,
    				path: "",
    				rErr: nil,
    			},
    			wantErr: false,
    		},
    		{
    			name: "error",
    			args: args{
    
    				path: "",
    				rErr: errors.New("deliberate test fail"),
    			},
    			wantErr: true,
    		},
    	}
    
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			deviceWithMockTransport := mockDevice()
    
    			pnd := newPnd()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			tr := deviceWithMockTransport.Transport().(*mocks.Transport)
    			tr.On("Get", mockContext, mock.Anything).Return(&gpb.GetResponse{}, tt.args.rErr)
    
    			tr.On("ProcessResponse", mock.Anything, mock.Anything, mock.Anything).Return(tt.args.rErr)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			_ = pnd.addDevice(deviceWithMockTransport)
    
    			if err := pnd.RequestAll(tt.args.path); (err != nil) != tt.wantErr {
    
    				t.Errorf("RequestAll() error = %v, wantErr %v", err, tt.wantErr)
    			}
    
    			if err := pnd.devices.Delete(mdid); err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    func Test_pndImplementation_ChangeOND(t *testing.T) {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	opts := &tpb.TransportOption{
    		TransportOption: &tpb.TransportOption_GnmiTransportOption{
    			GnmiTransportOption: &tpb.GnmiTransportOption{},
    		},
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	}
    	type args struct {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		operation ppb.ApiOperation
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		path      string
    		value     []string
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "update",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: ppb.ApiOperation_UPDATE,
    
    				path:      "/system/config/hostname",
    				value:     []string{"ceos3000"},
    			},
    			wantErr: false,
    		},
    		{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "replace",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: ppb.ApiOperation_REPLACE,
    
    				path:      "/system/config/hostname",
    				value:     []string{"ceos3000"},
    			},
    			wantErr: false,
    		},
    		{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "delete",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: ppb.ApiOperation_DELETE,
    
    				path:      "/system/config/hostname",
    			},
    			wantErr: false,
    		},
    		{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "delete w/args",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: ppb.ApiOperation_DELETE,
    
    				path:      "/system/config/hostname",
    				value:     []string{"ceos3000"},
    			},
    			wantErr: false,
    		},
    
    		// Negative test cases
    		{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "invalid operation",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: 54,
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "invalid arg count",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: ppb.ApiOperation_UPDATE,
    
    				path:      "/system/config/hostname",
    				value:     []string{"ceos3000", "ceos3001"},
    			},
    			wantErr: true,
    		},
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "invalid arg count - update, no args",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			args: args{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: ppb.ApiOperation_UPDATE,
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				path:      "/system/config/hostname",
    			},
    			wantErr: true,
    		},
    		{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "invalid arg count - replace, no args",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			args: args{
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: ppb.ApiOperation_UPDATE,
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				path:      "/system/config/hostname",
    			},
    			wantErr: true,
    		},
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			name: "device not found",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				operation: ppb.ApiOperation_UPDATE,
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			pnd := newPnd()
    			if err := pnd.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
    				t.Error(err)
    			}
    			if err := pnd.AddDevice("testdevice", opts, defaultSbiID); err != nil {
    
    			did, ok := pnd.devices.DeviceNameToUUIDLookup["testdevice"]
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			if !ok {
    				err := errors.New("error fetching device")
    				t.Error(err)
    				return
    			}
    
    
    			_, err := pnd.ChangeOND(did, tt.args.operation, tt.args.path, tt.args.value...)
    			if (err != nil) != tt.wantErr {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				t.Errorf("ChangeOND() error = %v, wantErr %v", err, tt.wantErr)
    
    				if len(pnd.changes.Store) != 1 {
    					t.Errorf("ChangeOND() unexpected change count. got %v, want 1", len(pnd.changes.Store))
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			}
    		})
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    func Test_pndImplementation_GetDevice(t *testing.T) {
    
    	pnd := newPnd()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	sbi := NewSBI(spb.Type_OPENCONFIG)
    
    	d, err := NewDevice("", uuid.Nil, newGnmiTransportOptions(), sbi)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	if err != nil {
    		t.Error(err)
    		return
    	}
    
    	if err = pnd.addDevice(d); err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		t.Error(err)
    		return
    	}
    	type args struct {
    		uuid uuid.UUID
    	}
    	tests := []struct {
    		name    string
    		args    args
    		want    ygot.GoStruct
    		wantErr bool
    	}{
    		{
    			name:    "default",
    			args:    args{uuid: d.ID()},
    			want:    sbi.Schema().Root,
    			wantErr: false,
    		},
    		{
    			name:    "device not found",
    			args:    args{uuid: mdid},
    			want:    nil,
    			wantErr: true,
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			foundDevice, err := pnd.GetDevice(tt.args.uuid.String())
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			if (err != nil) != tt.wantErr {
    				t.Errorf("GetDevice() error = %v, wantErr %v", err, tt.wantErr)
    				return
    			}
    
    			if foundDevice != nil {
    
    				if !reflect.DeepEqual(foundDevice.(device.Device).Model(), tt.want) {
    					t.Errorf("GetDevice() got = %v, want %v", foundDevice.(device.Device).Model(), tt.want)
    
    		})
    	}
    }
    
    func Test_pndImplementation_GetDeviceByName(t *testing.T) {
    	p := newPnd()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	sbi := NewSBI(spb.Type_OPENCONFIG)
    
    	d, err := NewDevice("my-device", uuid.Nil, newGnmiTransportOptions(), sbi)
    
    	if err != nil {
    		t.Error(err)
    		return
    	}
    	if err = p.addDevice(d); err != nil {
    		t.Error(err)
    		return
    	}
    	type args struct {
    		name string
    	}
    	tests := []struct {
    		name    string
    		args    args
    		want    ygot.GoStruct
    		wantErr bool
    	}{
    		{
    			name:    "default",
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			args:    args{name: d.Name()},
    
    			want:    sbi.Schema().Root,
    			wantErr: false,
    		},
    		{
    			name:    "device not found",
    			args:    args{name: "test-device"},
    			want:    nil,
    			wantErr: true,
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    			foundDevice, err := p.GetDevice(tt.args.name)
    			if (err != nil) != tt.wantErr {
    				t.Errorf("GetDeviceByName() error = %v, wantErr %v", err, tt.wantErr)
    				return
    			}
    			if foundDevice != nil {
    
    				if !reflect.DeepEqual(foundDevice.(device.Device).Model(), tt.want) {
    					t.Errorf("GetDeviceByName() got = %v, want %v", foundDevice.(device.Device).Model(), tt.want)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		})
    	}
    }
    
    func Test_pndImplementation_Confirm(t *testing.T) {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	tests := []struct {
    		name    string
    		wantErr bool
    	}{
    		{
    			name:    "default",
    			wantErr: false,
    		},
    		{
    			name:    "uncommitted",
    			wantErr: true,
    		},
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    			pnd := newPnd()
    			d := mockDevice()
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			tr := d.Transport().(*mocks.Transport)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			tr.On("Set", mockContext, mock.Anything, mock.Anything).Return(nil)
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			if err := pnd.addDevice(d); err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				t.Error(err)
    				return
    			}
    
    			_, err := pnd.ChangeOND(d.ID(), ppb.ApiOperation_UPDATE, "system/config/hostname", "ceos3000")
    			if err != nil {
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    				t.Error(err)
    				return
    			}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			u := pnd.PendingChanges()[0]
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			if tt.name != "uncommitted" {
    				if err := pnd.Commit(u); (err != nil) != tt.wantErr {
    					t.Errorf("Confirm() error = %v, wantErr %v", err, tt.wantErr)
    					return
    				}
    			}
    			if err := pnd.Confirm(u); (err != nil) != tt.wantErr {
    				t.Errorf("Confirm() error = %v, wantErr %v", err, tt.wantErr)
    			}
    		})
    	}
    }
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    
    func Test_pndImplementation_PendingChanges(t *testing.T) {
    
    	testName := t.Name()
    	callback := func(first ygot.GoStruct, second ygot.GoStruct) error {
    		log.Infof("callback in test %v", testName)
    		return nil
    	}
    
    
    	store := store.NewChangeStore()
    
    	pending := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback)
    	if err := store.Add(pending); err != nil {
    		t.Error(err)
    		return
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	tests := []struct {
    		name string
    		want []uuid.UUID
    	}{
    		{
    			name: "default",
    
    			want: []uuid.UUID{pending.cuid},
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    			pnd := newPnd()
    
    			pnd.changes = store
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			if got := pnd.PendingChanges(); !reflect.DeepEqual(got, tt.want) {
    				t.Errorf("pndImplementation.PendingChanges() = %v, want %v", got, tt.want)
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_CommittedChanges(t *testing.T) {
    
    	testName := t.Name()
    	callback := func(first ygot.GoStruct, second ygot.GoStruct) error {
    		log.Infof("callback in test %v", testName)
    		return nil
    	}
    
    
    	store := store.NewChangeStore()
    
    	committed := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback)
    	if err := committed.Commit(); err != nil {
    		t.Error(err)
    		return
    	}
    	if err := store.Add(committed); err != nil {
    		t.Error(err)
    		return
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	tests := []struct {
    		name string
    		want []uuid.UUID
    	}{
    		{
    			name: "default",
    
    			want: []uuid.UUID{committed.cuid},
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    			pnd := newPnd()
    
    			pnd.changes = store
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			if got := pnd.CommittedChanges(); !reflect.DeepEqual(got, tt.want) {
    				t.Errorf("pndImplementation.CommittedChanges() = %v, want %v", got, tt.want)
    			}
    		})
    	}
    }
    
    func Test_pndImplementation_ConfirmedChanges(t *testing.T) {
    
    	testName := t.Name()
    	callback := func(first ygot.GoStruct, second ygot.GoStruct) error {
    		log.Infof("callback in test %v", testName)
    		return nil
    	}
    
    	store := store.NewChangeStore()
    
    	confirmed := NewChange(did, &openconfig.Device{}, &openconfig.Device{}, callback)
    	if err := confirmed.Commit(); err != nil {
    		t.Error(err)
    		return
    	}
    	if err := confirmed.Confirm(); err != nil {
    		t.Error(err)
    		return
    	}
    	if err := store.Add(confirmed); err != nil {
    		t.Error(err)
    		return
    	}
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    	tests := []struct {
    		name string
    		want []uuid.UUID
    	}{
    		{
    			name: "default",
    
    			want: []uuid.UUID{confirmed.cuid},
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    			pnd := newPnd()
    
    			pnd.changes = store
    
    Manuel Kieweg's avatar
    Manuel Kieweg committed
    			if got := pnd.ConfirmedChanges(); !reflect.DeepEqual(got, tt.want) {
    				t.Errorf("pndImplementation.ConfirmedChanges() = %v, want %v", got, tt.want)
    			}
    		})
    	}
    }
    
    
    func Test_pndImplementation_LoadStoredDevices(t *testing.T) {
    	type args struct {
    		device interface{}
    		name   string
    		opts   *tpb.TransportOption
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    		{
    			name: "default",
    			args: args{
    				name: "fridolin",
    				opts: &tpb.TransportOption{
    					TransportOption: &tpb.TransportOption_GnmiTransportOption{
    						GnmiTransportOption: &tpb.GnmiTransportOption{},
    					},
    				},
    			},
    			wantErr: false,
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    			pnd := newPnd()
    			if err := pnd.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
    				t.Error(err)
    			}
    			if tt.name == "already exists" {
    				pnd.devices.Store[did] = tt.args.device.(device.Device)
    			}
    			err := pnd.AddDevice(tt.args.name, tt.args.opts, defaultSbiID)
    			if (err != nil) != tt.wantErr {
    				t.Errorf("AddDevice() error = %v, wantErr %v", err, tt.wantErr)
    			}